{"action":"created","comment":{"url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/comments/66691374","id":66691374,"diff_hunk":"@@ -0,0 +1,654 @@\n+/* azureiothub.c\n+ *\n+ * Copyright (C) 2006-2016 wolfSSL Inc.\n+ *\n+ * This file is part of wolfMQTT.\n+ *\n+ * wolfMQTT is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License as published by\n+ * the Free Software Foundation; either version 2 of the License, or\n+ * (at your option) any later version.\n+ *\n+ * wolfMQTT is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA\n+ */\n+\n+/* Include the autoconf generated config.h */\n+#ifdef HAVE_CONFIG_H\n+    #include <config.h>\n+#endif\n+\n+#include \"wolfmqtt/mqtt_client.h\"\n+#include <wolfssl/options.h>\n+#include <wolfssl/version.h>\n+\n+#include \"mqttexample.h\"\n+\n+/* This example only works with ENABLE_MQTT_TLS (wolfSSL library) */\n+/* Notes:\n+ *  The wolfSSL library must be built with\n+ *  #define WOLFSSL_BASE64_ENCODE\n+ *  or\n+ *  ./configure --enable-base64encode\"\n+ *\n+ *  The \"wc_GetTime\" API was added in 3.9.1 and if not present you'll need to implement\n+ *  your own version of this to get current UTC seconds or update your wolfSSL library\n+*/\n+\n+/* This example requires features in wolfSSL 3.9.1 or later */\n+#if defined(ENABLE_MQTT_TLS) && defined(LIBWOLFSSL_VERSION_HEX) && \\\n+    LIBWOLFSSL_VERSION_HEX >= 0x03009001 && defined(WOLFSSL_BASE64_ENCODE)\n+    #undef ENABLE_AZUREIOTHUB_EXAMPLE\n+    #define ENABLE_AZUREIOTHUB_EXAMPLE\n+#endif\n+\n+\n+#ifdef ENABLE_AZUREIOTHUB_EXAMPLE\n+\n+#include <wolfssl/ssl.h>\n+#include <wolfssl/wolfcrypt/asn_public.h>\n+#include <wolfssl/wolfcrypt/coding.h>\n+#include <wolfssl/wolfcrypt/hmac.h>\n+\n+#include \"azureiothub.h\"\n+#include \"mqttnet.h\"\n+\n+/* Globals */\n+int myoptind = 0;\n+char* myoptarg = NULL;\n+\n+/* Locals */\n+static int mStopRead = 0;\n+static const char* mTlsFile = NULL;\n+static int mPacketIdLast;\n+\n+/* Configuration */\n+/* Reference:\n+ * https://azure.microsoft.com/en-us/documentation/articles/iot-hub-mqtt-support\n+ * https://azure.microsoft.com/en-us/documentation/articles/iot-hub-devguide/#mqtt-support\n+ * https://azure.microsoft.com/en-us/documentation/articles/iot-hub-sas-tokens/#using-sas-tokens-as-a-device\n+ */\n+#define MAX_BUFFER_SIZE         1024    /* Maximum size for network read/write callbacks */\n+#define AZURE_HOST              \"wolfMQTT.azure-devices.net\"\n+#define AZURE_DEVICE_ID         \"demoDevice\"\n+#define AZURE_KEY               \"Vd8RHMAFPyRnAozkNCNFIPhVSffyZkB13r/YqiTWq5s=\" /* Base64 Encoded */\n+#define AZURE_QOS               MQTT_QOS_1 /* Azure IoT Hub does not yet support QoS level 2 */\n+#define AZURE_KEEP_ALIVE_SEC    DEFAULT_KEEP_ALIVE_SEC\n+#define AZURE_CMD_TIMEOUT_MS    DEFAULT_CMD_TIMEOUT_MS\n+#define AZURE_TOKEN_EXPIRY_SEC  (60 * 60 * 1) /* 1 hour */\n+\n+#define AZURE_DEVICE_NAME       AZURE_HOST\"/devices/\"AZURE_DEVICE_ID\n+#define AZURE_USERNAME          AZURE_HOST\"/\"AZURE_DEVICE_ID \n+#define AZURE_SIG_FMT           \"%s\\n%ld\"\n+    /* [device name (URL Encoded)]\\n[Expiration sec UTC] */\n+#define AZURE_PASSWORD_FMT      \"SharedAccessSignature sr=%s&sig=%s&se=%ld\"\n+    /* sr=[device name (URL Encoded)]\n+       sig=[HMAC-SHA256 of AZURE_SIG_FMT using AZURE_KEY (URL Encoded)]\n+       se=[Expiration sec UTC] */\n+\n+#define AZURE_MSGS_TOPIC_NAME   \"devices/\"AZURE_DEVICE_ID\"/messages/devicebound/#\" /* subscribe */\n+#define AZURE_EVENT_TOPIC       \"devices/\"AZURE_DEVICE_ID\"/messages/events/\" /* publish */\n+\n+\n+/* Usage */\n+static void Usage(void)\n+{\n+    PRINTF(\"azureiothub:\");\n+    PRINTF(\"-?          Help, print this usage\");\n+    PRINTF(\"-h <host>   Host to connect to, default %s\",\n+        AZURE_HOST);\n+    PRINTF(\"-p <num>    Port to connect on, default: Normal %d, TLS %d\",\n+        MQTT_DEFAULT_PORT, MQTT_SECURE_PORT);\n+    PRINTF(\"-t          Enable TLS, default: on\");\n+    PRINTF(\"-c <file>   Use provided certificate file\");\n+    PRINTF(\"-q <num>    Qos Level 0-2, default %d\",\n+        AZURE_QOS);\n+    PRINTF(\"-s          Disable clean session connect flag\");\n+    PRINTF(\"-k <num>    Keep alive seconds, default %d\",\n+        AZURE_KEEP_ALIVE_SEC);\n+    PRINTF(\"-i <id>     Client Id, default %s\",\n+        AZURE_DEVICE_ID);\n+    PRINTF(\"-l          Enable LWT (Last Will and Testament)\");\n+    PRINTF(\"-C <num>    Command Timeout, default %dms\", AZURE_CMD_TIMEOUT_MS);\n+    PRINTF(\"-T          Test mode\");\n+}\n+\n+\n+/* Encoding Support */\n+static char mRfc3986[256] = {0};\n+//static char mHtml5[256] = {0};\n+static void url_encoder_init(void)\n+{\n+    int i;\n+    for (i = 0; i < 256; i++){\n+        mRfc3986[i] = XISALNUM( i) || i == '~' || i == '-' || i == '.' || i == '_' ? i : 0;\n+        //mHtml5[i] = XISALNUM( i) || i == '*' || i == '-' || i == '.' || i == '_' ? i : (i == ' ') ? '+' : 0;\n+    }\n+}\n+\n+static char* url_encode(char* table, unsigned char *s, char *enc)\n+{\n+    for (; *s; s++){\n+        if (table[*s]) {\n+            sprintf(enc, \"%c\", table[*s]);\n+        }\n+        else {\n+            sprintf(enc, \"%%%02x\", *s);\n+        }\n+        while (*++enc); /* locate end */\n+    }\n+    return enc;\n+}\n+\n+\n+static word16 mqttclient_get_packetid(void)\n+{\n+    mPacketIdLast = (mPacketIdLast >= MAX_PACKET_ID) ?\n+        1 : mPacketIdLast + 1;\n+    return (word16)mPacketIdLast;\n+}\n+\n+static int mqttclient_tls_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)\n+{\n+    char buffer[WOLFSSL_MAX_ERROR_SZ];\n+\n+    PRINTF(\"MQTT TLS Verify Callback: PreVerify %d, Error %d (%s)\", preverify,\n+        store->error, wolfSSL_ERR_error_string(store->error, buffer));\n+    PRINTF(\"  Subject's domain name is %s\", store->domain);\n+\n+    /* Allowing to continue */\n+    /* Should check certificate and return 0 if not okay */\n+    PRINTF(\"  Allowing cert anyways\");\n+\n+    return 1;\n+}\n+\n+/* Use this callback to setup TLS certificates and verify callbacks */\n+static int mqttclient_tls_cb(MqttClient* client)\n+{\n+    int rc = SSL_FAILURE;\n+    (void)client; /* Supress un-used argument */\n+\n+    client->tls.ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());\n+    if (client->tls.ctx) {\n+        wolfSSL_CTX_set_verify(client->tls.ctx, SSL_VERIFY_PEER, mqttclient_tls_verify_cb);\n+\n+        rc = SSL_SUCCESS;\n+        if (mTlsFile) {\n+    #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)\n+            /* Load CA certificate file */\n+            rc = wolfSSL_CTX_load_verify_locations(client->tls.ctx, mTlsFile, NULL);\n+    #endif\n+        }\n+    }\n+\n+    PRINTF(\"MQTT TLS Setup (%d)\", rc);\n+\n+    return rc;\n+}\n+\n+static int mqttclient_message_cb(MqttClient *client, MqttMessage *msg,\n+    byte msg_new, byte msg_done)\n+{\n+    byte buf[PRINT_BUFFER_SIZE+1];\n+    word32 len;\n+\n+    (void)client; /* Supress un-used argument */\n+\n+    if (msg_new) {\n+        /* Determine min size to dump */\n+        len = msg->topic_name_len;\n+        if (len > PRINT_BUFFER_SIZE) {\n+            len = PRINT_BUFFER_SIZE;\n+        }\n+        XMEMCPY(buf, msg->topic_name, len);\n+        buf[len] = '\\0'; /* Make sure its null terminated */\n+\n+        /* Print incoming message */\n+        PRINTF(\"MQTT Message: Topic %s, Qos %d, Len %u\",\n+            buf, msg->qos, msg->total_len);\n+    }\n+\n+    /* Print message payload */\n+    len = msg->buffer_len;\n+    if (len > PRINT_BUFFER_SIZE) {\n+        len = PRINT_BUFFER_SIZE;\n+    }\n+    XMEMCPY(buf, msg->buffer, len);\n+    buf[len] = '\\0'; /* Make sure its null terminated */\n+    PRINTF(\"Payload (%d - %d): %s\",\n+        msg->buffer_pos, msg->buffer_pos + len, buf);\n+\n+    if (msg_done) {\n+        PRINTF(\"MQTT Message: Done\");\n+    }\n+\n+    /* Return negative to terminate publish processing */\n+    return MQTT_CODE_SUCCESS;\n+}\n+\n+static int SasTokenCreate(char* sasToken, int sasTokenLen)\n+{\n+    int rc;\n+    const char* encodedKey = AZURE_KEY;\n+    byte decodedKey[SHA256_DIGEST_SIZE+1];\n+    word32 decodedKeyLen = (word32)sizeof(decodedKey);\n+    char deviceName[150]; /* uri */\n+    char sigData[200]; /* max uri + expiration */\n+    byte sig[SHA256_DIGEST_SIZE];\n+    byte base64Sig[SHA256_DIGEST_SIZE*2];\n+    word32 base64SigLen = (word32)sizeof(base64Sig);\n+    byte encodedSig[SHA256_DIGEST_SIZE*4];\n+    long lTime;\n+    Hmac hmac;\n+\n+    if (sasToken == NULL) {\n+        return MQTT_CODE_ERROR_BAD_ARG;\n+    }\n+\n+    /* Decode Key */\n+    rc = Base64_Decode((const byte*)encodedKey, (word32)XSTRLEN(encodedKey), decodedKey, &decodedKeyLen);\n+    if (rc != 0) {\n+        PRINTF(\"SasTokenCreate: Decode shared access key failed! %d\", rc);\n+        return rc;\n+    }\n+\n+    /* Get time */\n+    rc = wc_GetTime(&lTime, (word32)sizeof(lTime));\n+    if (rc != 0) {\n+        PRINTF(\"SasTokenCreate: Unable to get time! %d\", rc);\n+        return rc;\n+    }\n+    lTime += AZURE_TOKEN_EXPIRY_SEC;\n+\n+    /* URL encode uri (device name) */\n+    url_encode(mRfc3986, (byte*)AZURE_DEVICE_NAME, deviceName);\n+\n+    /* Build signature sting \"uri \\n expiration\" */\n+    snprintf(sigData, sizeof(sigData), AZURE_SIG_FMT, deviceName, lTime);\n+\n+    /* HMAC-SHA256 Hash sigData using decoded key */\n+    rc = wc_HmacSetKey(&hmac, SHA256, decodedKey, decodedKeyLen);\n+    if (rc < 0) {\n+        PRINTF(\"SasTokenCreate: Hmac setkey failed! %d\", rc);\n+        return rc;\n+    }\n+    rc = wc_HmacUpdate(&hmac, (byte*)sigData, (word32)XSTRLEN(sigData));\n+    if (rc < 0) {\n+        PRINTF(\"SasTokenCreate: Hmac update failed! %d\", rc);\n+        return rc;\n+    }\n+    rc = wc_HmacFinal(&hmac, sig);\n+    if (rc < 0) {\n+        PRINTF(\"SasTokenCreate: Hmac final failed! %d\", rc);\n+        return rc;\n+    }\n+\n+    /* Base64 encode signature */\n+    rc = Base64_Encode_NoNl(sig, sizeof(sig), base64Sig, &base64SigLen);\n+    if (rc < 0) {\n+        PRINTF(\"SasTokenCreate: Encoding sig failed! %d\", rc);\n+        return rc;\n+    }\n+\n+    /* URL encode signature */\n+    url_encode(mRfc3986, base64Sig, (char*)encodedSig);\n+\n+    /* Build sasToken */\n+    snprintf(sasToken, sasTokenLen, AZURE_PASSWORD_FMT, deviceName, encodedSig, lTime);\n+    PRINTF(\"%s\", sasToken);\n+\n+    return 0;\n+}\n+\n+int azureiothub_test(void* args)\n+{\n+    int rc;\n+    MqttClient client;\n+    MqttNet net;\n+    word16 port = 0;\n+    const char* host = AZURE_HOST;\n+    int use_tls = 1;\n+    MqttQoS qos = AZURE_QOS;\n+    byte clean_session = 1;\n+    word16 keep_alive_sec = AZURE_KEEP_ALIVE_SEC;\n+    const char* client_id = AZURE_DEVICE_ID;\n+    int enable_lwt = 0;\n+    byte *tx_buf = NULL, *rx_buf = NULL;\n+    word32 cmd_timeout_ms = AZURE_CMD_TIMEOUT_MS;\n+    byte test_mode = 0;\n+    char sasToken[400];\n+\n+    int     argc = ((func_args*)args)->argc;\n+    char**  argv = ((func_args*)args)->argv;\n+\n+    ((func_args*)args)->return_code = -1; /* error state */\n+\n+    while ((rc = mygetopt(argc, argv, \"?h:p:tc:q:sk:i:lC:T\")) != -1) {\n+        switch ((char)rc) {\n+            case '?' :\n+                Usage();\n+                exit(EXIT_SUCCESS);\n+\n+            case 'h' :\n+                host = myoptarg;\n+                break;\n+\n+            case 'p' :\n+                port = (word16)XATOI(myoptarg);\n+                if (port == 0) {\n+                    return err_sys(\"Invalid Port Number!\");\n+                }\n+                break;\n+\n+            case 't':\n+                use_tls = 1;\n+                break;\n+\n+            case 'c':\n+                mTlsFile = myoptarg;\n+                break;\n+\n+            case 'q' :\n+                qos = (MqttQoS)((byte)XATOI(myoptarg));\n+                if (qos > MQTT_QOS_2) {\n+                    return err_sys(\"Invalid QoS value!\");\n+                }\n+                break;\n+\n+            case 's':\n+                clean_session = 0;\n+                break;\n+\n+            case 'k':\n+                keep_alive_sec = XATOI(myoptarg);\n+                break;\n+\n+            case 'i':\n+                client_id = myoptarg;\n+                break;\n+\n+            case 'l':\n+                enable_lwt = 1;\n+                break;\n+\n+            case 'C':\n+                cmd_timeout_ms = XATOI(myoptarg);\n+                break;\n+\n+            case 'T':\n+                test_mode = 1;\n+                break;\n+\n+            default:\n+                Usage();\n+                exit(MY_EX_USAGE);\n+        }\n+    }\n+\n+    myoptind = 0; /* reset for test cases */\n+    url_encoder_init();\n+\n+    /* Start example MQTT Client */\n+    PRINTF(\"AzureIoTHub Client: QoS %d, Use TLS %d\", qos, use_tls);\n+\n+    /* Initialize Network */\n+    rc = MqttClientNet_Init(&net);\n+    PRINTF(\"MQTT Net Init: %s (%d)\",\n+        MqttClient_ReturnCodeToString(rc), rc);\n+    if (rc != MQTT_CODE_SUCCESS) {\n+        goto exit;\n+    }\n+\n+    /* Initialize MqttClient structure */\n+    tx_buf = (byte*)WOLFMQTT_MALLOC(MAX_BUFFER_SIZE);\n+    rx_buf = (byte*)WOLFMQTT_MALLOC(MAX_BUFFER_SIZE);\n+    rc = MqttClient_Init(&client, &net, mqttclient_message_cb,\n+        tx_buf, MAX_BUFFER_SIZE, rx_buf, MAX_BUFFER_SIZE,\n+        cmd_timeout_ms);\n+    PRINTF(\"MQTT Init: %s (%d)\",\n+        MqttClient_ReturnCodeToString(rc), rc);\n+    if (rc != MQTT_CODE_SUCCESS) {\n+        goto exit;\n+    }\n+\n+    /* Connect to broker */\n+    rc = MqttClient_NetConnect(&client, host, port,\n+        DEFAULT_CON_TIMEOUT_MS, use_tls, mqttclient_tls_cb);\n+    PRINTF(\"MQTT Socket Connect: %s (%d)\",\n+        MqttClient_ReturnCodeToString(rc), rc);\n+    if (rc == MQTT_CODE_SUCCESS) {\n+        /* Define connect parameters */\n+        MqttConnect connect;\n+        MqttMessage lwt_msg;\n+        XMEMSET(&connect, 0, sizeof(MqttConnect));\n+        connect.keep_alive_sec = keep_alive_sec;\n+        connect.clean_session = clean_session;\n+        connect.client_id = client_id;\n+        /* Last will and testament sent by broker to subscribers\n+            of topic when broker connection is lost */\n+        XMEMSET(&lwt_msg, 0, sizeof(lwt_msg));\n+        connect.lwt_msg = &lwt_msg;\n+        connect.enable_lwt = enable_lwt;\n+        if (enable_lwt) {\n+            /* Send client id in LWT payload */\n+            lwt_msg.qos = qos;\n+            lwt_msg.retain = 0;\n+            lwt_msg.topic_name = AZURE_EVENT_TOPIC;\n+            lwt_msg.buffer = (byte*)client_id;\n+            lwt_msg.total_len = (word16)XSTRLEN(client_id);\n+        }\n+        /* Authentication */\n+        /* build sas token for password */\n+        rc = SasTokenCreate(sasToken, (int)sizeof(sasToken));\n+        if (rc < 0) {\n+            goto exit;\n+        }\n+        connect.username = AZURE_USERNAME;\n+        connect.password = sasToken;\n+\n+        /* Send Connect and wait for Connect Ack */\n+        rc = MqttClient_Connect(&client, &connect);\n+        PRINTF(\"MQTT Connect: %s (%d)\",\n+            MqttClient_ReturnCodeToString(rc), rc);\n+        if (rc == MQTT_CODE_SUCCESS) {\n+            MqttSubscribe subscribe;\n+            MqttUnsubscribe unsubscribe;\n+            MqttTopic topics[1], *topic;\n+            MqttPublish publish;\n+            int i;\n+\n+            /* Build list of topics */\n+            topics[0].topic_filter = AZURE_MSGS_TOPIC_NAME;\n+            topics[0].qos = qos;\n+\n+            /* Validate Connect Ack info */\n+            PRINTF(\"MQTT Connect Ack: Return Code %u, Session Present %d\",\n+                connect.ack.return_code,\n+                (connect.ack.flags & MQTT_CONNECT_ACK_FLAG_SESSION_PRESENT) ?\n+                    1 : 0\n+            );\n+\n+            /* Subscribe Topic */\n+            XMEMSET(&subscribe, 0, sizeof(MqttSubscribe));\n+            subscribe.packet_id = mqttclient_get_packetid();\n+            subscribe.topic_count = sizeof(topics)/sizeof(MqttTopic);\n+            subscribe.topics = topics;\n+            rc = MqttClient_Subscribe(&client, &subscribe);\n+            PRINTF(\"MQTT Subscribe: %s (%d)\",\n+                MqttClient_ReturnCodeToString(rc), rc);\n+            if (rc != MQTT_CODE_SUCCESS) {\n+                goto exit;\n+            }\n+            for (i = 0; i < subscribe.topic_count; i++) {\n+                topic = &subscribe.topics[i];\n+                PRINTF(\"  Topic %s, Qos %u, Return Code %u\",\n+                    topic->topic_filter, topic->qos, topic->return_code);\n+            }\n+\n+            /* Publish Topic */\n+            XMEMSET(&publish, 0, sizeof(MqttPublish));\n+            publish.retain = 0;\n+            publish.qos = qos;\n+            publish.duplicate = 0;\n+            publish.topic_name = AZURE_EVENT_TOPIC;\n+            publish.packet_id = mqttclient_get_packetid();\n+            publish.buffer = NULL;\n+            publish.total_len = 0;\n+            rc = MqttClient_Publish(&client, &publish);\n+            PRINTF(\"MQTT Publish: Topic %s, %s (%d)\",\n+                publish.topic_name, MqttClient_ReturnCodeToString(rc), rc);\n+            if (rc != MQTT_CODE_SUCCESS) {\n+                goto exit;\n+            }\n+\n+            /* Read Loop */\n+            PRINTF(\"MQTT Waiting for message...\");\n+            MqttClientNet_CheckForCommand_Enable(&net);\n+            while (mStopRead == 0) {\n+                /* Try and read packet */\n+                rc = MqttClient_WaitMessage(&client, cmd_timeout_ms);\n+                if (rc == MQTT_CODE_ERROR_TIMEOUT) {\n+                    /* Check to see if command data (stdin) is available */\n+                    rc = MqttClientNet_CheckForCommand(&net, rx_buf, MAX_BUFFER_SIZE);\n+                    if (rc > 0) {\n+                        /* Publish Topic */\n+                        XMEMSET(&publish, 0, sizeof(MqttPublish));\n+                        publish.retain = 0;\n+                        publish.qos = qos;\n+                        publish.duplicate = 0;\n+                        publish.topic_name = AZURE_EVENT_TOPIC;\n+                        publish.packet_id = mqttclient_get_packetid();\n+                        publish.buffer = rx_buf;\n+                        publish.total_len = (word16)rc;\n+                        rc = MqttClient_Publish(&client, &publish);\n+                        PRINTF(\"MQTT Publish: Topic %s, %s (%d)\",\n+                            publish.topic_name, MqttClient_ReturnCodeToString(rc), rc);\n+                    }\n+                    /* Keep Alive */\n+                    else {\n+                        rc = MqttClient_Ping(&client);\n+                        if (rc != MQTT_CODE_SUCCESS) {\n+                            PRINTF(\"MQTT Ping Keep Alive Error: %s (%d)\",\n+                                MqttClient_ReturnCodeToString(rc), rc);\n+                            break;\n+                        }\n+                    }\n+                }\n+                else if (rc != MQTT_CODE_SUCCESS) {\n+                    /* There was an error */\n+                    PRINTF(\"MQTT Message Wait: %s (%d)\",\n+                        MqttClient_ReturnCodeToString(rc), rc);\n+                    break;\n+                }\n+\n+                /* Exit if test mode */\n+                if (test_mode) {\n+                    break;\n+                }\n+            }\n+            /* Check for error */\n+            if (rc != MQTT_CODE_SUCCESS) {\n+                goto exit;\n+            }\n+\n+            /* Unsubscribe Topics */\n+            XMEMSET(&unsubscribe, 0, sizeof(MqttUnsubscribe));\n+            unsubscribe.packet_id = mqttclient_get_packetid();\n+            unsubscribe.topic_count = sizeof(topics)/sizeof(MqttTopic);\n+            unsubscribe.topics = topics;\n+            rc = MqttClient_Unsubscribe(&client, &unsubscribe);\n+            PRINTF(\"MQTT Unsubscribe: %s (%d)\",\n+                MqttClient_ReturnCodeToString(rc), rc);\n+            if (rc != MQTT_CODE_SUCCESS) {\n+                goto exit;\n+            }\n+\n+            /* Disconnect */\n+            rc = MqttClient_Disconnect(&client);\n+            PRINTF(\"MQTT Disconnect: %s (%d)\",\n+                MqttClient_ReturnCodeToString(rc), rc);\n+        }\n+\n+        rc = MqttClient_NetDisconnect(&client);\n+        PRINTF(\"MQTT Socket Disconnect: %s (%d)\",\n+             MqttClient_ReturnCodeToString(rc), rc);\n+    }\n+\n+exit:\n+    /* Free resources */\n+    if (tx_buf) WOLFMQTT_FREE(tx_buf);\n+    if (rx_buf) WOLFMQTT_FREE(rx_buf);\n+\n+    /* Cleanup network */\n+    MqttClientNet_DeInit(&net);\n+\n+    /* Set return code */\n+    ((func_args*)args)->return_code = (rc == 0) ? 0 : EXIT_FAILURE;\n+\n+    return 0;\n+}\n+#endif /* ENABLE_AZUREIOTHUB_EXAMPLE */\n+\n+\n+/* so overall tests can pull in test function */\n+#ifndef NO_MAIN_DRIVER\n+    #ifdef USE_WINDOWS_API\n+        static BOOL CtrlHandler(DWORD fdwCtrlType)\n+        {\n+            if (fdwCtrlType == CTRL_C_EVENT) {\n+            #ifdef ENABLE_AZUREIOTHUB_EXAMPLE\n+                mStopRead = 1;\n+            #endif\n+                PRINTF(\"Received Ctrl+c\");\n+                return TRUE;\n+            }\n+            return FALSE;\n+        }\n+    #elif HAVE_SIGNAL\n+        #include <signal.h>\n+        static void sig_handler(int signo)\n+        {\n+            if (signo == SIGINT) {\n+            #ifdef ENABLE_AZUREIOTHUB_EXAMPLE\n+                mStopRead = 1;\n+            #endif\n+                PRINTF(\"Received SIGINT\");\n+            }\n+        }\n+    #endif\n+\n+    int main(int argc, char** argv)\n+    {\n+        func_args args;\n+\n+        args.argc = argc;\n+        args.argv = argv;\n+\n+#ifdef USE_WINDOWS_API\n+        if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE) == FALSE) {\n+            PRINTF(\"Error setting Ctrl Handler! Error %d\", (int)GetLastError());\n+        }\n+#elif HAVE_SIGNAL\n+        if (signal(SIGINT, sig_handler) == SIG_ERR) {\n+            PRINTF(\"Can't catch SIGINT\");\n+        }\n+#endif\n+\n+    #ifdef ENABLE_AZUREIOTHUB_EXAMPLE\n+        azureiothub_test(&args);\n+    #else\n+        /* This example requires wolfSSL 3.9.1 or later with base64encode enabled */\n+        PRINTF(\"Example not compiled in!\");","path":"examples/azure/azureiothub.c","position":648,"original_position":648,"commit_id":"3fb86b88b7cc0bf61b5acb632fbd15761cb0765a","original_commit_id":"3fb86b88b7cc0bf61b5acb632fbd15761cb0765a","user":{"login":"JacobBarthelmeh","id":7565298,"avatar_url":"https://avatars.githubusercontent.com/u/7565298?v=3","gravatar_id":"","url":"https://api.github.com/users/JacobBarthelmeh","html_url":"https://github.com/JacobBarthelmeh","followers_url":"https://api.github.com/users/JacobBarthelmeh/followers","following_url":"https://api.github.com/users/JacobBarthelmeh/following{/other_user}","gists_url":"https://api.github.com/users/JacobBarthelmeh/gists{/gist_id}","starred_url":"https://api.github.com/users/JacobBarthelmeh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JacobBarthelmeh/subscriptions","organizations_url":"https://api.github.com/users/JacobBarthelmeh/orgs","repos_url":"https://api.github.com/users/JacobBarthelmeh/repos","events_url":"https://api.github.com/users/JacobBarthelmeh/events{/privacy}","received_events_url":"https://api.github.com/users/JacobBarthelmeh/received_events","type":"User","site_admin":false},"body":"args return value should be set in the else case","created_at":"2016-06-10T22:50:04Z","updated_at":"2016-06-10T22:50:04Z","html_url":"https://github.com/wolfSSL/wolfMQTT/pull/9#discussion_r66691374","pull_request_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9","_links":{"self":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/comments/66691374"},"html":{"href":"https://github.com/wolfSSL/wolfMQTT/pull/9#discussion_r66691374"},"pull_request":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9"}}},"pull_request":{"url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9","id":73436424,"html_url":"https://github.com/wolfSSL/wolfMQTT/pull/9","diff_url":"https://github.com/wolfSSL/wolfMQTT/pull/9.diff","patch_url":"https://github.com/wolfSSL/wolfMQTT/pull/9.patch","issue_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues/9","number":9,"state":"open","locked":false,"title":"Azure IoT hub MQTT client support","user":{"login":"dgarske","id":2692870,"avatar_url":"https://avatars.githubusercontent.com/u/2692870?v=3","gravatar_id":"","url":"https://api.github.com/users/dgarske","html_url":"https://github.com/dgarske","followers_url":"https://api.github.com/users/dgarske/followers","following_url":"https://api.github.com/users/dgarske/following{/other_user}","gists_url":"https://api.github.com/users/dgarske/gists{/gist_id}","starred_url":"https://api.github.com/users/dgarske/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dgarske/subscriptions","organizations_url":"https://api.github.com/users/dgarske/orgs","repos_url":"https://api.github.com/users/dgarske/repos","events_url":"https://api.github.com/users/dgarske/events{/privacy}","received_events_url":"https://api.github.com/users/dgarske/received_events","type":"User","site_admin":false},"body":"Uses wolfMQTT demo IoT hub with \"demoDevice\" device / key. Demonstrates how to create a SasToken using the key, uri and expiration. Demonstrates how to publish events and listening to devicebound messages.","created_at":"2016-06-10T21:09:18Z","updated_at":"2016-06-10T22:50:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3e3af4c0225196eb71a8a359a275d825cd23af3a","assignee":{"login":"JacobBarthelmeh","id":7565298,"avatar_url":"https://avatars.githubusercontent.com/u/7565298?v=3","gravatar_id":"","url":"https://api.github.com/users/JacobBarthelmeh","html_url":"https://github.com/JacobBarthelmeh","followers_url":"https://api.github.com/users/JacobBarthelmeh/followers","following_url":"https://api.github.com/users/JacobBarthelmeh/following{/other_user}","gists_url":"https://api.github.com/users/JacobBarthelmeh/gists{/gist_id}","starred_url":"https://api.github.com/users/JacobBarthelmeh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JacobBarthelmeh/subscriptions","organizations_url":"https://api.github.com/users/JacobBarthelmeh/orgs","repos_url":"https://api.github.com/users/JacobBarthelmeh/repos","events_url":"https://api.github.com/users/JacobBarthelmeh/events{/privacy}","received_events_url":"https://api.github.com/users/JacobBarthelmeh/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9/commits","review_comments_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9/comments","review_comment_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues/9/comments","statuses_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/statuses/3fb86b88b7cc0bf61b5acb632fbd15761cb0765a","head":{"label":"dgarske:azureiothub","ref":"azureiothub","sha":"3fb86b88b7cc0bf61b5acb632fbd15761cb0765a","user":{"login":"dgarske","id":2692870,"avatar_url":"https://avatars.githubusercontent.com/u/2692870?v=3","gravatar_id":"","url":"https://api.github.com/users/dgarske","html_url":"https://github.com/dgarske","followers_url":"https://api.github.com/users/dgarske/followers","following_url":"https://api.github.com/users/dgarske/following{/other_user}","gists_url":"https://api.github.com/users/dgarske/gists{/gist_id}","starred_url":"https://api.github.com/users/dgarske/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dgarske/subscriptions","organizations_url":"https://api.github.com/users/dgarske/orgs","repos_url":"https://api.github.com/users/dgarske/repos","events_url":"https://api.github.com/users/dgarske/events{/privacy}","received_events_url":"https://api.github.com/users/dgarske/received_events","type":"User","site_admin":false},"repo":{"id":51347588,"name":"wolfMQTT","full_name":"dgarske/wolfMQTT","owner":{"login":"dgarske","id":2692870,"avatar_url":"https://avatars.githubusercontent.com/u/2692870?v=3","gravatar_id":"","url":"https://api.github.com/users/dgarske","html_url":"https://github.com/dgarske","followers_url":"https://api.github.com/users/dgarske/followers","following_url":"https://api.github.com/users/dgarske/following{/other_user}","gists_url":"https://api.github.com/users/dgarske/gists{/gist_id}","starred_url":"https://api.github.com/users/dgarske/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dgarske/subscriptions","organizations_url":"https://api.github.com/users/dgarske/orgs","repos_url":"https://api.github.com/users/dgarske/repos","events_url":"https://api.github.com/users/dgarske/events{/privacy}","received_events_url":"https://api.github.com/users/dgarske/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dgarske/wolfMQTT","description":"","fork":true,"url":"https://api.github.com/repos/dgarske/wolfMQTT","forks_url":"https://api.github.com/repos/dgarske/wolfMQTT/forks","keys_url":"https://api.github.com/repos/dgarske/wolfMQTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dgarske/wolfMQTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dgarske/wolfMQTT/teams","hooks_url":"https://api.github.com/repos/dgarske/wolfMQTT/hooks","issue_events_url":"https://api.github.com/repos/dgarske/wolfMQTT/issues/events{/number}","events_url":"https://api.github.com/repos/dgarske/wolfMQTT/events","assignees_url":"https://api.github.com/repos/dgarske/wolfMQTT/assignees{/user}","branches_url":"https://api.github.com/repos/dgarske/wolfMQTT/branches{/branch}","tags_url":"https://api.github.com/repos/dgarske/wolfMQTT/tags","blobs_url":"https://api.github.com/repos/dgarske/wolfMQTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dgarske/wolfMQTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dgarske/wolfMQTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/dgarske/wolfMQTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dgarske/wolfMQTT/statuses/{sha}","languages_url":"https://api.github.com/repos/dgarske/wolfMQTT/languages","stargazers_url":"https://api.github.com/repos/dgarske/wolfMQTT/stargazers","contributors_url":"https://api.github.com/repos/dgarske/wolfMQTT/contributors","subscribers_url":"https://api.github.com/repos/dgarske/wolfMQTT/subscribers","subscription_url":"https://api.github.com/repos/dgarske/wolfMQTT/subscription","commits_url":"https://api.github.com/repos/dgarske/wolfMQTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/dgarske/wolfMQTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/dgarske/wolfMQTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/dgarske/wolfMQTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/dgarske/wolfMQTT/contents/{+path}","compare_url":"https://api.github.com/repos/dgarske/wolfMQTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dgarske/wolfMQTT/merges","archive_url":"https://api.github.com/repos/dgarske/wolfMQTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dgarske/wolfMQTT/downloads","issues_url":"https://api.github.com/repos/dgarske/wolfMQTT/issues{/number}","pulls_url":"https://api.github.com/repos/dgarske/wolfMQTT/pulls{/number}","milestones_url":"https://api.github.com/repos/dgarske/wolfMQTT/milestones{/number}","notifications_url":"https://api.github.com/repos/dgarske/wolfMQTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dgarske/wolfMQTT/labels{/name}","releases_url":"https://api.github.com/repos/dgarske/wolfMQTT/releases{/id}","deployments_url":"https://api.github.com/repos/dgarske/wolfMQTT/deployments","created_at":"2016-02-09T04:58:53Z","updated_at":"2016-03-18T16:28:45Z","pushed_at":"2016-06-10T22:34:00Z","git_url":"git://github.com/dgarske/wolfMQTT.git","ssh_url":"git@github.com:dgarske/wolfMQTT.git","clone_url":"https://github.com/dgarske/wolfMQTT.git","svn_url":"https://github.com/dgarske/wolfMQTT","homepage":null,"size":234,"stargazers_count":0,"watchers_count":0,"language":"M4","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"wolfSSL:master","ref":"master","sha":"7a1ab12a48042c3f93ec28463c0db49e752c1cbd","user":{"login":"wolfSSL","id":5891092,"avatar_url":"https://avatars.githubusercontent.com/u/5891092?v=3","gravatar_id":"","url":"https://api.github.com/users/wolfSSL","html_url":"https://github.com/wolfSSL","followers_url":"https://api.github.com/users/wolfSSL/followers","following_url":"https://api.github.com/users/wolfSSL/following{/other_user}","gists_url":"https://api.github.com/users/wolfSSL/gists{/gist_id}","starred_url":"https://api.github.com/users/wolfSSL/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wolfSSL/subscriptions","organizations_url":"https://api.github.com/users/wolfSSL/orgs","repos_url":"https://api.github.com/users/wolfSSL/repos","events_url":"https://api.github.com/users/wolfSSL/events{/privacy}","received_events_url":"https://api.github.com/users/wolfSSL/received_events","type":"Organization","site_admin":false},"repo":{"id":44983668,"name":"wolfMQTT","full_name":"wolfSSL/wolfMQTT","owner":{"login":"wolfSSL","id":5891092,"avatar_url":"https://avatars.githubusercontent.com/u/5891092?v=3","gravatar_id":"","url":"https://api.github.com/users/wolfSSL","html_url":"https://github.com/wolfSSL","followers_url":"https://api.github.com/users/wolfSSL/followers","following_url":"https://api.github.com/users/wolfSSL/following{/other_user}","gists_url":"https://api.github.com/users/wolfSSL/gists{/gist_id}","starred_url":"https://api.github.com/users/wolfSSL/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wolfSSL/subscriptions","organizations_url":"https://api.github.com/users/wolfSSL/orgs","repos_url":"https://api.github.com/users/wolfSSL/repos","events_url":"https://api.github.com/users/wolfSSL/events{/privacy}","received_events_url":"https://api.github.com/users/wolfSSL/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wolfSSL/wolfMQTT","description":"","fork":false,"url":"https://api.github.com/repos/wolfSSL/wolfMQTT","forks_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/forks","keys_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/teams","hooks_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/hooks","issue_events_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues/events{/number}","events_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/events","assignees_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/assignees{/user}","branches_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/branches{/branch}","tags_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/tags","blobs_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/git/refs{/sha}","trees_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/statuses/{sha}","languages_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/languages","stargazers_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/stargazers","contributors_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/contributors","subscribers_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/subscribers","subscription_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/subscription","commits_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/commits{/sha}","git_commits_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/git/commits{/sha}","comments_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/comments{/number}","issue_comment_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues/comments{/number}","contents_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/contents/{+path}","compare_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/merges","archive_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/downloads","issues_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues{/number}","pulls_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls{/number}","milestones_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/milestones{/number}","notifications_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/labels{/name}","releases_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/releases{/id}","deployments_url":"https://api.github.com/repos/wolfSSL/wolfMQTT/deployments","created_at":"2015-10-26T16:58:13Z","updated_at":"2016-06-05T13:07:05Z","pushed_at":"2016-06-10T22:34:00Z","git_url":"git://github.com/wolfSSL/wolfMQTT.git","ssh_url":"git@github.com:wolfSSL/wolfMQTT.git","clone_url":"https://github.com/wolfSSL/wolfMQTT.git","svn_url":"https://github.com/wolfSSL/wolfMQTT","homepage":null,"size":231,"stargazers_count":24,"watchers_count":24,"language":"M4","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"open_issues_count":1,"forks":8,"open_issues":1,"watchers":24,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9"},"html":{"href":"https://github.com/wolfSSL/wolfMQTT/pull/9"},"issue":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues/9"},"comments":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/issues/9/comments"},"review_comments":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9/comments"},"review_comment":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/pulls/9/commits"},"statuses":{"href":"https://api.github.com/repos/wolfSSL/wolfMQTT/statuses/3fb86b88b7cc0bf61b5acb632fbd15761cb0765a"}}}}
{"actor":{"display_login":"JacobBarthelmeh"}}