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

TlsMQTTClient.cpp

Committer:
miaotwilio
Date:
2017-05-09
Revision:
0:b32fa0c757d7
Child:
1:5a896191c3c4

File content as of revision 0:b32fa0c757d7:

#include <cyassl/ctaocrypt/types.h>
#include "TlsMQTTClient.hpp"

TlsMQTTClient::TlsMQTTClient() :
    tcp(NULL), ctx(NULL), ssl(NULL),
    mqttClient(new MQTTClient(*this)) {
}

int TlsMQTTClient::connect(const char* host, const int port,
        const char* certificates,
        MQTTPacket_connectData& options) {
    cleanupTransport();

    // create TCP transport
    tcp = new TCPSocketConnection();
    if (tcp->connect(host, port)) {
        logError("tcp connection failed");
        goto fail;
    }

    // setup SSL context
    ctx = CyaSSL_CTX_new((CYASSL_METHOD *)CyaSSLv23_client_method());
    { //Localize pMethod array for less overall memory time-use
        SSLMethod peerMethod = certificates != NULL ? (SSLMethod)(VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT) : VERIFY_NONE;
        std::string pMethod;
        if(peerMethod == VERIFY_NONE) {
            pMethod = "not verify peer";
        } else if (peerMethod == VERIFY_PEER) {
            pMethod = "verify peer if certificates available";
            //Load the CA certificate(s) (If using multiple, concatenate them in the buffer being passed)
            if (SSL_SUCCESS != CyaSSL_CTX_load_verify_buffer(ctx, (const unsigned char*)certificates, strlen(certificates), SSL_FILETYPE_PEM)) {
                logError("unable to load root certificates");
                goto fail;
            }
        }
        logDebug("SSL connection set to %s", pMethod.c_str());
        CyaSSL_CTX_set_verify(ctx, peerMethod, 0); //SSL_VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_NONE, SSL_VERIFY_PEER
    }

    // setup SSL operations
    ssl = CyaSSL_new(ctx);

    CyaSSL_SetIOReadCtx(ssl, this);
    CyaSSL_SetIORecv(ctx, ioRecv);
    CyaSSL_SetIOWriteCtx(ssl, this);
    CyaSSL_SetIOSend(ctx, ioSend);

    // SSL connect
    {
        int ret = CyaSSL_connect(ssl);
    
        if (ret != SSL_SUCCESS) {
            logError("SSL_connect failed");
            int err = CyaSSL_get_error(ssl, ret);
            char data[CYASSL_MAX_ERROR_SZ];
            char data_new[CYASSL_MAX_ERROR_SZ];
            strcpy(data_new, CyaSSL_ERR_error_string(err, data));
            if(!strcmp(data,data_new)) {
                logError("Error code [%d] is [%s]\r\n", err, data);
            } else {
                logError("Failed to get error code [%d], Reason: [%s]\r\n", err, data_new);
            }
            goto fail;
        }
    }

    return mqttClient->connect(options);

fail:
    cleanupTransport() ;
    return MQTT::FAILURE;
}

int TlsMQTTClient::publish(const char* topicName, MQTT::Message& message) {
    return mqttClient->publish(topicName, message);
}

int TlsMQTTClient::publish(const char* topicName, void* payload, size_t payloadlen, enum MQTT::QoS qos, bool retained) {
    return mqttClient->publish(topicName, payload, payloadlen, qos, retained);
}

int TlsMQTTClient::publish(const char* topicName, void* payload, size_t payloadlen, unsigned short& id, enum MQTT::QoS qos, bool retained) {
    return mqttClient->publish(topicName, payload, payloadlen, id, qos, retained);
}

int TlsMQTTClient::subscribe(const char* topicFilter, enum MQTT::QoS qos, MessageHandler mh) {
    return mqttClient->subscribe(topicFilter, qos, mh);
}

int TlsMQTTClient::unsubscribe(const char* topicFilter) {
    return mqttClient->unsubscribe(topicFilter);
}

int TlsMQTTClient::disconnect() {
    int r = mqttClient->disconnect();
    cleanupTransport();
    return r;
}

int TlsMQTTClient::yield(unsigned long timeout_ms) {
    return mqttClient->yield(timeout_ms);
}

bool TlsMQTTClient::isConnected() {
    return mqttClient->isConnected();
}

void TlsMQTTClient::cleanupTransport() {
    if (ssl) {
        logTrace("freeing ssl");
        CyaSSL_free(ssl) ;
        ssl = NULL ;
    }
    if (ctx) {
        logTrace("freeing ssl ctx");
        CyaSSL_CTX_free(ctx) ;
        ctx = NULL ;
    }
    if (tcp) {
        if (tcp->is_connected()) {
            logTrace("disconnect tcp");
            tcp->close();
        }
        logTrace("freeing tcp");
        delete tcp;
        tcp = NULL;
    }
}

TlsMQTTClient::~TlsMQTTClient() {
    cleanupTransport();
    delete mqttClient;
}

int TlsMQTTClient::read(unsigned char* data, int max, int timeout) {
    return CyaSSL_read(ssl, data, max);
}

int TlsMQTTClient::write(const unsigned char* data, int length, int timeout) {
    return CyaSSL_write(ssl, data, length);
}

int TlsMQTTClient::ioRecv(CYASSL* ssl, char *buf, int sz, void *ctx) {
    TlsMQTTClient* thiz = (TlsMQTTClient*) ctx;
    return thiz->tcp->receive(buf, sz);
}

int TlsMQTTClient::ioSend(CYASSL* ssl, char *buf, int sz, void *ctx) {
    TlsMQTTClient* thiz = (TlsMQTTClient*) ctx;
    return thiz->tcp->send(buf, sz);
}