Hi,
I'm trying to make a https post request to my Azure endpoint with a nrf9160 using Zephyr. I've first made the post request in a python script to check if everything is working on the Azure side, and that seems to work fine, I've included the python script below:
(The script first gets a bearer token and then uses that token to make a post request)
import requests from datetime import datetime # Define variables app_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" app_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" tenant_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" dce_uri = "https://log-ingestion-xxxx.westeurope-1.ingest.monitor.azure.com" dcr_immutable_id = "dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" table = "table_name" # Obtain a bearer token scope = "https://monitor.azure.com//.default" body = f"client_id={app_id}&scope={scope}&client_secret={app_secret}&grant_type=client_credentials" headers = {"Content-Type": "application/x-www-form-urlencoded"} uri = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token" response = requests.post(uri, data=body, headers=headers) bearer_token = response.json()["access_token"] # Generate and send some data body = [{ "device" : "2405235235211243", "timestamp" : "2022-02-19T15:30:49.4337994Z", "log_level": "DEBUG", "log_message": "This is a test" }] headers = {"Authorization": f"Bearer {bearer_token}", "Content-Type": "application/json"} uri = f"{dce_uri}/dataCollectionRules/{dcr_immutable_id}/streams/Custom-{table}?api-version=2023-01-01" upload_response = requests.post(uri, json=body, headers=headers)
To implement this on the nrf9160 using Zephyr, I've modified the https_client sample, but I keep getting error -2 on getaddrinfo(). I've included the code below:
/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include <string.h> #include <zephyr/kernel.h> #include <stdlib.h> #include <zephyr/net/socket.h> #include <modem/nrf_modem_lib.h> #include <zephyr/net/tls_credentials.h> #include <modem/pdn.h> #include <modem/lte_lc.h> #include <modem/modem_key_mgmt.h> #define HTTPS_PORT "443" #define HTTPS_HOSTNAME "https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token" #define BODY "client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&scope=https://monitor.azure.com//.default&client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxgrant_type=client_credentials" // #define HTTP_HEAD \ // "HEAD / HTTP/1.1\r\n" \ // "Host: " HTTPS_HOSTNAME ":" HTTPS_PORT "\r\n" \ // "Connection: close\r\n\r\n" #define HTTP_HEAD "POST / HTTP/1.1\r\n"\ "Host: "HTTPS_HOSTNAME"\r\n"\ "Connection: close\r\n"\ "Content-type: application/x-www-form-urlencoded\r\n"\ "\r\n"\ ""BODY"\r\n\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 #define PDN_IPV6_WAIT_MS 1000 static const char send_buf[] = HTTP_HEAD; static char recv_buf[RECV_BUF_SIZE]; static K_SEM_DEFINE(pdn_ipv6_up_sem, 0, 1); /* Certificate for `example.com` */ static const char cert[] = { #include "../cert/DigiCertGlobalRootCA.pem" }; BUILD_ASSERT(sizeof(cert) < KB(4), "Certificate too large"); /* Provision certificate to modem */ int cert_provision(void) { int err; bool exists; int mismatch; /* It may be sufficient for you application to check whether the correct * certificate is provisioned with a given tag directly using modem_key_mgmt_cmp(). * Here, for the sake of the completeness, we check that a certificate exists * before comparing it with what we expect it to be. */ err = modem_key_mgmt_exists(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, &exists); if (err) { printk("Failed to check for certificates err %d\n", err); return err; } if (exists) { mismatch = modem_key_mgmt_cmp(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert, strlen(cert)); if (!mismatch) { printk("Certificate match\n"); return 0; } printk("Certificate mismatch\n"); 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; } void pdn_event_handler(uint8_t cid, enum pdn_event event, int reason) { switch (event) { case PDN_EVENT_CNEC_ESM: printk("PDP context %d error, %s\n", cid, pdn_esm_strerror(reason)); break; case PDN_EVENT_ACTIVATED: printk("PDP context %d activated\n", cid); break; case PDN_EVENT_DEACTIVATED: printk("PDP context %d deactivated\n", cid); break; case PDN_EVENT_NETWORK_DETACH: printk("PDP context %d network detached\n", cid); break; #if !IS_ENABLED(CONFIG_PDN_DEFAULT_FAM_IPV4) case PDN_EVENT_IPV6_UP: printk("PDP context %d IPv6 up\n", cid); k_sem_give(&pdn_ipv6_up_sem); break; case PDN_EVENT_IPV6_DOWN: printk("PDP context %d IPv6 down\n", cid); break; #endif default: printk("PDP context %d, unknown event %d\n", cid, event); break; } } /* 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, }; #if defined(CONFIG_SAMPLE_TFM_MBEDTLS) err = tls_credential_add(tls_sec_tag[0], TLS_CREDENTIAL_CA_CERTIFICATE, cert, sizeof(cert)); if (err) { return err; } #endif /* 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; } err = setsockopt(fd, SOL_TLS, TLS_HOSTNAME, HTTPS_HOSTNAME, sizeof(HTTPS_HOSTNAME) - 1); if (err) { printk("Failed to setup TLS hostname, err %d\n", errno); return err; } return 0; } int main(void) { int err; int fd; char *p; int bytes; size_t off; struct addrinfo *res; struct addrinfo hints = { .ai_flags = AI_NUMERICSERV, /* Let getaddrinfo() set port */ .ai_socktype = SOCK_STREAM, }; char peer_addr[INET6_ADDRSTRLEN]; printk("HTTPS client sample started\n\r"); err = nrf_modem_lib_init(); if (err) { printk("Modem library initialization failed, error: %d\n", err); return 0; } /* Setup a callback for the default PDP context (zero). * Do this before switching to function mode 1 (CFUN=1) * to receive the first activation event. */ err = pdn_default_ctx_cb_reg(pdn_event_handler); if (err) { printk("pdn_default_ctx_cb_reg() failed, err %d\n", err); return 0; } #if !defined(CONFIG_SAMPLE_TFM_MBEDTLS) /* Provision certificates before connecting to the LTE network */ err = cert_provision(); if (err) { return 0; } #endif 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 0; } printk("OK\n"); printk("Looking up %s\n", HTTPS_HOSTNAME); err = getaddrinfo(HTTPS_HOSTNAME, HTTPS_PORT, &hints, &res); if (err) { printk("getaddrinfo() failed, err %d\n", err); return 0; } inet_ntop(res->ai_family, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, peer_addr, INET6_ADDRSTRLEN); printk("Resolved %s (%s)\n", peer_addr, net_family2str(res->ai_family)); if (IS_ENABLED(CONFIG_SAMPLE_TFM_MBEDTLS)) { fd = socket(res->ai_family, SOCK_STREAM | SOCK_NATIVE_TLS, IPPROTO_TLS_1_2); } else { fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TLS_1_2); } if (fd == -1) { printk("Failed to open socket!\n"); goto clean_up; } /* Setup TLS socket options */ err = tls_setup(fd); if (err) { goto clean_up; } printk("Connecting to %s:%d\n", HTTPS_HOSTNAME, ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port)); err = connect(fd, res->ai_addr, res->ai_addrlen); 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); /* Make sure recv_buf is NULL terminated (for safe use with strstr) */ if (off < sizeof(recv_buf)) { recv_buf[off] = '\0'; } else { recv_buf[sizeof(recv_buf) - 1] = '\0'; } /* 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); } printk("Finished, closing socket.\n"); clean_up: freeaddrinfo(res); (void)close(fd); lte_lc_power_off(); return 0; }
HTTPS client sample started Certificate match Waiting for network.. PDP context 0 activated PDP context 0 error, PDN type IPv4 only allowed OK Looking up https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token getaddrinfo() failed, err 0
How do I implement the 2 post request from my python script on the nrf9160 using Zephyr?