From 2ef9a9413a4c579cb7af3fe9c4ec5a95ade31dd2 Mon Sep 17 00:00:00 2001 From: William Reid Date: Mon, 25 Feb 2019 17:05:37 -0500 Subject: [PATCH] heartbeats, ssl, constants --- constants.go | 16 +++++++++ rootCA.pem | 25 ++++++++++++++ server.go | 95 +++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 constants.go create mode 100644 rootCA.pem diff --git a/constants.go b/constants.go new file mode 100644 index 0000000..b0a4a07 --- /dev/null +++ b/constants.go @@ -0,0 +1,16 @@ +package main + +const ( + // Gateway addresses + dataEndpoint = "https://sd5-endpoint.engr.uconn.edu:48820/data" + heartbeatEndpoint = "https://sd5-endpoint.engr.uconn.edu:48820/heartbeat" + + // Header constants + headerUUID = "uuid" + headerTimestamp = "time" + + // Time (in seconds) to wait between performing read/send operations + dataReadPeriod = 1 + dataSendPeriod = 10 + heartbeatPeriod = 10 +) diff --git a/rootCA.pem b/rootCA.pem new file mode 100644 index 0000000..95ced7e --- /dev/null +++ b/rootCA.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIERzCCAy+gAwIBAgIJAOmiqMfsrBs/MA0GCSqGSIb3DQEBCwUAMIG5MQswCQYD +VQQGEwJVUzEUMBIGA1UECAwLQ29ubmVjdGljdXQxDzANBgNVBAcMBlN0b3JyczEi +MCAGA1UECgwZVW5pdmVyc2l0eSBvZiBDb25uZWN0aWN1dDEhMB8GA1UECwwYQ1NF +IFNlbmlvciBEZXNpZ24gVGVhbSA1MRUwEwYDVQQDDAxzZDUtZW5kcG9pbnQxJTAj +BgkqhkiG9w0BCQEWFndpbGxpYW0ucmVpZEB1Y29ubi5lZHUwHhcNMTkwMjIwMTQz +ODI0WhcNMjMwMjE5MTQzODI0WjCBuTELMAkGA1UEBhMCVVMxFDASBgNVBAgMC0Nv +bm5lY3RpY3V0MQ8wDQYDVQQHDAZTdG9ycnMxIjAgBgNVBAoMGVVuaXZlcnNpdHkg +b2YgQ29ubmVjdGljdXQxITAfBgNVBAsMGENTRSBTZW5pb3IgRGVzaWduIFRlYW0g +NTEVMBMGA1UEAwwMc2Q1LWVuZHBvaW50MSUwIwYJKoZIhvcNAQkBFhZ3aWxsaWFt +LnJlaWRAdWNvbm4uZWR1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +sa79VMjTVCegD+r+nF/vJJwXWAB55ZqoG0tsuntL3gp4LhY8CelYczltL2HwwAG2 +YMxdo1TTvBxSn/BHhE2h0gamlooCGMEeh+c8/MAjwkeHGH8CT9ywNT7hzmHwbDLW +SIwO1V9rHJpeiC7aXcI3cqR5kS+zine3m2GgQ2LAW0vDpmNYIjJLz3GmQAeTFLnp +TKIQQqGcR1SiosCnMmBVKLLTXyE/blhuqdGJi61LI7YfhAujX4yJISHzdn9GZmQT +G/kKHlva3Ub7tU0gkzX24tB/x4OZDz5eCLTNhgzx+r5VTpDfipSQoSaNSh7lFUU0 +kg/qv0cDmUy00Tea+zo5BwIDAQABo1AwTjAdBgNVHQ4EFgQUABSQnNbFjHULtSGD +UTJb2GKTX8kwHwYDVR0jBBgwFoAUABSQnNbFjHULtSGDUTJb2GKTX8kwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAW4KiJLtjpzDiWZoPNKRYvFDyaZ7O +oNjWn3bPF8fWO//sQgy4o3fZE9LwporZ3Vz9uAJi1mGS3d/r0kPJi/i3pqNsd2hc +PpSHQS+dxgiB6JXDJkQjoSwGiBj4LXOCbeTcgxGt3Yj5lQeO41lv4Rw7n52IbeDx ++0QmK2/DpCjL2jHv/u9HW1V8ZzT/CJ0b9xNmV9TJHO0uJfVnBIWMU9FN4XuRoElU +md7ym3c5fGWvK7UKZn/Z4jUFvcMr/tpHkQMXtE2vzNvGj504Cx/XaTuGOnnMPUAG +LjTQnTEPhck4TXfNZ/BL6gLx+laXxXZBpVyYooVv3cx787SnsIIyB9H17g== +-----END CERTIFICATE----- diff --git a/server.go b/server.go index c60dbcb..8db30dd 100644 --- a/server.go +++ b/server.go @@ -2,20 +2,45 @@ package main import ( "bytes" + "crypto/tls" + "crypto/x509" "encoding/json" + "errors" "fmt" + "io/ioutil" "math/rand" "net/http" "strconv" "time" ) +type gatewayClient struct { + client *http.Client +} + func main() { + rootCAs := x509.NewCertPool() // Initialize a cert pool + rootCert, _ := ioutil.ReadFile("rootCA.pem") // Read our root CA cert + + if ok := rootCAs.AppendCertsFromPEM(rootCert); !ok { + fmt.Printf("Error adding gateway cert") + } + + config := &tls.Config{RootCAs: rootCAs,} // Trust our root CA + + tr := &http.Transport{TLSClientConfig: config,} + client := gatewayClient{&http.Client{Transport: tr}} + dataReadChan := make(chan map[string]StampedReading) // Channel to handle data readings dataBuffer := make(map[string][]StampedReading) // Map to store readings in until they are sent - go dataReadLoop(dataReadChan) // Start our async read loop - dataSendTick := time.NewTicker(time.Second * 10) // Ticker to send data + go dataReadLoop(dataReadChan) // Start our async read loop + dataSendTick := time.NewTicker(time.Second * dataSendPeriod) // Ticker to send data + heartbeatTick := time.NewTicker(time.Second * heartbeatPeriod) // Ticker to send heartbeats + + if err := client.sendHeartbeat(); err != nil { + fmt.Printf("Error sending startup heartbeat: %v\n", err) + } // Non-blocking channel reads for { @@ -37,9 +62,10 @@ func main() { case <-dataSendTick.C: // Time to send some data if len(dataBuffer) > 0 { // Only send if we have data - if err := sendData(dataBuffer); err != nil { // Something went wrong + if err := client.sendData(dataBuffer); err != nil { // Something went wrong fmt.Printf("Error sending data: %v\n", err) } else { // Data sent, clear the map + fmt.Println("Sent data") dataBuffer = make(map[string][]StampedReading) } } else { // There was no data to send @@ -47,6 +73,13 @@ func main() { // TODO: manage the map so that it doesn't run out of memory and kill everything if we don't send data } + case <-heartbeatTick.C: + // Send a heartbeat + if err := client.sendHeartbeat(); err != nil { + fmt.Printf("Error sending heartbeat: %v\n", err) + } else { + fmt.Println("Sent heartbeat") + } } } } @@ -74,35 +107,59 @@ func readData() map[string]StampedReading { } } -func sendData(data map[string][]StampedReading) error { +func (client *gatewayClient) sendData(data map[string][]StampedReading) error { + + jsonStr, err := json.Marshal(data) // Dump our data map into a json string + if err != nil { + return err + } - url := "http://localhost:8081/data" - jsonStr, err := json.Marshal(data) + req, err := http.NewRequest("POST", dataEndpoint, bytes.NewBuffer(jsonStr)) // Create our request if err != nil { - fmt.Printf("Error marshalling data: %v\n", err) return err } - fmt.Printf("Sending json: %v\n", string(jsonStr)) + fillHeader(req) // Get id and timestamp + + resp, err := client.client.Do(req) // Do the request + if err != nil { + return err + } + + defer func() { + if err := resp.Body.Close(); err != nil { // Honestly not sure what this is for + fmt.Printf("Error: %v\n", err) + } + }() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { // Make sure it was successful + return errors.New(fmt.Sprintf("Received a non-200 response: %v\n", resp.StatusCode)) + } + + return nil +} + +func (client *gatewayClient) sendHeartbeat() error { + req, err := http.NewRequest("GET", heartbeatEndpoint, nil) // Send to heartbeat endpoint + if err != nil { + return err + } - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) - fillHeader(req) + fillHeader(req) // Get id and timestamp - client := &http.Client{} - resp, err := client.Do(req) + resp, err := client.client.Do(req) // Do it if err != nil { return err } defer func() { - if err := resp.Body.Close(); err != nil { - fmt.Printf("Error: %v", err) + if err := resp.Body.Close(); err != nil { // This thing again + fmt.Printf("Error: %v\n", err) } }() - fmt.Println("response Status:", resp.Status) - if resp.StatusCode != 200 { - fmt.Printf("Received a non-200 response: %v\n", resp.StatusCode) + if resp.StatusCode < 200 || resp.StatusCode >= 300 { // Make sure it was successful + return errors.New(fmt.Sprintf("Received a non-200 response: %v\n", resp.StatusCode)) } return nil @@ -110,6 +167,6 @@ func sendData(data map[string][]StampedReading) error { func fillHeader(req *http.Request) { // Sets the uuid and timestamp for a request req.Header.Set("Content-Type", "application/json") - req.Header.Set("uuid", "0000001bcd3f") // TODO: get this from somewhere - req.Header.Set("time", strconv.FormatInt(time.Now().Unix(), 10)) + req.Header.Set(headerUUID, "0000001bcd3f") // TODO: get this from somewhere + req.Header.Set(headerTimestamp, strconv.FormatInt(time.Now().Unix(), 10)) }