Connecting a Multi-Tech Systems Dragonfly™ to Twilio's Sync for IoT Quickstart. Blink a dev board LED.

Dependencies:   MQTT MbedJSONValue mbed mtsas

Fork of DragonflyMQTT by miao zhicheng

Code to connect a Multi-Tech® MultiConnect® Dragonfly™ to Twilio's Sync for IoT: https://www.twilio.com/docs/api/devices

Uses MQTT over TLS and subscribes to a topic where you can control an LED. See also our Quickstart using this code, here: https://www.twilio.com/docs/quickstart/sync-iot/mqtt-multi-tech-multiconnect-dragonfly-sync-iot

Committer:
miaotwilio
Date:
Thu Aug 17 13:38:58 2017 +0000
Revision:
3:0a48c984e15b
Parent:
1:5a896191c3c4
Child:
9:2d119fbe7482
fix a CA validation issue

Who changed what in which revision?

UserRevisionLine numberNew contents of line
miaotwilio 0:b32fa0c757d7 1 #include <cyassl/ctaocrypt/types.h>
miaotwilio 0:b32fa0c757d7 2 #include "TlsMQTTClient.hpp"
miaotwilio 0:b32fa0c757d7 3
miaotwilio 0:b32fa0c757d7 4 TlsMQTTClient::TlsMQTTClient() :
miaotwilio 0:b32fa0c757d7 5 tcp(NULL), ctx(NULL), ssl(NULL),
miaotwilio 0:b32fa0c757d7 6 mqttClient(new MQTTClient(*this)) {
miaotwilio 0:b32fa0c757d7 7 }
miaotwilio 0:b32fa0c757d7 8
miaotwilio 0:b32fa0c757d7 9 int TlsMQTTClient::connect(const char* host, const int port,
miaotwilio 0:b32fa0c757d7 10 const char* certificates,
miaotwilio 0:b32fa0c757d7 11 MQTTPacket_connectData& options) {
miaotwilio 0:b32fa0c757d7 12 cleanupTransport();
miaotwilio 0:b32fa0c757d7 13
miaotwilio 0:b32fa0c757d7 14 // create TCP transport
miaotwilio 0:b32fa0c757d7 15 tcp = new TCPSocketConnection();
miaotwilio 0:b32fa0c757d7 16 if (tcp->connect(host, port)) {
miaotwilio 0:b32fa0c757d7 17 logError("tcp connection failed");
miaotwilio 0:b32fa0c757d7 18 goto fail;
miaotwilio 0:b32fa0c757d7 19 }
miaotwilio 1:5a896191c3c4 20 tcp->set_blocking(false, 50);
miaotwilio 0:b32fa0c757d7 21
miaotwilio 0:b32fa0c757d7 22 // setup SSL context
miaotwilio 0:b32fa0c757d7 23 ctx = CyaSSL_CTX_new((CYASSL_METHOD *)CyaSSLv23_client_method());
miaotwilio 0:b32fa0c757d7 24 { //Localize pMethod array for less overall memory time-use
miaotwilio 0:b32fa0c757d7 25 SSLMethod peerMethod = certificates != NULL ? (SSLMethod)(VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT) : VERIFY_NONE;
miaotwilio 0:b32fa0c757d7 26 std::string pMethod;
miaotwilio 0:b32fa0c757d7 27 if(peerMethod == VERIFY_NONE) {
miaotwilio 0:b32fa0c757d7 28 pMethod = "not verify peer";
miaotwilio 3:0a48c984e15b 29 } else if (peerMethod & VERIFY_PEER) {
miaotwilio 0:b32fa0c757d7 30 pMethod = "verify peer if certificates available";
miaotwilio 0:b32fa0c757d7 31 //Load the CA certificate(s) (If using multiple, concatenate them in the buffer being passed)
miaotwilio 0:b32fa0c757d7 32 if (SSL_SUCCESS != CyaSSL_CTX_load_verify_buffer(ctx, (const unsigned char*)certificates, strlen(certificates), SSL_FILETYPE_PEM)) {
miaotwilio 0:b32fa0c757d7 33 logError("unable to load root certificates");
miaotwilio 0:b32fa0c757d7 34 goto fail;
miaotwilio 0:b32fa0c757d7 35 }
miaotwilio 0:b32fa0c757d7 36 }
miaotwilio 0:b32fa0c757d7 37 logDebug("SSL connection set to %s", pMethod.c_str());
miaotwilio 0:b32fa0c757d7 38 CyaSSL_CTX_set_verify(ctx, peerMethod, 0); //SSL_VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_NONE, SSL_VERIFY_PEER
miaotwilio 0:b32fa0c757d7 39 }
miaotwilio 0:b32fa0c757d7 40
miaotwilio 0:b32fa0c757d7 41 // setup SSL operations
miaotwilio 0:b32fa0c757d7 42 ssl = CyaSSL_new(ctx);
miaotwilio 0:b32fa0c757d7 43
miaotwilio 1:5a896191c3c4 44 CyaSSL_set_using_nonblock(ssl, 1);
miaotwilio 0:b32fa0c757d7 45 CyaSSL_SetIOReadCtx(ssl, this);
miaotwilio 0:b32fa0c757d7 46 CyaSSL_SetIORecv(ctx, ioRecv);
miaotwilio 0:b32fa0c757d7 47 CyaSSL_SetIOWriteCtx(ssl, this);
miaotwilio 0:b32fa0c757d7 48 CyaSSL_SetIOSend(ctx, ioSend);
miaotwilio 0:b32fa0c757d7 49
miaotwilio 0:b32fa0c757d7 50 // SSL connect
miaotwilio 1:5a896191c3c4 51 while (true) {
miaotwilio 0:b32fa0c757d7 52 int ret = CyaSSL_connect(ssl);
miaotwilio 1:5a896191c3c4 53
miaotwilio 1:5a896191c3c4 54 if (ret != SSL_SUCCESS) {
miaotwilio 1:5a896191c3c4 55 int err = CyaSSL_get_error(ssl, ret);
miaotwilio 0:b32fa0c757d7 56
miaotwilio 1:5a896191c3c4 57 if (SSL_ERROR_WANT_READ == err ||
miaotwilio 1:5a896191c3c4 58 SSL_ERROR_WANT_WRITE == err) {
miaotwilio 1:5a896191c3c4 59 continue;
miaotwilio 1:5a896191c3c4 60 }
miaotwilio 1:5a896191c3c4 61
miaotwilio 1:5a896191c3c4 62 logError("SSL_connect failed ret %d", ret);
miaotwilio 1:5a896191c3c4 63
miaotwilio 0:b32fa0c757d7 64 char data[CYASSL_MAX_ERROR_SZ];
miaotwilio 0:b32fa0c757d7 65 char data_new[CYASSL_MAX_ERROR_SZ];
miaotwilio 0:b32fa0c757d7 66 strcpy(data_new, CyaSSL_ERR_error_string(err, data));
miaotwilio 0:b32fa0c757d7 67 if(!strcmp(data,data_new)) {
miaotwilio 0:b32fa0c757d7 68 logError("Error code [%d] is [%s]\r\n", err, data);
miaotwilio 0:b32fa0c757d7 69 } else {
miaotwilio 0:b32fa0c757d7 70 logError("Failed to get error code [%d], Reason: [%s]\r\n", err, data_new);
miaotwilio 0:b32fa0c757d7 71 }
miaotwilio 1:5a896191c3c4 72
miaotwilio 0:b32fa0c757d7 73 goto fail;
miaotwilio 1:5a896191c3c4 74 } else {
miaotwilio 1:5a896191c3c4 75 break;
miaotwilio 0:b32fa0c757d7 76 }
miaotwilio 0:b32fa0c757d7 77 }
miaotwilio 0:b32fa0c757d7 78
miaotwilio 0:b32fa0c757d7 79 return mqttClient->connect(options);
miaotwilio 0:b32fa0c757d7 80
miaotwilio 0:b32fa0c757d7 81 fail:
miaotwilio 0:b32fa0c757d7 82 cleanupTransport() ;
miaotwilio 0:b32fa0c757d7 83 return MQTT::FAILURE;
miaotwilio 0:b32fa0c757d7 84 }
miaotwilio 0:b32fa0c757d7 85
miaotwilio 0:b32fa0c757d7 86 int TlsMQTTClient::publish(const char* topicName, MQTT::Message& message) {
miaotwilio 0:b32fa0c757d7 87 return mqttClient->publish(topicName, message);
miaotwilio 0:b32fa0c757d7 88 }
miaotwilio 0:b32fa0c757d7 89
miaotwilio 0:b32fa0c757d7 90 int TlsMQTTClient::publish(const char* topicName, void* payload, size_t payloadlen, enum MQTT::QoS qos, bool retained) {
miaotwilio 0:b32fa0c757d7 91 return mqttClient->publish(topicName, payload, payloadlen, qos, retained);
miaotwilio 0:b32fa0c757d7 92 }
miaotwilio 0:b32fa0c757d7 93
miaotwilio 0:b32fa0c757d7 94 int TlsMQTTClient::publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum MQTT::QoS qos, bool retained) {
miaotwilio 0:b32fa0c757d7 95 return mqttClient->publish(topicName, payload, payloadlen, id, qos, retained);
miaotwilio 0:b32fa0c757d7 96 }
miaotwilio 0:b32fa0c757d7 97
miaotwilio 0:b32fa0c757d7 98 int TlsMQTTClient::subscribe(const char* topicFilter, enum MQTT::QoS qos, MessageHandler mh) {
miaotwilio 0:b32fa0c757d7 99 return mqttClient->subscribe(topicFilter, qos, mh);
miaotwilio 0:b32fa0c757d7 100 }
miaotwilio 0:b32fa0c757d7 101
miaotwilio 0:b32fa0c757d7 102 int TlsMQTTClient::unsubscribe(const char* topicFilter) {
miaotwilio 0:b32fa0c757d7 103 return mqttClient->unsubscribe(topicFilter);
miaotwilio 0:b32fa0c757d7 104 }
miaotwilio 0:b32fa0c757d7 105
miaotwilio 0:b32fa0c757d7 106 int TlsMQTTClient::disconnect() {
miaotwilio 0:b32fa0c757d7 107 int r = mqttClient->disconnect();
miaotwilio 0:b32fa0c757d7 108 cleanupTransport();
miaotwilio 0:b32fa0c757d7 109 return r;
miaotwilio 0:b32fa0c757d7 110 }
miaotwilio 0:b32fa0c757d7 111
miaotwilio 0:b32fa0c757d7 112 int TlsMQTTClient::yield(unsigned long timeout_ms) {
miaotwilio 0:b32fa0c757d7 113 return mqttClient->yield(timeout_ms);
miaotwilio 0:b32fa0c757d7 114 }
miaotwilio 0:b32fa0c757d7 115
miaotwilio 0:b32fa0c757d7 116 bool TlsMQTTClient::isConnected() {
miaotwilio 0:b32fa0c757d7 117 return mqttClient->isConnected();
miaotwilio 0:b32fa0c757d7 118 }
miaotwilio 0:b32fa0c757d7 119
miaotwilio 0:b32fa0c757d7 120 void TlsMQTTClient::cleanupTransport() {
miaotwilio 0:b32fa0c757d7 121 if (ssl) {
miaotwilio 0:b32fa0c757d7 122 logTrace("freeing ssl");
miaotwilio 0:b32fa0c757d7 123 CyaSSL_free(ssl) ;
miaotwilio 0:b32fa0c757d7 124 ssl = NULL ;
miaotwilio 0:b32fa0c757d7 125 }
miaotwilio 0:b32fa0c757d7 126 if (ctx) {
miaotwilio 0:b32fa0c757d7 127 logTrace("freeing ssl ctx");
miaotwilio 0:b32fa0c757d7 128 CyaSSL_CTX_free(ctx) ;
miaotwilio 0:b32fa0c757d7 129 ctx = NULL ;
miaotwilio 0:b32fa0c757d7 130 }
miaotwilio 0:b32fa0c757d7 131 if (tcp) {
miaotwilio 0:b32fa0c757d7 132 if (tcp->is_connected()) {
miaotwilio 0:b32fa0c757d7 133 logTrace("disconnect tcp");
miaotwilio 0:b32fa0c757d7 134 tcp->close();
miaotwilio 0:b32fa0c757d7 135 }
miaotwilio 0:b32fa0c757d7 136 logTrace("freeing tcp");
miaotwilio 0:b32fa0c757d7 137 delete tcp;
miaotwilio 0:b32fa0c757d7 138 tcp = NULL;
miaotwilio 0:b32fa0c757d7 139 }
miaotwilio 0:b32fa0c757d7 140 }
miaotwilio 0:b32fa0c757d7 141
miaotwilio 0:b32fa0c757d7 142 TlsMQTTClient::~TlsMQTTClient() {
miaotwilio 0:b32fa0c757d7 143 cleanupTransport();
miaotwilio 0:b32fa0c757d7 144 delete mqttClient;
miaotwilio 0:b32fa0c757d7 145 }
miaotwilio 0:b32fa0c757d7 146
miaotwilio 0:b32fa0c757d7 147 int TlsMQTTClient::read(unsigned char* data, int max, int timeout) {
miaotwilio 1:5a896191c3c4 148 //logTrace("TlsMQTTClient::read data %p max %d timeout %d", data, max, timeout);
miaotwilio 1:5a896191c3c4 149 Timer tmr;
miaotwilio 1:5a896191c3c4 150 int bytes = 0;
miaotwilio 1:5a896191c3c4 151 int totalbytes = 0;
miaotwilio 1:5a896191c3c4 152
miaotwilio 1:5a896191c3c4 153 tmr.start();
miaotwilio 1:5a896191c3c4 154 do {
miaotwilio 1:5a896191c3c4 155 bytes = CyaSSL_read(ssl, data, max);
miaotwilio 1:5a896191c3c4 156 if (bytes < 0) {
miaotwilio 1:5a896191c3c4 157 int err = CyaSSL_get_error(ssl, bytes);
miaotwilio 1:5a896191c3c4 158 if (SSL_ERROR_WANT_READ == err) {
miaotwilio 1:5a896191c3c4 159 continue;
miaotwilio 1:5a896191c3c4 160 }
miaotwilio 1:5a896191c3c4 161 logTrace("CyaSSL_read fail %d", err);
miaotwilio 1:5a896191c3c4 162 return -1;
miaotwilio 1:5a896191c3c4 163 }
miaotwilio 1:5a896191c3c4 164 totalbytes += bytes;
miaotwilio 1:5a896191c3c4 165 } while ( tmr.read_ms() < timeout && totalbytes < max);
miaotwilio 1:5a896191c3c4 166 //logTrace("TlsMQTTClient::read totalbytes %d", totalbytes);
miaotwilio 1:5a896191c3c4 167 return totalbytes;
miaotwilio 0:b32fa0c757d7 168 }
miaotwilio 0:b32fa0c757d7 169
miaotwilio 0:b32fa0c757d7 170 int TlsMQTTClient::write(const unsigned char* data, int length, int timeout) {
miaotwilio 1:5a896191c3c4 171 //logTrace("TlsMQTTClient::write data %p max %d timeout %d", data, length, timeout);
miaotwilio 1:5a896191c3c4 172 Timer tmr;
miaotwilio 1:5a896191c3c4 173 int bytes = 0;
miaotwilio 1:5a896191c3c4 174 int totalbytes = 0;
miaotwilio 1:5a896191c3c4 175
miaotwilio 1:5a896191c3c4 176 tmr.start();
miaotwilio 1:5a896191c3c4 177 do {
miaotwilio 1:5a896191c3c4 178 bytes = CyaSSL_write(ssl, data, length);
miaotwilio 1:5a896191c3c4 179 if (bytes < 0) {
miaotwilio 1:5a896191c3c4 180 int err = CyaSSL_get_error(ssl, bytes);
miaotwilio 1:5a896191c3c4 181 if (SSL_ERROR_WANT_WRITE == err) {
miaotwilio 1:5a896191c3c4 182 continue;
miaotwilio 1:5a896191c3c4 183 }
miaotwilio 1:5a896191c3c4 184 logTrace("CyaSSL_write fail %d", err);
miaotwilio 1:5a896191c3c4 185 return -1;
miaotwilio 1:5a896191c3c4 186 }
miaotwilio 1:5a896191c3c4 187 totalbytes += bytes;
miaotwilio 1:5a896191c3c4 188 } while (tmr.read_ms() < timeout && totalbytes < length);
miaotwilio 1:5a896191c3c4 189 //logTrace("TlsMQTTClient::write totalbytes %d", totalbytes);
miaotwilio 1:5a896191c3c4 190 return totalbytes;
miaotwilio 0:b32fa0c757d7 191 }
miaotwilio 0:b32fa0c757d7 192
miaotwilio 0:b32fa0c757d7 193 int TlsMQTTClient::ioRecv(CYASSL* ssl, char *buf, int sz, void *ctx) {
miaotwilio 0:b32fa0c757d7 194 TlsMQTTClient* thiz = (TlsMQTTClient*) ctx;
miaotwilio 1:5a896191c3c4 195 int n = thiz->tcp->receive(buf, sz);
miaotwilio 1:5a896191c3c4 196 if (0 == n) {
miaotwilio 1:5a896191c3c4 197 return CYASSL_CBIO_ERR_WANT_READ;
miaotwilio 1:5a896191c3c4 198 } else if (n > 0) {
miaotwilio 1:5a896191c3c4 199 return n;
miaotwilio 1:5a896191c3c4 200 } else {
miaotwilio 1:5a896191c3c4 201 return CYASSL_CBIO_ERR_GENERAL;
miaotwilio 1:5a896191c3c4 202 }
miaotwilio 0:b32fa0c757d7 203 }
miaotwilio 0:b32fa0c757d7 204
miaotwilio 0:b32fa0c757d7 205 int TlsMQTTClient::ioSend(CYASSL* ssl, char *buf, int sz, void *ctx) {
miaotwilio 0:b32fa0c757d7 206 TlsMQTTClient* thiz = (TlsMQTTClient*) ctx;
miaotwilio 1:5a896191c3c4 207 int n = thiz->tcp->send(buf, sz);
miaotwilio 1:5a896191c3c4 208 if (0 == n) {
miaotwilio 1:5a896191c3c4 209 return CYASSL_CBIO_ERR_WANT_WRITE;
miaotwilio 1:5a896191c3c4 210 } else if (n > 0) {
miaotwilio 1:5a896191c3c4 211 return n;
miaotwilio 1:5a896191c3c4 212 } else {
miaotwilio 1:5a896191c3c4 213 return CYASSL_CBIO_ERR_GENERAL;
miaotwilio 1:5a896191c3c4 214 }
miaotwilio 0:b32fa0c757d7 215 }