diff --git a/samples/net/mqtt_azure/CMakeLists.txt b/samples/net/mqtt_azure/CMakeLists.txt new file mode 100644 index 00000000000..14163b20a19 --- /dev/null +++ b/samples/net/mqtt_azure/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(mqtt-azure) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/net/mqtt_azure/Kconfig b/samples/net/mqtt_azure/Kconfig new file mode 100644 index 00000000000..423b00b228d --- /dev/null +++ b/samples/net/mqtt_azure/Kconfig @@ -0,0 +1,56 @@ +# Kconfig - Private config options for mqtt-azure sample app + +# +# Copyright (c) 2019 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +mainmenu "Networking mqtt-azure sample application" + +config SAMPLE_CLOUD_AZURE_USERNAME + string "Azure cloud username" + help + Username of your Azure account. + +config SAMPLE_CLOUD_AZURE_PASSWORD + string "Azure cloud password" + help + Password of your Azure account. + +config SAMPLE_CLOUD_AZURE_CLIENT_ID + string "Azure cloud IoT hub MQTT client ID" + help + Device ID which you have setup in IoT hub account. + +config SAMPLE_CLOUD_AZURE_HOSTNAME + string "Azure cloud IoT hub hostname" + help + Hostname of your Azure cloud IoT hub. + +config SAMPLE_CLOUD_AZURE_SERVER_ADDR + string "Azure cloud server address" + help + Azure cloud server address. + +config SAMPLE_CLOUD_AZURE_SERVER_PORT + int "Azure cloud server port number" + default 8883 + help + Azure cloud server port number. + +config SAMPLE_SOCKS_ADDR + string "Proxy address" + depends on SOCKS + help + Provide proxy address if you are running this application + behind proxy. + +config SAMPLE_SOCKS_PORT + int "Proxy port" + depends on SOCKS + help + Provide proxy port if you are running this application + behind proxy. + +source "Kconfig.zephyr" diff --git a/samples/net/mqtt_azure/README.rst b/samples/net/mqtt_azure/README.rst new file mode 100644 index 00000000000..769f23e5933 --- /dev/null +++ b/samples/net/mqtt_azure/README.rst @@ -0,0 +1,115 @@ +.. _mqtt-azure-sample: + +MQTT Azure Sample +################# + +Overview +******** + +This sample application demonstrates how an MQTT client +can publish messages to an Azure Cloud IoT hub based on MQTT protocol. + +- Acquire a DHCPv4 lease +- Establish a TLS connection with Azure Cloud IoT hub +- Publish data to the Azure cloud +- SOCKS5 supported +- DNS supported + +The source code of this sample application can be found at: +:zephyr_file:`samples/net/mqtt_azure`. + +Requirements +************ + +- Azure Cloud account +- Azure IOT Cloud credentials and required information +- Freedom Board (FRDM-K64F) +- Network connectivity + +Building and Running +******************** + +This application has been built and tested on the NXP FRDMK64F. +Certs are required to authenticate to the Azure Cloud IoT hub. +Current certs in :zephyr_file:`samples/net/mqtt_azure/src/digicert.cer` are +copied from ``_ + +Configure the following Kconfig options based on your Azure Cloud IoT Hub +in your own overlay config file: + +- SAMPLE_CLOUD_AZURE_USERNAME - Username field use:: + + {iothubhostname}/{device_id}/?api-version=2018-06-30, + + where ``{iothubhostname}`` is the full CName of the IoT hub. + +- SAMPLE_CLOUD_AZURE_PASSWORD - Password field, use an SAS token. +- SAMPLE_CLOUD_AZURE_CLIENT_ID - ClientId field, use the deviceId. +- SAMPLE_CLOUD_AZURE_HOSTNAME - IoT hub hostname +- SAMPLE_CLOUD_AZURE_SERVER_ADDR - IP address of the Azure MQTT broker +- SAMPLE_CLOUD_AZURE_SERVER_PORT - Port number of the Azure MQTT broker + +You'll also need to set these Kconfig options if you're running +the sample behind a proxy: + +- SAMPLE_SOCKS_ADDR - IP address of SOCKS5 Proxy server +- SAMPLE_SOCKS_PORT - Port number of SOCKS5 Proxy server + +On your Linux host computer, open a terminal window, locate the source code +of this sample application (i.e., :zephyr_file:`samples/net/mqtt_azure`) and type: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/mqtt_azure + :board: frdm_k64f + :conf: "prj.conf " + :goals: build flash + :compact: + +Also this application can be tested with QEMU. This is described in +:ref:`networking_with_qemu`. Set up Zephyr and NAT/masquerading on host +to access Internet and use :file:`overlay-qemu_x86.conf`. +DHCP support is not enabled with QEMU. It uses static IP addresses. + +Sample overlay file +=================== + +This is the overlay template for Azure IoT hub and other details: + +.. code-block:: console + + CONFIG_SAMPLE_CLOUD_AZURE_USERNAME="" + CONFIG_SAMPLE_CLOUD_AZURE_PASSWORD="" + CONFIG_SAMPLE_CLOUD_AZURE_CLIENT_ID="" + CONFIG_SAMPLE_CLOUD_AZURE_HOSTNAME="" + CONFIG_SAMPLE_SOCKS_ADDR="" + CONFIG_SAMPLE_SOCKS_PORT= + CONFIG_SAMPLE_CLOUD_AZURE_SERVER_ADDR="" + CONFIG_SAMPLE_CLOUD_AZURE_SERVER_PORT= + +Sample output +============= + +This is the output from the FRDM UART console, with: + +.. code-block:: console + + [00:00:03.001,000] eth_mcux: Enabled 100M full-duplex mode. + [00:00:03.010,000] mqtt_azure.main: Waiting for network to setup... + [00:00:03.115,000] net_dhcpv4: Received: 10.0.0.2 + [00:00:03.124,000] net_config: IPv4 address: 10.0.0.2 + [00:00:03.132,000] net_config: Lease time: 43200 seconds + [00:00:03.140,000] net_config: Subnet: 255.255.255.0 + [00:00:03.149,000] net_config: Router: 10.0.0.10 + [00:00:06.157,000] mqtt_azure.try_to_connect: attempting to connect... + [00:00:06.167,000] net_sock_tls.tls_alloc: (0x200024f8): Allocated TLS context, 0x20001110 + [00:00:19.412,000] mqtt_azure.mqtt_event_handler: MQTT client connected! + [00:00:19.424,000] mqtt_azure.publish_message: mqtt_publish OK + [00:00:19.830,000] mqtt_azure.mqtt_event_handler: PUBACK packet id: 63387 + [00:00:31.842,000] mqtt_azure.publish_message: mqtt_publish OK + [00:00:51.852,000] mqtt_azure.publish_message: mqtt_publish OK + [00:00:51.861,000] mqtt_azure.mqtt_event_handler: PUBACK packet id: 38106 + +You can also check events or messages information on Azure Portal. + +See `Azure Cloud MQTT Documentation +`_. diff --git a/samples/net/mqtt_azure/overlay-qemu_x86.conf b/samples/net/mqtt_azure/overlay-qemu_x86.conf new file mode 100644 index 00000000000..e6656be0a66 --- /dev/null +++ b/samples/net/mqtt_azure/overlay-qemu_x86.conf @@ -0,0 +1,10 @@ + +# Disable DHCPv4 and use static address +CONFIG_NET_DHCPV4=n + +# Use local DNS server on host +CONFIG_DNS_SERVER1="192.0.2.2" + +# Configure static addresses +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" diff --git a/samples/net/mqtt_azure/prj.conf b/samples/net/mqtt_azure/prj.conf new file mode 100644 index 00000000000..a8312afc113 --- /dev/null +++ b/samples/net/mqtt_azure/prj.conf @@ -0,0 +1,71 @@ +CONFIG_NETWORKING=y + +# Disable IPv6 support +CONFIG_NET_IPV6=n + +# Enable IPv4 support +CONFIG_NET_IPV4=y +CONFIG_NET_IF_MAX_IPV4_COUNT=2 +CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 + +# Enable TCP support +CONFIG_NET_TCP=y + +# Enable Sockets support +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y + +# Enable DHCPv4 support +CONFIG_NET_DHCPV4=y + +# Enable SOCKS5 proxy support +CONFIG_SOCKS=n + +# Enable MQTT Lib support +CONFIG_MQTT_LIB=y +CONFIG_MQTT_LIB_TLS=y + +# Enable Mbed TLS configuration +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=100000 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=10240 +CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y + +# Network configuration +CONFIG_NET_CONFIG_SETTINGS=y + +# Network connection manager +CONFIG_NET_CONNECTION_MANAGER=y + +CONFIG_NET_MGMT_EVENT_STACK_SIZE=1024 +CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=5 +CONFIG_NET_MGMT_EVENT_LOG_LEVEL_DBG=n + +CONFIG_DNS_RESOLVER=y +CONFIG_DNS_SERVER_IP_ADDRESSES=y +CONFIG_DNS_SERVER1="8.8.8.8" +CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR=2 +CONFIG_NEWLIB_LIBC=y + +CONFIG_INIT_STACKS=y +CONFIG_NET_SHELL=y + +CONFIG_MAIN_STACK_SIZE=4096 + +# Enable Logging support +CONFIG_LOG_IMMEDIATE=y +CONFIG_NET_LOG=y +CONFIG_NET_TCP_LOG_LEVEL_DBG=n +CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=n +CONFIG_MQTT_LOG_LEVEL_DBG=n +CONFIG_NET_DHCPV4_LOG_LEVEL_INF=n +CONFIG_NET_IF_LOG_LEVEL_DBG=n +CONFIG_MBEDTLS_DEBUG=n +#CONFIG_MBEDTLS_DEBUG_LEVEL=4 +CONFIG_SOCKS_LOG_LEVEL_DBG=n +CONFIG_NET_CONFIG_LOG_LEVEL_DBG=y +CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL_DBG=n +CONFIG_DNS_RESOLVER_LOG_LEVEL_DBG=n +CONFIG_NET_CONTEXT_LOG_LEVEL_DBG=n diff --git a/samples/net/mqtt_azure/sample.yaml b/samples/net/mqtt_azure/sample.yaml new file mode 100644 index 00000000000..9a0bcf2f939 --- /dev/null +++ b/samples/net/mqtt_azure/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: MQTT sample app to Azure cloud + name: mqtt-azure +tests: + sample.net.mqtt_azure: + harness: net + platform_whitelist: sam_e70_xplained frdm_k64f qemu_x86 + tags: net mqtt cloud diff --git a/samples/net/mqtt_azure/src/config.h b/samples/net/mqtt_azure/src/config.h new file mode 100644 index 00000000000..afb9f583278 --- /dev/null +++ b/samples/net/mqtt_azure/src/config.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#define SERVER_ADDR CONFIG_SAMPLE_CLOUD_AZURE_SERVER_ADDR +#define SERVER_PORT CONFIG_SAMPLE_CLOUD_AZURE_SERVER_PORT + +#if defined(CONFIG_SOCKS) +#define SOCKS5_PROXY_ADDR CONFIG_SAMPLE_SOCKS_ADDR +#define SOCKS5_PROXY_PORT CONFIG_SAMPLE_SOCKS_PORT +#endif + +#define MQTT_CLIENTID CONFIG_SAMPLE_CLOUD_AZURE_CLIENT_ID + +#define APP_SLEEP_MSECS 8000 + +#define APP_MQTT_BUFFER_SIZE 1024 + +#endif /* __CONFIG_H__ */ diff --git a/samples/net/mqtt_azure/src/digicert.cer b/samples/net/mqtt_azure/src/digicert.cer new file mode 100644 index 00000000000..cb0db66eb25 --- /dev/null +++ b/samples/net/mqtt_azure/src/digicert.cer @@ -0,0 +1,21 @@ +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\r\n" +"RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\r\n" +"VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\r\n" +"DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\r\n" +"ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\r\n" +"VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\r\n" +"mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\r\n" +"IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\r\n" +"mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\r\n" +"XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\r\n" +"dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\r\n" +"jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\r\n" +"BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\r\n" +"DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\r\n" +"9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\r\n" +"jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\r\n" +"Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\r\n" +"ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\r\n" +"R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\r\n" +"-----END CERTIFICATE-----\r\n" diff --git a/samples/net/mqtt_azure/src/main.c b/samples/net/mqtt_azure/src/main.c new file mode 100644 index 00000000000..2887f0115de --- /dev/null +++ b/samples/net/mqtt_azure/src/main.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(mqtt_azure, LOG_LEVEL_DBG); + +#include +#include +#include + +#include +#include +#include + +#include "config.h" +#include "test_certs.h" + +/* Buffers for MQTT client. */ +static u8_t rx_buffer[APP_MQTT_BUFFER_SIZE]; +static u8_t tx_buffer[APP_MQTT_BUFFER_SIZE]; + +/* The mqtt client struct */ +static struct mqtt_client client_ctx; + +/* MQTT Broker details. */ +static struct sockaddr_storage broker; + +#if defined(CONFIG_SOCKS) +static struct sockaddr socks5_proxy; +#endif + +/* Socket Poll */ +static struct pollfd fds[1]; +static int nfds; + +static bool mqtt_connected; + +static struct k_delayed_work pub_message; +#if defined(CONFIG_NET_DHCPV4) +static struct k_delayed_work check_network_conn; + +/* Network Management events */ +#define L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED) + +static struct net_mgmt_event_callback l4_mgmt_cb; +#endif + +#if defined(CONFIG_DNS_RESOLVER) +static struct addrinfo hints; +static struct addrinfo *haddr; +#endif + +static K_SEM_DEFINE(mqtt_start, 0, 1); +static K_SEM_DEFINE(publish_msg, 0, 1); + +/* Application TLS configuration details */ +#define TLS_SNI_HOSTNAME CONFIG_SAMPLE_CLOUD_AZURE_HOSTNAME +#define APP_CA_CERT_TAG 1 + +static sec_tag_t m_sec_tags[] = { + APP_CA_CERT_TAG, +}; + +static void mqtt_event_handler(struct mqtt_client *const client, + const struct mqtt_evt *evt); + +static int tls_init(void) +{ + int err; + + err = tls_credential_add(APP_CA_CERT_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, + ca_certificate, sizeof(ca_certificate)); + if (err < 0) { + LOG_ERR("Failed to register public certificate: %d", err); + return err; + } + + return err; +} + +static void prepare_fds(struct mqtt_client *client) +{ + if (client->transport.type == MQTT_TRANSPORT_SECURE) { + fds[0].fd = client->transport.tls.sock; + } + + fds[0].events = ZSOCK_POLLIN; + nfds = 1; +} + +static void clear_fds(void) +{ + nfds = 0; +} + +static int wait(int timeout) +{ + int rc = -EINVAL; + + if (nfds <= 0) { + return rc; + } + + rc = poll(fds, nfds, timeout); + if (rc < 0) { + LOG_ERR("poll error: %d", errno); + return -errno; + } + + return rc; +} + +static void broker_init(void) +{ + struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker; + + broker4->sin_family = AF_INET; + broker4->sin_port = htons(SERVER_PORT); + +#if defined(CONFIG_DNS_RESOLVER) + net_ipaddr_copy(&broker4->sin_addr, + &net_sin(haddr->ai_addr)->sin_addr); +#else + inet_pton(AF_INET, SERVER_ADDR, &broker4->sin_addr); +#endif + +#if defined(CONFIG_SOCKS) + struct sockaddr_in *proxy4 = (struct sockaddr_in *)&socks5_proxy; + + proxy4->sin_family = AF_INET; + proxy4->sin_port = htons(SOCKS5_PROXY_PORT); + inet_pton(AF_INET, SOCKS5_PROXY_ADDR, &proxy4->sin_addr); +#endif +} + +static void client_init(struct mqtt_client *client) +{ + static struct mqtt_utf8 password; + static struct mqtt_utf8 username; + struct mqtt_sec_config *tls_config; + + mqtt_client_init(client); + + broker_init(); + + /* MQTT client configuration */ + client->broker = &broker; + client->evt_cb = mqtt_event_handler; + + client->client_id.utf8 = (u8_t *)MQTT_CLIENTID; + client->client_id.size = strlen(MQTT_CLIENTID); + + password.utf8 = (u8_t *)CONFIG_SAMPLE_CLOUD_AZURE_PASSWORD; + password.size = strlen(CONFIG_SAMPLE_CLOUD_AZURE_PASSWORD); + + client->password = &password; + + username.utf8 = (u8_t *)CONFIG_SAMPLE_CLOUD_AZURE_USERNAME; + username.size = strlen(CONFIG_SAMPLE_CLOUD_AZURE_USERNAME); + + client->user_name = &username; + + client->protocol_version = MQTT_VERSION_3_1_1; + + /* MQTT buffers configuration */ + client->rx_buf = rx_buffer; + client->rx_buf_size = sizeof(rx_buffer); + client->tx_buf = tx_buffer; + client->tx_buf_size = sizeof(tx_buffer); + + /* MQTT transport configuration */ + client->transport.type = MQTT_TRANSPORT_SECURE; + + tls_config = &client->transport.tls.config; + + tls_config->peer_verify = 2; + tls_config->cipher_list = NULL; + tls_config->sec_tag_list = m_sec_tags; + tls_config->sec_tag_count = ARRAY_SIZE(m_sec_tags); + tls_config->hostname = TLS_SNI_HOSTNAME; + +#if defined(CONFIG_SOCKS) + mqtt_client_set_proxy(client, &socks5_proxy, + socks5_proxy.sa_family == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); +#endif +} + +static void mqtt_event_handler(struct mqtt_client *const client, + const struct mqtt_evt *evt) +{ + switch (evt->type) { + case MQTT_EVT_CONNACK: + if (evt->result) { + LOG_ERR("MQTT connect failed %d", evt->result); + break; + } + + mqtt_connected = true; + LOG_DBG("MQTT client connected!"); + break; + + case MQTT_EVT_DISCONNECT: + LOG_DBG("MQTT client disconnected %d", evt->result); + + mqtt_connected = false; + clear_fds(); + break; + + case MQTT_EVT_PUBACK: + if (evt->result) { + LOG_ERR("MQTT PUBACK error %d", evt->result); + break; + } + + LOG_DBG("PUBACK packet id: %u\n", evt->param.puback.message_id); + break; + + default: + LOG_DBG("Unhandled MQTT event %d", evt->type); + break; + } +} + +static int publish(struct mqtt_client *client, enum mqtt_qos qos) +{ + char payload[] = "{id=123}"; + char topic[] = "devices/" MQTT_CLIENTID "/messages/events/"; + u8_t len = strlen(topic); + struct mqtt_publish_param param; + + param.message.topic.qos = qos; + param.message.topic.topic.utf8 = (u8_t *)topic; + param.message.topic.topic.size = len; + param.message.payload.data = payload; + param.message.payload.len = strlen(payload); + param.message_id = sys_rand32_get(); + param.dup_flag = 0U; + param.retain_flag = 0U; + + return mqtt_publish(client, ¶m); +} + +/* Random time between 10 - 15 seconds + * If you prefer to have this value more than CONFIG_MQTT_KEEPALIVE, + * then keep the application connection live by calling mqtt_live() + * in regular intervals. + */ +static u8_t timeout_for_publish(void) +{ + return (10 + sys_rand32_get() % 5); +} + +static void publish_timeout(struct k_work *work) +{ + k_sem_give(&publish_msg); +} + +static void publish_message(void) +{ + while (mqtt_connected) { + int rc; + + rc = publish(&client_ctx, MQTT_QOS_1_AT_LEAST_ONCE); + if (rc) { + LOG_ERR("mqtt_publish ERROR"); + goto end; + } + + LOG_DBG("mqtt_publish OK"); + + rc = wait(APP_SLEEP_MSECS); + if (rc <= 0) { + goto end; + } + + mqtt_input(&client_ctx); + +end: + k_delayed_work_submit(&pub_message, + MSEC_PER_SEC * timeout_for_publish()); + k_sem_take(&publish_msg, K_FOREVER); + } +} + +static int try_to_connect(struct mqtt_client *client) +{ + u8_t retries = 3U; + int rc; + + LOG_DBG("attempting to connect..."); + + while (retries--) { + client_init(client); + + rc = mqtt_connect(client); + if (rc) { + LOG_ERR("mqtt_connect failed %d", rc); + continue; + } + + prepare_fds(client); + + rc = wait(APP_SLEEP_MSECS); + if (rc < 0) { + mqtt_abort(client); + return rc; + } + + mqtt_input(client); + + if (mqtt_connected) { + return 0; + } + + mqtt_abort(client); + + wait(10 * MSEC_PER_SEC); + } + + return -EINVAL; +} + +#if defined(CONFIG_DNS_RESOLVER) +static int get_mqtt_broker_addrinfo(void) +{ + int retries = 3; + int rc = -EINVAL; + + while (retries--) { + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + + rc = getaddrinfo(CONFIG_SAMPLE_CLOUD_AZURE_HOSTNAME, "8883", + &hints, &haddr); + if (rc == 0) { + LOG_INF("DNS resolved for %s:%d", + CONFIG_SAMPLE_CLOUD_AZURE_HOSTNAME, + CONFIG_SAMPLE_CLOUD_AZURE_SERVER_PORT); + + return 0; + } + + LOG_ERR("DNS not resolved for %s:%d, retrying", + CONFIG_SAMPLE_CLOUD_AZURE_HOSTNAME, + CONFIG_SAMPLE_CLOUD_AZURE_SERVER_PORT); + } + + return rc; +} +#endif + +static void connect_to_cloud_and_publish(void) +{ + int rc = -EINVAL; + +#if defined(CONFIG_NET_DHCPV4) + while (true) { + k_sem_take(&mqtt_start, K_FOREVER); +#endif +#if defined(CONFIG_DNS_RESOLVER) + rc = get_mqtt_broker_addrinfo(); + if (rc) { + return; + } +#endif + rc = try_to_connect(&client_ctx); + if (rc) { + return; + } + + publish_message(); +#if defined(CONFIG_NET_DHCPV4) + } +#endif +} + +/* DHCP tries to renew the address after interface is down and up. + * If DHCPv4 address renewal is success, then it doesn't generate + * any event. We have to monitor this way. + * If DHCPv4 attempts exceeds maximum number, it will delete iface + * address and attempts for new request. In this case we can rely + * on IPV4_ADDR_ADD event. + */ +#if defined(CONFIG_NET_DHCPV4) +static void check_network_connection(struct k_work *work) +{ + struct net_if *iface; + + if (mqtt_connected) { + return; + } + + iface = net_if_get_default(); + if (!iface) { + goto end; + } + + if (iface->config.dhcpv4.state == NET_DHCPV4_BOUND) { + k_sem_give(&mqtt_start); + return; + } + + LOG_INF("waiting for DHCP to acquire addr"); + +end: + k_delayed_work_submit(&check_network_conn, 3 * MSEC_PER_SEC); +} +#endif + +#if defined(CONFIG_NET_DHCPV4) +static void abort_mqtt_connection(void) +{ + if (mqtt_connected) { + mqtt_connected = false; + mqtt_abort(&client_ctx); + k_delayed_work_cancel(&pub_message); + } +} + +static void l4_event_handler(struct net_mgmt_event_callback *cb, + u32_t mgmt_event, struct net_if *iface) +{ + if ((mgmt_event & L4_EVENT_MASK) != mgmt_event) { + return; + } + + if (mgmt_event == NET_EVENT_L4_CONNECTED) { + /* Wait for DHCP to be back in BOUND state */ + k_delayed_work_submit(&check_network_conn, 3 * MSEC_PER_SEC); + + return; + } + + if (mgmt_event == NET_EVENT_L4_DISCONNECTED) { + k_sem_give(&publish_msg); + abort_mqtt_connection(); + k_delayed_work_cancel(&check_network_conn); + + return; + } +} +#endif + +void main(void) +{ + int rc; + + LOG_DBG("Waiting for network to setup..."); + + rc = tls_init(); + if (rc) { + return; + } + + k_delayed_work_init(&pub_message, publish_timeout); + +#if defined(CONFIG_NET_DHCPV4) + k_delayed_work_init(&check_network_conn, check_network_connection); + + net_mgmt_init_event_callback(&l4_mgmt_cb, l4_event_handler, + L4_EVENT_MASK); + net_mgmt_add_event_callback(&l4_mgmt_cb); +#endif + + connect_to_cloud_and_publish(); +} diff --git a/samples/net/mqtt_azure/src/test_certs.h b/samples/net/mqtt_azure/src/test_certs.h new file mode 100644 index 00000000000..e52ca230f1f --- /dev/null +++ b/samples/net/mqtt_azure/src/test_certs.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __TEST_CERTS_H__ +#define __TEST_CERTS_H__ + +static const unsigned char ca_certificate[] = { +#include "digicert.cer" +}; + +#endif /* __TEST_CERTS_H__ */