Hi everyone,
I am looking at sending data via HTTPS to Azure.
I have used the https_sample and modified it to send the data to Azure with no issue. But now I am trying to not only send 1 request but several and I got a weird issue.
I use a while loop in which I open a socket, I then set up the tls on this socket, connect to Azure and send the request. In the end of the loop I use the same "clean-up" than in the example (which closes the socket).
Here is my code :
/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic */ #include <string.h> #include <zephyr.h> #include <stdlib.h> #include <net/socket.h> #include <net/bsdlib.h> #include <net/tls_credentials.h> #include <lte_lc.h> #include <at_cmd.h> #include <at_notif.h> #include <modem_key_mgmt.h> #define HTTPS_PORT 443 #define HTTP_HEAD "POST /devices/test-1/messages/events?api-version=2018-06-30 HTTP/1.1\r\nHost: test-aptus.azure-devices.net\r\nConnection: close\r\nAuthorization: SharedAccessSignature sr=test-aptus.azure-devices.net%2Fdevices%2Ftest-1&sig=d4QxSCDxhUHMLO2Jp2ygU0cxhModw0oaNzAQI%2BzVH%2F8%3D&se=601590498671\r\nContent-Type: text/plain\r\nContent-Length: 6\r\n\r\ncancer\r\n" #define HTTP_HEAD_LEN (sizeof(HTTP_HEAD) - 1) #define HTTP_HDR_END "\r\n\r\n" #define RECV_BUF_SIZE 2048 #define TLS_SEC_TAG 42 static const char send_buf[] = HTTP_HEAD; static char recv_buf[RECV_BUF_SIZE]; /* Certificate*/ static const char cert[] = { //#include "../cert/GlobalSign-Root-CA-R2" #include "../cert/Azure" }; BUILD_ASSERT_MSG(sizeof(cert) < KB(4), "Certificate too large"); /* Initialize AT communications */ int at_comms_init(void) { int err; err = at_cmd_init(); if (err) { printk("Failed to initialize AT commands, err %d\n", err); return err; } err = at_notif_init(); if (err) { printk("Failed to initialize AT notifications, err %d\n", err); return err; } return 0; } /* Provision certificate to modem */ int cert_provision(void) { int err; bool exists; u8_t unused; err = modem_key_mgmt_exists(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, &exists, &unused); if (err) { printk("Failed to check for certificates err %d\n", err); return err; } if (exists) { /* For the sake of simplicity we delete what is provisioned * with our security tag and reprovision our certificate. */ err = modem_key_mgmt_delete(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN); if (err) { printk("Failed to delete existing certificate, err %d\n", err); } } printk("Provisioning certificate\n"); /* Provision certificate to the modem */ err = modem_key_mgmt_write(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert, sizeof(cert) - 1); if (err) { printk("Failed to provision certificate, err %d\n", err); return err; } return 0; } /* Setup TLS options on a given socket */ int tls_setup(int fd) { int err; int verify; /* Security tag that we have provisioned the certificate with */ const sec_tag_t tls_sec_tag[] = { TLS_SEC_TAG, }; /* Set up TLS peer verification */ enum { NONE = 0, OPTIONAL = 1, REQUIRED = 2, }; verify = REQUIRED; err = setsockopt(fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify)); if (err) { printk("Failed to setup peer verification, err %d\n", errno); return err; } /* Associate the socket with the security tag * we have provisioned the certificate with. */ err = setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_sec_tag, sizeof(tls_sec_tag)); if (err) { printk("Failed to setup TLS sec tag, err %d\n", errno); return err; } return 0; } void send_request() { printk("Sending a request to microsoft!\n"); int err; int fd; char *p; int bytes; size_t off; struct addrinfo *res; struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM, }; err = getaddrinfo("test-aptus.azure-devices.net", NULL, &hints, &res); if (err) { printk("getaddrinfo() failed, err %d\n", errno); return; } printk("Address info done!\n"); ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTPS_PORT); fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2); printk("\n Socket number %d",fd); if (fd == -1) { printk("Failed to open socket!\n"); goto clean_up; } printk("opened socket!\n"); /* Setup TLS socket options */ err = tls_setup(fd); if (err) { goto clean_up; } printk("tls done...\n"); printk("Connecting to Azure"); err = connect(fd, res->ai_addr, sizeof(struct sockaddr_in)); if (err) { printk("connect() failed, err: %d\n", errno); goto clean_up; } off = 0; do { bytes = send(fd, &send_buf[off], HTTP_HEAD_LEN - off, 0); if (bytes < 0) { printk("send() failed, err %d\n", errno); goto clean_up; } off += bytes; } while (off < HTTP_HEAD_LEN); printk("Sent %d bytes\n", off); off = 0; do { bytes = recv(fd, &recv_buf[off], RECV_BUF_SIZE - off, 0); if (bytes < 0) { printk("recv() failed, err %d\n", errno); goto clean_up; } off += bytes; } while (bytes != 0 /* peer closed connection */); printk("Received %d bytes\n", off); /* Print HTTP response */ p = strstr(recv_buf, "\r\n"); if (p) { off = p - recv_buf; recv_buf[off + 1] = '\0'; printk("\n>\t %s\n\n", recv_buf); } clean_up: printk("Finished, closing socket.\n"); freeaddrinfo(res); (void)close(fd); } void main(void) { int err; printk("HTTPS client sample started\n\r"); err = bsdlib_init(); if (err) { printk("Failed to initialize bsdlib!"); return; } /* Initialize AT comms in order to provision the certificate */ err = at_comms_init(); if (err) { return; } /* Provision certificates before connecting to the LTE network */ err = cert_provision(); if (err) { return; } printk("Waiting for network.. "); err = lte_lc_init_and_connect(); if (err) { printk("Failed to connect to the LTE network, err %d\n", err); return; } printk("OK\n"); send_request(); printk("done\n"); while(true) { //k_cpu_idle(); //printk("test\n"); send_request(); k_usleep(1000 * 5000); } }
When I test it I got the sending of the request working a first time, but the second time the NRF9160 just freezes in the connecting step. It bugs me that I do not get any error message and when debugging the firmware just goes and stays in "cpu_idle.S".
Here is my log :
*** Booting Zephyr OS build v2.1.99-ncs1 *** HTTPS client sample started Provisioning certificate Waiting for network.. OK Sending a request to microsoft! Address info done! Socket number 2 opened socket! tls done... Connecting to azure Sent 340 bytes Received 133 bytes > HTTP/1.1 204 No Content Finished, closing socket. done Sending a request to microsoft! Address info done! Socket number 2 opened socket! tls done... Connecting to azure
I would like to know what is wrong in my code and how I can re-use the socket to send several HTPPS request.
Kind regards,
Thomas