From 417701110b763b68f08c96aeb8a6cf2bcc45b5a5 Mon Sep 17 00:00:00 2001 From: Sylvain Giroudon Date: Thu, 10 Sep 2020 16:31:07 +0200 Subject: [PATCH] Add support for MQTT-over-WebSocket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aurélien Chevé --- component.mk | 12 ++++- .../main/Kconfig.projbuild | 6 +++ .../main/iothub_client_sample_mqtt.c | 17 ++++++- port/src/socketio_esp.c | 11 +++++ port/src/tlsio_esp_tls.c | 46 ++++++++++++++++--- 5 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 port/src/socketio_esp.c diff --git a/component.mk b/component.mk index d5fbc36..6099655 100644 --- a/component.mk +++ b/component.mk @@ -1,12 +1,13 @@ # # Component Makefile # - + # Component configuration in preprocessor defines CFLAGS += -DUSE_LWIP_SOCKET_FOR_AZURE_IOT COMPONENT_ADD_INCLUDEDIRS := \ azure-iot-sdk-c/c-utility/inc \ +azure-iot-sdk-c/c-utility/inc/azure_c_shared_utility \ azure-iot-sdk-c/c-utility/deps/azure-macro-utils-c/inc \ azure-iot-sdk-c/c-utility/deps/umock-c/inc \ azure-iot-sdk-c/iothub_client/inc \ @@ -14,6 +15,7 @@ azure-iot-sdk-c/serializer/inc \ azure-iot-sdk-c/umqtt/inc \ azure-iot-sdk-c/umqtt/inc/azure_umqtt_c \ azure-iot-sdk-c/deps/parson \ +azure-iot-sdk-c/deps/umock-c/inc \ azure-iot-sdk-c/provisioning_client/inc \ azure-iot-sdk-c/provisioning_client/adapters \ azure-iot-sdk-c/provisioning_client/deps/utpm/inc \ @@ -38,6 +40,7 @@ azure-iot-sdk-c/c-utility/pal/tlsio_options.o \ port/src/agenttime_esp.o \ port/src/platform_esp.o \ port/src/tlsio_esp_tls.o \ +port/src/socketio_esp.o \ \ azure-iot-sdk-c/c-utility/src/xlogging.o \ azure-iot-sdk-c/c-utility/src/singlylinkedlist.o \ @@ -48,6 +51,7 @@ azure-iot-sdk-c/c-utility/src/constmap.o \ azure-iot-sdk-c/c-utility/src/crt_abstractions.o \ azure-iot-sdk-c/c-utility/src/doublylinkedlist.o \ azure-iot-sdk-c/c-utility/src/gballoc.o \ +azure-iot-sdk-c/c-utility/src/gb_rand.o \ azure-iot-sdk-c/c-utility/src/gb_stdio.o \ azure-iot-sdk-c/c-utility/src/gb_time.o \ azure-iot-sdk-c/c-utility/src/hmac.o \ @@ -65,9 +69,13 @@ azure-iot-sdk-c/c-utility/src/strings.o \ azure-iot-sdk-c/c-utility/src/string_tokenizer.o \ azure-iot-sdk-c/c-utility/src/urlencode.o \ azure-iot-sdk-c/c-utility/src/usha.o \ +azure-iot-sdk-c/c-utility/src/utf8_checker.o \ azure-iot-sdk-c/c-utility/src/vector.o \ azure-iot-sdk-c/c-utility/src/xio.o \ +azure-iot-sdk-c/c-utility/src/wsio.o \ azure-iot-sdk-c/c-utility/src/azure_base64.o \ +azure-iot-sdk-c/c-utility/src/uws_frame_encoder.o \ +azure-iot-sdk-c/c-utility/src/uws_client.o \ azure-iot-sdk-c/c-utility/adapters/httpapi_compact.o \ \ \ @@ -82,6 +90,7 @@ azure-iot-sdk-c/iothub_client/src/iothub_message.o \ azure-iot-sdk-c/iothub_client/src/iothubtransport.o \ azure-iot-sdk-c/iothub_client/src/iothubtransportmqtt.o \ azure-iot-sdk-c/iothub_client/src/iothubtransport_mqtt_common.o \ +azure-iot-sdk-c/iothub_client/src/iothubtransportmqtt_websockets.o \ azure-iot-sdk-c/iothub_client/src/iothub_transport_ll_private.o \ azure-iot-sdk-c/iothub_client/src/version.o \ azure-iot-sdk-c/iothub_client/src/blob.o \ @@ -113,6 +122,7 @@ azure-iot-sdk-c/serializer/src/schemaserializer.o \ azure-iot-sdk-c/provisioning_client/src/prov_device_client.o \ azure-iot-sdk-c/provisioning_client/src/prov_transport_mqtt_client.o \ azure-iot-sdk-c/provisioning_client/src/prov_transport_mqtt_common.o \ +azure-iot-sdk-c/provisioning_client/src/prov_transport_mqtt_ws_client.o \ azure-iot-sdk-c/provisioning_client/src/prov_security_factory.o \ azure-iot-sdk-c/provisioning_client/src/prov_device_ll_client.o \ azure-iot-sdk-c/provisioning_client/src/iothub_security_factory.o \ diff --git a/examples/iothub_client_sample_mqtt/main/Kconfig.projbuild b/examples/iothub_client_sample_mqtt/main/Kconfig.projbuild index 1d1bbb9..4e83fb3 100644 --- a/examples/iothub_client_sample_mqtt/main/Kconfig.projbuild +++ b/examples/iothub_client_sample_mqtt/main/Kconfig.projbuild @@ -36,4 +36,10 @@ config MESSAGE_COUNT messages. If the message count is set as 0 then this example will send indefinite messages to the cloud. +config SAMPLE_MQTT_OVER_WEBSOCKET + bool "MQTT over WebSocket" + default n + help + This option enables MQTT over WebSocket protocol, instead of raw MQTT. + endmenu diff --git a/examples/iothub_client_sample_mqtt/main/iothub_client_sample_mqtt.c b/examples/iothub_client_sample_mqtt/main/iothub_client_sample_mqtt.c index e7bb89d..ead18c6 100644 --- a/examples/iothub_client_sample_mqtt/main/iothub_client_sample_mqtt.c +++ b/examples/iothub_client_sample_mqtt/main/iothub_client_sample_mqtt.c @@ -12,12 +12,19 @@ #include "azure_c_shared_utility/crt_abstractions.h" #include "azure_c_shared_utility/platform.h" #include "azure_c_shared_utility/shared_util_options.h" -#include "iothubtransportmqtt.h" #include "iothub_client_options.h" #include "esp_system.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#if CONFIG_SAMPLE_MQTT_OVER_WEBSOCKET + #include "iothubtransportmqtt_websockets.h" + #define PROTOCOL MQTT_WebSocket_Protocol +#else // CONFIG_SAMPLE_MQTT_OVER_WEBSOCKET + #include "iothubtransportmqtt.h" + #define PROTOCOL MQTT_Protocol +#endif // !CONFIG_SAMPLE_MQTT_OVER_WEBSOCKET + #ifdef MBED_BUILD_TIMESTAMP #define SET_TRUSTED_CERT_IN_SAMPLES #endif // MBED_BUILD_TIMESTAMP @@ -148,7 +155,7 @@ void iothub_client_sample_mqtt_run(void) } else { - if ((iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, MQTT_Protocol)) == NULL) + if ((iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, PROTOCOL)) == NULL) { (void)printf("ERROR: iotHubClientHandle is NULL!\r\n"); } @@ -157,6 +164,12 @@ void iothub_client_sample_mqtt_run(void) bool traceOn = true; IoTHubClient_LL_SetOption(iotHubClientHandle, OPTION_LOG_TRACE, &traceOn); +#if CONFIG_SAMPLE_MQTT_OVER_WEBSOCKET + // MQTT over WebSocket requires TLS renegociation + bool enable = 1; + IoTHubDeviceClient_LL_SetOption(iotHubClientHandle, OPTION_SET_TLS_RENEGOTIATION, &enable); +#endif // CONFIG_SAMPLE_MQTT_OVER_WEBSOCKET + IoTHubClient_LL_SetConnectionStatusCallback(iotHubClientHandle, connection_status_callback, NULL); // Setting the Trusted Certificate. This is only necessary on system with without // built in certificate stores. diff --git a/port/src/socketio_esp.c b/port/src/socketio_esp.c new file mode 100644 index 0000000..4c66e99 --- /dev/null +++ b/port/src/socketio_esp.c @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#include + +#include "azure_c_shared_utility/socketio.h" + +const IO_INTERFACE_DESCRIPTION* socketio_get_interface_description(void) +{ + return NULL; +} diff --git a/port/src/tlsio_esp_tls.c b/port/src/tlsio_esp_tls.c index 1f5ad37..caa57e5 100644 --- a/port/src/tlsio_esp_tls.c +++ b/port/src/tlsio_esp_tls.c @@ -11,6 +11,7 @@ #include #include #include +#include "esp_log.h" #include "tlsio_pal.h" #include "azure_c_shared_utility/optimize_size.h" #include "azure_c_shared_utility/gballoc.h" @@ -19,6 +20,7 @@ #include "azure_c_shared_utility/singlylinkedlist.h" #include "azure_c_shared_utility/crt_abstractions.h" #include "azure_c_shared_utility/tlsio_options.h" +#include "azure_c_shared_utility/shared_util_options.h" #include "esp_tls.h" @@ -68,6 +70,7 @@ typedef struct TLS_IO_INSTANCE_TAG char* hostname; SINGLYLINKEDLIST_HANDLE pending_transmission_list; TLSIO_OPTIONS options; + bool set_renegotiation; } TLS_IO_INSTANCE; /* Codes_SRS_TLSIO_30_005: [ The phrase "enter TLSIO_STATE_EXT_ERROR" means the adapter shall call the on_io_error function and pass the on_io_error_context that was supplied in tlsio_open_async. ]*/ @@ -482,6 +485,10 @@ static void tlsio_esp_tls_dowork(CONCRETE_IO_HANDLE tls_io) { int result = esp_tls_conn_new_async(tls_io_instance->hostname, strlen(tls_io_instance->hostname), tls_io_instance->port, &tls_io_instance->esp_tls_cfg, tls_io_instance->esp_tls_handle); if (result == 1) { + if (tls_io_instance->set_renegotiation) { + //ESP_LOGI("esp-azure", "TLSIO_STATE_INIT: Set renegotiation"); + mbedtls_ssl_conf_renegotiation(&tls_io_instance->esp_tls_handle->conf, MBEDTLS_SSL_RENEGOTIATION_ENABLED); + } tls_io_instance->tlsio_state = TLSIO_STATE_OPEN; tls_io_instance->on_open_complete(tls_io_instance->on_open_complete_context, IO_OPEN_OK); } else if (result == -1) { @@ -618,17 +625,44 @@ static int tlsio_esp_tls_setoption(CONCRETE_IO_HANDLE tls_io, const char* option else { /* Codes_SRS_TLSIO_30_121: [ If the optionName parameter is NULL, tlsio_esp_tls_setoption shall do nothing except log an error and return FAILURE. ]*/ - /* Codes_SRS_TLSIO_30_122: [ If the value parameter is NULL, tlsio_esp_tls_setoption shall do nothing except log an error and return FAILURE. ]*/ - /* Codes_SRS_TLSIO_ESP_TLS_COMPACT_30_520 [ The tlsio_esp_tls_setoption shall do nothing and return FAILURE. ]*/ - TLSIO_OPTIONS_RESULT options_result = tlsio_options_set(&tls_io_instance->options, optionName, value); - if (options_result != TLSIO_OPTIONS_RESULT_SUCCESS) + if (optionName == NULL) { - LogError("Failed tlsio_options_set"); + LogError("NULL optionName"); result = MU_FAILURE; } else { - result = 0; + /* Codes_SRS_TLSIO_30_122: [ If the value parameter is NULL, tlsio_esp_tls_setoption shall do nothing except log an error and return FAILURE. ]*/ + if (value == NULL) + { + LogError("NULL value"); + result = MU_FAILURE; + } + else + { + if (strcmp(optionName, OPTION_SET_TLS_RENEGOTIATION) == 0) + { + tls_io_instance->set_renegotiation = *((bool*)(value)); + //ESP_LOGI("esp-azure", "Set renegotiation to : %u", tls_io_instance->set_renegotiation); + mbedtls_ssl_conf_renegotiation(&tls_io_instance->esp_tls_handle->conf, + tls_io_instance->set_renegotiation ? MBEDTLS_SSL_RENEGOTIATION_ENABLED : MBEDTLS_SSL_RENEGOTIATION_DISABLED); + result = 0; + } + else + { + /* Codes_SRS_TLSIO_ESP_TLS_COMPACT_30_520 [ The tlsio_esp_tls_setoption shall do nothing and return FAILURE. ]*/ + TLSIO_OPTIONS_RESULT options_result = tlsio_options_set(&tls_io_instance->options, optionName, value); + if (options_result != TLSIO_OPTIONS_RESULT_SUCCESS) + { + LogError("Failed tlsio_options_set"); + result = MU_FAILURE; + } + else + { + result = 0; + } + } + } } } return result;