Microsoft Azure IoTHub client MQTT transport

Dependents:   STM32F746_iothub_client_sample_mqtt FXOS8700CQ_To_Azure_IoT f767zi_mqtt FXOS8700CQ_To_Azure_IoT ... more

Committer:
AzureIoTClient
Date:
Thu Oct 20 17:07:21 2016 -0700
Revision:
11:31ebaeb51e1e
Child:
12:658ca6865de2
1.0.10

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 11:31ebaeb51e1e 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 11:31ebaeb51e1e 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 11:31ebaeb51e1e 3
AzureIoTClient 11:31ebaeb51e1e 4 #include <stdlib.h>
AzureIoTClient 11:31ebaeb51e1e 5 #ifdef _CRTDBG_MAP_ALLOC
AzureIoTClient 11:31ebaeb51e1e 6 #include <crtdbg.h>
AzureIoTClient 11:31ebaeb51e1e 7 #endif
AzureIoTClient 11:31ebaeb51e1e 8 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 11:31ebaeb51e1e 9
AzureIoTClient 11:31ebaeb51e1e 10 #include "azure_c_shared_utility/xlogging.h"
AzureIoTClient 11:31ebaeb51e1e 11 #include "azure_c_shared_utility/strings.h"
AzureIoTClient 11:31ebaeb51e1e 12 #include "azure_c_shared_utility/doublylinkedlist.h"
AzureIoTClient 11:31ebaeb51e1e 13 #include "azure_c_shared_utility/crt_abstractions.h"
AzureIoTClient 11:31ebaeb51e1e 14
AzureIoTClient 11:31ebaeb51e1e 15 #include "iothub_client_ll.h"
AzureIoTClient 11:31ebaeb51e1e 16 #include "iothub_client_options.h"
AzureIoTClient 11:31ebaeb51e1e 17 #include "iothub_client_private.h"
AzureIoTClient 11:31ebaeb51e1e 18 #include "azure_umqtt_c/mqtt_client.h"
AzureIoTClient 11:31ebaeb51e1e 19 #include "azure_c_shared_utility/sastoken.h"
AzureIoTClient 11:31ebaeb51e1e 20 #include "azure_c_shared_utility/tickcounter.h"
AzureIoTClient 11:31ebaeb51e1e 21
AzureIoTClient 11:31ebaeb51e1e 22 #include "azure_c_shared_utility/tlsio.h"
AzureIoTClient 11:31ebaeb51e1e 23 #include "azure_c_shared_utility/platform.h"
AzureIoTClient 11:31ebaeb51e1e 24
AzureIoTClient 11:31ebaeb51e1e 25 #include "azure_c_shared_utility/string_tokenizer.h"
AzureIoTClient 11:31ebaeb51e1e 26 #include "iothub_client_version.h"
AzureIoTClient 11:31ebaeb51e1e 27
AzureIoTClient 11:31ebaeb51e1e 28 #include "iothubtransport_mqtt_common.h"
AzureIoTClient 11:31ebaeb51e1e 29
AzureIoTClient 11:31ebaeb51e1e 30 #include <stdarg.h>
AzureIoTClient 11:31ebaeb51e1e 31 #include <stdio.h>
AzureIoTClient 11:31ebaeb51e1e 32
AzureIoTClient 11:31ebaeb51e1e 33 #include <limits.h>
AzureIoTClient 11:31ebaeb51e1e 34
AzureIoTClient 11:31ebaeb51e1e 35 #define SAS_TOKEN_DEFAULT_LIFETIME 3600
AzureIoTClient 11:31ebaeb51e1e 36 #define SAS_REFRESH_MULTIPLIER .8
AzureIoTClient 11:31ebaeb51e1e 37 #define EPOCH_TIME_T_VALUE 0
AzureIoTClient 11:31ebaeb51e1e 38 #define DEFAULT_MQTT_KEEPALIVE 4*60 // 4 min
AzureIoTClient 11:31ebaeb51e1e 39 #define BUILD_CONFIG_USERNAME 24
AzureIoTClient 11:31ebaeb51e1e 40 #define SAS_TOKEN_DEFAULT_LEN 10
AzureIoTClient 11:31ebaeb51e1e 41 #define RESEND_TIMEOUT_VALUE_MIN 1*60
AzureIoTClient 11:31ebaeb51e1e 42 #define MAX_SEND_RECOUNT_LIMIT 2
AzureIoTClient 11:31ebaeb51e1e 43 #define DEFAULT_CONNECTION_INTERVAL 30
AzureIoTClient 11:31ebaeb51e1e 44 #define FAILED_CONN_BACKOFF_VALUE 5
AzureIoTClient 11:31ebaeb51e1e 45
AzureIoTClient 11:31ebaeb51e1e 46 static const char* TOPIC_DEVICE_MSG = "devices/%s/messages/devicebound/#";
AzureIoTClient 11:31ebaeb51e1e 47 static const char* TOPIC_DEVICE_DEVICE = "devices/%s/messages/events/";
AzureIoTClient 11:31ebaeb51e1e 48 static const char* PROPERTY_SEPARATOR = "&";
AzureIoTClient 11:31ebaeb51e1e 49
AzureIoTClient 11:31ebaeb51e1e 50 #define UNSUBSCRIBE_FROM_TOPIC 0x0000
AzureIoTClient 11:31ebaeb51e1e 51 #define SUBSCRIBE_TELEMETRY_TOPIC 0x0004
AzureIoTClient 11:31ebaeb51e1e 52 #define SUBSCRIBE_TOPIC_COUNT 1
AzureIoTClient 11:31ebaeb51e1e 53
AzureIoTClient 11:31ebaeb51e1e 54 typedef struct SYSTEM_PROPERTY_INFO_TAG
AzureIoTClient 11:31ebaeb51e1e 55 {
AzureIoTClient 11:31ebaeb51e1e 56 const char* propName;
AzureIoTClient 11:31ebaeb51e1e 57 size_t propLength;
AzureIoTClient 11:31ebaeb51e1e 58 } SYSTEM_PROPERTY_INFO;
AzureIoTClient 11:31ebaeb51e1e 59
AzureIoTClient 11:31ebaeb51e1e 60 static SYSTEM_PROPERTY_INFO sysPropList[] = {
AzureIoTClient 11:31ebaeb51e1e 61 { "%24.exp", 7 },
AzureIoTClient 11:31ebaeb51e1e 62 { "%24.mid", 7 },
AzureIoTClient 11:31ebaeb51e1e 63 { "%24.uid", 7 },
AzureIoTClient 11:31ebaeb51e1e 64 { "%24.to", 6 },
AzureIoTClient 11:31ebaeb51e1e 65 { "%24.cid", 7 },
AzureIoTClient 11:31ebaeb51e1e 66 { "devices/", 8 },
AzureIoTClient 11:31ebaeb51e1e 67 { "iothub-operation", 16 },
AzureIoTClient 11:31ebaeb51e1e 68 { "iothub-ack", 10 }
AzureIoTClient 11:31ebaeb51e1e 69 };
AzureIoTClient 11:31ebaeb51e1e 70
AzureIoTClient 11:31ebaeb51e1e 71 static TICK_COUNTER_HANDLE g_msgTickCounter;
AzureIoTClient 11:31ebaeb51e1e 72
AzureIoTClient 11:31ebaeb51e1e 73 typedef enum MQTT_TRANSPORT_CREDENTIAL_TYPE_TAG
AzureIoTClient 11:31ebaeb51e1e 74 {
AzureIoTClient 11:31ebaeb51e1e 75 CREDENTIAL_NOT_BUILD,
AzureIoTClient 11:31ebaeb51e1e 76 X509,
AzureIoTClient 11:31ebaeb51e1e 77 SAS_TOKEN_FROM_USER,
AzureIoTClient 11:31ebaeb51e1e 78 DEVICE_KEY,
AzureIoTClient 11:31ebaeb51e1e 79 } MQTT_TRANSPORT_CREDENTIAL_TYPE;
AzureIoTClient 11:31ebaeb51e1e 80
AzureIoTClient 11:31ebaeb51e1e 81 typedef struct MQTT_TRANSPORT_CREDENTIALS_TAG
AzureIoTClient 11:31ebaeb51e1e 82 {
AzureIoTClient 11:31ebaeb51e1e 83 MQTT_TRANSPORT_CREDENTIAL_TYPE credential_type;
AzureIoTClient 11:31ebaeb51e1e 84 union
AzureIoTClient 11:31ebaeb51e1e 85 {
AzureIoTClient 11:31ebaeb51e1e 86 // Key associated to the device to be used.
AzureIoTClient 11:31ebaeb51e1e 87 STRING_HANDLE deviceKey;
AzureIoTClient 11:31ebaeb51e1e 88
AzureIoTClient 11:31ebaeb51e1e 89 // SAS associated to the device to be used.
AzureIoTClient 11:31ebaeb51e1e 90 STRING_HANDLE deviceSasToken;
AzureIoTClient 11:31ebaeb51e1e 91
AzureIoTClient 11:31ebaeb51e1e 92 } CREDENTIAL_VALUE;
AzureIoTClient 11:31ebaeb51e1e 93 } MQTT_TRANSPORT_CREDENTIALS;
AzureIoTClient 11:31ebaeb51e1e 94
AzureIoTClient 11:31ebaeb51e1e 95 typedef struct MQTTTRANSPORT_HANDLE_DATA_TAG
AzureIoTClient 11:31ebaeb51e1e 96 {
AzureIoTClient 11:31ebaeb51e1e 97 // Topic control
AzureIoTClient 11:31ebaeb51e1e 98 STRING_HANDLE topic_MqttEvent;
AzureIoTClient 11:31ebaeb51e1e 99 STRING_HANDLE topic_MqttMessage;
AzureIoTClient 11:31ebaeb51e1e 100
AzureIoTClient 11:31ebaeb51e1e 101 uint32_t topics_ToSubscribe;
AzureIoTClient 11:31ebaeb51e1e 102 // Connection related constants
AzureIoTClient 11:31ebaeb51e1e 103 STRING_HANDLE hostAddress;
AzureIoTClient 11:31ebaeb51e1e 104 STRING_HANDLE device_id;
AzureIoTClient 11:31ebaeb51e1e 105 STRING_HANDLE devicesPath;
AzureIoTClient 11:31ebaeb51e1e 106 int portNum;
AzureIoTClient 11:31ebaeb51e1e 107
AzureIoTClient 11:31ebaeb51e1e 108 // Authentication
AzureIoTClient 11:31ebaeb51e1e 109 MQTT_TRANSPORT_CREDENTIALS transport_creds;
AzureIoTClient 11:31ebaeb51e1e 110
AzureIoTClient 11:31ebaeb51e1e 111 MQTT_GET_IO_TRANSPORT get_io_transport;
AzureIoTClient 11:31ebaeb51e1e 112
AzureIoTClient 11:31ebaeb51e1e 113 // The current mqtt iothub implementation requires that the hub name and the domain suffix be passed as the first of a series of segments
AzureIoTClient 11:31ebaeb51e1e 114 // passed through the username portion of the connection frame.
AzureIoTClient 11:31ebaeb51e1e 115 // The second segment will contain the device id. The two segments are delemited by a "/".
AzureIoTClient 11:31ebaeb51e1e 116 // The first segment can be a maximum 256 characters.
AzureIoTClient 11:31ebaeb51e1e 117 // The second segment can be a maximum 128 characters.
AzureIoTClient 11:31ebaeb51e1e 118 // With the / delimeter you have 384 chars (Plus a terminator of 0).
AzureIoTClient 11:31ebaeb51e1e 119 STRING_HANDLE configPassedThroughUsername;
AzureIoTClient 11:31ebaeb51e1e 120
AzureIoTClient 11:31ebaeb51e1e 121 // Upper layer
AzureIoTClient 11:31ebaeb51e1e 122 IOTHUB_CLIENT_LL_HANDLE llClientHandle;
AzureIoTClient 11:31ebaeb51e1e 123
AzureIoTClient 11:31ebaeb51e1e 124 // Protocol
AzureIoTClient 11:31ebaeb51e1e 125 MQTT_CLIENT_HANDLE mqttClient;
AzureIoTClient 11:31ebaeb51e1e 126 XIO_HANDLE xioTransport;
AzureIoTClient 11:31ebaeb51e1e 127
AzureIoTClient 11:31ebaeb51e1e 128 // Session - connection
AzureIoTClient 11:31ebaeb51e1e 129 uint16_t packetId;
AzureIoTClient 11:31ebaeb51e1e 130
AzureIoTClient 11:31ebaeb51e1e 131 // Connection state control
AzureIoTClient 11:31ebaeb51e1e 132 bool isRegistered;
AzureIoTClient 11:31ebaeb51e1e 133 bool isConnected;
AzureIoTClient 11:31ebaeb51e1e 134 bool isDestroyCalled;
AzureIoTClient 11:31ebaeb51e1e 135 uint16_t keepAliveValue;
AzureIoTClient 11:31ebaeb51e1e 136 uint64_t mqtt_connect_time;
AzureIoTClient 11:31ebaeb51e1e 137 size_t connectFailCount;
AzureIoTClient 11:31ebaeb51e1e 138 uint64_t connectTick;
AzureIoTClient 11:31ebaeb51e1e 139 bool log_trace;
AzureIoTClient 11:31ebaeb51e1e 140 bool raw_trace;
AzureIoTClient 11:31ebaeb51e1e 141
AzureIoTClient 11:31ebaeb51e1e 142 // Internal lists for message tracking
AzureIoTClient 11:31ebaeb51e1e 143 PDLIST_ENTRY waitingToSend;
AzureIoTClient 11:31ebaeb51e1e 144 // Message tracking
AzureIoTClient 11:31ebaeb51e1e 145 CONTROL_PACKET_TYPE currPacketState;
AzureIoTClient 11:31ebaeb51e1e 146
AzureIoTClient 11:31ebaeb51e1e 147 // Telemetry specific
AzureIoTClient 11:31ebaeb51e1e 148 DLIST_ENTRY telemetry_waitingForAck;
AzureIoTClient 11:31ebaeb51e1e 149 } MQTTTRANSPORT_HANDLE_DATA, *PMQTTTRANSPORT_HANDLE_DATA;
AzureIoTClient 11:31ebaeb51e1e 150
AzureIoTClient 11:31ebaeb51e1e 151 typedef struct MQTT_MESSAGE_DETAILS_LIST_TAG
AzureIoTClient 11:31ebaeb51e1e 152 {
AzureIoTClient 11:31ebaeb51e1e 153 uint64_t msgPublishTime;
AzureIoTClient 11:31ebaeb51e1e 154 size_t retryCount;
AzureIoTClient 11:31ebaeb51e1e 155 IOTHUB_MESSAGE_LIST* iotHubMessageEntry;
AzureIoTClient 11:31ebaeb51e1e 156 void* context;
AzureIoTClient 11:31ebaeb51e1e 157 uint16_t packet_id;
AzureIoTClient 11:31ebaeb51e1e 158 DLIST_ENTRY entry;
AzureIoTClient 11:31ebaeb51e1e 159 } MQTT_MESSAGE_DETAILS_LIST, *PMQTT_MESSAGE_DETAILS_LIST;
AzureIoTClient 11:31ebaeb51e1e 160
AzureIoTClient 11:31ebaeb51e1e 161 static uint16_t get_next_packet_id(PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 162 {
AzureIoTClient 11:31ebaeb51e1e 163 if (transport_data->packetId+1 >= USHRT_MAX)
AzureIoTClient 11:31ebaeb51e1e 164 {
AzureIoTClient 11:31ebaeb51e1e 165 transport_data->packetId = 1;
AzureIoTClient 11:31ebaeb51e1e 166 }
AzureIoTClient 11:31ebaeb51e1e 167 else
AzureIoTClient 11:31ebaeb51e1e 168 {
AzureIoTClient 11:31ebaeb51e1e 169 transport_data->packetId++;
AzureIoTClient 11:31ebaeb51e1e 170 }
AzureIoTClient 11:31ebaeb51e1e 171 return transport_data->packetId;
AzureIoTClient 11:31ebaeb51e1e 172 }
AzureIoTClient 11:31ebaeb51e1e 173
AzureIoTClient 11:31ebaeb51e1e 174 static const char* retrieve_mqtt_return_codes(CONNECT_RETURN_CODE rtn_code)
AzureIoTClient 11:31ebaeb51e1e 175 {
AzureIoTClient 11:31ebaeb51e1e 176 switch (rtn_code)
AzureIoTClient 11:31ebaeb51e1e 177 {
AzureIoTClient 11:31ebaeb51e1e 178 case CONNECTION_ACCEPTED:
AzureIoTClient 11:31ebaeb51e1e 179 return "Accepted";
AzureIoTClient 11:31ebaeb51e1e 180 case CONN_REFUSED_UNACCEPTABLE_VERSION:
AzureIoTClient 11:31ebaeb51e1e 181 return "Unacceptable Version";
AzureIoTClient 11:31ebaeb51e1e 182 case CONN_REFUSED_ID_REJECTED:
AzureIoTClient 11:31ebaeb51e1e 183 return "Id Rejected";
AzureIoTClient 11:31ebaeb51e1e 184 case CONN_REFUSED_SERVER_UNAVAIL:
AzureIoTClient 11:31ebaeb51e1e 185 return "Server Unavailable";
AzureIoTClient 11:31ebaeb51e1e 186 case CONN_REFUSED_BAD_USERNAME_PASSWORD:
AzureIoTClient 11:31ebaeb51e1e 187 return "Bad Username/Password";
AzureIoTClient 11:31ebaeb51e1e 188 case CONN_REFUSED_NOT_AUTHORIZED:
AzureIoTClient 11:31ebaeb51e1e 189 return "Not Authorized";
AzureIoTClient 11:31ebaeb51e1e 190 case CONN_REFUSED_UNKNOWN:
AzureIoTClient 11:31ebaeb51e1e 191 default:
AzureIoTClient 11:31ebaeb51e1e 192 return "Unknown";
AzureIoTClient 11:31ebaeb51e1e 193 }
AzureIoTClient 11:31ebaeb51e1e 194 }
AzureIoTClient 11:31ebaeb51e1e 195
AzureIoTClient 11:31ebaeb51e1e 196 static void sendMsgComplete(IOTHUB_MESSAGE_LIST* iothubMsgList, PMQTTTRANSPORT_HANDLE_DATA transport_data, IOTHUB_CLIENT_CONFIRMATION_RESULT confirmResult)
AzureIoTClient 11:31ebaeb51e1e 197 {
AzureIoTClient 11:31ebaeb51e1e 198 DLIST_ENTRY messageCompleted;
AzureIoTClient 11:31ebaeb51e1e 199 DList_InitializeListHead(&messageCompleted);
AzureIoTClient 11:31ebaeb51e1e 200 DList_InsertTailList(&messageCompleted, &(iothubMsgList->entry));
AzureIoTClient 11:31ebaeb51e1e 201 IoTHubClient_LL_SendComplete(transport_data->llClientHandle, &messageCompleted, confirmResult);
AzureIoTClient 11:31ebaeb51e1e 202 }
AzureIoTClient 11:31ebaeb51e1e 203
AzureIoTClient 11:31ebaeb51e1e 204 static STRING_HANDLE addPropertiesTouMqttMessage(IOTHUB_MESSAGE_HANDLE iothub_message_handle, const char* eventTopic)
AzureIoTClient 11:31ebaeb51e1e 205 {
AzureIoTClient 11:31ebaeb51e1e 206 STRING_HANDLE result = STRING_construct(eventTopic);
AzureIoTClient 11:31ebaeb51e1e 207 const char* const* propertyKeys;
AzureIoTClient 11:31ebaeb51e1e 208 const char* const* propertyValues;
AzureIoTClient 11:31ebaeb51e1e 209 size_t propertyCount;
AzureIoTClient 11:31ebaeb51e1e 210
AzureIoTClient 11:31ebaeb51e1e 211 // Construct Properties
AzureIoTClient 11:31ebaeb51e1e 212 MAP_HANDLE properties_map = IoTHubMessage_Properties(iothub_message_handle);
AzureIoTClient 11:31ebaeb51e1e 213 if (properties_map != NULL)
AzureIoTClient 11:31ebaeb51e1e 214 {
AzureIoTClient 11:31ebaeb51e1e 215 if (Map_GetInternals(properties_map, &propertyKeys, &propertyValues, &propertyCount) != MAP_OK)
AzureIoTClient 11:31ebaeb51e1e 216 {
AzureIoTClient 11:31ebaeb51e1e 217 LogError("Failed to get the internals of the property map.");
AzureIoTClient 11:31ebaeb51e1e 218 STRING_delete(result);
AzureIoTClient 11:31ebaeb51e1e 219 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 220 }
AzureIoTClient 11:31ebaeb51e1e 221 else
AzureIoTClient 11:31ebaeb51e1e 222 {
AzureIoTClient 11:31ebaeb51e1e 223 if (propertyCount != 0)
AzureIoTClient 11:31ebaeb51e1e 224 {
AzureIoTClient 11:31ebaeb51e1e 225 for (size_t index = 0; index < propertyCount && result != NULL; index++)
AzureIoTClient 11:31ebaeb51e1e 226 {
AzureIoTClient 11:31ebaeb51e1e 227 if (STRING_sprintf(result, "%s=%s%s", propertyKeys[index], propertyValues[index], propertyCount - 1 == index ? "" : PROPERTY_SEPARATOR) != 0)
AzureIoTClient 11:31ebaeb51e1e 228 {
AzureIoTClient 11:31ebaeb51e1e 229 STRING_delete(result);
AzureIoTClient 11:31ebaeb51e1e 230 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 231 }
AzureIoTClient 11:31ebaeb51e1e 232 }
AzureIoTClient 11:31ebaeb51e1e 233 }
AzureIoTClient 11:31ebaeb51e1e 234 }
AzureIoTClient 11:31ebaeb51e1e 235 }
AzureIoTClient 11:31ebaeb51e1e 236 return result;
AzureIoTClient 11:31ebaeb51e1e 237 }
AzureIoTClient 11:31ebaeb51e1e 238
AzureIoTClient 11:31ebaeb51e1e 239 static int publish_mqtt_telemetry_msg(PMQTTTRANSPORT_HANDLE_DATA transport_data, MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry, const unsigned char* payload, size_t len)
AzureIoTClient 11:31ebaeb51e1e 240 {
AzureIoTClient 11:31ebaeb51e1e 241 int result;
AzureIoTClient 11:31ebaeb51e1e 242 STRING_HANDLE msgTopic = addPropertiesTouMqttMessage(mqttMsgEntry->iotHubMessageEntry->messageHandle, STRING_c_str(transport_data->topic_MqttEvent));
AzureIoTClient 11:31ebaeb51e1e 243 if (msgTopic == NULL)
AzureIoTClient 11:31ebaeb51e1e 244 {
AzureIoTClient 11:31ebaeb51e1e 245 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 246 }
AzureIoTClient 11:31ebaeb51e1e 247 else
AzureIoTClient 11:31ebaeb51e1e 248 {
AzureIoTClient 11:31ebaeb51e1e 249 MQTT_MESSAGE_HANDLE mqttMsg = mqttmessage_create(mqttMsgEntry->packet_id, STRING_c_str(msgTopic), DELIVER_AT_LEAST_ONCE, payload, len);
AzureIoTClient 11:31ebaeb51e1e 250 if (mqttMsg == NULL)
AzureIoTClient 11:31ebaeb51e1e 251 {
AzureIoTClient 11:31ebaeb51e1e 252 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 253 }
AzureIoTClient 11:31ebaeb51e1e 254 else
AzureIoTClient 11:31ebaeb51e1e 255 {
AzureIoTClient 11:31ebaeb51e1e 256 if (tickcounter_get_current_ms(g_msgTickCounter, &mqttMsgEntry->msgPublishTime) != 0)
AzureIoTClient 11:31ebaeb51e1e 257 {
AzureIoTClient 11:31ebaeb51e1e 258 LogError("Failed retrieving tickcounter info");
AzureIoTClient 11:31ebaeb51e1e 259 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 260 }
AzureIoTClient 11:31ebaeb51e1e 261 else
AzureIoTClient 11:31ebaeb51e1e 262 {
AzureIoTClient 11:31ebaeb51e1e 263 if (mqtt_client_publish(transport_data->mqttClient, mqttMsg) != 0)
AzureIoTClient 11:31ebaeb51e1e 264 {
AzureIoTClient 11:31ebaeb51e1e 265 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 266 }
AzureIoTClient 11:31ebaeb51e1e 267 else
AzureIoTClient 11:31ebaeb51e1e 268 {
AzureIoTClient 11:31ebaeb51e1e 269 mqttMsgEntry->retryCount++;
AzureIoTClient 11:31ebaeb51e1e 270 result = 0;
AzureIoTClient 11:31ebaeb51e1e 271 }
AzureIoTClient 11:31ebaeb51e1e 272 }
AzureIoTClient 11:31ebaeb51e1e 273 mqttmessage_destroy(mqttMsg);
AzureIoTClient 11:31ebaeb51e1e 274 }
AzureIoTClient 11:31ebaeb51e1e 275 STRING_delete(msgTopic);
AzureIoTClient 11:31ebaeb51e1e 276 }
AzureIoTClient 11:31ebaeb51e1e 277 return result;
AzureIoTClient 11:31ebaeb51e1e 278 }
AzureIoTClient 11:31ebaeb51e1e 279
AzureIoTClient 11:31ebaeb51e1e 280 static bool isSystemProperty(const char* tokenData)
AzureIoTClient 11:31ebaeb51e1e 281 {
AzureIoTClient 11:31ebaeb51e1e 282 bool result = false;
AzureIoTClient 11:31ebaeb51e1e 283 size_t propCount = sizeof(sysPropList)/sizeof(sysPropList[0]);
AzureIoTClient 11:31ebaeb51e1e 284 for (size_t index = 0; index < propCount; index++)
AzureIoTClient 11:31ebaeb51e1e 285 {
AzureIoTClient 11:31ebaeb51e1e 286 if (memcmp(tokenData, sysPropList[index].propName, sysPropList[index].propLength) == 0)
AzureIoTClient 11:31ebaeb51e1e 287 {
AzureIoTClient 11:31ebaeb51e1e 288 result = true;
AzureIoTClient 11:31ebaeb51e1e 289 break;
AzureIoTClient 11:31ebaeb51e1e 290 }
AzureIoTClient 11:31ebaeb51e1e 291 }
AzureIoTClient 11:31ebaeb51e1e 292 return result;
AzureIoTClient 11:31ebaeb51e1e 293 }
AzureIoTClient 11:31ebaeb51e1e 294
AzureIoTClient 11:31ebaeb51e1e 295 static int extractMqttProperties(IOTHUB_MESSAGE_HANDLE IoTHubMessage, const char* topic_name)
AzureIoTClient 11:31ebaeb51e1e 296 {
AzureIoTClient 11:31ebaeb51e1e 297 int result;
AzureIoTClient 11:31ebaeb51e1e 298 STRING_HANDLE mqttTopic = STRING_construct(topic_name);
AzureIoTClient 11:31ebaeb51e1e 299 if (mqttTopic == NULL)
AzureIoTClient 11:31ebaeb51e1e 300 {
AzureIoTClient 11:31ebaeb51e1e 301 LogError("Failure constructing string topic name.");
AzureIoTClient 11:31ebaeb51e1e 302 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 303 }
AzureIoTClient 11:31ebaeb51e1e 304 else
AzureIoTClient 11:31ebaeb51e1e 305 {
AzureIoTClient 11:31ebaeb51e1e 306 STRING_TOKENIZER_HANDLE token = STRING_TOKENIZER_create(mqttTopic);
AzureIoTClient 11:31ebaeb51e1e 307 if (token != NULL)
AzureIoTClient 11:31ebaeb51e1e 308 {
AzureIoTClient 11:31ebaeb51e1e 309 MAP_HANDLE propertyMap = IoTHubMessage_Properties(IoTHubMessage);
AzureIoTClient 11:31ebaeb51e1e 310 if (propertyMap == NULL)
AzureIoTClient 11:31ebaeb51e1e 311 {
AzureIoTClient 11:31ebaeb51e1e 312 LogError("Failure to retrieve IoTHubMessage_properties.");
AzureIoTClient 11:31ebaeb51e1e 313 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 314 }
AzureIoTClient 11:31ebaeb51e1e 315 else
AzureIoTClient 11:31ebaeb51e1e 316 {
AzureIoTClient 11:31ebaeb51e1e 317 STRING_HANDLE output = STRING_new();
AzureIoTClient 11:31ebaeb51e1e 318 if (output == NULL)
AzureIoTClient 11:31ebaeb51e1e 319 {
AzureIoTClient 11:31ebaeb51e1e 320 LogError("Failure to allocate STRING_new.");
AzureIoTClient 11:31ebaeb51e1e 321 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 322 }
AzureIoTClient 11:31ebaeb51e1e 323 else
AzureIoTClient 11:31ebaeb51e1e 324 {
AzureIoTClient 11:31ebaeb51e1e 325 result = 0;
AzureIoTClient 11:31ebaeb51e1e 326 while (STRING_TOKENIZER_get_next_token(token, output, PROPERTY_SEPARATOR) == 0 && result == 0)
AzureIoTClient 11:31ebaeb51e1e 327 {
AzureIoTClient 11:31ebaeb51e1e 328 const char* tokenData = STRING_c_str(output);
AzureIoTClient 11:31ebaeb51e1e 329 size_t tokenLen = strlen(tokenData);
AzureIoTClient 11:31ebaeb51e1e 330 if (tokenData == NULL || tokenLen == 0)
AzureIoTClient 11:31ebaeb51e1e 331 {
AzureIoTClient 11:31ebaeb51e1e 332 break;
AzureIoTClient 11:31ebaeb51e1e 333 }
AzureIoTClient 11:31ebaeb51e1e 334 else
AzureIoTClient 11:31ebaeb51e1e 335 {
AzureIoTClient 11:31ebaeb51e1e 336 if (!isSystemProperty(tokenData) )
AzureIoTClient 11:31ebaeb51e1e 337 {
AzureIoTClient 11:31ebaeb51e1e 338 const char* iterator = tokenData;
AzureIoTClient 11:31ebaeb51e1e 339 while (iterator != NULL && *iterator != '\0' && result == 0)
AzureIoTClient 11:31ebaeb51e1e 340 {
AzureIoTClient 11:31ebaeb51e1e 341 if (*iterator == '=')
AzureIoTClient 11:31ebaeb51e1e 342 {
AzureIoTClient 11:31ebaeb51e1e 343 size_t nameLen = iterator - tokenData;
AzureIoTClient 11:31ebaeb51e1e 344 char* propName = malloc(nameLen + 1);
AzureIoTClient 11:31ebaeb51e1e 345
AzureIoTClient 11:31ebaeb51e1e 346 size_t valLen = tokenLen - (nameLen + 1) + 1;
AzureIoTClient 11:31ebaeb51e1e 347 char* propValue = malloc(valLen + 1);
AzureIoTClient 11:31ebaeb51e1e 348
AzureIoTClient 11:31ebaeb51e1e 349 if (propName == NULL || propValue == NULL)
AzureIoTClient 11:31ebaeb51e1e 350 {
AzureIoTClient 11:31ebaeb51e1e 351 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 352 }
AzureIoTClient 11:31ebaeb51e1e 353 else
AzureIoTClient 11:31ebaeb51e1e 354 {
AzureIoTClient 11:31ebaeb51e1e 355 strncpy(propName, tokenData, nameLen);
AzureIoTClient 11:31ebaeb51e1e 356 propName[nameLen] = '\0';
AzureIoTClient 11:31ebaeb51e1e 357
AzureIoTClient 11:31ebaeb51e1e 358 strncpy(propValue, iterator + 1, valLen);
AzureIoTClient 11:31ebaeb51e1e 359 propValue[valLen] = '\0';
AzureIoTClient 11:31ebaeb51e1e 360
AzureIoTClient 11:31ebaeb51e1e 361 if (Map_AddOrUpdate(propertyMap, propName, propValue) != MAP_OK)
AzureIoTClient 11:31ebaeb51e1e 362 {
AzureIoTClient 11:31ebaeb51e1e 363 LogError("Map_AddOrUpdate failed.");
AzureIoTClient 11:31ebaeb51e1e 364 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 365 }
AzureIoTClient 11:31ebaeb51e1e 366 }
AzureIoTClient 11:31ebaeb51e1e 367 free(propName);
AzureIoTClient 11:31ebaeb51e1e 368 free(propValue);
AzureIoTClient 11:31ebaeb51e1e 369
AzureIoTClient 11:31ebaeb51e1e 370 break;
AzureIoTClient 11:31ebaeb51e1e 371 }
AzureIoTClient 11:31ebaeb51e1e 372 iterator++;
AzureIoTClient 11:31ebaeb51e1e 373 }
AzureIoTClient 11:31ebaeb51e1e 374 }
AzureIoTClient 11:31ebaeb51e1e 375 }
AzureIoTClient 11:31ebaeb51e1e 376 }
AzureIoTClient 11:31ebaeb51e1e 377 STRING_delete(output);
AzureIoTClient 11:31ebaeb51e1e 378 }
AzureIoTClient 11:31ebaeb51e1e 379 }
AzureIoTClient 11:31ebaeb51e1e 380 STRING_TOKENIZER_destroy(token);
AzureIoTClient 11:31ebaeb51e1e 381 }
AzureIoTClient 11:31ebaeb51e1e 382 else
AzureIoTClient 11:31ebaeb51e1e 383 {
AzureIoTClient 11:31ebaeb51e1e 384 LogError("Unable to create Tokenizer object.");
AzureIoTClient 11:31ebaeb51e1e 385 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 386 }
AzureIoTClient 11:31ebaeb51e1e 387 STRING_delete(mqttTopic);
AzureIoTClient 11:31ebaeb51e1e 388 }
AzureIoTClient 11:31ebaeb51e1e 389 return result;
AzureIoTClient 11:31ebaeb51e1e 390 }
AzureIoTClient 11:31ebaeb51e1e 391
AzureIoTClient 11:31ebaeb51e1e 392 static void mqtt_notification_callback(MQTT_MESSAGE_HANDLE msgHandle, void* callbackCtx)
AzureIoTClient 11:31ebaeb51e1e 393 {
AzureIoTClient 11:31ebaeb51e1e 394 if (msgHandle != NULL && callbackCtx != NULL)
AzureIoTClient 11:31ebaeb51e1e 395 {
AzureIoTClient 11:31ebaeb51e1e 396 const char* topic_resp = mqttmessage_getTopicName(msgHandle);
AzureIoTClient 11:31ebaeb51e1e 397 if (topic_resp == NULL)
AzureIoTClient 11:31ebaeb51e1e 398 {
AzureIoTClient 11:31ebaeb51e1e 399 LogError("Failure: NULL topic name encountered");
AzureIoTClient 11:31ebaeb51e1e 400 }
AzureIoTClient 11:31ebaeb51e1e 401 else
AzureIoTClient 11:31ebaeb51e1e 402 {
AzureIoTClient 11:31ebaeb51e1e 403 PMQTTTRANSPORT_HANDLE_DATA transportData = (PMQTTTRANSPORT_HANDLE_DATA)callbackCtx;
AzureIoTClient 11:31ebaeb51e1e 404
AzureIoTClient 11:31ebaeb51e1e 405 const APP_PAYLOAD* appPayload = mqttmessage_getApplicationMsg(msgHandle);
AzureIoTClient 11:31ebaeb51e1e 406 IOTHUB_MESSAGE_HANDLE IoTHubMessage = IoTHubMessage_CreateFromByteArray(appPayload->message, appPayload->length);
AzureIoTClient 11:31ebaeb51e1e 407 if (IoTHubMessage == NULL)
AzureIoTClient 11:31ebaeb51e1e 408 {
AzureIoTClient 11:31ebaeb51e1e 409 LogError("Failure: IotHub Message creation has failed.");
AzureIoTClient 11:31ebaeb51e1e 410 }
AzureIoTClient 11:31ebaeb51e1e 411 else
AzureIoTClient 11:31ebaeb51e1e 412 {
AzureIoTClient 11:31ebaeb51e1e 413 // Will need to update this when the service has messages that can be rejected
AzureIoTClient 11:31ebaeb51e1e 414 if (extractMqttProperties(IoTHubMessage, topic_resp) != 0)
AzureIoTClient 11:31ebaeb51e1e 415 {
AzureIoTClient 11:31ebaeb51e1e 416 LogError("failure extracting mqtt properties.");
AzureIoTClient 11:31ebaeb51e1e 417 }
AzureIoTClient 11:31ebaeb51e1e 418 else
AzureIoTClient 11:31ebaeb51e1e 419 {
AzureIoTClient 11:31ebaeb51e1e 420 if (IoTHubClient_LL_MessageCallback(transportData->llClientHandle, IoTHubMessage) != IOTHUBMESSAGE_ACCEPTED)
AzureIoTClient 11:31ebaeb51e1e 421 {
AzureIoTClient 11:31ebaeb51e1e 422 LogError("Event not accepted by our client.");
AzureIoTClient 11:31ebaeb51e1e 423 }
AzureIoTClient 11:31ebaeb51e1e 424 }
AzureIoTClient 11:31ebaeb51e1e 425 IoTHubMessage_Destroy(IoTHubMessage);
AzureIoTClient 11:31ebaeb51e1e 426 }
AzureIoTClient 11:31ebaeb51e1e 427 }
AzureIoTClient 11:31ebaeb51e1e 428 }
AzureIoTClient 11:31ebaeb51e1e 429 }
AzureIoTClient 11:31ebaeb51e1e 430
AzureIoTClient 11:31ebaeb51e1e 431 static void mqtt_operation_complete_callback(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_RESULT actionResult, const void* msgInfo, void* callbackCtx)
AzureIoTClient 11:31ebaeb51e1e 432 {
AzureIoTClient 11:31ebaeb51e1e 433 (void)handle;
AzureIoTClient 11:31ebaeb51e1e 434 if (callbackCtx != NULL)
AzureIoTClient 11:31ebaeb51e1e 435 {
AzureIoTClient 11:31ebaeb51e1e 436 PMQTTTRANSPORT_HANDLE_DATA transport_data = (PMQTTTRANSPORT_HANDLE_DATA)callbackCtx;
AzureIoTClient 11:31ebaeb51e1e 437
AzureIoTClient 11:31ebaeb51e1e 438 switch (actionResult)
AzureIoTClient 11:31ebaeb51e1e 439 {
AzureIoTClient 11:31ebaeb51e1e 440 case MQTT_CLIENT_ON_PUBLISH_ACK:
AzureIoTClient 11:31ebaeb51e1e 441 case MQTT_CLIENT_ON_PUBLISH_COMP:
AzureIoTClient 11:31ebaeb51e1e 442 {
AzureIoTClient 11:31ebaeb51e1e 443 const PUBLISH_ACK* puback = (const PUBLISH_ACK*)msgInfo;
AzureIoTClient 11:31ebaeb51e1e 444 if (puback != NULL)
AzureIoTClient 11:31ebaeb51e1e 445 {
AzureIoTClient 11:31ebaeb51e1e 446 PDLIST_ENTRY currentListEntry = transport_data->telemetry_waitingForAck.Flink;
AzureIoTClient 11:31ebaeb51e1e 447 while (currentListEntry != &transport_data->telemetry_waitingForAck)
AzureIoTClient 11:31ebaeb51e1e 448 {
AzureIoTClient 11:31ebaeb51e1e 449 MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = containingRecord(currentListEntry, MQTT_MESSAGE_DETAILS_LIST, entry);
AzureIoTClient 11:31ebaeb51e1e 450 DLIST_ENTRY saveListEntry;
AzureIoTClient 11:31ebaeb51e1e 451 saveListEntry.Flink = currentListEntry->Flink;
AzureIoTClient 11:31ebaeb51e1e 452
AzureIoTClient 11:31ebaeb51e1e 453 if (puback->packetId == mqttMsgEntry->packet_id)
AzureIoTClient 11:31ebaeb51e1e 454 {
AzureIoTClient 11:31ebaeb51e1e 455 (void)DList_RemoveEntryList(currentListEntry); //First remove the item from Waiting for Ack List.
AzureIoTClient 11:31ebaeb51e1e 456 sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transport_data, IOTHUB_CLIENT_CONFIRMATION_OK);
AzureIoTClient 11:31ebaeb51e1e 457 free(mqttMsgEntry);
AzureIoTClient 11:31ebaeb51e1e 458 }
AzureIoTClient 11:31ebaeb51e1e 459 currentListEntry = saveListEntry.Flink;
AzureIoTClient 11:31ebaeb51e1e 460 }
AzureIoTClient 11:31ebaeb51e1e 461 }
AzureIoTClient 11:31ebaeb51e1e 462 else
AzureIoTClient 11:31ebaeb51e1e 463 {
AzureIoTClient 11:31ebaeb51e1e 464 LogError("Failure: MQTT_CLIENT_ON_PUBLISH_ACK publish_ack structure NULL.");
AzureIoTClient 11:31ebaeb51e1e 465 }
AzureIoTClient 11:31ebaeb51e1e 466 break;
AzureIoTClient 11:31ebaeb51e1e 467 }
AzureIoTClient 11:31ebaeb51e1e 468 case MQTT_CLIENT_ON_CONNACK:
AzureIoTClient 11:31ebaeb51e1e 469 {
AzureIoTClient 11:31ebaeb51e1e 470 const CONNECT_ACK* connack = (const CONNECT_ACK*)msgInfo;
AzureIoTClient 11:31ebaeb51e1e 471 if (connack != NULL)
AzureIoTClient 11:31ebaeb51e1e 472 {
AzureIoTClient 11:31ebaeb51e1e 473 if (connack->returnCode == CONNECTION_ACCEPTED)
AzureIoTClient 11:31ebaeb51e1e 474 {
AzureIoTClient 11:31ebaeb51e1e 475 // The connect packet has been acked
AzureIoTClient 11:31ebaeb51e1e 476 transport_data->currPacketState = CONNACK_TYPE;
AzureIoTClient 11:31ebaeb51e1e 477 }
AzureIoTClient 11:31ebaeb51e1e 478 else
AzureIoTClient 11:31ebaeb51e1e 479 {
AzureIoTClient 11:31ebaeb51e1e 480 LogError("Connection Not Accepted: 0x%x: %s", connack->returnCode, retrieve_mqtt_return_codes(connack->returnCode) );
AzureIoTClient 11:31ebaeb51e1e 481 (void)mqtt_client_disconnect(transport_data->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 482 transport_data->isConnected = false;
AzureIoTClient 11:31ebaeb51e1e 483 transport_data->currPacketState = PACKET_TYPE_ERROR;
AzureIoTClient 11:31ebaeb51e1e 484 }
AzureIoTClient 11:31ebaeb51e1e 485 }
AzureIoTClient 11:31ebaeb51e1e 486 else
AzureIoTClient 11:31ebaeb51e1e 487 {
AzureIoTClient 11:31ebaeb51e1e 488 LogError("MQTT_CLIENT_ON_CONNACK CONNACK parameter is NULL.");
AzureIoTClient 11:31ebaeb51e1e 489 }
AzureIoTClient 11:31ebaeb51e1e 490 break;
AzureIoTClient 11:31ebaeb51e1e 491 }
AzureIoTClient 11:31ebaeb51e1e 492 case MQTT_CLIENT_ON_SUBSCRIBE_ACK:
AzureIoTClient 11:31ebaeb51e1e 493 {
AzureIoTClient 11:31ebaeb51e1e 494 const SUBSCRIBE_ACK* suback = (const SUBSCRIBE_ACK*)msgInfo;
AzureIoTClient 11:31ebaeb51e1e 495 if (suback != NULL)
AzureIoTClient 11:31ebaeb51e1e 496 {
AzureIoTClient 11:31ebaeb51e1e 497 for (size_t index = 0; index < suback->qosCount; index++)
AzureIoTClient 11:31ebaeb51e1e 498 {
AzureIoTClient 11:31ebaeb51e1e 499 if (suback->qosReturn[index] == DELIVER_FAILURE)
AzureIoTClient 11:31ebaeb51e1e 500 {
AzureIoTClient 11:31ebaeb51e1e 501 LogError("Subscribe delivery failure of subscribe %zu", index);
AzureIoTClient 11:31ebaeb51e1e 502 }
AzureIoTClient 11:31ebaeb51e1e 503 }
AzureIoTClient 11:31ebaeb51e1e 504 // The connect packet has been acked
AzureIoTClient 11:31ebaeb51e1e 505 transport_data->currPacketState = SUBACK_TYPE;
AzureIoTClient 11:31ebaeb51e1e 506 }
AzureIoTClient 11:31ebaeb51e1e 507 else
AzureIoTClient 11:31ebaeb51e1e 508 {
AzureIoTClient 11:31ebaeb51e1e 509 LogError("Failure: MQTT_CLIENT_ON_SUBSCRIBE_ACK SUBSCRIBE_ACK parameter is NULL.");
AzureIoTClient 11:31ebaeb51e1e 510 }
AzureIoTClient 11:31ebaeb51e1e 511 break;
AzureIoTClient 11:31ebaeb51e1e 512 }
AzureIoTClient 11:31ebaeb51e1e 513 case MQTT_CLIENT_ON_PUBLISH_RECV:
AzureIoTClient 11:31ebaeb51e1e 514 case MQTT_CLIENT_ON_PUBLISH_REL:
AzureIoTClient 11:31ebaeb51e1e 515 {
AzureIoTClient 11:31ebaeb51e1e 516 // Currently not used
AzureIoTClient 11:31ebaeb51e1e 517 break;
AzureIoTClient 11:31ebaeb51e1e 518 }
AzureIoTClient 11:31ebaeb51e1e 519 case MQTT_CLIENT_ON_DISCONNECT:
AzureIoTClient 11:31ebaeb51e1e 520 {
AzureIoTClient 11:31ebaeb51e1e 521 // Close the client so we can reconnect again
AzureIoTClient 11:31ebaeb51e1e 522 transport_data->isConnected = false;
AzureIoTClient 11:31ebaeb51e1e 523 transport_data->currPacketState = DISCONNECT_TYPE;
AzureIoTClient 11:31ebaeb51e1e 524 break;
AzureIoTClient 11:31ebaeb51e1e 525 }
AzureIoTClient 11:31ebaeb51e1e 526 case MQTT_CLIENT_NO_PING_RESPONSE:
AzureIoTClient 11:31ebaeb51e1e 527 LogError("Mqtt Ping Response was not encountered. Reconnecting device...");
AzureIoTClient 11:31ebaeb51e1e 528 case MQTT_CLIENT_ON_ERROR:
AzureIoTClient 11:31ebaeb51e1e 529 {
AzureIoTClient 11:31ebaeb51e1e 530 transport_data->isConnected = false;
AzureIoTClient 11:31ebaeb51e1e 531 transport_data->currPacketState = PACKET_TYPE_ERROR;
AzureIoTClient 11:31ebaeb51e1e 532 if (transport_data->topic_MqttMessage != NULL)
AzureIoTClient 11:31ebaeb51e1e 533 {
AzureIoTClient 11:31ebaeb51e1e 534 transport_data->topics_ToSubscribe |= SUBSCRIBE_TELEMETRY_TOPIC;
AzureIoTClient 11:31ebaeb51e1e 535 }
AzureIoTClient 11:31ebaeb51e1e 536 }
AzureIoTClient 11:31ebaeb51e1e 537 }
AzureIoTClient 11:31ebaeb51e1e 538 }
AzureIoTClient 11:31ebaeb51e1e 539 }
AzureIoTClient 11:31ebaeb51e1e 540
AzureIoTClient 11:31ebaeb51e1e 541 static void SubscribeToMqttProtocol(PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 542 {
AzureIoTClient 11:31ebaeb51e1e 543 if (transport_data->topics_ToSubscribe != UNSUBSCRIBE_FROM_TOPIC)
AzureIoTClient 11:31ebaeb51e1e 544 {
AzureIoTClient 11:31ebaeb51e1e 545 uint32_t topic_subscription = 0;
AzureIoTClient 11:31ebaeb51e1e 546 size_t subscribe_count = 0;
AzureIoTClient 11:31ebaeb51e1e 547 SUBSCRIBE_PAYLOAD subscribe[SUBSCRIBE_TOPIC_COUNT];
AzureIoTClient 11:31ebaeb51e1e 548 if ((transport_data->topic_MqttMessage != NULL) && (SUBSCRIBE_TELEMETRY_TOPIC & transport_data->topics_ToSubscribe))
AzureIoTClient 11:31ebaeb51e1e 549 {
AzureIoTClient 11:31ebaeb51e1e 550 subscribe[subscribe_count].subscribeTopic = STRING_c_str(transport_data->topic_MqttMessage);
AzureIoTClient 11:31ebaeb51e1e 551 subscribe[subscribe_count].qosReturn = DELIVER_AT_LEAST_ONCE;
AzureIoTClient 11:31ebaeb51e1e 552 topic_subscription |= SUBSCRIBE_TELEMETRY_TOPIC;
AzureIoTClient 11:31ebaeb51e1e 553 subscribe_count++;
AzureIoTClient 11:31ebaeb51e1e 554 }
AzureIoTClient 11:31ebaeb51e1e 555
AzureIoTClient 11:31ebaeb51e1e 556 if (subscribe_count != 0)
AzureIoTClient 11:31ebaeb51e1e 557 {
AzureIoTClient 11:31ebaeb51e1e 558 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_016: [IoTHubTransportMqtt_Subscribe shall call mqtt_client_subscribe to subscribe to the Message Topic.] */
AzureIoTClient 11:31ebaeb51e1e 559 if (mqtt_client_subscribe(transport_data->mqttClient, get_next_packet_id(transport_data), subscribe, subscribe_count) != 0)
AzureIoTClient 11:31ebaeb51e1e 560 {
AzureIoTClient 11:31ebaeb51e1e 561 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_017: [Upon failure IoTHubTransportMqtt_Subscribe shall return a non-zero value.] */
AzureIoTClient 11:31ebaeb51e1e 562 LogError("Failure: mqtt_client_subscribe returned error.");
AzureIoTClient 11:31ebaeb51e1e 563 }
AzureIoTClient 11:31ebaeb51e1e 564 else
AzureIoTClient 11:31ebaeb51e1e 565 {
AzureIoTClient 11:31ebaeb51e1e 566 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_018: [On success IoTHubTransportMqtt_Subscribe shall return 0.] */
AzureIoTClient 11:31ebaeb51e1e 567 transport_data->topics_ToSubscribe &= ~topic_subscription;
AzureIoTClient 11:31ebaeb51e1e 568 transport_data->currPacketState = SUBSCRIBE_TYPE;
AzureIoTClient 11:31ebaeb51e1e 569 }
AzureIoTClient 11:31ebaeb51e1e 570 }
AzureIoTClient 11:31ebaeb51e1e 571 else
AzureIoTClient 11:31ebaeb51e1e 572 {
AzureIoTClient 11:31ebaeb51e1e 573 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_017: [Upon failure IoTHubTransportMqtt_Subscribe shall return a non-zero value.] */
AzureIoTClient 11:31ebaeb51e1e 574 LogError("Failure: subscribe_topic is empty.");
AzureIoTClient 11:31ebaeb51e1e 575 }
AzureIoTClient 11:31ebaeb51e1e 576 transport_data->currPacketState = SUBSCRIBE_TYPE;
AzureIoTClient 11:31ebaeb51e1e 577 }
AzureIoTClient 11:31ebaeb51e1e 578 else
AzureIoTClient 11:31ebaeb51e1e 579 {
AzureIoTClient 11:31ebaeb51e1e 580 transport_data->currPacketState = PUBLISH_TYPE;
AzureIoTClient 11:31ebaeb51e1e 581 }
AzureIoTClient 11:31ebaeb51e1e 582 }
AzureIoTClient 11:31ebaeb51e1e 583
AzureIoTClient 11:31ebaeb51e1e 584 static const unsigned char* RetrieveMessagePayload(IOTHUB_MESSAGE_HANDLE messageHandle, size_t* length)
AzureIoTClient 11:31ebaeb51e1e 585 {
AzureIoTClient 11:31ebaeb51e1e 586 const unsigned char* result;
AzureIoTClient 11:31ebaeb51e1e 587
AzureIoTClient 11:31ebaeb51e1e 588 IOTHUBMESSAGE_CONTENT_TYPE contentType = IoTHubMessage_GetContentType(messageHandle);
AzureIoTClient 11:31ebaeb51e1e 589 if (contentType == IOTHUBMESSAGE_BYTEARRAY)
AzureIoTClient 11:31ebaeb51e1e 590 {
AzureIoTClient 11:31ebaeb51e1e 591 if (IoTHubMessage_GetByteArray(messageHandle, &result, length) != IOTHUB_MESSAGE_OK)
AzureIoTClient 11:31ebaeb51e1e 592 {
AzureIoTClient 11:31ebaeb51e1e 593 LogError("Failure result from IoTHubMessage_GetByteArray");
AzureIoTClient 11:31ebaeb51e1e 594 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 595 *length = 0;
AzureIoTClient 11:31ebaeb51e1e 596 }
AzureIoTClient 11:31ebaeb51e1e 597 }
AzureIoTClient 11:31ebaeb51e1e 598 else if (contentType == IOTHUBMESSAGE_STRING)
AzureIoTClient 11:31ebaeb51e1e 599 {
AzureIoTClient 11:31ebaeb51e1e 600 result = (const unsigned char*)IoTHubMessage_GetString(messageHandle);
AzureIoTClient 11:31ebaeb51e1e 601 if (result == NULL)
AzureIoTClient 11:31ebaeb51e1e 602 {
AzureIoTClient 11:31ebaeb51e1e 603 LogError("Failure result from IoTHubMessage_GetString");
AzureIoTClient 11:31ebaeb51e1e 604 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 605 *length = 0;
AzureIoTClient 11:31ebaeb51e1e 606 }
AzureIoTClient 11:31ebaeb51e1e 607 else
AzureIoTClient 11:31ebaeb51e1e 608 {
AzureIoTClient 11:31ebaeb51e1e 609 *length = strlen((const char*)result);
AzureIoTClient 11:31ebaeb51e1e 610 }
AzureIoTClient 11:31ebaeb51e1e 611 }
AzureIoTClient 11:31ebaeb51e1e 612 else
AzureIoTClient 11:31ebaeb51e1e 613 {
AzureIoTClient 11:31ebaeb51e1e 614 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 615 *length = 0;
AzureIoTClient 11:31ebaeb51e1e 616 }
AzureIoTClient 11:31ebaeb51e1e 617 return result;
AzureIoTClient 11:31ebaeb51e1e 618 }
AzureIoTClient 11:31ebaeb51e1e 619
AzureIoTClient 11:31ebaeb51e1e 620 static int GetTransportProviderIfNecessary(PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 621 {
AzureIoTClient 11:31ebaeb51e1e 622 int result;
AzureIoTClient 11:31ebaeb51e1e 623
AzureIoTClient 11:31ebaeb51e1e 624 if (transport_data->xioTransport == NULL)
AzureIoTClient 11:31ebaeb51e1e 625 {
AzureIoTClient 11:31ebaeb51e1e 626 // construct address
AzureIoTClient 11:31ebaeb51e1e 627 const char* hostAddress = STRING_c_str(transport_data->hostAddress);
AzureIoTClient 11:31ebaeb51e1e 628 transport_data->xioTransport = transport_data->get_io_transport(hostAddress);
AzureIoTClient 11:31ebaeb51e1e 629 if (transport_data->xioTransport == NULL)
AzureIoTClient 11:31ebaeb51e1e 630 {
AzureIoTClient 11:31ebaeb51e1e 631 LogError("Unable to create the lower level TLS layer.");
AzureIoTClient 11:31ebaeb51e1e 632 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 633 }
AzureIoTClient 11:31ebaeb51e1e 634 else
AzureIoTClient 11:31ebaeb51e1e 635 {
AzureIoTClient 11:31ebaeb51e1e 636 result = 0;
AzureIoTClient 11:31ebaeb51e1e 637 }
AzureIoTClient 11:31ebaeb51e1e 638 }
AzureIoTClient 11:31ebaeb51e1e 639 else
AzureIoTClient 11:31ebaeb51e1e 640 {
AzureIoTClient 11:31ebaeb51e1e 641 result = 0;
AzureIoTClient 11:31ebaeb51e1e 642 }
AzureIoTClient 11:31ebaeb51e1e 643 return result;
AzureIoTClient 11:31ebaeb51e1e 644 }
AzureIoTClient 11:31ebaeb51e1e 645
AzureIoTClient 11:31ebaeb51e1e 646 static int SendMqttConnectMsg(PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 647 {
AzureIoTClient 11:31ebaeb51e1e 648 int result;
AzureIoTClient 11:31ebaeb51e1e 649
AzureIoTClient 11:31ebaeb51e1e 650 // Not checking the success of this variable, if fail it will fail in the SASToken creation and return false;
AzureIoTClient 11:31ebaeb51e1e 651 STRING_HANDLE emptyKeyName = STRING_new();
AzureIoTClient 11:31ebaeb51e1e 652 if (emptyKeyName == NULL)
AzureIoTClient 11:31ebaeb51e1e 653 {
AzureIoTClient 11:31ebaeb51e1e 654 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 655 }
AzureIoTClient 11:31ebaeb51e1e 656 else
AzureIoTClient 11:31ebaeb51e1e 657 {
AzureIoTClient 11:31ebaeb51e1e 658 STRING_HANDLE sasToken = NULL;
AzureIoTClient 11:31ebaeb51e1e 659
AzureIoTClient 11:31ebaeb51e1e 660 switch (transport_data->transport_creds.credential_type)
AzureIoTClient 11:31ebaeb51e1e 661 {
AzureIoTClient 11:31ebaeb51e1e 662 case SAS_TOKEN_FROM_USER:
AzureIoTClient 11:31ebaeb51e1e 663 sasToken = STRING_clone(transport_data->transport_creds.CREDENTIAL_VALUE.deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 664 break;
AzureIoTClient 11:31ebaeb51e1e 665 case DEVICE_KEY:
AzureIoTClient 11:31ebaeb51e1e 666 {
AzureIoTClient 11:31ebaeb51e1e 667 // Construct SAS token
AzureIoTClient 11:31ebaeb51e1e 668 size_t secSinceEpoch = (size_t)(difftime(get_time(NULL), EPOCH_TIME_T_VALUE) + 0);
AzureIoTClient 11:31ebaeb51e1e 669 size_t expiryTime = secSinceEpoch + SAS_TOKEN_DEFAULT_LIFETIME;
AzureIoTClient 11:31ebaeb51e1e 670
AzureIoTClient 11:31ebaeb51e1e 671 sasToken = SASToken_Create(transport_data->transport_creds.CREDENTIAL_VALUE.deviceKey, transport_data->devicesPath, emptyKeyName, expiryTime);
AzureIoTClient 11:31ebaeb51e1e 672 break;
AzureIoTClient 11:31ebaeb51e1e 673 }
AzureIoTClient 11:31ebaeb51e1e 674 case X509:
AzureIoTClient 11:31ebaeb51e1e 675 default:
AzureIoTClient 11:31ebaeb51e1e 676 // The assumption here is that x509 is in place, if not setup
AzureIoTClient 11:31ebaeb51e1e 677 // correctly the connection will be rejected.
AzureIoTClient 11:31ebaeb51e1e 678 sasToken = NULL;
AzureIoTClient 11:31ebaeb51e1e 679 break;
AzureIoTClient 11:31ebaeb51e1e 680 }
AzureIoTClient 11:31ebaeb51e1e 681
AzureIoTClient 11:31ebaeb51e1e 682 MQTT_CLIENT_OPTIONS options = { 0 };
AzureIoTClient 11:31ebaeb51e1e 683 options.clientId = (char*)STRING_c_str(transport_data->device_id);
AzureIoTClient 11:31ebaeb51e1e 684 options.willMessage = NULL;
AzureIoTClient 11:31ebaeb51e1e 685 options.username = (char*)STRING_c_str(transport_data->configPassedThroughUsername);
AzureIoTClient 11:31ebaeb51e1e 686 if (sasToken != NULL)
AzureIoTClient 11:31ebaeb51e1e 687 {
AzureIoTClient 11:31ebaeb51e1e 688 options.password = (char*)STRING_c_str(sasToken);
AzureIoTClient 11:31ebaeb51e1e 689 }
AzureIoTClient 11:31ebaeb51e1e 690 options.keepAliveInterval = transport_data->keepAliveValue;
AzureIoTClient 11:31ebaeb51e1e 691 options.useCleanSession = false;
AzureIoTClient 11:31ebaeb51e1e 692 options.qualityOfServiceValue = DELIVER_AT_LEAST_ONCE;
AzureIoTClient 11:31ebaeb51e1e 693
AzureIoTClient 11:31ebaeb51e1e 694 if (GetTransportProviderIfNecessary(transport_data) == 0)
AzureIoTClient 11:31ebaeb51e1e 695 {
AzureIoTClient 11:31ebaeb51e1e 696 if (mqtt_client_connect(transport_data->mqttClient, transport_data->xioTransport, &options) != 0)
AzureIoTClient 11:31ebaeb51e1e 697 {
AzureIoTClient 11:31ebaeb51e1e 698 LogError("failure connecting to address %s:%d.", STRING_c_str(transport_data->hostAddress), transport_data->portNum);
AzureIoTClient 11:31ebaeb51e1e 699 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 700 }
AzureIoTClient 11:31ebaeb51e1e 701 else
AzureIoTClient 11:31ebaeb51e1e 702 {
AzureIoTClient 11:31ebaeb51e1e 703 (void)tickcounter_get_current_ms(g_msgTickCounter, &transport_data->mqtt_connect_time);
AzureIoTClient 11:31ebaeb51e1e 704 result = 0;
AzureIoTClient 11:31ebaeb51e1e 705 }
AzureIoTClient 11:31ebaeb51e1e 706 }
AzureIoTClient 11:31ebaeb51e1e 707 else
AzureIoTClient 11:31ebaeb51e1e 708 {
AzureIoTClient 11:31ebaeb51e1e 709 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 710 }
AzureIoTClient 11:31ebaeb51e1e 711 STRING_delete(emptyKeyName);
AzureIoTClient 11:31ebaeb51e1e 712 STRING_delete(sasToken);
AzureIoTClient 11:31ebaeb51e1e 713 }
AzureIoTClient 11:31ebaeb51e1e 714 return result;
AzureIoTClient 11:31ebaeb51e1e 715 }
AzureIoTClient 11:31ebaeb51e1e 716
AzureIoTClient 11:31ebaeb51e1e 717 static int InitializeConnection(PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 718 {
AzureIoTClient 11:31ebaeb51e1e 719 int result = 0;
AzureIoTClient 11:31ebaeb51e1e 720
AzureIoTClient 11:31ebaeb51e1e 721 // Make sure we're not destroying the object
AzureIoTClient 11:31ebaeb51e1e 722 if (!transport_data->isDestroyCalled)
AzureIoTClient 11:31ebaeb51e1e 723 {
AzureIoTClient 11:31ebaeb51e1e 724 // If we are not isConnected then check to see if we need
AzureIoTClient 11:31ebaeb51e1e 725 // to back off the connecting to the server
AzureIoTClient 11:31ebaeb51e1e 726 if (!transport_data->isConnected)
AzureIoTClient 11:31ebaeb51e1e 727 {
AzureIoTClient 11:31ebaeb51e1e 728 // Default makeConnection as true if something goes wrong we'll make the connection
AzureIoTClient 11:31ebaeb51e1e 729 bool makeConnection = true;
AzureIoTClient 11:31ebaeb51e1e 730 // If we've failed for FAILED_CONN_BACKOFF_VALUE straight times them let's slow down connection
AzureIoTClient 11:31ebaeb51e1e 731 // to the service
AzureIoTClient 11:31ebaeb51e1e 732 if (transport_data->connectFailCount > FAILED_CONN_BACKOFF_VALUE)
AzureIoTClient 11:31ebaeb51e1e 733 {
AzureIoTClient 11:31ebaeb51e1e 734 uint64_t currentTick;
AzureIoTClient 11:31ebaeb51e1e 735 if (tickcounter_get_current_ms(g_msgTickCounter, &currentTick) == 0)
AzureIoTClient 11:31ebaeb51e1e 736 {
AzureIoTClient 11:31ebaeb51e1e 737 if ( ((currentTick - transport_data->connectTick)/1000) <= DEFAULT_CONNECTION_INTERVAL)
AzureIoTClient 11:31ebaeb51e1e 738 {
AzureIoTClient 11:31ebaeb51e1e 739 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 740 makeConnection = false;
AzureIoTClient 11:31ebaeb51e1e 741 }
AzureIoTClient 11:31ebaeb51e1e 742 }
AzureIoTClient 11:31ebaeb51e1e 743 }
AzureIoTClient 11:31ebaeb51e1e 744
AzureIoTClient 11:31ebaeb51e1e 745 if (makeConnection)
AzureIoTClient 11:31ebaeb51e1e 746 {
AzureIoTClient 11:31ebaeb51e1e 747 if (tickcounter_get_current_ms(g_msgTickCounter, &transport_data->connectTick) != 0)
AzureIoTClient 11:31ebaeb51e1e 748 {
AzureIoTClient 11:31ebaeb51e1e 749 transport_data->connectFailCount++;
AzureIoTClient 11:31ebaeb51e1e 750 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 751 }
AzureIoTClient 11:31ebaeb51e1e 752 else
AzureIoTClient 11:31ebaeb51e1e 753 {
AzureIoTClient 11:31ebaeb51e1e 754 if (SendMqttConnectMsg(transport_data) != 0)
AzureIoTClient 11:31ebaeb51e1e 755 {
AzureIoTClient 11:31ebaeb51e1e 756 transport_data->connectFailCount++;
AzureIoTClient 11:31ebaeb51e1e 757 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 758 }
AzureIoTClient 11:31ebaeb51e1e 759 else
AzureIoTClient 11:31ebaeb51e1e 760 {
AzureIoTClient 11:31ebaeb51e1e 761 transport_data->connectFailCount = 0;
AzureIoTClient 11:31ebaeb51e1e 762 transport_data->isConnected = true;
AzureIoTClient 11:31ebaeb51e1e 763 result = 0;
AzureIoTClient 11:31ebaeb51e1e 764 }
AzureIoTClient 11:31ebaeb51e1e 765 }
AzureIoTClient 11:31ebaeb51e1e 766 }
AzureIoTClient 11:31ebaeb51e1e 767 }
AzureIoTClient 11:31ebaeb51e1e 768
AzureIoTClient 11:31ebaeb51e1e 769 if (transport_data->isConnected)
AzureIoTClient 11:31ebaeb51e1e 770 {
AzureIoTClient 11:31ebaeb51e1e 771 // We are isConnected and not being closed, so does SAS need to reconnect?
AzureIoTClient 11:31ebaeb51e1e 772 uint64_t current_time;
AzureIoTClient 11:31ebaeb51e1e 773 if (tickcounter_get_current_ms(g_msgTickCounter, &current_time) != 0)
AzureIoTClient 11:31ebaeb51e1e 774 {
AzureIoTClient 11:31ebaeb51e1e 775 transport_data->connectFailCount++;
AzureIoTClient 11:31ebaeb51e1e 776 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 777 }
AzureIoTClient 11:31ebaeb51e1e 778 else
AzureIoTClient 11:31ebaeb51e1e 779 {
AzureIoTClient 11:31ebaeb51e1e 780 if ((current_time - transport_data->mqtt_connect_time) / 1000 > (SAS_TOKEN_DEFAULT_LIFETIME*SAS_REFRESH_MULTIPLIER))
AzureIoTClient 11:31ebaeb51e1e 781 {
AzureIoTClient 11:31ebaeb51e1e 782 (void)mqtt_client_disconnect(transport_data->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 783 transport_data->isConnected = false;
AzureIoTClient 11:31ebaeb51e1e 784 transport_data->currPacketState = UNKNOWN_TYPE;
AzureIoTClient 11:31ebaeb51e1e 785 if (transport_data->topic_MqttMessage != NULL)
AzureIoTClient 11:31ebaeb51e1e 786 {
AzureIoTClient 11:31ebaeb51e1e 787 transport_data->topics_ToSubscribe |= SUBSCRIBE_TELEMETRY_TOPIC;
AzureIoTClient 11:31ebaeb51e1e 788 }
AzureIoTClient 11:31ebaeb51e1e 789 }
AzureIoTClient 11:31ebaeb51e1e 790 }
AzureIoTClient 11:31ebaeb51e1e 791 }
AzureIoTClient 11:31ebaeb51e1e 792 }
AzureIoTClient 11:31ebaeb51e1e 793 return result;
AzureIoTClient 11:31ebaeb51e1e 794 }
AzureIoTClient 11:31ebaeb51e1e 795
AzureIoTClient 11:31ebaeb51e1e 796 static STRING_HANDLE buildConfigForUsername(const IOTHUB_CLIENT_CONFIG* upperConfig)
AzureIoTClient 11:31ebaeb51e1e 797 {
AzureIoTClient 11:31ebaeb51e1e 798 STRING_HANDLE result = STRING_construct_sprintf("%s.%s/%s/DeviceClientType=%s%%2F%s", upperConfig->iotHubName, upperConfig->iotHubSuffix, upperConfig->deviceId, CLIENT_DEVICE_TYPE_PREFIX, IOTHUB_SDK_VERSION);
AzureIoTClient 11:31ebaeb51e1e 799 return result;
AzureIoTClient 11:31ebaeb51e1e 800 }
AzureIoTClient 11:31ebaeb51e1e 801
AzureIoTClient 11:31ebaeb51e1e 802 static int construct_credential_information(const IOTHUB_CLIENT_CONFIG* upperConfig, PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 803 {
AzureIoTClient 11:31ebaeb51e1e 804 int result;
AzureIoTClient 11:31ebaeb51e1e 805 if (upperConfig->deviceKey != NULL)
AzureIoTClient 11:31ebaeb51e1e 806 {
AzureIoTClient 11:31ebaeb51e1e 807 transport_data->transport_creds.CREDENTIAL_VALUE.deviceKey = STRING_construct(upperConfig->deviceKey);
AzureIoTClient 11:31ebaeb51e1e 808 if (transport_data->transport_creds.CREDENTIAL_VALUE.deviceKey == NULL)
AzureIoTClient 11:31ebaeb51e1e 809 {
AzureIoTClient 11:31ebaeb51e1e 810 LogError("Could not create device key for MQTT");
AzureIoTClient 11:31ebaeb51e1e 811 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 812 }
AzureIoTClient 11:31ebaeb51e1e 813 else if ((transport_data->devicesPath = STRING_construct_sprintf("%s.%s/devices/%s", upperConfig->iotHubName, upperConfig->iotHubSuffix, upperConfig->deviceId)) == NULL)
AzureIoTClient 11:31ebaeb51e1e 814 {
AzureIoTClient 11:31ebaeb51e1e 815 STRING_delete(transport_data->transport_creds.CREDENTIAL_VALUE.deviceKey);
AzureIoTClient 11:31ebaeb51e1e 816 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 817 }
AzureIoTClient 11:31ebaeb51e1e 818 else
AzureIoTClient 11:31ebaeb51e1e 819 {
AzureIoTClient 11:31ebaeb51e1e 820 transport_data->transport_creds.credential_type = DEVICE_KEY;
AzureIoTClient 11:31ebaeb51e1e 821 result = 0;
AzureIoTClient 11:31ebaeb51e1e 822 }
AzureIoTClient 11:31ebaeb51e1e 823 }
AzureIoTClient 11:31ebaeb51e1e 824 else if (upperConfig->deviceSasToken != NULL)
AzureIoTClient 11:31ebaeb51e1e 825 {
AzureIoTClient 11:31ebaeb51e1e 826 transport_data->transport_creds.CREDENTIAL_VALUE.deviceSasToken = STRING_construct(upperConfig->deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 827 if (transport_data->transport_creds.CREDENTIAL_VALUE.deviceSasToken == NULL)
AzureIoTClient 11:31ebaeb51e1e 828 {
AzureIoTClient 11:31ebaeb51e1e 829 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 830 }
AzureIoTClient 11:31ebaeb51e1e 831 else
AzureIoTClient 11:31ebaeb51e1e 832 {
AzureIoTClient 11:31ebaeb51e1e 833 transport_data->transport_creds.credential_type = SAS_TOKEN_FROM_USER;
AzureIoTClient 11:31ebaeb51e1e 834 transport_data->devicesPath = NULL;
AzureIoTClient 11:31ebaeb51e1e 835 result = 0;
AzureIoTClient 11:31ebaeb51e1e 836 }
AzureIoTClient 11:31ebaeb51e1e 837 }
AzureIoTClient 11:31ebaeb51e1e 838 else
AzureIoTClient 11:31ebaeb51e1e 839 {
AzureIoTClient 11:31ebaeb51e1e 840 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_041: [If both deviceKey and deviceSasToken fields are NULL then IoTHubTransportMqtt_Create shall assume a x509 authentication.] */
AzureIoTClient 11:31ebaeb51e1e 841 transport_data->transport_creds.credential_type = X509;
AzureIoTClient 11:31ebaeb51e1e 842 transport_data->devicesPath = NULL;
AzureIoTClient 11:31ebaeb51e1e 843 result = 0;
AzureIoTClient 11:31ebaeb51e1e 844 }
AzureIoTClient 11:31ebaeb51e1e 845 return result;
AzureIoTClient 11:31ebaeb51e1e 846 }
AzureIoTClient 11:31ebaeb51e1e 847
AzureIoTClient 11:31ebaeb51e1e 848 static PMQTTTRANSPORT_HANDLE_DATA InitializeTransportHandleData(const IOTHUB_CLIENT_CONFIG* upperConfig, PDLIST_ENTRY waitingToSend)
AzureIoTClient 11:31ebaeb51e1e 849 {
AzureIoTClient 11:31ebaeb51e1e 850 PMQTTTRANSPORT_HANDLE_DATA state = (PMQTTTRANSPORT_HANDLE_DATA)malloc(sizeof(MQTTTRANSPORT_HANDLE_DATA));
AzureIoTClient 11:31ebaeb51e1e 851 if (state == NULL)
AzureIoTClient 11:31ebaeb51e1e 852 {
AzureIoTClient 11:31ebaeb51e1e 853 LogError("Could not create MQTT transport state. Memory allocation failed.");
AzureIoTClient 11:31ebaeb51e1e 854 }
AzureIoTClient 11:31ebaeb51e1e 855 else if ((state->device_id = STRING_construct(upperConfig->deviceId)) == NULL)
AzureIoTClient 11:31ebaeb51e1e 856 {
AzureIoTClient 11:31ebaeb51e1e 857 LogError("failure constructing device_id.");
AzureIoTClient 11:31ebaeb51e1e 858 free(state);
AzureIoTClient 11:31ebaeb51e1e 859 state = NULL;
AzureIoTClient 11:31ebaeb51e1e 860 }
AzureIoTClient 11:31ebaeb51e1e 861 else
AzureIoTClient 11:31ebaeb51e1e 862 {
AzureIoTClient 11:31ebaeb51e1e 863 if (construct_credential_information(upperConfig, state) != 0)
AzureIoTClient 11:31ebaeb51e1e 864 {
AzureIoTClient 11:31ebaeb51e1e 865 STRING_delete(state->device_id);
AzureIoTClient 11:31ebaeb51e1e 866 free(state);
AzureIoTClient 11:31ebaeb51e1e 867 state = NULL;
AzureIoTClient 11:31ebaeb51e1e 868 }
AzureIoTClient 11:31ebaeb51e1e 869 else if ( (state->topic_MqttEvent = STRING_construct_sprintf(TOPIC_DEVICE_DEVICE, upperConfig->deviceId) ) == NULL)
AzureIoTClient 11:31ebaeb51e1e 870 {
AzureIoTClient 11:31ebaeb51e1e 871 LogError("Could not create topic_MqttEvent for MQTT");
AzureIoTClient 11:31ebaeb51e1e 872 STRING_delete(state->devicesPath);
AzureIoTClient 11:31ebaeb51e1e 873 if (state->transport_creds.credential_type == DEVICE_KEY)
AzureIoTClient 11:31ebaeb51e1e 874 {
AzureIoTClient 11:31ebaeb51e1e 875 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceKey);
AzureIoTClient 11:31ebaeb51e1e 876 }
AzureIoTClient 11:31ebaeb51e1e 877 else if (state->transport_creds.credential_type == SAS_TOKEN_FROM_USER)
AzureIoTClient 11:31ebaeb51e1e 878 {
AzureIoTClient 11:31ebaeb51e1e 879 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 880 }
AzureIoTClient 11:31ebaeb51e1e 881 STRING_delete(state->device_id);
AzureIoTClient 11:31ebaeb51e1e 882 free(state);
AzureIoTClient 11:31ebaeb51e1e 883 state = NULL;
AzureIoTClient 11:31ebaeb51e1e 884 }
AzureIoTClient 11:31ebaeb51e1e 885 else
AzureIoTClient 11:31ebaeb51e1e 886 {
AzureIoTClient 11:31ebaeb51e1e 887 state->mqttClient = mqtt_client_init(mqtt_notification_callback, mqtt_operation_complete_callback, state);
AzureIoTClient 11:31ebaeb51e1e 888 if (state->mqttClient == NULL)
AzureIoTClient 11:31ebaeb51e1e 889 {
AzureIoTClient 11:31ebaeb51e1e 890 LogError("failure initializing mqtt client.");
AzureIoTClient 11:31ebaeb51e1e 891 STRING_delete(state->devicesPath);
AzureIoTClient 11:31ebaeb51e1e 892 if (state->transport_creds.credential_type == DEVICE_KEY)
AzureIoTClient 11:31ebaeb51e1e 893 {
AzureIoTClient 11:31ebaeb51e1e 894 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceKey);
AzureIoTClient 11:31ebaeb51e1e 895 }
AzureIoTClient 11:31ebaeb51e1e 896 else if (state->transport_creds.credential_type == SAS_TOKEN_FROM_USER)
AzureIoTClient 11:31ebaeb51e1e 897 {
AzureIoTClient 11:31ebaeb51e1e 898 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 899 }
AzureIoTClient 11:31ebaeb51e1e 900 STRING_delete(state->topic_MqttEvent);
AzureIoTClient 11:31ebaeb51e1e 901 STRING_delete(state->device_id);
AzureIoTClient 11:31ebaeb51e1e 902 free(state);
AzureIoTClient 11:31ebaeb51e1e 903 state = NULL;
AzureIoTClient 11:31ebaeb51e1e 904 }
AzureIoTClient 11:31ebaeb51e1e 905 else
AzureIoTClient 11:31ebaeb51e1e 906 {
AzureIoTClient 11:31ebaeb51e1e 907 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_008: [If the upperConfig contains a valid protocolGatewayHostName value the this shall be used for the hostname, otherwise the hostname shall be constructed using the iothubname and iothubSuffix.] */
AzureIoTClient 11:31ebaeb51e1e 908 if (upperConfig->protocolGatewayHostName == NULL)
AzureIoTClient 11:31ebaeb51e1e 909 {
AzureIoTClient 11:31ebaeb51e1e 910 state->hostAddress = STRING_construct_sprintf("%s.%s", upperConfig->iotHubName, upperConfig->iotHubSuffix);
AzureIoTClient 11:31ebaeb51e1e 911 }
AzureIoTClient 11:31ebaeb51e1e 912 else
AzureIoTClient 11:31ebaeb51e1e 913 {
AzureIoTClient 11:31ebaeb51e1e 914 state->hostAddress = STRING_construct(upperConfig->protocolGatewayHostName);
AzureIoTClient 11:31ebaeb51e1e 915 }
AzureIoTClient 11:31ebaeb51e1e 916
AzureIoTClient 11:31ebaeb51e1e 917 if (state->hostAddress == NULL)
AzureIoTClient 11:31ebaeb51e1e 918 {
AzureIoTClient 11:31ebaeb51e1e 919 LogError("failure constructing host address.");
AzureIoTClient 11:31ebaeb51e1e 920 STRING_delete(state->devicesPath);
AzureIoTClient 11:31ebaeb51e1e 921 if (state->transport_creds.credential_type == DEVICE_KEY)
AzureIoTClient 11:31ebaeb51e1e 922 {
AzureIoTClient 11:31ebaeb51e1e 923 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceKey);
AzureIoTClient 11:31ebaeb51e1e 924 }
AzureIoTClient 11:31ebaeb51e1e 925 else if (state->transport_creds.credential_type == SAS_TOKEN_FROM_USER)
AzureIoTClient 11:31ebaeb51e1e 926 {
AzureIoTClient 11:31ebaeb51e1e 927 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 928 }
AzureIoTClient 11:31ebaeb51e1e 929 mqtt_client_deinit(state->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 930 STRING_delete(state->topic_MqttEvent);
AzureIoTClient 11:31ebaeb51e1e 931 STRING_delete(state->device_id);
AzureIoTClient 11:31ebaeb51e1e 932 free(state);
AzureIoTClient 11:31ebaeb51e1e 933 state = NULL;
AzureIoTClient 11:31ebaeb51e1e 934 }
AzureIoTClient 11:31ebaeb51e1e 935 else if ((state->configPassedThroughUsername = buildConfigForUsername(upperConfig)) == NULL)
AzureIoTClient 11:31ebaeb51e1e 936 {
AzureIoTClient 11:31ebaeb51e1e 937 STRING_delete(state->devicesPath);
AzureIoTClient 11:31ebaeb51e1e 938 if (state->transport_creds.credential_type == DEVICE_KEY)
AzureIoTClient 11:31ebaeb51e1e 939 {
AzureIoTClient 11:31ebaeb51e1e 940 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceKey);
AzureIoTClient 11:31ebaeb51e1e 941 }
AzureIoTClient 11:31ebaeb51e1e 942 else if (state->transport_creds.credential_type == SAS_TOKEN_FROM_USER)
AzureIoTClient 11:31ebaeb51e1e 943 {
AzureIoTClient 11:31ebaeb51e1e 944 STRING_delete(state->transport_creds.CREDENTIAL_VALUE.deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 945 }
AzureIoTClient 11:31ebaeb51e1e 946 mqtt_client_deinit(state->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 947 STRING_delete(state->hostAddress);
AzureIoTClient 11:31ebaeb51e1e 948 STRING_delete(state->topic_MqttEvent);
AzureIoTClient 11:31ebaeb51e1e 949 STRING_delete(state->device_id);
AzureIoTClient 11:31ebaeb51e1e 950 free(state);
AzureIoTClient 11:31ebaeb51e1e 951 state = NULL;
AzureIoTClient 11:31ebaeb51e1e 952 }
AzureIoTClient 11:31ebaeb51e1e 953 else
AzureIoTClient 11:31ebaeb51e1e 954 {
AzureIoTClient 11:31ebaeb51e1e 955 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_010: [IoTHubTransportMqtt_Create shall allocate memory to save its internal state where all topics, hostname, device_id, device_key, sasTokenSr and client handle shall be saved.] */
AzureIoTClient 11:31ebaeb51e1e 956 DList_InitializeListHead(&(state->telemetry_waitingForAck));
AzureIoTClient 11:31ebaeb51e1e 957 state->isDestroyCalled = false;
AzureIoTClient 11:31ebaeb51e1e 958 state->isRegistered = false;
AzureIoTClient 11:31ebaeb51e1e 959 state->isConnected = false;
AzureIoTClient 11:31ebaeb51e1e 960 state->packetId = 1;
AzureIoTClient 11:31ebaeb51e1e 961 state->llClientHandle = NULL;
AzureIoTClient 11:31ebaeb51e1e 962 state->xioTransport = NULL;
AzureIoTClient 11:31ebaeb51e1e 963 state->portNum = 0;
AzureIoTClient 11:31ebaeb51e1e 964 state->waitingToSend = waitingToSend;
AzureIoTClient 11:31ebaeb51e1e 965 state->currPacketState = CONNECT_TYPE;
AzureIoTClient 11:31ebaeb51e1e 966 state->keepAliveValue = DEFAULT_MQTT_KEEPALIVE;
AzureIoTClient 11:31ebaeb51e1e 967 state->connectFailCount = 0;
AzureIoTClient 11:31ebaeb51e1e 968 state->connectTick = 0;
AzureIoTClient 11:31ebaeb51e1e 969 state->topic_MqttMessage = NULL;
AzureIoTClient 11:31ebaeb51e1e 970 state->topics_ToSubscribe = UNSUBSCRIBE_FROM_TOPIC;
AzureIoTClient 11:31ebaeb51e1e 971 state->log_trace = state->raw_trace = false;
AzureIoTClient 11:31ebaeb51e1e 972 }
AzureIoTClient 11:31ebaeb51e1e 973 }
AzureIoTClient 11:31ebaeb51e1e 974 }
AzureIoTClient 11:31ebaeb51e1e 975 }
AzureIoTClient 11:31ebaeb51e1e 976 return state;
AzureIoTClient 11:31ebaeb51e1e 977 }
AzureIoTClient 11:31ebaeb51e1e 978
AzureIoTClient 11:31ebaeb51e1e 979 TRANSPORT_LL_HANDLE IoTHubTransport_MQTT_Common_Create(const IOTHUBTRANSPORT_CONFIG* config, MQTT_GET_IO_TRANSPORT get_io_transport)
AzureIoTClient 11:31ebaeb51e1e 980 {
AzureIoTClient 11:31ebaeb51e1e 981 PMQTTTRANSPORT_HANDLE_DATA result;
AzureIoTClient 11:31ebaeb51e1e 982 size_t deviceIdSize;
AzureIoTClient 11:31ebaeb51e1e 983
AzureIoTClient 11:31ebaeb51e1e 984 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [If parameter config is NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 985 /* Codes_SRS_IOTHUB_TRANSPORT_MQTT_COMMON_07_041: [ if get_io_transport is NULL then IoTHubTransport_MQTT_Common_Create shall return NULL. ] */
AzureIoTClient 11:31ebaeb51e1e 986 if (config == NULL || get_io_transport == NULL)
AzureIoTClient 11:31ebaeb51e1e 987 {
AzureIoTClient 11:31ebaeb51e1e 988 LogError("Invalid Argument: Config Parameter is NULL.");
AzureIoTClient 11:31ebaeb51e1e 989 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 990 }
AzureIoTClient 11:31ebaeb51e1e 991 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [If the parameter config's variables upperConfig or waitingToSend are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 992 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, both deviceKey and deviceSasToken, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 993 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_03_003: [If both deviceKey & deviceSasToken fields are NOT NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 994 else if (config->upperConfig == NULL ||
AzureIoTClient 11:31ebaeb51e1e 995 config->upperConfig->protocol == NULL ||
AzureIoTClient 11:31ebaeb51e1e 996 config->upperConfig->deviceId == NULL ||
AzureIoTClient 11:31ebaeb51e1e 997 ((config->upperConfig->deviceKey != NULL) && (config->upperConfig->deviceSasToken != NULL)) ||
AzureIoTClient 11:31ebaeb51e1e 998 config->upperConfig->iotHubName == NULL ||
AzureIoTClient 11:31ebaeb51e1e 999 config->upperConfig->iotHubSuffix == NULL)
AzureIoTClient 11:31ebaeb51e1e 1000 {
AzureIoTClient 11:31ebaeb51e1e 1001 LogError("Invalid Argument: upperConfig structure contains an invalid parameter");
AzureIoTClient 11:31ebaeb51e1e 1002 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1003 }
AzureIoTClient 11:31ebaeb51e1e 1004 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [If the parameter config's variables upperConfig or waitingToSend are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1005 else if (config->waitingToSend == NULL)
AzureIoTClient 11:31ebaeb51e1e 1006 {
AzureIoTClient 11:31ebaeb51e1e 1007 LogError("Invalid Argument: waitingToSend is NULL)");
AzureIoTClient 11:31ebaeb51e1e 1008 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1009 }
AzureIoTClient 11:31ebaeb51e1e 1010 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_006: [If the upperConfig's variables deviceId is an empty strings or length is greater then 128 then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1011 else if ( ( (deviceIdSize = strlen(config->upperConfig->deviceId)) > 128U) || (deviceIdSize == 0) )
AzureIoTClient 11:31ebaeb51e1e 1012 {
AzureIoTClient 11:31ebaeb51e1e 1013 LogError("Invalid Argument: DeviceId is of an invalid size");
AzureIoTClient 11:31ebaeb51e1e 1014 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1015 }
AzureIoTClient 11:31ebaeb51e1e 1016 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, both deviceKey and deviceSasToken, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1017 else if ((config->upperConfig->deviceKey != NULL) && (strlen(config->upperConfig->deviceKey) == 0))
AzureIoTClient 11:31ebaeb51e1e 1018 {
AzureIoTClient 11:31ebaeb51e1e 1019 LogError("Invalid Argument: deviceKey is empty");
AzureIoTClient 11:31ebaeb51e1e 1020 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1021 }
AzureIoTClient 11:31ebaeb51e1e 1022 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, both deviceKey and deviceSasToken, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1023 else if ((config->upperConfig->deviceSasToken != NULL) && (strlen(config->upperConfig->deviceSasToken) == 0))
AzureIoTClient 11:31ebaeb51e1e 1024 {
AzureIoTClient 11:31ebaeb51e1e 1025 LogError("Invalid Argument: deviceSasToken is empty");
AzureIoTClient 11:31ebaeb51e1e 1026 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1027 }
AzureIoTClient 11:31ebaeb51e1e 1028 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [If the upperConfig's variables deviceId, deviceKey, iotHubName, protocol, or iotHubSuffix are NULL then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1029 else if (strlen(config->upperConfig->iotHubName) == 0)
AzureIoTClient 11:31ebaeb51e1e 1030 {
AzureIoTClient 11:31ebaeb51e1e 1031 LogError("Invalid Argument: iotHubName is empty");
AzureIoTClient 11:31ebaeb51e1e 1032 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1033 }
AzureIoTClient 11:31ebaeb51e1e 1034 else if ((g_msgTickCounter = tickcounter_create()) == NULL)
AzureIoTClient 11:31ebaeb51e1e 1035 {
AzureIoTClient 11:31ebaeb51e1e 1036 LogError("Invalid Argument: iotHubName is empty");
AzureIoTClient 11:31ebaeb51e1e 1037 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1038 }
AzureIoTClient 11:31ebaeb51e1e 1039 else
AzureIoTClient 11:31ebaeb51e1e 1040 {
AzureIoTClient 11:31ebaeb51e1e 1041 result = InitializeTransportHandleData(config->upperConfig, config->waitingToSend);
AzureIoTClient 11:31ebaeb51e1e 1042 if (result == NULL)
AzureIoTClient 11:31ebaeb51e1e 1043 {
AzureIoTClient 11:31ebaeb51e1e 1044 tickcounter_destroy(g_msgTickCounter);
AzureIoTClient 11:31ebaeb51e1e 1045 }
AzureIoTClient 11:31ebaeb51e1e 1046 else
AzureIoTClient 11:31ebaeb51e1e 1047 {
AzureIoTClient 11:31ebaeb51e1e 1048 result->get_io_transport = get_io_transport;
AzureIoTClient 11:31ebaeb51e1e 1049 }
AzureIoTClient 11:31ebaeb51e1e 1050 }
AzureIoTClient 11:31ebaeb51e1e 1051 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_009: [If any error is encountered then IoTHubTransportMqtt_Create shall return NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1052 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_011: [On Success IoTHubTransportMqtt_Create shall return a non-NULL value.] */
AzureIoTClient 11:31ebaeb51e1e 1053 return result;
AzureIoTClient 11:31ebaeb51e1e 1054 }
AzureIoTClient 11:31ebaeb51e1e 1055
AzureIoTClient 11:31ebaeb51e1e 1056 static void DisconnectFromClient(PMQTTTRANSPORT_HANDLE_DATA transport_data)
AzureIoTClient 11:31ebaeb51e1e 1057 {
AzureIoTClient 11:31ebaeb51e1e 1058 (void)mqtt_client_disconnect(transport_data->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 1059 xio_destroy(transport_data->xioTransport);
AzureIoTClient 11:31ebaeb51e1e 1060 transport_data->xioTransport = NULL;
AzureIoTClient 11:31ebaeb51e1e 1061
AzureIoTClient 11:31ebaeb51e1e 1062 transport_data->isConnected = false;
AzureIoTClient 11:31ebaeb51e1e 1063 transport_data->currPacketState = DISCONNECT_TYPE;
AzureIoTClient 11:31ebaeb51e1e 1064 }
AzureIoTClient 11:31ebaeb51e1e 1065
AzureIoTClient 11:31ebaeb51e1e 1066 void IoTHubTransport_MQTT_Common_Destroy(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 11:31ebaeb51e1e 1067 {
AzureIoTClient 11:31ebaeb51e1e 1068 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_012: [IoTHubTransportMqtt_Destroy shall do nothing if parameter handle is NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1069 PMQTTTRANSPORT_HANDLE_DATA transport_data = (PMQTTTRANSPORT_HANDLE_DATA)handle;
AzureIoTClient 11:31ebaeb51e1e 1070 if (transport_data != NULL)
AzureIoTClient 11:31ebaeb51e1e 1071 {
AzureIoTClient 11:31ebaeb51e1e 1072 transport_data->isDestroyCalled = true;
AzureIoTClient 11:31ebaeb51e1e 1073
AzureIoTClient 11:31ebaeb51e1e 1074 DisconnectFromClient(transport_data);
AzureIoTClient 11:31ebaeb51e1e 1075
AzureIoTClient 11:31ebaeb51e1e 1076 //Empty the Waiting for Ack Messages.
AzureIoTClient 11:31ebaeb51e1e 1077 while (!DList_IsListEmpty(&transport_data->telemetry_waitingForAck))
AzureIoTClient 11:31ebaeb51e1e 1078 {
AzureIoTClient 11:31ebaeb51e1e 1079 PDLIST_ENTRY currentEntry = DList_RemoveHeadList(&transport_data->telemetry_waitingForAck);
AzureIoTClient 11:31ebaeb51e1e 1080 MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = containingRecord(currentEntry, MQTT_MESSAGE_DETAILS_LIST, entry);
AzureIoTClient 11:31ebaeb51e1e 1081 sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transport_data, IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY);
AzureIoTClient 11:31ebaeb51e1e 1082 free(mqttMsgEntry);
AzureIoTClient 11:31ebaeb51e1e 1083 }
AzureIoTClient 11:31ebaeb51e1e 1084
AzureIoTClient 11:31ebaeb51e1e 1085 switch (transport_data->transport_creds.credential_type)
AzureIoTClient 11:31ebaeb51e1e 1086 {
AzureIoTClient 11:31ebaeb51e1e 1087 case SAS_TOKEN_FROM_USER:
AzureIoTClient 11:31ebaeb51e1e 1088 STRING_delete(transport_data->transport_creds.CREDENTIAL_VALUE.deviceSasToken);
AzureIoTClient 11:31ebaeb51e1e 1089 break;
AzureIoTClient 11:31ebaeb51e1e 1090 case DEVICE_KEY:
AzureIoTClient 11:31ebaeb51e1e 1091 STRING_delete(transport_data->transport_creds.CREDENTIAL_VALUE.deviceKey);
AzureIoTClient 11:31ebaeb51e1e 1092 STRING_delete(transport_data->devicesPath);
AzureIoTClient 11:31ebaeb51e1e 1093 break;
AzureIoTClient 11:31ebaeb51e1e 1094 case X509:
AzureIoTClient 11:31ebaeb51e1e 1095 default:
AzureIoTClient 11:31ebaeb51e1e 1096 break;
AzureIoTClient 11:31ebaeb51e1e 1097 }
AzureIoTClient 11:31ebaeb51e1e 1098
AzureIoTClient 11:31ebaeb51e1e 1099 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_014: [IoTHubTransportMqtt_Destroy shall free all the resources currently in use.] */
AzureIoTClient 11:31ebaeb51e1e 1100 mqtt_client_deinit(transport_data->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 1101 STRING_delete(transport_data->topic_MqttEvent);
AzureIoTClient 11:31ebaeb51e1e 1102 STRING_delete(transport_data->topic_MqttMessage);
AzureIoTClient 11:31ebaeb51e1e 1103 STRING_delete(transport_data->device_id);
AzureIoTClient 11:31ebaeb51e1e 1104 STRING_delete(transport_data->hostAddress);
AzureIoTClient 11:31ebaeb51e1e 1105 STRING_delete(transport_data->configPassedThroughUsername);
AzureIoTClient 11:31ebaeb51e1e 1106 tickcounter_destroy(g_msgTickCounter);
AzureIoTClient 11:31ebaeb51e1e 1107 free(transport_data);
AzureIoTClient 11:31ebaeb51e1e 1108 }
AzureIoTClient 11:31ebaeb51e1e 1109 }
AzureIoTClient 11:31ebaeb51e1e 1110
AzureIoTClient 11:31ebaeb51e1e 1111 int IoTHubTransport_MQTT_Common_Subscribe(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 11:31ebaeb51e1e 1112 {
AzureIoTClient 11:31ebaeb51e1e 1113 int result;
AzureIoTClient 11:31ebaeb51e1e 1114 PMQTTTRANSPORT_HANDLE_DATA transport_data = (PMQTTTRANSPORT_HANDLE_DATA)handle;
AzureIoTClient 11:31ebaeb51e1e 1115 if (transport_data == NULL)
AzureIoTClient 11:31ebaeb51e1e 1116 {
AzureIoTClient 11:31ebaeb51e1e 1117 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_015: [If parameter handle is NULL than IoTHubTransportMqtt_Subscribe shall return a non-zero value.] */
AzureIoTClient 11:31ebaeb51e1e 1118 LogError("Invalid handle parameter. NULL.");
AzureIoTClient 11:31ebaeb51e1e 1119 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 1120 }
AzureIoTClient 11:31ebaeb51e1e 1121 else
AzureIoTClient 11:31ebaeb51e1e 1122 {
AzureIoTClient 11:31ebaeb51e1e 1123 /* Code_SRS_IOTHUB_MQTT_TRANSPORT_07_016: [IoTHubTransportMqtt_Subscribe shall set a flag to enable mqtt_client_subscribe to be called to subscribe to the Message Topic.] */
AzureIoTClient 11:31ebaeb51e1e 1124 transport_data->topic_MqttMessage = STRING_construct_sprintf(TOPIC_DEVICE_MSG, STRING_c_str(transport_data->device_id) );
AzureIoTClient 11:31ebaeb51e1e 1125 if (transport_data->topic_MqttMessage == NULL)
AzureIoTClient 11:31ebaeb51e1e 1126 {
AzureIoTClient 11:31ebaeb51e1e 1127 LogError("Failure constructing Message Topic");
AzureIoTClient 11:31ebaeb51e1e 1128 result = __LINE__;
AzureIoTClient 11:31ebaeb51e1e 1129 }
AzureIoTClient 11:31ebaeb51e1e 1130 else
AzureIoTClient 11:31ebaeb51e1e 1131 {
AzureIoTClient 11:31ebaeb51e1e 1132 transport_data->topics_ToSubscribe |= SUBSCRIBE_TELEMETRY_TOPIC;
AzureIoTClient 11:31ebaeb51e1e 1133 /* Code_SRS_IOTHUB_MQTT_TRANSPORT_07_035: [If current packet state is not CONNACT, DISCONNECT_TYPE, or PACKET_TYPE_ERROR then IoTHubTransportMqtt_Subscribe shall set the packet state to SUBSCRIBE_TYPE.]*/
AzureIoTClient 11:31ebaeb51e1e 1134 if (transport_data->currPacketState != CONNACK_TYPE &&
AzureIoTClient 11:31ebaeb51e1e 1135 transport_data->currPacketState != CONNECT_TYPE &&
AzureIoTClient 11:31ebaeb51e1e 1136 transport_data->currPacketState != DISCONNECT_TYPE &&
AzureIoTClient 11:31ebaeb51e1e 1137 transport_data->currPacketState != PACKET_TYPE_ERROR)
AzureIoTClient 11:31ebaeb51e1e 1138 {
AzureIoTClient 11:31ebaeb51e1e 1139 transport_data->currPacketState = SUBSCRIBE_TYPE;
AzureIoTClient 11:31ebaeb51e1e 1140 }
AzureIoTClient 11:31ebaeb51e1e 1141 result = 0;
AzureIoTClient 11:31ebaeb51e1e 1142 }
AzureIoTClient 11:31ebaeb51e1e 1143 }
AzureIoTClient 11:31ebaeb51e1e 1144 return result;
AzureIoTClient 11:31ebaeb51e1e 1145 }
AzureIoTClient 11:31ebaeb51e1e 1146
AzureIoTClient 11:31ebaeb51e1e 1147 void IoTHubTransport_MQTT_Common_Unsubscribe(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 11:31ebaeb51e1e 1148 {
AzureIoTClient 11:31ebaeb51e1e 1149 PMQTTTRANSPORT_HANDLE_DATA transport_data = (PMQTTTRANSPORT_HANDLE_DATA)handle;
AzureIoTClient 11:31ebaeb51e1e 1150 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_019: [If parameter handle is NULL then IoTHubTransportMqtt_Unsubscribe shall do nothing.] */
AzureIoTClient 11:31ebaeb51e1e 1151 if (transport_data != NULL)
AzureIoTClient 11:31ebaeb51e1e 1152 {
AzureIoTClient 11:31ebaeb51e1e 1153 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_020: [IoTHubTransportMqtt_Unsubscribe shall call mqtt_client_unsubscribe to unsubscribe the mqtt message topic.] */
AzureIoTClient 11:31ebaeb51e1e 1154 const char* unsubscribe[1];
AzureIoTClient 11:31ebaeb51e1e 1155 unsubscribe[0] = STRING_c_str(transport_data->topic_MqttMessage);
AzureIoTClient 11:31ebaeb51e1e 1156 if (mqtt_client_unsubscribe(transport_data->mqttClient, get_next_packet_id(transport_data), unsubscribe, 1) != 0)
AzureIoTClient 11:31ebaeb51e1e 1157 {
AzureIoTClient 11:31ebaeb51e1e 1158 LogError("Failure calling mqtt_client_unsubscribe");
AzureIoTClient 11:31ebaeb51e1e 1159 }
AzureIoTClient 11:31ebaeb51e1e 1160 STRING_delete(transport_data->topic_MqttMessage);
AzureIoTClient 11:31ebaeb51e1e 1161 transport_data->topic_MqttMessage = NULL;
AzureIoTClient 11:31ebaeb51e1e 1162 transport_data->topics_ToSubscribe &= ~SUBSCRIBE_TELEMETRY_TOPIC;
AzureIoTClient 11:31ebaeb51e1e 1163 }
AzureIoTClient 11:31ebaeb51e1e 1164 else
AzureIoTClient 11:31ebaeb51e1e 1165 {
AzureIoTClient 11:31ebaeb51e1e 1166 LogError("Invalid argument to unsubscribe (NULL).");
AzureIoTClient 11:31ebaeb51e1e 1167 }
AzureIoTClient 11:31ebaeb51e1e 1168 }
AzureIoTClient 11:31ebaeb51e1e 1169
AzureIoTClient 11:31ebaeb51e1e 1170 void IoTHubTransport_MQTT_Common_DoWork(TRANSPORT_LL_HANDLE handle, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle)
AzureIoTClient 11:31ebaeb51e1e 1171 {
AzureIoTClient 11:31ebaeb51e1e 1172 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_026: [IoTHubTransportMqtt_DoWork shall do nothing if parameter handle and/or iotHubClientHandle is NULL.] */
AzureIoTClient 11:31ebaeb51e1e 1173 PMQTTTRANSPORT_HANDLE_DATA transport_data = (PMQTTTRANSPORT_HANDLE_DATA)handle;
AzureIoTClient 11:31ebaeb51e1e 1174 if (transport_data != NULL && iotHubClientHandle != NULL)
AzureIoTClient 11:31ebaeb51e1e 1175 {
AzureIoTClient 11:31ebaeb51e1e 1176 transport_data->llClientHandle = iotHubClientHandle;
AzureIoTClient 11:31ebaeb51e1e 1177
AzureIoTClient 11:31ebaeb51e1e 1178 if (InitializeConnection(transport_data) != 0)
AzureIoTClient 11:31ebaeb51e1e 1179 {
AzureIoTClient 11:31ebaeb51e1e 1180 // Don't want to flood the logs with failures here
AzureIoTClient 11:31ebaeb51e1e 1181 }
AzureIoTClient 11:31ebaeb51e1e 1182 else
AzureIoTClient 11:31ebaeb51e1e 1183 {
AzureIoTClient 11:31ebaeb51e1e 1184 if (transport_data->currPacketState == CONNACK_TYPE || transport_data->currPacketState == SUBSCRIBE_TYPE)
AzureIoTClient 11:31ebaeb51e1e 1185 {
AzureIoTClient 11:31ebaeb51e1e 1186 SubscribeToMqttProtocol(transport_data);
AzureIoTClient 11:31ebaeb51e1e 1187 }
AzureIoTClient 11:31ebaeb51e1e 1188 else if (transport_data->currPacketState == SUBACK_TYPE)
AzureIoTClient 11:31ebaeb51e1e 1189 {
AzureIoTClient 11:31ebaeb51e1e 1190 // Publish can be called now
AzureIoTClient 11:31ebaeb51e1e 1191 transport_data->currPacketState = PUBLISH_TYPE;
AzureIoTClient 11:31ebaeb51e1e 1192 }
AzureIoTClient 11:31ebaeb51e1e 1193 else if (transport_data->currPacketState == PUBLISH_TYPE)
AzureIoTClient 11:31ebaeb51e1e 1194 {
AzureIoTClient 11:31ebaeb51e1e 1195 PDLIST_ENTRY currentListEntry = transport_data->telemetry_waitingForAck.Flink;
AzureIoTClient 11:31ebaeb51e1e 1196 while (currentListEntry != &transport_data->telemetry_waitingForAck)
AzureIoTClient 11:31ebaeb51e1e 1197 {
AzureIoTClient 11:31ebaeb51e1e 1198 MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = containingRecord(currentListEntry, MQTT_MESSAGE_DETAILS_LIST, entry);
AzureIoTClient 11:31ebaeb51e1e 1199 DLIST_ENTRY nextListEntry;
AzureIoTClient 11:31ebaeb51e1e 1200 nextListEntry.Flink = currentListEntry->Flink;
AzureIoTClient 11:31ebaeb51e1e 1201
AzureIoTClient 11:31ebaeb51e1e 1202 uint64_t current_ms;
AzureIoTClient 11:31ebaeb51e1e 1203 (void)tickcounter_get_current_ms(g_msgTickCounter, &current_ms);
AzureIoTClient 11:31ebaeb51e1e 1204 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_033: [IoTHubTransportMqtt_DoWork shall iterate through the Waiting Acknowledge messages looking for any message that has been waiting longer than 2 min.]*/
AzureIoTClient 11:31ebaeb51e1e 1205 if (((current_ms - mqttMsgEntry->msgPublishTime) / 1000) > RESEND_TIMEOUT_VALUE_MIN)
AzureIoTClient 11:31ebaeb51e1e 1206 {
AzureIoTClient 11:31ebaeb51e1e 1207 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_034: [If IoTHubTransportMqtt_DoWork has resent the message two times then it shall fail the message] */
AzureIoTClient 11:31ebaeb51e1e 1208 if (mqttMsgEntry->retryCount >= MAX_SEND_RECOUNT_LIMIT)
AzureIoTClient 11:31ebaeb51e1e 1209 {
AzureIoTClient 11:31ebaeb51e1e 1210 (void)DList_RemoveEntryList(currentListEntry);
AzureIoTClient 11:31ebaeb51e1e 1211 sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transport_data, IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT);
AzureIoTClient 11:31ebaeb51e1e 1212 free(mqttMsgEntry);
AzureIoTClient 11:31ebaeb51e1e 1213 }
AzureIoTClient 11:31ebaeb51e1e 1214 else
AzureIoTClient 11:31ebaeb51e1e 1215 {
AzureIoTClient 11:31ebaeb51e1e 1216 size_t messageLength;
AzureIoTClient 11:31ebaeb51e1e 1217 const unsigned char* messagePayload = RetrieveMessagePayload(mqttMsgEntry->iotHubMessageEntry->messageHandle, &messageLength);
AzureIoTClient 11:31ebaeb51e1e 1218 if (messageLength == 0 || messagePayload == NULL)
AzureIoTClient 11:31ebaeb51e1e 1219 {
AzureIoTClient 11:31ebaeb51e1e 1220 LogError("Failure from creating Message IoTHubMessage_GetData");
AzureIoTClient 11:31ebaeb51e1e 1221 }
AzureIoTClient 11:31ebaeb51e1e 1222 else
AzureIoTClient 11:31ebaeb51e1e 1223 {
AzureIoTClient 11:31ebaeb51e1e 1224 if (publish_mqtt_telemetry_msg(transport_data, mqttMsgEntry, messagePayload, messageLength) != 0)
AzureIoTClient 11:31ebaeb51e1e 1225 {
AzureIoTClient 11:31ebaeb51e1e 1226 (void)DList_RemoveEntryList(currentListEntry);
AzureIoTClient 11:31ebaeb51e1e 1227 sendMsgComplete(mqttMsgEntry->iotHubMessageEntry, transport_data, IOTHUB_CLIENT_CONFIRMATION_ERROR);
AzureIoTClient 11:31ebaeb51e1e 1228 free(mqttMsgEntry);
AzureIoTClient 11:31ebaeb51e1e 1229 }
AzureIoTClient 11:31ebaeb51e1e 1230 }
AzureIoTClient 11:31ebaeb51e1e 1231 }
AzureIoTClient 11:31ebaeb51e1e 1232 }
AzureIoTClient 11:31ebaeb51e1e 1233 currentListEntry = nextListEntry.Flink;
AzureIoTClient 11:31ebaeb51e1e 1234 }
AzureIoTClient 11:31ebaeb51e1e 1235
AzureIoTClient 11:31ebaeb51e1e 1236 currentListEntry = transport_data->waitingToSend->Flink;
AzureIoTClient 11:31ebaeb51e1e 1237 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_027: [IoTHubTransportMqtt_DoWork shall inspect the "waitingToSend" DLIST passed in config structure.] */
AzureIoTClient 11:31ebaeb51e1e 1238 while (currentListEntry != transport_data->waitingToSend)
AzureIoTClient 11:31ebaeb51e1e 1239 {
AzureIoTClient 11:31ebaeb51e1e 1240 IOTHUB_MESSAGE_LIST* iothubMsgList = containingRecord(currentListEntry, IOTHUB_MESSAGE_LIST, entry);
AzureIoTClient 11:31ebaeb51e1e 1241 DLIST_ENTRY savedFromCurrentListEntry;
AzureIoTClient 11:31ebaeb51e1e 1242 savedFromCurrentListEntry.Flink = currentListEntry->Flink;
AzureIoTClient 11:31ebaeb51e1e 1243
AzureIoTClient 11:31ebaeb51e1e 1244 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_027: [IoTHubTransportMqtt_DoWork shall inspect the "waitingToSend" DLIST passed in config structure.] */
AzureIoTClient 11:31ebaeb51e1e 1245 size_t messageLength;
AzureIoTClient 11:31ebaeb51e1e 1246 const unsigned char* messagePayload = RetrieveMessagePayload(iothubMsgList->messageHandle, &messageLength);
AzureIoTClient 11:31ebaeb51e1e 1247 if (messageLength == 0 || messagePayload == NULL)
AzureIoTClient 11:31ebaeb51e1e 1248 {
AzureIoTClient 11:31ebaeb51e1e 1249 LogError("Failure result from IoTHubMessage_GetData");
AzureIoTClient 11:31ebaeb51e1e 1250 }
AzureIoTClient 11:31ebaeb51e1e 1251 else
AzureIoTClient 11:31ebaeb51e1e 1252 {
AzureIoTClient 11:31ebaeb51e1e 1253 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_029: [IoTHubTransportMqtt_DoWork shall create a MQTT_MESSAGE_HANDLE and pass this to a call to mqtt_client_publish.] */
AzureIoTClient 11:31ebaeb51e1e 1254 MQTT_MESSAGE_DETAILS_LIST* mqttMsgEntry = (MQTT_MESSAGE_DETAILS_LIST*)malloc(sizeof(MQTT_MESSAGE_DETAILS_LIST));
AzureIoTClient 11:31ebaeb51e1e 1255 if (mqttMsgEntry == NULL)
AzureIoTClient 11:31ebaeb51e1e 1256 {
AzureIoTClient 11:31ebaeb51e1e 1257 LogError("Allocation Error: Failure allocating MQTT Message Detail List.");
AzureIoTClient 11:31ebaeb51e1e 1258 }
AzureIoTClient 11:31ebaeb51e1e 1259 else
AzureIoTClient 11:31ebaeb51e1e 1260 {
AzureIoTClient 11:31ebaeb51e1e 1261 mqttMsgEntry->retryCount = 0;
AzureIoTClient 11:31ebaeb51e1e 1262 mqttMsgEntry->iotHubMessageEntry = iothubMsgList;
AzureIoTClient 11:31ebaeb51e1e 1263 mqttMsgEntry->packet_id = get_next_packet_id(transport_data);
AzureIoTClient 11:31ebaeb51e1e 1264 if (publish_mqtt_telemetry_msg(transport_data, mqttMsgEntry, messagePayload, messageLength) != 0)
AzureIoTClient 11:31ebaeb51e1e 1265 {
AzureIoTClient 11:31ebaeb51e1e 1266 (void)(DList_RemoveEntryList(currentListEntry));
AzureIoTClient 11:31ebaeb51e1e 1267 sendMsgComplete(iothubMsgList, transport_data, IOTHUB_CLIENT_CONFIRMATION_ERROR);
AzureIoTClient 11:31ebaeb51e1e 1268 free(mqttMsgEntry);
AzureIoTClient 11:31ebaeb51e1e 1269 }
AzureIoTClient 11:31ebaeb51e1e 1270 else
AzureIoTClient 11:31ebaeb51e1e 1271 {
AzureIoTClient 11:31ebaeb51e1e 1272 (void)(DList_RemoveEntryList(currentListEntry));
AzureIoTClient 11:31ebaeb51e1e 1273 DList_InsertTailList(&(transport_data->telemetry_waitingForAck), &(mqttMsgEntry->entry));
AzureIoTClient 11:31ebaeb51e1e 1274 }
AzureIoTClient 11:31ebaeb51e1e 1275 }
AzureIoTClient 11:31ebaeb51e1e 1276 }
AzureIoTClient 11:31ebaeb51e1e 1277 currentListEntry = savedFromCurrentListEntry.Flink;
AzureIoTClient 11:31ebaeb51e1e 1278 }
AzureIoTClient 11:31ebaeb51e1e 1279 }
AzureIoTClient 11:31ebaeb51e1e 1280 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_030: [IoTHubTransportMqtt_DoWork shall call mqtt_client_dowork everytime it is called if it is isConnected.] */
AzureIoTClient 11:31ebaeb51e1e 1281 mqtt_client_dowork(transport_data->mqttClient);
AzureIoTClient 11:31ebaeb51e1e 1282 }
AzureIoTClient 11:31ebaeb51e1e 1283 }
AzureIoTClient 11:31ebaeb51e1e 1284 }
AzureIoTClient 11:31ebaeb51e1e 1285
AzureIoTClient 11:31ebaeb51e1e 1286 IOTHUB_CLIENT_RESULT IoTHubTransport_MQTT_Common_GetSendStatus(IOTHUB_DEVICE_HANDLE handle, IOTHUB_CLIENT_STATUS *iotHubClientStatus)
AzureIoTClient 11:31ebaeb51e1e 1287 {
AzureIoTClient 11:31ebaeb51e1e 1288 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 11:31ebaeb51e1e 1289
AzureIoTClient 11:31ebaeb51e1e 1290 if (handle == NULL || iotHubClientStatus == NULL)
AzureIoTClient 11:31ebaeb51e1e 1291 {
AzureIoTClient 11:31ebaeb51e1e 1292 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_023: [IoTHubTransportMqtt_GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL parameter.] */
AzureIoTClient 11:31ebaeb51e1e 1293 LogError("invalid arument.");
AzureIoTClient 11:31ebaeb51e1e 1294 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 11:31ebaeb51e1e 1295 }
AzureIoTClient 11:31ebaeb51e1e 1296 else
AzureIoTClient 11:31ebaeb51e1e 1297 {
AzureIoTClient 11:31ebaeb51e1e 1298 MQTTTRANSPORT_HANDLE_DATA* handleData = (MQTTTRANSPORT_HANDLE_DATA*)handle;
AzureIoTClient 11:31ebaeb51e1e 1299 if (!DList_IsListEmpty(handleData->waitingToSend) || !DList_IsListEmpty(&(handleData->telemetry_waitingForAck)))
AzureIoTClient 11:31ebaeb51e1e 1300 {
AzureIoTClient 11:31ebaeb51e1e 1301 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_025: [IoTHubTransportMqtt_GetSendStatus shall return IOTHUB_CLIENT_OK and status IOTHUB_CLIENT_SEND_STATUS_BUSY if there are currently event items to be sent or being sent.] */
AzureIoTClient 11:31ebaeb51e1e 1302 *iotHubClientStatus = IOTHUB_CLIENT_SEND_STATUS_BUSY;
AzureIoTClient 11:31ebaeb51e1e 1303 }
AzureIoTClient 11:31ebaeb51e1e 1304 else
AzureIoTClient 11:31ebaeb51e1e 1305 {
AzureIoTClient 11:31ebaeb51e1e 1306 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_024: [IoTHubTransportMqtt_GetSendStatus shall return IOTHUB_CLIENT_OK and status IOTHUB_CLIENT_SEND_STATUS_IDLE if there are currently no event items to be sent or being sent.] */
AzureIoTClient 11:31ebaeb51e1e 1307 *iotHubClientStatus = IOTHUB_CLIENT_SEND_STATUS_IDLE;
AzureIoTClient 11:31ebaeb51e1e 1308 }
AzureIoTClient 11:31ebaeb51e1e 1309 result = IOTHUB_CLIENT_OK;
AzureIoTClient 11:31ebaeb51e1e 1310 }
AzureIoTClient 11:31ebaeb51e1e 1311 return result;
AzureIoTClient 11:31ebaeb51e1e 1312 }
AzureIoTClient 11:31ebaeb51e1e 1313
AzureIoTClient 11:31ebaeb51e1e 1314 IOTHUB_CLIENT_RESULT IoTHubTransport_MQTT_Common_SetOption(TRANSPORT_LL_HANDLE handle, const char* option, const void* value)
AzureIoTClient 11:31ebaeb51e1e 1315 {
AzureIoTClient 11:31ebaeb51e1e 1316 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_021: [If any parameter is NULL then IoTHubTransportMqtt_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */
AzureIoTClient 11:31ebaeb51e1e 1317 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 11:31ebaeb51e1e 1318 if (
AzureIoTClient 11:31ebaeb51e1e 1319 (handle == NULL) ||
AzureIoTClient 11:31ebaeb51e1e 1320 (option == NULL) ||
AzureIoTClient 11:31ebaeb51e1e 1321 (value == NULL)
AzureIoTClient 11:31ebaeb51e1e 1322 )
AzureIoTClient 11:31ebaeb51e1e 1323 {
AzureIoTClient 11:31ebaeb51e1e 1324 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 11:31ebaeb51e1e 1325 LogError("invalid parameter (NULL) passed to clientTransportAMQP_SetOption.");
AzureIoTClient 11:31ebaeb51e1e 1326 }
AzureIoTClient 11:31ebaeb51e1e 1327 else
AzureIoTClient 11:31ebaeb51e1e 1328 {
AzureIoTClient 11:31ebaeb51e1e 1329 MQTTTRANSPORT_HANDLE_DATA* transport_data = (MQTTTRANSPORT_HANDLE_DATA*)handle;
AzureIoTClient 11:31ebaeb51e1e 1330 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_031: [If the option parameter is set to "logtrace" then the value shall be a bool_ptr and the value will determine if the mqtt client log is on or off.] */
AzureIoTClient 11:31ebaeb51e1e 1331 if (strcmp(OPTION_LOG_TRACE, option) == 0)
AzureIoTClient 11:31ebaeb51e1e 1332 {
AzureIoTClient 11:31ebaeb51e1e 1333 transport_data->log_trace = *((bool*)value);
AzureIoTClient 11:31ebaeb51e1e 1334 mqtt_client_set_trace(transport_data->mqttClient, transport_data->log_trace, transport_data->raw_trace);
AzureIoTClient 11:31ebaeb51e1e 1335 result = IOTHUB_CLIENT_OK;
AzureIoTClient 11:31ebaeb51e1e 1336 }
AzureIoTClient 11:31ebaeb51e1e 1337 else if (strcmp("rawlogtrace", option) == 0)
AzureIoTClient 11:31ebaeb51e1e 1338 {
AzureIoTClient 11:31ebaeb51e1e 1339 transport_data->raw_trace = *((bool*)value);
AzureIoTClient 11:31ebaeb51e1e 1340 mqtt_client_set_trace(transport_data->mqttClient, transport_data->log_trace, transport_data->raw_trace);
AzureIoTClient 11:31ebaeb51e1e 1341 result = IOTHUB_CLIENT_OK;
AzureIoTClient 11:31ebaeb51e1e 1342 }
AzureIoTClient 11:31ebaeb51e1e 1343 else if (strcmp(OPTION_KEEP_ALIVE, option) == 0)
AzureIoTClient 11:31ebaeb51e1e 1344 {
AzureIoTClient 11:31ebaeb51e1e 1345 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_036: [If the option parameter is set to "keepalive" then the value shall be a int_ptr and the value will determine the mqtt keepalive time that is set for pings.] */
AzureIoTClient 11:31ebaeb51e1e 1346 int* keepAliveOption = (int*)value;
AzureIoTClient 11:31ebaeb51e1e 1347 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_037 : [If the option parameter is set to supplied int_ptr keepalive is the same value as the existing keepalive then IoTHubTransportMqtt_SetOption shall do nothing.] */
AzureIoTClient 11:31ebaeb51e1e 1348 if (*keepAliveOption != transport_data->keepAliveValue)
AzureIoTClient 11:31ebaeb51e1e 1349 {
AzureIoTClient 11:31ebaeb51e1e 1350 transport_data->keepAliveValue = (uint16_t)(*keepAliveOption);
AzureIoTClient 11:31ebaeb51e1e 1351 if (transport_data->isConnected)
AzureIoTClient 11:31ebaeb51e1e 1352 {
AzureIoTClient 11:31ebaeb51e1e 1353 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_038: [If the client is isConnected when the keepalive is set then IoTHubTransportMqtt_SetOption shall disconnect and reconnect with the specified keepalive value.] */
AzureIoTClient 11:31ebaeb51e1e 1354 DisconnectFromClient(transport_data);
AzureIoTClient 11:31ebaeb51e1e 1355 }
AzureIoTClient 11:31ebaeb51e1e 1356 }
AzureIoTClient 11:31ebaeb51e1e 1357 result = IOTHUB_CLIENT_OK;
AzureIoTClient 11:31ebaeb51e1e 1358 }
AzureIoTClient 11:31ebaeb51e1e 1359 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_039: [If the option parameter is set to "x509certificate" then the value shall be a const char of the certificate to be used for x509.] */
AzureIoTClient 11:31ebaeb51e1e 1360 else if ((strcmp(OPTION_X509_CERT, option) == 0) && (transport_data->transport_creds.credential_type != X509))
AzureIoTClient 11:31ebaeb51e1e 1361 {
AzureIoTClient 11:31ebaeb51e1e 1362 LogError("x509certificate specified, but authentication method is not x509");
AzureIoTClient 11:31ebaeb51e1e 1363 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 11:31ebaeb51e1e 1364 }
AzureIoTClient 11:31ebaeb51e1e 1365 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_040: [If the option parameter is set to "x509privatekey" then the value shall be a const char of the RSA Private Key to be used for x509.] */
AzureIoTClient 11:31ebaeb51e1e 1366 else if ((strcmp(OPTION_X509_PRIVATE_KEY, option) == 0) && (transport_data->transport_creds.credential_type != X509))
AzureIoTClient 11:31ebaeb51e1e 1367 {
AzureIoTClient 11:31ebaeb51e1e 1368 LogError("x509privatekey specified, but authentication method is not x509");
AzureIoTClient 11:31ebaeb51e1e 1369 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 11:31ebaeb51e1e 1370 }
AzureIoTClient 11:31ebaeb51e1e 1371 else
AzureIoTClient 11:31ebaeb51e1e 1372 {
AzureIoTClient 11:31ebaeb51e1e 1373 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_032: [IoTHubTransportMqtt_SetOption shall pass down the option to xio_setoption if the option parameter is not a known option string for the MQTT transport.] */
AzureIoTClient 11:31ebaeb51e1e 1374 if (GetTransportProviderIfNecessary(transport_data) == 0)
AzureIoTClient 11:31ebaeb51e1e 1375 {
AzureIoTClient 11:31ebaeb51e1e 1376 if (xio_setoption(transport_data->xioTransport, option, value) == 0)
AzureIoTClient 11:31ebaeb51e1e 1377 {
AzureIoTClient 11:31ebaeb51e1e 1378 result = IOTHUB_CLIENT_OK;
AzureIoTClient 11:31ebaeb51e1e 1379 }
AzureIoTClient 11:31ebaeb51e1e 1380 else
AzureIoTClient 11:31ebaeb51e1e 1381 {
AzureIoTClient 11:31ebaeb51e1e 1382 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_132: [IoTHubTransportMqtt_SetOption shall return IOTHUB_CLIENT_INVALID_ARG xio_setoption fails] */
AzureIoTClient 11:31ebaeb51e1e 1383 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 11:31ebaeb51e1e 1384 }
AzureIoTClient 11:31ebaeb51e1e 1385 }
AzureIoTClient 11:31ebaeb51e1e 1386 else
AzureIoTClient 11:31ebaeb51e1e 1387 {
AzureIoTClient 11:31ebaeb51e1e 1388 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 11:31ebaeb51e1e 1389 }
AzureIoTClient 11:31ebaeb51e1e 1390 }
AzureIoTClient 11:31ebaeb51e1e 1391 }
AzureIoTClient 11:31ebaeb51e1e 1392 return result;
AzureIoTClient 11:31ebaeb51e1e 1393 }
AzureIoTClient 11:31ebaeb51e1e 1394
AzureIoTClient 11:31ebaeb51e1e 1395 IOTHUB_DEVICE_HANDLE IoTHubTransport_MQTT_Common_Register(TRANSPORT_LL_HANDLE handle, const IOTHUB_DEVICE_CONFIG* device, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, PDLIST_ENTRY waitingToSend)
AzureIoTClient 11:31ebaeb51e1e 1396 {
AzureIoTClient 11:31ebaeb51e1e 1397 IOTHUB_DEVICE_HANDLE result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1398 (void)iotHubClientHandle;
AzureIoTClient 11:31ebaeb51e1e 1399
AzureIoTClient 11:31ebaeb51e1e 1400 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_17_001: [ IoTHubTransportMqtt_Register shall return NULL if the TRANSPORT_LL_HANDLE is NULL.]
AzureIoTClient 11:31ebaeb51e1e 1401 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_17_002: [ IoTHubTransportMqtt_Register shall return NULL if device or waitingToSend are NULL.]
AzureIoTClient 11:31ebaeb51e1e 1402 if ((handle == NULL) || (device == NULL) || (waitingToSend == NULL))
AzureIoTClient 11:31ebaeb51e1e 1403 {
AzureIoTClient 11:31ebaeb51e1e 1404 LogError("IoTHubTransportMqtt_Register: handle, device or waitingToSend is NULL.");
AzureIoTClient 11:31ebaeb51e1e 1405 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1406 }
AzureIoTClient 11:31ebaeb51e1e 1407 else
AzureIoTClient 11:31ebaeb51e1e 1408 {
AzureIoTClient 11:31ebaeb51e1e 1409 MQTTTRANSPORT_HANDLE_DATA* transport_data = (MQTTTRANSPORT_HANDLE_DATA*)handle;
AzureIoTClient 11:31ebaeb51e1e 1410
AzureIoTClient 11:31ebaeb51e1e 1411 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_03_001: [ IoTHubTransportMqtt_Register shall return NULL if deviceId, or both deviceKey and deviceSasToken are NULL.]
AzureIoTClient 11:31ebaeb51e1e 1412 if (device->deviceId == NULL)
AzureIoTClient 11:31ebaeb51e1e 1413 {
AzureIoTClient 11:31ebaeb51e1e 1414 LogError("IoTHubTransportMqtt_Register: deviceId is NULL.");
AzureIoTClient 11:31ebaeb51e1e 1415 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1416 }
AzureIoTClient 11:31ebaeb51e1e 1417 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_03_002: [ IoTHubTransportMqtt_Register shall return NULL if both deviceKey and deviceSasToken are provided.]
AzureIoTClient 11:31ebaeb51e1e 1418 else if ((device->deviceKey != NULL) && (device->deviceSasToken != NULL))
AzureIoTClient 11:31ebaeb51e1e 1419 {
AzureIoTClient 11:31ebaeb51e1e 1420 LogError("IoTHubTransportMqtt_Register: Both deviceKey and deviceSasToken are defined. Only one can be used.");
AzureIoTClient 11:31ebaeb51e1e 1421 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1422 }
AzureIoTClient 11:31ebaeb51e1e 1423 else
AzureIoTClient 11:31ebaeb51e1e 1424 {
AzureIoTClient 11:31ebaeb51e1e 1425 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_17_003: [ IoTHubTransportMqtt_Register shall return NULL if deviceId or deviceKey do not match the deviceId and deviceKey passed in during IoTHubTransportMqtt_Create.]
AzureIoTClient 11:31ebaeb51e1e 1426 if (strcmp(STRING_c_str(transport_data->device_id), device->deviceId) != 0)
AzureIoTClient 11:31ebaeb51e1e 1427 {
AzureIoTClient 11:31ebaeb51e1e 1428 LogError("IoTHubTransportMqtt_Register: deviceId does not match.");
AzureIoTClient 11:31ebaeb51e1e 1429 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1430 }
AzureIoTClient 11:31ebaeb51e1e 1431 else if ( (transport_data->transport_creds.credential_type == DEVICE_KEY) && (strcmp(STRING_c_str(transport_data->transport_creds.CREDENTIAL_VALUE.deviceKey), device->deviceKey) != 0))
AzureIoTClient 11:31ebaeb51e1e 1432 {
AzureIoTClient 11:31ebaeb51e1e 1433 LogError("IoTHubTransportMqtt_Register: deviceKey does not match.");
AzureIoTClient 11:31ebaeb51e1e 1434 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1435 }
AzureIoTClient 11:31ebaeb51e1e 1436 else
AzureIoTClient 11:31ebaeb51e1e 1437 {
AzureIoTClient 11:31ebaeb51e1e 1438 if (transport_data->isRegistered == true)
AzureIoTClient 11:31ebaeb51e1e 1439 {
AzureIoTClient 11:31ebaeb51e1e 1440 LogError("Transport already has device registered by id: [%s]", device->deviceId);
AzureIoTClient 11:31ebaeb51e1e 1441 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1442 }
AzureIoTClient 11:31ebaeb51e1e 1443 else
AzureIoTClient 11:31ebaeb51e1e 1444 {
AzureIoTClient 11:31ebaeb51e1e 1445 transport_data->isRegistered = true;
AzureIoTClient 11:31ebaeb51e1e 1446 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_17_004: [ IoTHubTransportMqtt_Register shall return the TRANSPORT_LL_HANDLE as the IOTHUB_DEVICE_HANDLE. ]
AzureIoTClient 11:31ebaeb51e1e 1447 result = (IOTHUB_DEVICE_HANDLE)handle;
AzureIoTClient 11:31ebaeb51e1e 1448 }
AzureIoTClient 11:31ebaeb51e1e 1449 }
AzureIoTClient 11:31ebaeb51e1e 1450 }
AzureIoTClient 11:31ebaeb51e1e 1451 }
AzureIoTClient 11:31ebaeb51e1e 1452
AzureIoTClient 11:31ebaeb51e1e 1453 return result;
AzureIoTClient 11:31ebaeb51e1e 1454 }
AzureIoTClient 11:31ebaeb51e1e 1455
AzureIoTClient 11:31ebaeb51e1e 1456 // Codes_SRS_IOTHUB_MQTT_TRANSPORT_17_005: [ IoTHubTransportMqtt_Unregister shall return. ]
AzureIoTClient 11:31ebaeb51e1e 1457 void IoTHubTransport_MQTT_Common_Unregister(IOTHUB_DEVICE_HANDLE deviceHandle)
AzureIoTClient 11:31ebaeb51e1e 1458 {
AzureIoTClient 11:31ebaeb51e1e 1459 if (deviceHandle != NULL)
AzureIoTClient 11:31ebaeb51e1e 1460 {
AzureIoTClient 11:31ebaeb51e1e 1461 MQTTTRANSPORT_HANDLE_DATA* transport_data = (MQTTTRANSPORT_HANDLE_DATA*)deviceHandle;
AzureIoTClient 11:31ebaeb51e1e 1462
AzureIoTClient 11:31ebaeb51e1e 1463 transport_data->isRegistered = false;
AzureIoTClient 11:31ebaeb51e1e 1464 }
AzureIoTClient 11:31ebaeb51e1e 1465 }
AzureIoTClient 11:31ebaeb51e1e 1466
AzureIoTClient 11:31ebaeb51e1e 1467 STRING_HANDLE IoTHubTransport_MQTT_Common_GetHostname(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 11:31ebaeb51e1e 1468 {
AzureIoTClient 11:31ebaeb51e1e 1469 STRING_HANDLE result;
AzureIoTClient 11:31ebaeb51e1e 1470 /*Codes_SRS_IOTHUB_MQTT_TRANSPORT_02_001: [ If handle is NULL then IoTHubTransportMqtt_GetHostname shall fail and return NULL. ]*/
AzureIoTClient 11:31ebaeb51e1e 1471 if (handle == NULL)
AzureIoTClient 11:31ebaeb51e1e 1472 {
AzureIoTClient 11:31ebaeb51e1e 1473 result = NULL;
AzureIoTClient 11:31ebaeb51e1e 1474 }
AzureIoTClient 11:31ebaeb51e1e 1475 else
AzureIoTClient 11:31ebaeb51e1e 1476 {
AzureIoTClient 11:31ebaeb51e1e 1477 /*Codes_SRS_IOTHUB_MQTT_TRANSPORT_02_002: [ Otherwise IoTHubTransportMqtt_GetHostname shall return a non-NULL STRING_HANDLE containg the hostname. ]*/
AzureIoTClient 11:31ebaeb51e1e 1478 result = ((MQTTTRANSPORT_HANDLE_DATA*)handle)->hostAddress;
AzureIoTClient 11:31ebaeb51e1e 1479 }
AzureIoTClient 11:31ebaeb51e1e 1480 return result;
AzureIoTClient 11:31ebaeb51e1e 1481 }