This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF9160 HTTPS Issue on sending data

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

Parents Reply Children
No Data
Related