From d2a5facdca5fb599dcbdd08e072bcf0fc98fa808 Mon Sep 17 00:00:00 2001 From: Espressif Systems Date: Tue, 27 Mar 2018 19:45:06 +0800 Subject: [PATCH] feat(mqtt): add APIs for mqtt ssl functionality internal: 2c667eef --- VERSION | 7 +- examples/mqtt_demo/README.md | 170 ++++++++++++- examples/mqtt_demo/include/user_config.h | 7 +- examples/mqtt_demo/user/MQTTEcho.c | 224 +++++++++-------- include/mqtt/MQTTFreeRTOS.h | 91 +++++-- lib/libmqtt.a | Bin 77208 -> 81646 bytes third_party/mqtt/platform/MQTTFreeRTOS.c | 308 ++++++++++++++++++----- 7 files changed, 606 insertions(+), 201 deletions(-) diff --git a/VERSION b/VERSION index b2e93f67..a9be58dc 100644 --- a/VERSION +++ b/VERSION @@ -11,11 +11,12 @@ gwen: wps: ff84a8b gitlab: + driver: 7bee5263 espconn: 3a998034 freertos: a9985a9c lwip: 1651e055 - driver: 7bee5263 mbedtls: 1ac9f1f4 - ssl: eefb383a + mqtt: 6c098065 + nopoll: 31f0ea07 openssl: 1669353f - nopoll: 31f0ea07 \ No newline at end of file + ssl: eefb383a \ No newline at end of file diff --git a/examples/mqtt_demo/README.md b/examples/mqtt_demo/README.md index 9c9958ec..b6625159 100644 --- a/examples/mqtt_demo/README.md +++ b/examples/mqtt_demo/README.md @@ -1,12 +1,168 @@ -# Paho MQTT demo +# ESP8266 MQTT Client Demo -This example shows how to use the Eclipse Paho MQTT as an example of ESP8266 RTOS SDK. In this demo, the following functions can be realized: MQTT publish, subscribe and ping. +## 1. Introduction -1. Config SSID and PASSWORD of the Wi-Fi AP to be connected in user_config.h +This MQTT demo is based on the Eclipse Paho MQTT library, and demonstrates a working MQTT client actions(subscribe, publish, ping). Using this MQTT demo, you can connect to the MQTT broker, subscribe to a topic and publish messages to the predefined topic. -2. Config MQTT Broker to be connected in MQTTEcho.c +Also, this demo will ping the MQTT broker in the defined interval if no sending or receiving action happens. And we add some APIs to realize the SSL functionality, these SSL APIs provide the one-way certification and two-way certification. -3. Export SDK_PATH and BIN_PATH, run gen_misc.sh to compile, then download and run the demo +## 2. Configuration -4. MQTT client will connect with the MQTT Broker, subscribe to the topic "ESP8266/sample/sub", and will publish messages - to the topic "ESP8266/sample/pub" +Some basic configurations need to be done before starting this demo and are listed in the include/user_config.h. + +* Wi-Fi SSID & Password +* MQTT Broker Address(can be a domain name) & MQTT Port +>Note: There is a publically accessible sandbox server for the Eclipse IoT projects available at iot.eclipse.org, please get some reference information from the website: https://iot.eclipse.org/getting-started + +## 3. Description + +### 3.1 MQTT-Normal + +This section describes the mqtt informations and API for MQTT client without SSL functionality. + +#### 3.1.1 MQTT Info + +For this MQTT demo, mqtt-related informations are defined in the mqtt_client_thread(), and they are listed below. + +* two buffers(i.e. sendbuf[80] & readbuf[80]) to store packets to be sent and received +* MQTTVersion, ClientID, KeepAliveInterval, etc are defined using **MQTTPacket_connectData_initializer** +* Command_timeout is defined as 30s, and you can use this value as default +* The subscribe topic is defined as "ESP8266/sample/sub" +* The subscribe message handler is "void messageArrived(MessageData* data)" +* The publish topic is defined as "ESP8266/sample/pub" +* The published message's QoS type is QoS2 + +These informarions are only defined as a demonstration, you can change them appropriately according to your own requirements. + +#### 3.1.2 Major API + +1.Platform-Related + +* NetworkInit(): used to initialize **Network** structure, which includes read/write functions, etc. +* NetworkConnect(): used to create socket and connect to the MQTT broker + +2.MQTT-Related + +* MQTTClientInit(): used to initialize **MQTTClient** structure, which includes MQTT client information +* MQTTStartTask(): a task used to perform MQTT **keep alive** +* MQTTConnect(): used to perform MQTT connect +* MQTTSubscribe(): used to subscribe to a topic +* MQTTPublish(): used to publish messages to a topic + +### 3.2 MQTT-SSL + +This section describes the mqtt informations and API for MQTT client with SSL functionality enabled. + +#### 3.2.1 MQTT Info + +The aforementioned informations in the **MQTT Info** section of **MQTT-Normal** are also used for MQTT-SSL. As for SSL functionality, some more information will be needed and are listed below in the "Added-Info" section. + +1.Existed-Info + +This section is the same with the **MQTT Info** section of **MQTT-Normal**. + +2.Added-Info + +* May need header files of CA (and client certificate & key) included in the include/ directory +* May need length of the CA (and client certificate & key) files +* Need a **ssl_ca_crt_key_t** structure initialized using the CA (and client certificate & key) files + +#### 3.2.2 Major API + +When SSL is enabled, the Platform-related API are different with **MQTT-Normal** section. + +1.Platform-related + +* NetworkInitSSL(): used to initialize **Network** structure, which includes SSL read/write functions, etc. +* NetworkConnectSSL(): used to create socket and connect to the MQTT broker with SSL enabled + +2.MQTT-Related + +This section is the same with the "MQTT-Related" section of "MQTT-Normal". + +#### 3.2.3 SSL Special + +For SSL functionality, three certification ways may be used: no certification, one-way certification and two-way certification. The specific configurations for each of them are described below: + +1.No Certification + +* No CA file and client certificate & key files need to be included +* Define a **ssl_ca_crt_key_t** structure +* Set the **cacrt**, **cert** and **key** parameters within the structure to be **NULL** +* Recommend to set the **verify_mode** parameter to **SSL_VERIFY_NONE** +* Set the **method** parameter to **TLSv1_1_client_method()** or **TLSv1_2_client_method()** +* Set the **frag_len** parameter with a value between **2048** and **8192** + +2.One-way Certification + +* CA file shall be included, also length of the CA file shall be provided +* Define a **ssl_ca_crt_key_t** structure +* Set the **cacrt** parameter within the structure to the array in the CA file +* Set the **cacrt_len** parameter to length of the CA file +* Set the **verify_mode** parameter to **SSL_VERIFY_PEER** +* Set the **method** parameter to **TLSv1_1_client_method()** or **TLSv1_2_client_method()** +* Set the **frag_len** parameter with a value between **2048** and **8192** + +3.Two-way Certification + +* CA file and client certificate & key files shall be included +* Also length of the CA file and client certificate & key files shall be provided +* Define a **ssl_ca_crt_key_t** structure +* Set the **cacrt** parameter within the structure to the array in the CA file +* Set the **cacrt_len** parameter to length of the CA file +* Set the **cert** parameter within the structure to the array in the client certificate file +* Set the **cert_len** parameter to length of the client certificate file +* Set the **key** parameter within the structure to the array in the client key file +* Set the **key_len** parameter to length of the client key file +* Set the **verify_mode** parameter to **SSL_VERIFY_PEER** +* Set the **method** parameter to **TLSv1_1_client_method()** or **TLSv1_2_client_method()** +* Set the **frag_len** parameter with a value between **2048** and **8192** + +>Note: two-way certification is decided by the SSL Server side, so on the client side we just provide all the files needed by the two-way certification. + +#### 3.2.4 SSL Demo + +The following shows a simple demo of the MQTT client SSL functionality, and only the different places compared with MQTT-Normal demo are displayed. The names of CA file, client certificate & key files are just a demonstration, changing these properly according to your own files. + +```c +#include "openssl/ssl.h" +#include "CA.h" +#include "cert.h" +#include "key.h" + +ssl_ca_crt_key_t ssl_cck; + +#define SSL_CA_CERT_KEY_INIT(s,a,b,c,d,e,f) ((ssl_ca_crt_key_t *)s)->cacrt = a;\ + ((ssl_ca_crt_key_t *)s)->cacrt_len = b;\ + ((ssl_ca_crt_key_t *)s)->cert = c;\ + ((ssl_ca_crt_key_t *)s)->cert_len = d;\ + ((ssl_ca_crt_key_t *)s)->key = e;\ + ((ssl_ca_crt_key_t *)s)->key_len = f; + +static void mqtt_client_thread(void *pvParameters) +{ + ...... + NetworkInitSSL(&network); + ...... + SSL_CA_CERT_KEY_INIT(&ssl_cck, ca_crt, ca_crt_len, client_crt, client_crt_len, client_key, client_key_len); + + if ((rc = NetworkConnectSSL(&network, address, MQTT_PORT, &ssl_cck, TLSv1_1_client_method(), SSL_VERIFY_NONE, 8192)) != 1) { + printf("Return code from network connect ssl is %d\n", rc); + } + ...... +} +``` + +## 4. Compiling & Execution + +Once all the aforementioned works are done, we can compile and download the MQTT client (SSL) demo, and a few more steps will be needed. + +* Export SDK_PATH & BIN_PATH, and run gen_misc.sh to compile and generate binary files +* Download the binary files to flash and run, also you can use UART console to watch the output log + +All these being done, the MQTT client demo will: + +* Connect to the MQTT Broker +* Subscribe to the topic "ESP8266/sample/sub" +* Publish messages to the topic "ESP8266/sample/pub" every 1 seconds +* MQTT keep alive interval is 60s, so if no sending and receiving actions happended during this interval, ping request will be sent and ping response is expected to be received. \ No newline at end of file diff --git a/examples/mqtt_demo/include/user_config.h b/examples/mqtt_demo/include/user_config.h index 46d5a724..cd378949 100644 --- a/examples/mqtt_demo/include/user_config.h +++ b/examples/mqtt_demo/include/user_config.h @@ -25,8 +25,11 @@ #ifndef __USER_CONFIG_H__ #define __USER_CONFIG_H__ -#define SSID "TEST001" -#define PASSWORD "1234567890" +#define SSID "espressif" /* Wi-Fi SSID */ +#define PASSWORD "1234567890" /* Wi-Fi Password */ + +#define MQTT_BROKER "iot.eclipse.org" /* MQTT Broker Address*/ +#define MQTT_PORT 1883 /* MQTT Port*/ #endif diff --git a/examples/mqtt_demo/user/MQTTEcho.c b/examples/mqtt_demo/user/MQTTEcho.c index 50fb1b0d..53252078 100755 --- a/examples/mqtt_demo/user/MQTTEcho.c +++ b/examples/mqtt_demo/user/MQTTEcho.c @@ -1,106 +1,118 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corp. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Ian Craggs - initial API and implementation and/or initial documentation - *******************************************************************************/ - -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "mqtt/MQTTClient.h" - -#define MQTT_CLIENT_THREAD_NAME "mqtt_client_thread" -#define MQTT_CLIENT_THREAD_STACK_WORDS 2048 -#define MQTT_CLIENT_THREAD_PRIO 8 -LOCAL xTaskHandle mqttc_client_handle; - -#define MQTT_BROKER "192.168.1.100" /* Address of the MQTT Broker to be connected*/ - -void messageArrived(MessageData* data) -{ - printf("Message arrived: %s\n", data->message->payload); -} - -static void mqtt_client_thread(void *pvParameters) -{ - printf("mqtt client thread starts\n"); - MQTTClient client; - Network network; - unsigned char sendbuf[80], readbuf[80] = {0}; - int rc = 0, count = 0; - MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer; - - pvParameters = 0; - NetworkInit(&network); - MQTTClientInit(&client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf)); - - char* address = MQTT_BROKER; - if ((rc = NetworkConnect(&network, address, 1883)) != 0) - printf("Return code from network connect is %d\n", rc); - -#if defined(MQTT_TASK) - if ((rc = MQTTStartTask(&client)) != pdPASS) - printf("Return code from start tasks is %d\n", rc); - else - printf("Use MQTTStartTask\n"); -#endif - - connectData.MQTTVersion = 3; - connectData.clientID.cstring = "ESP8266_sample"; - - if ((rc = MQTTConnect(&client, &connectData)) != 0) - printf("Return code from MQTT connect is %d\n", rc); - else - printf("MQTT Connected\n"); - - if ((rc = MQTTSubscribe(&client, "ESP8266/sample/sub", 2, messageArrived)) != 0) - printf("Return code from MQTT subscribe is %d\n", rc); - else - printf("MQTT subscribe to topic \"ESP8266/sample/sub\"\n"); - - while (++count) { - MQTTMessage message; - char payload[30]; - - message.qos = QOS2; - message.retained = 0; - message.payload = payload; - sprintf(payload, "message number %d", count); - message.payloadlen = strlen(payload); - - if ((rc = MQTTPublish(&client, "ESP8266/sample/pub", &message)) != 0) - printf("Return code from MQTT publish is %d\n", rc); - else - printf("MQTT publish topic \"ESP8266/sample/pub\", message number is %d\n", count); - - vTaskDelay(100000 / portTICK_RATE_MS); //send every 100 seconds - } - - printf("mqtt_client_thread going to be deleted\n"); - vTaskDelete(NULL); - return; -} - -void user_conn_init(void) -{ - int ret; - ret = xTaskCreate(mqtt_client_thread, - MQTT_CLIENT_THREAD_NAME, - MQTT_CLIENT_THREAD_STACK_WORDS, - NULL, - MQTT_CLIENT_THREAD_PRIO, - &mqttc_client_handle); - if (ret != pdPASS) { - printf("mqtt create client thread %s failed\n", MQTT_CLIENT_THREAD_NAME); - } -} +/******************************************************************************* + * Copyright (c) 2014 IBM Corp. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Ian Craggs - initial API and implementation and/or initial documentation + *******************************************************************************/ + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "mqtt/MQTTClient.h" + +#include "user_config.h" + +#define MQTT_CLIENT_THREAD_NAME "mqtt_client_thread" +#define MQTT_CLIENT_THREAD_STACK_WORDS 2048 +#define MQTT_CLIENT_THREAD_PRIO 8 + +LOCAL xTaskHandle mqttc_client_handle; + +static void messageArrived(MessageData* data) +{ + printf("Message arrived: %s\n", data->message->payload); +} + +static void mqtt_client_thread(void* pvParameters) +{ + printf("mqtt client thread starts\n"); + MQTTClient client; + Network network; + unsigned char sendbuf[80], readbuf[80] = {0}; + int rc = 0, count = 0; + MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer; + + pvParameters = 0; + NetworkInit(&network); + MQTTClientInit(&client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf)); + + char* address = MQTT_BROKER; + + if ((rc = NetworkConnect(&network, address, MQTT_PORT)) != 0) { + printf("Return code from network connect is %d\n", rc); + } + +#if defined(MQTT_TASK) + + if ((rc = MQTTStartTask(&client)) != pdPASS) { + printf("Return code from start tasks is %d\n", rc); + } else { + printf("Use MQTTStartTask\n"); + } + +#endif + + connectData.MQTTVersion = 3; + connectData.clientID.cstring = "ESP8266_sample"; + + if ((rc = MQTTConnect(&client, &connectData)) != 0) { + printf("Return code from MQTT connect is %d\n", rc); + } else { + printf("MQTT Connected\n"); + } + + if ((rc = MQTTSubscribe(&client, "ESP8266/sample/sub", 2, messageArrived)) != 0) { + printf("Return code from MQTT subscribe is %d\n", rc); + } else { + printf("MQTT subscribe to topic \"ESP8266/sample/sub\"\n"); + } + + while (++count) { + MQTTMessage message; + char payload[30]; + + message.qos = QOS2; + message.retained = 0; + message.payload = payload; + sprintf(payload, "message number %d", count); + message.payloadlen = strlen(payload); + + if ((rc = MQTTPublish(&client, "ESP8266/sample/pub", &message)) != 0) { + printf("Return code from MQTT publish is %d\n", rc); + } else { + printf("MQTT publish topic \"ESP8266/sample/pub\", message number is %d\n", count); + } + + vTaskDelay(1000 / portTICK_RATE_MS); //send every 1 seconds + } + + printf("mqtt_client_thread going to be deleted\n"); + vTaskDelete(NULL); + return; +} + +void user_conn_init(void) +{ + int ret; + ret = xTaskCreate(mqtt_client_thread, + MQTT_CLIENT_THREAD_NAME, + MQTT_CLIENT_THREAD_STACK_WORDS, + NULL, + MQTT_CLIENT_THREAD_PRIO, + &mqttc_client_handle); + + if (ret != pdPASS) { + printf("mqtt create client thread %s failed\n", MQTT_CLIENT_THREAD_NAME); + } +} diff --git a/include/mqtt/MQTTFreeRTOS.h b/include/mqtt/MQTTFreeRTOS.h index 3ad67092..7ec4d288 100755 --- a/include/mqtt/MQTTFreeRTOS.h +++ b/include/mqtt/MQTTFreeRTOS.h @@ -21,20 +21,24 @@ #include "freertos/semphr.h" #include "freertos/task.h" -typedef struct Timer -{ - portTickType xTicksToWait; - xTimeOutType xTimeOut; +#include "openssl/ssl.h" + +typedef struct Timer { + portTickType xTicksToWait; + xTimeOutType xTimeOut; } Timer; typedef struct Network Network; -struct Network -{ - int my_socket; - int (*mqttread) (Network*, unsigned char*, int, int); - int (*mqttwrite) (Network*, unsigned char*, int, int); - void (*disconnect) (Network*); +struct Network { + int my_socket; + int (*mqttread)(Network*, unsigned char*, unsigned int, unsigned int); + int (*mqttwrite)(Network*, unsigned char*, unsigned int, unsigned int); + void (*disconnect)(Network*); + + int read_count; + SSL_CTX* ctx; + SSL* ssl; }; void TimerInit(Timer*); @@ -43,28 +47,73 @@ void TimerCountdownMS(Timer*, unsigned int); void TimerCountdown(Timer*, unsigned int); int TimerLeftMS(Timer*); -typedef struct Mutex -{ - xSemaphoreHandle sem; +typedef struct Mutex { + xSemaphoreHandle sem; } Mutex; void MutexInit(Mutex*); int MutexLock(Mutex*); int MutexUnlock(Mutex*); -typedef struct Thread -{ - xTaskHandle task; +typedef struct Thread { + xTaskHandle task; } Thread; int ThreadStart(Thread*, void (*fn)(void*), void* arg); -int esp_read(Network*, unsigned char*, int, int); -int esp_write(Network*, unsigned char*, int, int); -void esp_disconnect(Network*); - +/** + * @brief Initialize the network structure + * + * @param m - network structure + * + * @return void + */ void NetworkInit(Network*); -int NetworkConnect(Network*, char*, int); + +/** + * @brief connect with mqtt broker + * + * @param n - mqtt network struct + * @param addr - mqtt broker address + * @param port - mqtt broker port + * + * @return connect status + */ +int NetworkConnect(Network* n, char* addr, int port); + +typedef struct ssl_ca_crt_key { + unsigned char* cacrt; + unsigned int cacrt_len; + unsigned char* cert; + unsigned int cert_len; + unsigned char* key; + unsigned int key_len; +} ssl_ca_crt_key_t; + +/** + * @brief Initialize the network structure for SSL connection + * + * @param m - network structure + * + * @return void + */ +void NetworkInitSSL(Network* n); + +/** + * @brief Use SSL to connect with mqtt broker + * + * @param n - mqtt network struct + * @param addr - mqtt broker address + * @param port - mqtt broker port + * @param ssl_cck - client CA, certificate and private key + * @param method - SSL context client method + * @param verify_mode - SSL verifying mode + * @param frag_len - SSL read buffer length + * + * @return connect status + */ +int NetworkConnectSSL(Network* n, char* addr, int port, ssl_ca_crt_key_t* ssl_cck, const SSL_METHOD* method, int verify_mode, unsigned int frag_len); + /*int NetworkConnectTLS(Network*, char*, int, SlSockSecureFiles_t*, unsigned char, unsigned int, char);*/ #endif diff --git a/lib/libmqtt.a b/lib/libmqtt.a index 20f27ae687e7d9a741ad2e55ee52e5da5ac87d62..138f30576f8b0553e4ecb337c70a481b190090f9 100644 GIT binary patch delta 16721 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 delta 12807 zcmbta4SZC^wZF63&2ExSST>tYNCMep^RXcz*?ba80?UUsLcj>IQVk@0L_>)rK&rGV zn^sCuK_Lgd{w%dvQ7O&C^tZI3m1>~YNBz;7B5m_~@{zV!X$1*=yp}4;J7;!g?{rIx zv?rOp|8wTdxp!vHeB3klgOANmzhmB(ZY`^~p-=3WwtoCqfjn_2oc1^QwGt#(b zP5V#N475RMZvVAYaPgp~T`%2#P}BaM^voqqlj%FNHH}ipWu(`-wB;K9Xm1W*JN@pm zrv2v$esOOaOphsnbjx4#pH60Jy1$&6A!tp8w%D=y6EQ3Se6bzy&6uI=wsl=CYulEt z& zc*^|#GUd0r8fBH`m3|MrW-BmVwufp~wwdymukBp7uDi3dW76t-CY6a8lT&U%|C8cz>BuuVgeS zxRvmjaN!OGuUGI!1#eUEP6h8#@P5J$v`O_Jlnmmd3LaMQ83m6j_=K4oLfCVQ?&#L3*091>UXTegz*?@DT+cSMZ2}&nft_g3T7=UQUO?WD<5p z=EgVQ^~FTywVGtOa@Lp(+moT;j|Tg6GVD~?gUN7CVI3~0{nM)vQ!89xe%~njpbMJb zUmeLk>w=?7?w%CLJZC76ra*_ndfaeOVf)=+KW`{Eq(bxg1vq2BeBNuiVAe<6%ng4! z?_dS+(RpRcPJ`SJ@?*b_wfEs-@9Gz3s#p>G^z-;UF^B7~ zRpXK(R>*<)$!r#b`7KW9YH{?oG{VrRf8gv?_Ld1+?yn^KJ&CrJo4L36Nic=hnvQ8&$qJUO%q#Bk_8!Rna#m=-n#sOVD4p za_6{UWnR|BH%t0N8*{Kd`cxY;#$H2$zQV@xEyLJr?fMfomJu0zJ8(g4$LAl9^+>0| zX9-|Go`f+=youC`wBk;nI?~vi>$hpzJ5*&s(otv&b#v$1dzXI7EmU>Y6krb*ntGB$ z#Sj13RF~tj|J+L5OeDaW4CH`8};fxT{-y|$3~PRuxa zwQ#KO+|abaoTa9<#qpv1O|Bbp64`ALH&d9#A4o8=~~TfsdXL+eMWiDE0ZnTL%qa?oNa&j~mO$mPF`&!kD%WB*E(ndnpNA+l<`$F|a~m&y0cn3hQxz zdAp(9?0_bPecA!Lx6|vvTid;+J1pVFCcf9fo`8&A#o@=o?B0CKTR1?ELuaqy?tQrW z(*`sj+swe>ORh~v1Gt`5ayve)MyrBf-j*8dKfKiWyQPkwo6g5fve=(Lwsh>@E}E7m z2abC_wy^)DkzkK4Tv`|Vh3xW~TE^XXZ~DI)yWQo_o8idWr6mWn%IE4$c8kB#GsVGbtoi6BnE;aPE=TZLQQvMoZ zd8a|dWR1!m#)KZo@!JvWyEBY=WS+73fU*$5y?YHE6`xe}nWB@Y;9C@|mffz%zrVK$ zc8>Q#OP|}qVI}-kgZ1aT6?zrJNRjpmCMW(8mPEUmLdoEj z_?jsGrYQbS4GL(+B_*fk)_U+NiEi*XCVKaqfyt?j)1JYrB+BoT z3|@(+81T1?tI-NTd>-fX_$olWhw}y6LXpoOAczgR7zL8(1}l)K8mC}#YDHQX@+4oy z`AM4EXC&{9D*s#*ueG#%amC8})~&4IAvGRlyRT{Kx>XC?x}oS$ws~#a^829i(6|aC z_SSL#%C44mZL3$b+}j-$h|_r9@{Z1RZI~H);ZQCM(o8*7lt@TSg2*7pAvsMd)SOJX z?z2KpGQtT$zFWwt0xt!vf^eUsKF!2LtR#Hp6AG@aM1&KBoOrpt zq8@Wucwj;}0JRB{2NP!SmLQxUYP^nZ68aXzn{vYn-dLUlK7~ChZTHA!J`Vk!ZBQ# zGZkM_8{110g?Dx{v}puuCkFpzl$L6V#G|wVf9fc$@Y#PBrKLSLMsmZhz@xOnIsavp zR`@25(hB@cD^Z{E(I*i ze3tcg=CgTlI=8^IkU?W-evq~S_^$~^;4dR@@$L=(&{qPL^08ZnJ! z$|G-H6J^hg{M#s(B<*#C?Nvk!)}R$yhXX=f(wy%V+;>}_gH2Hei_u{2H4NSw zW$>tCkhWT~#;c?3HKM(!E)Lg!Wt72D#URy48hkj)U>6#sCYB^?ydlb-3zt*bCA9EL zd(W8g{%RlZK!XoRYeJFOC!-8DqrpLxQy+(y*6`f$vUotTozlkOou;CWB)S)+1E^;u zp&Y4m%sjdid{Y>pJfg3nfvzy*zf_p$r%?}-=?=e>(*w~yP1f)?QTG0f8FbhsN!mLW zw&&IYBIk89NQz{zg2#@&fD7SBICj*4OOPKe(Y7s*$BrJvnf-gx7)m89o&5KQ`PYjb zRa9eChsVQr#}8CG*n2l{PEkhz@yKcZBWV-#C!H);20!&5I9cQD){Usxs*k29;p%p)9&juC4x7Hs z&BN8NxG`Mqr*L%vYsYi_RDD7!vqcPb#OeN2mLJ=L9pGYmb1F+u3h-NCI0wB0Wh135 z$3mW2L4j)15wkvoCFZu{O#Tz0NtZ~IPpR;zbiF1oudL$X>7B7U9t`D$e)c8b4K%tu z9D~z|5hqWmHq|Rn)c0-WFs6#0gZux%n*k`$B~yhlywT3jZ#O+qYZ*up4@69KMY!i z9d$B%7!-(shG71@R#a@ehK*)HUCztopeUJ_u4v z@j&mt!hPtZz>eAn?=l$eayxTTrZ)M0D~$|yU3HZD$H>#0fFxZardoV^RB5B(lLNaF%mZ^Kuz5Gs zc^KJ+(59*1v{3jpY}1Ub3auD zD@!zpiJ54Vt?$cLx^9O>@6S7$wot8|4XFmva;~8g6WJi zGfIT+6g1XP6*2nIZA|F< zcMP-8<4gW%|lR|Rf~-isVxrJu{b}r0PF5B!Qf(J zNjr{{HHywI&M{4n1^beGQ>6_mm*mgu#6i*%W_eCEq}F zPY<27J!*0}4~@o^*<;FQX4+$>e6^-`%PjUGtlF7{BQ+6T9b*r@now_Z+VMoz_grDN zucWZdH?43+O>rpAb<+(E;+ImkNgpe7Z;;~``rO80#*q7JM1C~&d4Al|oo0O5wk0j% zhoOUMA;z7vLphz@mTr6|r=HrnGUmdCIsVzuPa3*e zQ276BEGEZDqk@|i+^*nm1@{ofeJ#-z1@mvGgq(jnB{2VXO6=K#{NpLX@Q~TBb!|ty{r83f@8(Lo7s3 zD|okp`#BE#pLS5mIHKU=3La7LIR#%PjPLqHW*lM?I~1I$V4s33Eu5isFZ62mF5|Pp z%p7RXGZwTHIdDK>>%CyhH*$M&VNt%ZHV);%kdmwAgQvhyJ~$D&6!yU)7*yEWVsQ8j z<@LqT>N6~#DTZMs_dp5w3Jv8GC9qy$*O$T(g>5KIi;N|@xf=Eq<(F*25gfpVlq8qkKj93HQtask); /* The task handle is not used. */ + "MQTTTask", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + arg, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + &thread->task); /* The task handle is not used. */ return rc; } @@ -40,17 +41,18 @@ void MutexInit(Mutex* mutex) mutex->sem = xSemaphoreCreateMutex(); } + int MutexLock(Mutex* mutex) { return xSemaphoreTake(mutex->sem, portMAX_DELAY); } + int MutexUnlock(Mutex* mutex) { return xSemaphoreGive(mutex->sem); } - void TimerCountdownMS(Timer* timer, unsigned int timeout_ms) { timer->xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */ @@ -58,13 +60,13 @@ void TimerCountdownMS(Timer* timer, unsigned int timeout_ms) } -void TimerCountdown(Timer* timer, unsigned int timeout) +void TimerCountdown(Timer* timer, unsigned int timeout) { TimerCountdownMS(timer, timeout * 1000); } -int TimerLeftMS(Timer* timer) +int TimerLeftMS(Timer* timer) { xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait); /* updates xTicksToWait to the number left */ return (timer->xTicksToWait < 0) ? 0 : (timer->xTicksToWait * portTICK_RATE_MS); @@ -84,7 +86,7 @@ void TimerInit(Timer* timer) } -int esp_read(Network* n, unsigned char* buffer, int len, int timeout_ms) +static int esp_read(Network* n, unsigned char* buffer, unsigned int len, unsigned int timeout_ms) { portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */ xTimeOutType xTimeOut; @@ -102,10 +104,12 @@ int esp_read(Network* n, unsigned char* buffer, int len, int timeout_ms) timeout.tv_usec = timeout_ms * 1000; vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */ + if (select(n->my_socket + 1, &fdset, NULL, NULL, &timeout) > 0) { if (FD_ISSET(n->my_socket, &fdset)) { do { rc = recv(n->my_socket, buffer + recvLen, len - recvLen, MSG_DONTWAIT); + if (rc > 0) { recvLen += rc; } else if (rc < 0) { @@ -115,11 +119,12 @@ int esp_read(Network* n, unsigned char* buffer, int len, int timeout_ms) } while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE); } } + return recvLen; } -int esp_write(Network* n, unsigned char* buffer, int len, int timeout_ms) +static int esp_write(Network* n, unsigned char* buffer, unsigned int len, unsigned int timeout_ms) { portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */ xTimeOutType xTimeOut; @@ -138,12 +143,15 @@ int esp_write(Network* n, unsigned char* buffer, int len, int timeout_ms) timeout.tv_usec = timeout_ms * 1000; vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */ + do { readysock = select(n->my_socket + 1, NULL, &fdset, NULL, &timeout); } while (readysock <= 0); + if (FD_ISSET(n->my_socket, &fdset)) { do { rc = send(n->my_socket, buffer + sentLen, len - sentLen, MSG_DONTWAIT); + if (rc > 0) { sentLen += rc; } else if (rc < 0) { @@ -157,7 +165,7 @@ int esp_write(Network* n, unsigned char* buffer, int len, int timeout_ms) } -void esp_disconnect(Network* n) +static void esp_disconnect(Network* n) { close(n->my_socket); } @@ -176,20 +184,21 @@ int NetworkConnect(Network* n, char* addr, int port) { struct sockaddr_in sAddr; int retVal = -1; - struct hostent *ipAddress; + struct hostent* ipAddress; - if ((ipAddress = gethostbyname(addr)) == 0) + if ((ipAddress = gethostbyname(addr)) == 0) { goto exit; + } sAddr.sin_family = AF_INET; sAddr.sin_addr.s_addr = ((struct in_addr*)(ipAddress->h_addr))->s_addr; sAddr.sin_port = htons(port); - if ((n->my_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) + if ((n->my_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { goto exit; + } - if ((retVal = connect(n->my_socket, (struct sockaddr*)&sAddr, sizeof(sAddr))) < 0) - { + if ((retVal = connect(n->my_socket, (struct sockaddr*)&sAddr, sizeof(sAddr))) < 0) { close(n->my_socket); goto exit; } @@ -199,64 +208,239 @@ exit: } -#if 0 -int NetworkConnectTLS(Network *n, char* addr, int port, SlSockSecureFiles_t* certificates, unsigned char sec_method, unsigned int cipher, char server_verify) +static int esp_ssl_read(Network* n, unsigned char* buffer, unsigned int len, unsigned int timeout_ms) { - SlSockAddrIn_t sAddr; - int addrSize; - int retVal; - unsigned long ipAddress; + portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */ + xTimeOutType xTimeOut; + int recvLen = 0; + int rc = 0; + static unsigned char* read_buffer; - retVal = sl_NetAppDnsGetHostByName(addr, strlen(addr), &ipAddress, AF_INET); - if (retVal < 0) { - return -1; + struct timeval timeout; + fd_set readset; + fd_set errset; + + FD_ZERO(&readset); + FD_ZERO(&errset); + FD_SET(n->my_socket, &readset); + FD_SET(n->my_socket, &errset); + + timeout.tv_sec = 0; + timeout.tv_usec = timeout_ms * 1000; + + vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */ + + if (!n->read_count) { /* read mqtt packet for the first time */ + if (select(n->my_socket + 1, &readset, NULL, &errset, &timeout) > 0) { + if (FD_ISSET(n->my_socket, &errset)) { + return recvLen; + } else if (FD_ISSET(n->my_socket, &readset)) { + read_buffer = buffer; + len = 2; /* len: msg_type(1 octet) + msg_len(1 octet) */ + + do { + rc = SSL_read(n->ssl, read_buffer, len); + + if (rc > 0) { + recvLen += rc; + } else if (rc < 0) { + recvLen = rc; + return recvLen; + } + } while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE); + + recvLen = 0; + len = *(read_buffer + 1); /* len: remaining msg */ + + if (len > 0) { + do { + rc = SSL_read(n->ssl, read_buffer + 2, len); + + if (rc > 0) { + recvLen += rc; + } else if (rc < 0) { + recvLen = rc; + return recvLen; + } + } while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE); + } + + n->read_count++; + return 1; + } + } + } else if (n->read_count == 1) { /* read same mqtt packet for the second time */ + if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdTRUE) { + n->read_count = 0; + read_buffer[0] = 0; + return 0; + } + + n->read_count++; + *buffer = *(read_buffer + 1); + return 1; + } else if (n->read_count == 2) { /* read same mqtt packet for the third time */ + n->read_count = 0; + + if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdTRUE) { + read_buffer[0] = 0; + return 0; + } + + memcpy(buffer, read_buffer + 2, len); + return len; } + return recvLen; +} + + +static int esp_ssl_write(Network* n, unsigned char* buffer, unsigned int len, unsigned int timeout_ms) +{ + portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */ + xTimeOutType xTimeOut; + int sentLen = 0; + int rc = 0; + int readysock; + + struct timeval timeout; + fd_set writeset; + fd_set errset; + + FD_ZERO(&writeset); + FD_ZERO(&errset); + FD_SET(n->my_socket, &writeset); + FD_SET(n->my_socket, &errset); + + timeout.tv_sec = 0; + timeout.tv_usec = timeout_ms * 1000; + + vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */ + + do { + readysock = select(n->my_socket + 1, NULL, &writeset, &errset, &timeout); + } while (readysock <= 0); + + if (FD_ISSET(n->my_socket, &errset)) { + return sentLen; + } else if (FD_ISSET(n->my_socket, &writeset)) { + do { + rc = SSL_write(n->ssl, buffer + sentLen, len - sentLen); + + if (rc > 0) { + sentLen += rc; + } else if (rc < 0) { + sentLen = rc; + break; + } + } while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE); + } + + return sentLen; +} + + +static void esp_ssl_disconnect(Network* n) +{ + close(n->my_socket); + SSL_free(n->ssl); + SSL_CTX_free(n->ctx); + n->read_count = 0; +} + + +void NetworkInitSSL(Network* n) +{ + n->my_socket = 0; + n->mqttread = esp_ssl_read; + n->mqttwrite = esp_ssl_write; + n->disconnect = esp_ssl_disconnect; + n->read_count = 0; + n->ctx = NULL; + n->ssl = NULL; +} + + +int NetworkConnectSSL(Network* n, char* addr, int port, ssl_ca_crt_key_t* ssl_cck, const SSL_METHOD* method, int verify_mode, size_t frag_len) +{ + struct sockaddr_in sAddr; + int retVal = -1; + struct hostent* ipAddress; + + if ((ipAddress = gethostbyname(addr)) == 0) { + goto exit; + } + + n->ctx = SSL_CTX_new(method); + + if (!n->ctx) { + goto exit; + } + + if (ssl_cck->cacrt) { + X509* cacrt = d2i_X509(NULL, ssl_cck->cacrt, ssl_cck->cacrt_len); + + if (!cacrt) { + goto exit1; + } + + SSL_CTX_add_client_CA(n->ctx, cacrt); + } + + if (ssl_cck->cert && ssl_cck->key) { + retVal = SSL_CTX_use_certificate_ASN1(n->ctx, ssl_cck->cert_len, ssl_cck->cert); + + if (!retVal) { + goto exit1; + } + + retVal = SSL_CTX_use_PrivateKey_ASN1(0, n->ctx, ssl_cck->key, ssl_cck->key_len); + + if (!retVal) { + goto exit1; + } + } + + if (ssl_cck->cacrt) { + SSL_CTX_set_verify(n->ctx, verify_mode, NULL); + } else { + SSL_CTX_set_verify(n->ctx, SSL_VERIFY_NONE, NULL); + } + + SSL_CTX_set_default_read_buffer_len(n->ctx, frag_len); + sAddr.sin_family = AF_INET; - sAddr.sin_port = sl_Htons((unsigned short)port); - sAddr.sin_addr.s_addr = sl_Htonl(ipAddress); + sAddr.sin_addr.s_addr = ((struct in_addr*)(ipAddress->h_addr))->s_addr; + sAddr.sin_port = htons(port); - addrSize = sizeof(SlSockAddrIn_t); - - n->my_socket = sl_Socket(SL_AF_INET, SL_SOCK_STREAM, SL_SEC_SOCKET); - if (n->my_socket < 0) { - return -1; + if ((n->my_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + goto exit1; } - SlSockSecureMethod method; - method.secureMethod = sec_method; - retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method)); - if (retVal < 0) { - return retVal; + if ((retVal = connect(n->my_socket, (struct sockaddr*)&sAddr, sizeof(sAddr))) < 0) { + goto exit2; } - SlSockSecureMask mask; - mask.secureMask = cipher; - retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_MASK, &mask, sizeof(mask)); - if (retVal < 0) { - return retVal; + n->ssl = SSL_new(n->ctx); + + if (!n->ssl) { + goto exit2; } - if (certificates != NULL) { - retVal = sl_SetSockOpt(n->my_socket, SL_SOL_SOCKET, SL_SO_SECURE_FILES, certificates->secureFiles, sizeof(SlSockSecureFiles_t)); - if (retVal < 0) - { - return retVal; - } + SSL_set_fd(n->ssl, n->my_socket); + + if ((retVal = SSL_connect(n->ssl)) <= 0) { + goto exit3; + } else { + goto exit; } - retVal = sl_Connect(n->my_socket, (SlSockAddr_t *)&sAddr, addrSize); - if (retVal < 0) { - if (server_verify || retVal != -453) { - sl_Close(n->my_socket); - return retVal; - } - } - - SysTickIntRegister(SysTickIntHandler); - SysTickPeriodSet(80000); - SysTickEnable(); - +exit3: + SSL_free(n->ssl); +exit2: + close(n->my_socket); +exit1: + SSL_CTX_free(n->ctx); +exit: return retVal; } -#endif