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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TlsMQTTClient.cpp Source File

TlsMQTTClient.cpp

00001 #include <cyassl/ctaocrypt/types.h>
00002 #include "TlsMQTTClient.hpp"
00003 
00004 
00005 TlsMQTTClient::TlsMQTTClient() :
00006     tcp(NULL), ctx(NULL), ssl(NULL),
00007     mqttClient(new MQTTClient(*this)) {
00008 }
00009 
00010 
00011 int TlsMQTTClient::connect(
00012     const char* host, 
00013     const int port,
00014     const char* certificates,
00015     MQTTPacket_connectData& options
00016 ) 
00017 {
00018     cleanupTransport();
00019 
00020     // create TCP transport
00021     tcp = new TCPSocketConnection();
00022     if (tcp->connect(host, port)) {
00023         logError("tcp connection failed");
00024         goto fail;
00025     }
00026     tcp->set_blocking(false, 50);
00027 
00028     // setup SSL context
00029     ctx = CyaSSL_CTX_new((CYASSL_METHOD *)CyaSSLv23_client_method());
00030     { //Localize pMethod array for less overall memory time-use
00031         SSLMethod peerMethod = certificates != \
00032             NULL ? (SSLMethod)(
00033                 VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
00034             ) : VERIFY_NONE;
00035             
00036         std::string pMethod;
00037         if(peerMethod == VERIFY_NONE) {
00038             pMethod = "not verify peer";
00039         } else if (peerMethod & VERIFY_PEER) {
00040             pMethod = "Verify peer if certificates available";
00041             //Load the CA certificate(s) 
00042             // (If using multiple, concatenate them in the buffer being passed)
00043             if (SSL_SUCCESS !=  CyaSSL_CTX_load_verify_buffer(
00044                                     ctx, 
00045                                     (const unsigned char*)certificates, 
00046                                     strlen(certificates), 
00047                                     SSL_FILETYPE_PEM)
00048                                 ) {
00049                                     
00050                 logError("Unable to load root certificates!");
00051                 goto fail;
00052             }
00053         }
00054         logDebug("SSL connection set to %s", pMethod.c_str());
00055         
00056         //SSL_VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_NONE, SSL_VERIFY_PEER
00057         CyaSSL_CTX_set_verify(ctx, peerMethod, 0); 
00058     }
00059 
00060     // setup SSL operations
00061     ssl = CyaSSL_new(ctx);
00062 
00063     CyaSSL_set_using_nonblock(ssl, 1);
00064     CyaSSL_SetIOReadCtx(ssl, this);
00065     CyaSSL_SetIORecv(ctx, ioRecv);
00066     CyaSSL_SetIOWriteCtx(ssl, this);
00067     CyaSSL_SetIOSend(ctx, ioSend);
00068 
00069     // SSL connect
00070     while (true) {
00071         int ret = CyaSSL_connect(ssl);
00072 
00073         if (ret != SSL_SUCCESS) {
00074             int err = CyaSSL_get_error(ssl, ret);
00075     
00076             if (SSL_ERROR_WANT_READ == err ||
00077                 SSL_ERROR_WANT_WRITE == err) {
00078                 continue;
00079             }
00080 
00081             logError("SSL_connect failed ret %d", ret);
00082 
00083             char data[CYASSL_MAX_ERROR_SZ];
00084             char data_new[CYASSL_MAX_ERROR_SZ];
00085             strcpy(data_new, CyaSSL_ERR_error_string(err, data));
00086             if(!strcmp(data,data_new)) {
00087                 logError("Error code [%d] is [%s]\r\n", err, data);
00088             } else {
00089                 logError(
00090                     "Failed to get error code [%d], Reason: [%s]\r\n", 
00091                     err, 
00092                     data_new
00093                 );
00094             }
00095 
00096             goto fail;
00097         } else {
00098             break;
00099         }
00100     }
00101 
00102     return mqttClient->connect(options);
00103 
00104 // Cleanup handler
00105 fail:
00106     cleanupTransport() ;
00107     return MQTT::FAILURE;
00108 }
00109 
00110 int TlsMQTTClient::publish(const char* topicName, MQTT::Message& message) 
00111 {
00112     return mqttClient->publish(topicName, message);
00113 }
00114 
00115 int TlsMQTTClient::publish(
00116     const char* topicName, 
00117     void* payload, 
00118     size_t payloadlen, 
00119     enum MQTT::QoS qos, 
00120     bool retained
00121 ) 
00122 {
00123     return mqttClient->publish(topicName, payload, payloadlen, qos, retained);
00124 }
00125 
00126 int TlsMQTTClient::publish(
00127     const char* topicName, 
00128     void* payload, size_t payloadlen, 
00129     unsigned short& id, 
00130     enum MQTT::QoS qos, 
00131     bool retained
00132 ) 
00133 {
00134     return mqttClient->publish(
00135         topicName, 
00136         payload, 
00137         payloadlen, 
00138         id, 
00139         qos, 
00140         retained
00141     );
00142 }
00143 
00144 int TlsMQTTClient::subscribe(
00145     const char* topicFilter, 
00146     enum MQTT::QoS qos, 
00147     MessageHandler mh
00148 ) 
00149 {
00150     return mqttClient->subscribe(topicFilter, qos, mh);
00151 }
00152 
00153 int TlsMQTTClient::unsubscribe(const char* topicFilter) 
00154 {
00155     return mqttClient->unsubscribe(topicFilter);
00156 }
00157 
00158 int TlsMQTTClient::disconnect() 
00159 {
00160     int r = mqttClient->disconnect();
00161     cleanupTransport();
00162     return r;
00163 }
00164 
00165 int TlsMQTTClient::yield(unsigned long timeout_ms) 
00166 {
00167     return mqttClient->yield(timeout_ms);
00168 }
00169 
00170 bool TlsMQTTClient::isConnected() 
00171 {
00172     return mqttClient->isConnected();
00173 }
00174 
00175 void TlsMQTTClient::cleanupTransport() {
00176     if (ssl) {
00177         logTrace("freeing ssl");
00178         CyaSSL_free(ssl) ;
00179         ssl = NULL ;
00180     }
00181     if (ctx) {
00182         logTrace("freeing ssl ctx");
00183         CyaSSL_CTX_free(ctx) ;
00184         ctx = NULL ;
00185     }
00186     if (tcp) {
00187         if (tcp->is_connected()) {
00188             logTrace("disconnect tcp");
00189             tcp->close();
00190         }
00191         logTrace("freeing tcp");
00192         delete tcp;
00193         tcp = NULL;
00194     }
00195 }
00196 
00197 TlsMQTTClient::~TlsMQTTClient() {
00198     cleanupTransport();
00199     delete mqttClient;
00200 }
00201 
00202 int TlsMQTTClient::read(
00203     unsigned char* data, 
00204     int max, 
00205     int timeout
00206 ) 
00207 {
00208 //    logTrace(
00209 //        "TlsMQTTClient::read data %p max %d timeout %d", 
00210 //        data, 
00211 //        max, 
00212 //        timeout
00213 //    );
00214     Timer tmr;
00215     int bytes = 0;    
00216     int totalbytes = 0;
00217     
00218     tmr.start();
00219     do {
00220         bytes = CyaSSL_read(ssl, data, max);
00221         if (bytes < 0) {
00222             int err = CyaSSL_get_error(ssl, bytes);
00223             if (SSL_ERROR_WANT_READ == err) {
00224                 continue;
00225             }
00226             logTrace("CyaSSL_read fail %d", err);
00227             return -1;
00228         }
00229         totalbytes += bytes;
00230     } while ( tmr.read_ms() < timeout && totalbytes < max);
00231     //logTrace("TlsMQTTClient::read totalbytes %d", totalbytes);
00232     return totalbytes;
00233 }
00234 
00235 int TlsMQTTClient::write(const unsigned char* data, int length, int timeout) {
00236 //    logTrace(
00237 //        "TlsMQTTClient::write data %p max %d timeout %d", 
00238 //        data, 
00239 //        length, 
00240 //        timeout
00241 //    );
00242     Timer tmr;
00243     int bytes = 0;    
00244     int totalbytes = 0;
00245     
00246     tmr.start();
00247     do {
00248         bytes = CyaSSL_write(ssl, data, length);
00249         if (bytes < 0) {
00250             int err = CyaSSL_get_error(ssl, bytes);
00251             if (SSL_ERROR_WANT_WRITE == err) {
00252                 continue;
00253             }
00254             logTrace("CyaSSL_write fail %d", err);
00255             return -1;
00256         }
00257         totalbytes += bytes;
00258     } while (tmr.read_ms() < timeout && totalbytes < length);
00259     //logTrace("TlsMQTTClient::write totalbytes %d", totalbytes);
00260     return totalbytes;
00261 }
00262 
00263 int TlsMQTTClient::ioRecv(CYASSL* ssl, char *buf, int sz, void *ctx) {
00264     TlsMQTTClient* thiz = (TlsMQTTClient*) ctx;
00265     int n = thiz->tcp->receive(buf, sz);
00266     if (0 == n) {
00267         return CYASSL_CBIO_ERR_WANT_READ;
00268     } else if (n > 0) {
00269         return n;
00270     } else {
00271         return CYASSL_CBIO_ERR_GENERAL;
00272     }
00273 }
00274 
00275 int TlsMQTTClient::ioSend(CYASSL* ssl, char *buf, int sz, void *ctx) {
00276     TlsMQTTClient* thiz = (TlsMQTTClient*) ctx;
00277     int n = thiz->tcp->send(buf, sz);
00278     if (0 == n) {
00279         return CYASSL_CBIO_ERR_WANT_WRITE;
00280     } else if (n > 0) {
00281         return n;
00282     } else {
00283         return CYASSL_CBIO_ERR_GENERAL;
00284     }
00285 }