Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

This library implements the AMQP transport for Microsoft Azure IoTHub client. The code is replicated from https://github.com/Azure/azure-iot-sdks

Committer:
AzureIoTClient
Date:
Thu Sep 22 18:15:46 2016 -0700
Revision:
24:834cf977abcf
Parent:
23:2c6779675a01
Child:
25:63f7d371c030
1.0.10

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 4:57e049bce51e 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 4:57e049bce51e 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 4:57e049bce51e 3
AzureIoTClient 4:57e049bce51e 4 #include <stdlib.h>
AzureIoTClient 4:57e049bce51e 5 #ifdef _CRTDBG_MAP_ALLOC
AzureIoTClient 4:57e049bce51e 6 #include <crtdbg.h>
AzureIoTClient 4:57e049bce51e 7 #endif
Azure.IoT Build 10:75c5e0d8537d 8 #include <stdint.h>
Azure.IoT Build 10:75c5e0d8537d 9 #include <time.h>
Azure.IoT Build 10:75c5e0d8537d 10 #include <limits.h>
Azure.IoT Build 12:841a4c36bd36 11 #include "azure_c_shared_utility/gballoc.h"
Azure.IoT Build 12:841a4c36bd36 12 #include "azure_c_shared_utility/crt_abstractions.h"
Azure.IoT Build 12:841a4c36bd36 13 #include "azure_c_shared_utility/doublylinkedlist.h"
Azure.IoT Build 18:239d162e3607 14 #include "azure_c_shared_utility/xlogging.h"
Azure.IoT Build 12:841a4c36bd36 15 #include "azure_c_shared_utility/platform.h"
Azure.IoT Build 12:841a4c36bd36 16 #include "azure_c_shared_utility/sastoken.h"
Azure.IoT Build 12:841a4c36bd36 17 #include "azure_c_shared_utility/strings.h"
Azure.IoT Build 12:841a4c36bd36 18 #include "azure_c_shared_utility/urlencode.h"
Azure.IoT Build 12:841a4c36bd36 19 #include "azure_c_shared_utility/tlsio.h"
AzureIoTClient 4:57e049bce51e 20
Azure.IoT Build 12:841a4c36bd36 21 #include "azure_uamqp_c/cbs.h"
Azure.IoT Build 12:841a4c36bd36 22 #include "azure_uamqp_c/link.h"
Azure.IoT Build 12:841a4c36bd36 23 #include "azure_uamqp_c/message.h"
Azure.IoT Build 12:841a4c36bd36 24 #include "azure_uamqp_c/amqpvalue.h"
Azure.IoT Build 12:841a4c36bd36 25 #include "azure_uamqp_c/message_receiver.h"
Azure.IoT Build 12:841a4c36bd36 26 #include "azure_uamqp_c/message_sender.h"
Azure.IoT Build 12:841a4c36bd36 27 #include "azure_uamqp_c/messaging.h"
Azure.IoT Build 12:841a4c36bd36 28 #include "azure_uamqp_c/sasl_mssbcbs.h"
Azure.IoT Build 12:841a4c36bd36 29 #include "azure_uamqp_c/saslclientio.h"
AzureIoTClient 4:57e049bce51e 30
AzureIoTClient 23:2c6779675a01 31 #include "uamqp_messaging.h"
AzureIoTClient 4:57e049bce51e 32 #include "iothub_client_ll.h"
AzureIoTClient 21:32a1746384ba 33 #include "iothub_client_options.h"
AzureIoTClient 4:57e049bce51e 34 #include "iothub_client_private.h"
AzureIoTClient 4:57e049bce51e 35 #include "iothubtransportamqp.h"
Azure.IoT Build 7:07bc440836b3 36 #include "iothub_client_version.h"
Azure.IoT Build 7:07bc440836b3 37
AzureIoTClient 22:8b70cf813f25 38 #define INDEFINITE_TIME ((time_t)(-1))
AzureIoTClient 22:8b70cf813f25 39
Azure.IoT Build 7:07bc440836b3 40 #define RESULT_OK 0
Azure.IoT Build 7:07bc440836b3 41 #define RESULT_FAILURE 1
Azure.IoT Build 7:07bc440836b3 42 #define RESULT_TIMEOUT 2
Azure.IoT Build 7:07bc440836b3 43
Azure.IoT Build 7:07bc440836b3 44 #define RFC1035_MAX_FQDN_LENGTH 255
Azure.IoT Build 7:07bc440836b3 45 #define DEFAULT_IOTHUB_AMQP_PORT 5671
Azure.IoT Build 7:07bc440836b3 46 #define DEFAULT_SAS_TOKEN_LIFETIME_MS 3600000
Azure.IoT Build 7:07bc440836b3 47 #define DEFAULT_CBS_REQUEST_TIMEOUT_MS 30000
Azure.IoT Build 7:07bc440836b3 48 #define CBS_AUDIENCE "servicebus.windows.net:sastoken"
Azure.IoT Build 7:07bc440836b3 49 #define DEFAULT_CONTAINER_ID "default_container_id"
Azure.IoT Build 10:75c5e0d8537d 50 #define DEFAULT_INCOMING_WINDOW_SIZE UINT_MAX
Azure.IoT Build 7:07bc440836b3 51 #define DEFAULT_OUTGOING_WINDOW_SIZE 100
Azure.IoT Build 7:07bc440836b3 52 #define MESSAGE_RECEIVER_LINK_NAME "receiver-link"
Azure.IoT Build 7:07bc440836b3 53 #define MESSAGE_RECEIVER_TARGET_ADDRESS "ingress-rx"
Azure.IoT Build 7:07bc440836b3 54 #define MESSAGE_RECEIVER_MAX_LINK_SIZE 65536
Azure.IoT Build 7:07bc440836b3 55 #define MESSAGE_SENDER_LINK_NAME "sender-link"
Azure.IoT Build 7:07bc440836b3 56 #define MESSAGE_SENDER_SOURCE_ADDRESS "ingress"
Azure.IoT Build 11:62d7b956e76e 57 #define MESSAGE_SENDER_MAX_LINK_SIZE UINT64_MAX
Azure.IoT Build 7:07bc440836b3 58
Azure.IoT Build 11:62d7b956e76e 59 typedef XIO_HANDLE(*TLS_IO_TRANSPORT_PROVIDER)(const char* fqdn, int port);
Azure.IoT Build 7:07bc440836b3 60
Azure.IoT Build 7:07bc440836b3 61 typedef enum CBS_STATE_TAG
Azure.IoT Build 7:07bc440836b3 62 {
Azure.IoT Build 7:07bc440836b3 63 CBS_STATE_IDLE,
Azure.IoT Build 7:07bc440836b3 64 CBS_STATE_AUTH_IN_PROGRESS,
Azure.IoT Build 7:07bc440836b3 65 CBS_STATE_AUTHENTICATED
Azure.IoT Build 7:07bc440836b3 66 } CBS_STATE;
AzureIoTClient 4:57e049bce51e 67
AzureIoTClient 19:ea016664011a 68 typedef enum AMQP_TRANSPORT_CREDENTIAL_TYPE_TAG
AzureIoTClient 19:ea016664011a 69 {
AzureIoTClient 19:ea016664011a 70 CREDENTIAL_NOT_BUILD,
AzureIoTClient 19:ea016664011a 71 X509,
AzureIoTClient 19:ea016664011a 72 DEVICE_KEY,
AzureIoTClient 19:ea016664011a 73 DEVICE_SAS_TOKEN,
AzureIoTClient 19:ea016664011a 74 }AMQP_TRANSPORT_CREDENTIAL_TYPE;
AzureIoTClient 19:ea016664011a 75
AzureIoTClient 19:ea016664011a 76 typedef struct X509_CREDENTIAL_TAG
AzureIoTClient 19:ea016664011a 77 {
AzureIoTClient 19:ea016664011a 78 const char* x509certificate;
AzureIoTClient 19:ea016664011a 79 const char* x509privatekey;
AzureIoTClient 19:ea016664011a 80 }X509_CREDENTIAL;
AzureIoTClient 19:ea016664011a 81
AzureIoTClient 19:ea016664011a 82 typedef union AMQP_TRANSPORT_CREDENTIAL_UNION_TAG
AzureIoTClient 19:ea016664011a 83 {
AzureIoTClient 19:ea016664011a 84 // Key associated to the device to be used.
AzureIoTClient 19:ea016664011a 85 STRING_HANDLE deviceKey;
AzureIoTClient 20:8dec76e7ba34 86
AzureIoTClient 19:ea016664011a 87 // SAS associated to the device to be used.
AzureIoTClient 19:ea016664011a 88 STRING_HANDLE deviceSasToken;
AzureIoTClient 19:ea016664011a 89
AzureIoTClient 19:ea016664011a 90 // X509
AzureIoTClient 19:ea016664011a 91 X509_CREDENTIAL x509credential;
AzureIoTClient 19:ea016664011a 92 }AMQP_TRANSPORT_CREDENTIAL_UNION;
AzureIoTClient 19:ea016664011a 93
AzureIoTClient 19:ea016664011a 94 typedef struct AMQP_TRANSPORT_CREDENTIAL_TAG
AzureIoTClient 19:ea016664011a 95 {
AzureIoTClient 19:ea016664011a 96 AMQP_TRANSPORT_CREDENTIAL_TYPE credentialType;
AzureIoTClient 19:ea016664011a 97 AMQP_TRANSPORT_CREDENTIAL_UNION credential;
AzureIoTClient 19:ea016664011a 98 }AMQP_TRANSPORT_CREDENTIAL;
AzureIoTClient 19:ea016664011a 99
AzureIoTClient 20:8dec76e7ba34 100 /*the below structure contains fields that are only used with CBS (when authentication mechanisn is based on deviceKey or deviceSasToken)*/
AzureIoTClient 20:8dec76e7ba34 101 /*these fields are mutually exclusive with the fields of the AMQP_TRANSPORT_STATE_X509 authentication*/
AzureIoTClient 20:8dec76e7ba34 102 typedef struct AMQP_TRANSPORT_STATE_CBS_TAG
AzureIoTClient 20:8dec76e7ba34 103 {
AzureIoTClient 20:8dec76e7ba34 104 // A component of the SAS token. Currently this must be an empty string.
AzureIoTClient 20:8dec76e7ba34 105 STRING_HANDLE sasTokenKeyName;
AzureIoTClient 20:8dec76e7ba34 106 size_t sas_token_lifetime;
AzureIoTClient 20:8dec76e7ba34 107 // Maximum period of time for the transport to wait before refreshing the SAS token it created previously, in milliseconds.
AzureIoTClient 20:8dec76e7ba34 108 size_t sas_token_refresh_time;
AzureIoTClient 20:8dec76e7ba34 109 // Maximum time the transport waits for uAMQP cbs_put_token() to complete before marking it a failure, in milliseconds.
AzureIoTClient 20:8dec76e7ba34 110 size_t cbs_request_timeout;
AzureIoTClient 20:8dec76e7ba34 111
AzureIoTClient 20:8dec76e7ba34 112 // AMQP SASL I/O transport created on top of the TLS I/O layer.
AzureIoTClient 20:8dec76e7ba34 113 XIO_HANDLE sasl_io;
AzureIoTClient 20:8dec76e7ba34 114 // AMQP SASL I/O mechanism to be used.
AzureIoTClient 20:8dec76e7ba34 115 SASL_MECHANISM_HANDLE sasl_mechanism;
AzureIoTClient 20:8dec76e7ba34 116
AzureIoTClient 20:8dec76e7ba34 117 // Connection instance with the Azure IoT CBS.
AzureIoTClient 20:8dec76e7ba34 118 CBS_HANDLE cbs;
AzureIoTClient 20:8dec76e7ba34 119 // Current state of the CBS connection.
AzureIoTClient 20:8dec76e7ba34 120 CBS_STATE cbs_state;
AzureIoTClient 20:8dec76e7ba34 121 // Time when the current SAS token was created, in seconds since epoch.
AzureIoTClient 20:8dec76e7ba34 122 size_t current_sas_token_create_time;
AzureIoTClient 20:8dec76e7ba34 123 }AMQP_TRANSPORT_STATE_CBS;
AzureIoTClient 20:8dec76e7ba34 124
Azure.IoT Build 7:07bc440836b3 125 typedef struct AMQP_TRANSPORT_STATE_TAG
Azure.IoT Build 7:07bc440836b3 126 {
Azure.IoT Build 10:75c5e0d8537d 127 // FQDN of the IoT Hub.
Azure.IoT Build 10:75c5e0d8537d 128 STRING_HANDLE iotHubHostFqdn;
Azure.IoT Build 10:75c5e0d8537d 129 // AMQP port of the IoT Hub.
Azure.IoT Build 10:75c5e0d8537d 130 int iotHubPort;
AzureIoTClient 19:ea016664011a 131 // contains the credentials to be used
AzureIoTClient 19:ea016664011a 132 AMQP_TRANSPORT_CREDENTIAL credential;
Azure.IoT Build 10:75c5e0d8537d 133 // Address to which the transport will connect to and send events.
Azure.IoT Build 10:75c5e0d8537d 134 STRING_HANDLE targetAddress;
Azure.IoT Build 10:75c5e0d8537d 135 // Address to which the transport will connect to and receive messages from.
Azure.IoT Build 10:75c5e0d8537d 136 STRING_HANDLE messageReceiveAddress;
AzureIoTClient 20:8dec76e7ba34 137
Azure.IoT Build 10:75c5e0d8537d 138 // Internal parameter that identifies the current logical device within the service.
Azure.IoT Build 10:75c5e0d8537d 139 STRING_HANDLE devicesPath;
Azure.IoT Build 10:75c5e0d8537d 140 // How long a SAS token created by the transport is valid, in milliseconds.
AzureIoTClient 20:8dec76e7ba34 141
Azure.IoT Build 10:75c5e0d8537d 142 // Maximum time for the connection establishment/retry logic should wait for a connection to succeed, in milliseconds.
Azure.IoT Build 10:75c5e0d8537d 143 size_t connection_timeout;
Azure.IoT Build 10:75c5e0d8537d 144 // Saved reference to the IoTHub LL Client.
Azure.IoT Build 10:75c5e0d8537d 145 IOTHUB_CLIENT_LL_HANDLE iothub_client_handle;
Azure.IoT Build 11:62d7b956e76e 146
Azure.IoT Build 10:75c5e0d8537d 147 // TSL I/O transport.
Azure.IoT Build 10:75c5e0d8537d 148 XIO_HANDLE tls_io;
Azure.IoT Build 10:75c5e0d8537d 149 // Pointer to the function that creates the TLS I/O (internal use only).
Azure.IoT Build 10:75c5e0d8537d 150 TLS_IO_TRANSPORT_PROVIDER tls_io_transport_provider;
AzureIoTClient 20:8dec76e7ba34 151
Azure.IoT Build 10:75c5e0d8537d 152 // AMQP connection.
Azure.IoT Build 10:75c5e0d8537d 153 CONNECTION_HANDLE connection;
Azure.IoT Build 10:75c5e0d8537d 154 // Current AMQP connection state;
Azure.IoT Build 10:75c5e0d8537d 155 AMQP_MANAGEMENT_STATE connection_state;
Azure.IoT Build 10:75c5e0d8537d 156 // Last time the AMQP connection establishment was initiated.
Azure.IoT Build 10:75c5e0d8537d 157 size_t connection_establish_time;
Azure.IoT Build 10:75c5e0d8537d 158 // AMQP session.
Azure.IoT Build 10:75c5e0d8537d 159 SESSION_HANDLE session;
Azure.IoT Build 10:75c5e0d8537d 160 // AMQP link used by the event sender.
Azure.IoT Build 10:75c5e0d8537d 161 LINK_HANDLE sender_link;
Azure.IoT Build 10:75c5e0d8537d 162 // uAMQP event sender.
Azure.IoT Build 10:75c5e0d8537d 163 MESSAGE_SENDER_HANDLE message_sender;
Azure.IoT Build 10:75c5e0d8537d 164 // Internal flag that controls if messages should be received or not.
Azure.IoT Build 10:75c5e0d8537d 165 bool receive_messages;
Azure.IoT Build 10:75c5e0d8537d 166 // AMQP link used by the message receiver.
Azure.IoT Build 10:75c5e0d8537d 167 LINK_HANDLE receiver_link;
Azure.IoT Build 10:75c5e0d8537d 168 // uAMQP message receiver.
Azure.IoT Build 10:75c5e0d8537d 169 MESSAGE_RECEIVER_HANDLE message_receiver;
Azure.IoT Build 10:75c5e0d8537d 170 // List with events still pending to be sent. It is provided by the upper layer.
Azure.IoT Build 10:75c5e0d8537d 171 PDLIST_ENTRY waitingToSend;
Azure.IoT Build 10:75c5e0d8537d 172 // Internal list with the items currently being processed/sent through uAMQP.
Azure.IoT Build 10:75c5e0d8537d 173 DLIST_ENTRY inProgress;
AzureIoTClient 20:8dec76e7ba34 174
AzureIoTClient 20:8dec76e7ba34 175 // all things CBS (and only CBS)
AzureIoTClient 20:8dec76e7ba34 176 AMQP_TRANSPORT_STATE_CBS cbs;
AzureIoTClient 20:8dec76e7ba34 177
Azure.IoT Build 10:75c5e0d8537d 178 // Mark if device is registered in transport (only one device per transport).
Azure.IoT Build 10:75c5e0d8537d 179 bool isRegistered;
AzureIoTClient 16:a49121e2300b 180 // Turns logging on and off
AzureIoTClient 16:a49121e2300b 181 bool is_trace_on;
AzureIoTClient 20:8dec76e7ba34 182
AzureIoTClient 20:8dec76e7ba34 183 /*here are the options from the xio layer if any is saved*/
AzureIoTClient 20:8dec76e7ba34 184 OPTIONHANDLER_HANDLE xioOptions;
Azure.IoT Build 7:07bc440836b3 185 } AMQP_TRANSPORT_INSTANCE;
Azure.IoT Build 7:07bc440836b3 186
AzureIoTClient 4:57e049bce51e 187
AzureIoTClient 4:57e049bce51e 188
Azure.IoT Build 7:07bc440836b3 189 // Auxiliary functions
AzureIoTClient 4:57e049bce51e 190
Azure.IoT Build 7:07bc440836b3 191 static STRING_HANDLE concat3Params(const char* prefix, const char* infix, const char* suffix)
AzureIoTClient 4:57e049bce51e 192 {
Azure.IoT Build 7:07bc440836b3 193 STRING_HANDLE result = NULL;
Azure.IoT Build 10:75c5e0d8537d 194 char* concat;
Azure.IoT Build 7:07bc440836b3 195 size_t totalLength = strlen(prefix) + strlen(infix) + strlen(suffix) + 1; // One extra for \0.
AzureIoTClient 5:8d58d20699dd 196
Azure.IoT Build 10:75c5e0d8537d 197 if ((concat = (char*)malloc(totalLength)) != NULL)
AzureIoTClient 5:8d58d20699dd 198 {
Azure.IoT Build 10:75c5e0d8537d 199 (void)strcpy(concat, prefix);
Azure.IoT Build 10:75c5e0d8537d 200 (void)strcat(concat, infix);
Azure.IoT Build 10:75c5e0d8537d 201 (void)strcat(concat, suffix);
Azure.IoT Build 10:75c5e0d8537d 202 result = STRING_construct(concat);
Azure.IoT Build 7:07bc440836b3 203 free(concat);
AzureIoTClient 5:8d58d20699dd 204 }
Azure.IoT Build 10:75c5e0d8537d 205 else
Azure.IoT Build 10:75c5e0d8537d 206 {
Azure.IoT Build 10:75c5e0d8537d 207 result = NULL;
Azure.IoT Build 10:75c5e0d8537d 208 }
AzureIoTClient 5:8d58d20699dd 209
AzureIoTClient 4:57e049bce51e 210 return result;
AzureIoTClient 4:57e049bce51e 211 }
AzureIoTClient 4:57e049bce51e 212
AzureIoTClient 22:8b70cf813f25 213 static int getSecondsSinceEpoch(size_t* seconds)
AzureIoTClient 4:57e049bce51e 214 {
AzureIoTClient 22:8b70cf813f25 215 int result;
AzureIoTClient 22:8b70cf813f25 216 time_t current_time;
AzureIoTClient 22:8b70cf813f25 217
AzureIoTClient 22:8b70cf813f25 218 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 22:8b70cf813f25 219 {
AzureIoTClient 22:8b70cf813f25 220 LogError("Failed getting the current local time (get_time() failed)");
AzureIoTClient 22:8b70cf813f25 221 result = __LINE__;
AzureIoTClient 22:8b70cf813f25 222 }
AzureIoTClient 22:8b70cf813f25 223 else
AzureIoTClient 22:8b70cf813f25 224 {
AzureIoTClient 22:8b70cf813f25 225 *seconds = (size_t)get_difftime(current_time, (time_t)0);
AzureIoTClient 22:8b70cf813f25 226
AzureIoTClient 22:8b70cf813f25 227 result = RESULT_OK;
AzureIoTClient 22:8b70cf813f25 228 }
AzureIoTClient 22:8b70cf813f25 229
AzureIoTClient 22:8b70cf813f25 230 return result;
AzureIoTClient 4:57e049bce51e 231 }
AzureIoTClient 4:57e049bce51e 232
Azure.IoT Build 12:841a4c36bd36 233 static void trackEventInProgress(IOTHUB_MESSAGE_LIST* message, AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 234 {
Azure.IoT Build 12:841a4c36bd36 235 DList_RemoveEntryList(&message->entry);
Azure.IoT Build 12:841a4c36bd36 236 DList_InsertTailList(&transport_state->inProgress, &message->entry);
AzureIoTClient 4:57e049bce51e 237 }
AzureIoTClient 4:57e049bce51e 238
Azure.IoT Build 7:07bc440836b3 239 static IOTHUB_MESSAGE_LIST* getNextEventToSend(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 240 {
Azure.IoT Build 10:75c5e0d8537d 241 IOTHUB_MESSAGE_LIST* message;
Azure.IoT Build 7:07bc440836b3 242
Azure.IoT Build 7:07bc440836b3 243 if (!DList_IsListEmpty(transport_state->waitingToSend))
AzureIoTClient 4:57e049bce51e 244 {
Azure.IoT Build 7:07bc440836b3 245 PDLIST_ENTRY list_entry = transport_state->waitingToSend->Flink;
Azure.IoT Build 7:07bc440836b3 246 message = containingRecord(list_entry, IOTHUB_MESSAGE_LIST, entry);
AzureIoTClient 4:57e049bce51e 247 }
Azure.IoT Build 10:75c5e0d8537d 248 else
Azure.IoT Build 10:75c5e0d8537d 249 {
Azure.IoT Build 10:75c5e0d8537d 250 message = NULL;
Azure.IoT Build 10:75c5e0d8537d 251 }
Azure.IoT Build 7:07bc440836b3 252
Azure.IoT Build 7:07bc440836b3 253 return message;
Azure.IoT Build 7:07bc440836b3 254 }
Azure.IoT Build 7:07bc440836b3 255
Azure.IoT Build 12:841a4c36bd36 256 static int isEventInInProgressList(IOTHUB_MESSAGE_LIST* message)
Azure.IoT Build 7:07bc440836b3 257 {
Azure.IoT Build 12:841a4c36bd36 258 return !DList_IsListEmpty(&message->entry);
AzureIoTClient 4:57e049bce51e 259 }
AzureIoTClient 4:57e049bce51e 260
Azure.IoT Build 12:841a4c36bd36 261 static void removeEventFromInProgressList(IOTHUB_MESSAGE_LIST* message)
AzureIoTClient 4:57e049bce51e 262 {
Azure.IoT Build 12:841a4c36bd36 263 DList_RemoveEntryList(&message->entry);
Azure.IoT Build 12:841a4c36bd36 264 DList_InitializeListHead(&message->entry);
AzureIoTClient 4:57e049bce51e 265 }
AzureIoTClient 4:57e049bce51e 266
Azure.IoT Build 12:841a4c36bd36 267 static void rollEventBackToWaitList(IOTHUB_MESSAGE_LIST* message, AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 268 {
Azure.IoT Build 12:841a4c36bd36 269 removeEventFromInProgressList(message);
AzureIoTClient 16:a49121e2300b 270 DList_InsertTailList(transport_state->waitingToSend, &message->entry);
Azure.IoT Build 7:07bc440836b3 271 }
Azure.IoT Build 7:07bc440836b3 272
Azure.IoT Build 7:07bc440836b3 273 static void rollEventsBackToWaitList(AMQP_TRANSPORT_INSTANCE* transport_state)
Azure.IoT Build 7:07bc440836b3 274 {
Azure.IoT Build 7:07bc440836b3 275 PDLIST_ENTRY entry = transport_state->inProgress.Blink;
Azure.IoT Build 7:07bc440836b3 276
Azure.IoT Build 7:07bc440836b3 277 while (entry != &transport_state->inProgress)
AzureIoTClient 4:57e049bce51e 278 {
AzureIoTClient 16:a49121e2300b 279 IOTHUB_MESSAGE_LIST* message = containingRecord(entry, IOTHUB_MESSAGE_LIST, entry);
Azure.IoT Build 7:07bc440836b3 280 entry = entry->Blink;
Azure.IoT Build 12:841a4c36bd36 281 rollEventBackToWaitList(message, transport_state);
AzureIoTClient 4:57e049bce51e 282 }
AzureIoTClient 4:57e049bce51e 283 }
AzureIoTClient 4:57e049bce51e 284
Azure.IoT Build 10:75c5e0d8537d 285 static void on_message_send_complete(void* context, MESSAGE_SEND_RESULT send_result)
AzureIoTClient 4:57e049bce51e 286 {
AzureIoTClient 16:a49121e2300b 287 IOTHUB_MESSAGE_LIST* message = (IOTHUB_MESSAGE_LIST*)context;
Azure.IoT Build 10:75c5e0d8537d 288
Azure.IoT Build 10:75c5e0d8537d 289 IOTHUB_CLIENT_RESULT iot_hub_send_result;
Azure.IoT Build 10:75c5e0d8537d 290
Azure.IoT Build 10:75c5e0d8537d 291 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_142: [The callback 'on_message_send_complete' shall pass to the upper layer callback an IOTHUB_CLIENT_CONFIRMATION_OK if the result received is MESSAGE_SEND_OK]
Azure.IoT Build 10:75c5e0d8537d 292 if (send_result == MESSAGE_SEND_OK)
AzureIoTClient 4:57e049bce51e 293 {
Azure.IoT Build 10:75c5e0d8537d 294 iot_hub_send_result = IOTHUB_CLIENT_CONFIRMATION_OK;
Azure.IoT Build 10:75c5e0d8537d 295 }
Azure.IoT Build 10:75c5e0d8537d 296 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_143: [The callback 'on_message_send_complete' shall pass to the upper layer callback an IOTHUB_CLIENT_CONFIRMATION_ERROR if the result received is MESSAGE_SEND_ERROR]
Azure.IoT Build 12:841a4c36bd36 297 else
Azure.IoT Build 10:75c5e0d8537d 298 {
Azure.IoT Build 10:75c5e0d8537d 299 iot_hub_send_result = IOTHUB_CLIENT_CONFIRMATION_ERROR;
Azure.IoT Build 10:75c5e0d8537d 300 }
Azure.IoT Build 7:07bc440836b3 301
Azure.IoT Build 10:75c5e0d8537d 302 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_102: [The callback 'on_message_send_complete' shall invoke the upper layer callback for message received if provided]
Azure.IoT Build 12:841a4c36bd36 303 if (message->callback != NULL)
Azure.IoT Build 10:75c5e0d8537d 304 {
Azure.IoT Build 12:841a4c36bd36 305 message->callback(iot_hub_send_result, message->context);
Azure.IoT Build 10:75c5e0d8537d 306 }
AzureIoTClient 4:57e049bce51e 307
AzureIoTClient 16:a49121e2300b 308 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_100: [The callback 'on_message_send_complete' shall remove the target message from the in-progress list after the upper layer callback]
AzureIoTClient 16:a49121e2300b 309 if (isEventInInProgressList(message))
AzureIoTClient 16:a49121e2300b 310 {
AzureIoTClient 16:a49121e2300b 311 removeEventFromInProgressList(message);
AzureIoTClient 16:a49121e2300b 312 }
Azure.IoT Build 12:841a4c36bd36 313
Azure.IoT Build 10:75c5e0d8537d 314 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_151: [The callback 'on_message_send_complete' shall destroy the message handle (IOTHUB_MESSAGE_HANDLE) using IoTHubMessage_Destroy()]
Azure.IoT Build 12:841a4c36bd36 315 IoTHubMessage_Destroy(message->messageHandle);
AzureIoTClient 4:57e049bce51e 316
AzureIoTClient 16:a49121e2300b 317 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_152: [The callback 'on_message_send_complete' shall destroy the IOTHUB_MESSAGE_LIST instance]
Azure.IoT Build 12:841a4c36bd36 318 free(message);
AzureIoTClient 4:57e049bce51e 319 }
AzureIoTClient 4:57e049bce51e 320
Azure.IoT Build 10:75c5e0d8537d 321 static void on_put_token_complete(void* context, CBS_OPERATION_RESULT operation_result, unsigned int status_code, const char* status_description)
AzureIoTClient 4:57e049bce51e 322 {
AzureIoTClient 22:8b70cf813f25 323 #ifdef NO_LOGGING
AzureIoTClient 22:8b70cf813f25 324 UNUSED(status_code);
AzureIoTClient 22:8b70cf813f25 325 UNUSED(status_description);
AzureIoTClient 22:8b70cf813f25 326 #endif
AzureIoTClient 22:8b70cf813f25 327
Azure.IoT Build 7:07bc440836b3 328 AMQP_TRANSPORT_INSTANCE* transportState = (AMQP_TRANSPORT_INSTANCE*)context;
Azure.IoT Build 7:07bc440836b3 329
Azure.IoT Build 12:841a4c36bd36 330 if (operation_result == CBS_OPERATION_RESULT_OK)
AzureIoTClient 4:57e049bce51e 331 {
AzureIoTClient 20:8dec76e7ba34 332 transportState->cbs.cbs_state = CBS_STATE_AUTHENTICATED;
Azure.IoT Build 7:07bc440836b3 333 }
AzureIoTClient 19:ea016664011a 334 else
AzureIoTClient 19:ea016664011a 335 {
AzureIoTClient 19:ea016664011a 336 LogError("CBS reported status %u error: %s", status_code, status_description);
AzureIoTClient 19:ea016664011a 337 }
Azure.IoT Build 7:07bc440836b3 338 }
Azure.IoT Build 7:07bc440836b3 339
Azure.IoT Build 10:75c5e0d8537d 340 static AMQP_VALUE on_message_received(const void* context, MESSAGE_HANDLE message)
Azure.IoT Build 7:07bc440836b3 341 {
Azure.IoT Build 7:07bc440836b3 342 AMQP_VALUE result = NULL;
AzureIoTClient 23:2c6779675a01 343 int api_call_result;
Azure.IoT Build 7:07bc440836b3 344 IOTHUB_MESSAGE_HANDLE iothub_message = NULL;
AzureIoTClient 23:2c6779675a01 345 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_195: [The callback 'on_message_received' shall shall get a IOTHUB_MESSAGE_HANDLE instance out of the uamqp's MESSAGE_HANDLE instance by using IoTHubMessage_CreateFromUamqpMessage()]
AzureIoTClient 23:2c6779675a01 346 if ((api_call_result = IoTHubMessage_CreateFromUamqpMessage(message, &iothub_message)) != RESULT_OK)
AzureIoTClient 23:2c6779675a01 347 {
AzureIoTClient 23:2c6779675a01 348 LogError("Transport failed processing the message received (error = %d).", api_call_result);
Azure.IoT Build 11:62d7b956e76e 349
AzureIoTClient 23:2c6779675a01 350 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_196: [If IoTHubMessage_CreateFromUamqpMessage fails, the callback 'on_message_received' shall reject the incoming message by calling messaging_delivery_rejected() and return.]
AzureIoTClient 23:2c6779675a01 351 result = messaging_delivery_rejected("Rejected due to failure reading AMQP message", "Failed reading AMQP message");
AzureIoTClient 23:2c6779675a01 352 }
AzureIoTClient 23:2c6779675a01 353 else
AzureIoTClient 23:2c6779675a01 354 {
AzureIoTClient 23:2c6779675a01 355 IOTHUBMESSAGE_DISPOSITION_RESULT disposition_result;
Azure.IoT Build 11:62d7b956e76e 356
AzureIoTClient 23:2c6779675a01 357 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_104: [The callback 'on_message_received' shall invoke IoTHubClient_LL_MessageCallback() passing the client and the incoming message handles as parameters]
AzureIoTClient 23:2c6779675a01 358 disposition_result = IoTHubClient_LL_MessageCallback((IOTHUB_CLIENT_LL_HANDLE)context, iothub_message);
AzureIoTClient 14:8e8e42008807 359
AzureIoTClient 23:2c6779675a01 360 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_197: [The callback 'on_message_received' shall destroy the IOTHUB_MESSAGE_HANDLE instance after invoking IoTHubClient_LL_MessageCallback().]
AzureIoTClient 23:2c6779675a01 361 IoTHubMessage_Destroy(iothub_message);
AzureIoTClient 14:8e8e42008807 362
AzureIoTClient 23:2c6779675a01 363 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_105: [The callback 'on_message_received' shall return the result of messaging_delivery_accepted() if the IoTHubClient_LL_MessageCallback() returns IOTHUBMESSAGE_ACCEPTED]
AzureIoTClient 23:2c6779675a01 364 if (disposition_result == IOTHUBMESSAGE_ACCEPTED)
AzureIoTClient 23:2c6779675a01 365 {
AzureIoTClient 23:2c6779675a01 366 result = messaging_delivery_accepted();
AzureIoTClient 23:2c6779675a01 367 }
AzureIoTClient 23:2c6779675a01 368 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_106: [The callback 'on_message_received' shall return the result of messaging_delivery_released() if the IoTHubClient_LL_MessageCallback() returns IOTHUBMESSAGE_ABANDONED]
AzureIoTClient 23:2c6779675a01 369 else if (disposition_result == IOTHUBMESSAGE_ABANDONED)
AzureIoTClient 23:2c6779675a01 370 {
AzureIoTClient 23:2c6779675a01 371 result = messaging_delivery_released();
AzureIoTClient 23:2c6779675a01 372 }
AzureIoTClient 23:2c6779675a01 373 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_107: [The callback 'on_message_received' shall return the result of messaging_delivery_rejected("Rejected by application", "Rejected by application") if the IoTHubClient_LL_MessageCallback() returns IOTHUBMESSAGE_REJECTED]
AzureIoTClient 23:2c6779675a01 374 else if (disposition_result == IOTHUBMESSAGE_REJECTED)
AzureIoTClient 23:2c6779675a01 375 {
AzureIoTClient 23:2c6779675a01 376 result = messaging_delivery_rejected("Rejected by application", "Rejected by application");
AzureIoTClient 23:2c6779675a01 377 }
AzureIoTClient 23:2c6779675a01 378 }
Azure.IoT Build 7:07bc440836b3 379
AzureIoTClient 23:2c6779675a01 380 return result;
Azure.IoT Build 7:07bc440836b3 381 }
Azure.IoT Build 7:07bc440836b3 382
Azure.IoT Build 11:62d7b956e76e 383 static XIO_HANDLE getTLSIOTransport(const char* fqdn, int port)
Azure.IoT Build 7:07bc440836b3 384 {
AzureIoTClient 20:8dec76e7ba34 385 XIO_HANDLE result;
AzureIoTClient 19:ea016664011a 386 TLSIO_CONFIG tls_io_config;
AzureIoTClient 19:ea016664011a 387 tls_io_config.hostname = fqdn;
AzureIoTClient 19:ea016664011a 388 tls_io_config.port = port;
Azure.IoT Build 10:75c5e0d8537d 389 const IO_INTERFACE_DESCRIPTION* io_interface_description = platform_get_default_tlsio();
AzureIoTClient 20:8dec76e7ba34 390 result = xio_create(io_interface_description, &tls_io_config);
AzureIoTClient 20:8dec76e7ba34 391 if (result == NULL)
AzureIoTClient 20:8dec76e7ba34 392 {
AzureIoTClient 20:8dec76e7ba34 393 LogError("unable to xio_create");
AzureIoTClient 20:8dec76e7ba34 394 /*return as is*/
AzureIoTClient 20:8dec76e7ba34 395 }
AzureIoTClient 20:8dec76e7ba34 396 else
AzureIoTClient 20:8dec76e7ba34 397 {
AzureIoTClient 20:8dec76e7ba34 398 /*also return as is*/
AzureIoTClient 20:8dec76e7ba34 399 }
AzureIoTClient 20:8dec76e7ba34 400 return result;
Azure.IoT Build 7:07bc440836b3 401 }
Azure.IoT Build 7:07bc440836b3 402
Azure.IoT Build 7:07bc440836b3 403 static void destroyConnection(AMQP_TRANSPORT_INSTANCE* transport_state)
Azure.IoT Build 7:07bc440836b3 404 {
AzureIoTClient 20:8dec76e7ba34 405 if (transport_state->cbs.cbs != NULL)
Azure.IoT Build 7:07bc440836b3 406 {
AzureIoTClient 20:8dec76e7ba34 407 cbs_destroy(transport_state->cbs.cbs);
AzureIoTClient 20:8dec76e7ba34 408 transport_state->cbs.cbs = NULL;
Azure.IoT Build 10:75c5e0d8537d 409 }
Azure.IoT Build 7:07bc440836b3 410
Azure.IoT Build 10:75c5e0d8537d 411 if (transport_state->session != NULL)
Azure.IoT Build 10:75c5e0d8537d 412 {
Azure.IoT Build 10:75c5e0d8537d 413 session_destroy(transport_state->session);
Azure.IoT Build 10:75c5e0d8537d 414 transport_state->session = NULL;
Azure.IoT Build 10:75c5e0d8537d 415 }
Azure.IoT Build 7:07bc440836b3 416
Azure.IoT Build 10:75c5e0d8537d 417 if (transport_state->connection != NULL)
Azure.IoT Build 10:75c5e0d8537d 418 {
Azure.IoT Build 10:75c5e0d8537d 419 connection_destroy(transport_state->connection);
Azure.IoT Build 10:75c5e0d8537d 420 transport_state->connection = NULL;
Azure.IoT Build 10:75c5e0d8537d 421 }
Azure.IoT Build 7:07bc440836b3 422
AzureIoTClient 20:8dec76e7ba34 423 if (transport_state->cbs.sasl_io != NULL)
Azure.IoT Build 10:75c5e0d8537d 424 {
AzureIoTClient 20:8dec76e7ba34 425 xio_destroy(transport_state->cbs.sasl_io);
AzureIoTClient 20:8dec76e7ba34 426 transport_state->cbs.sasl_io = NULL;
Azure.IoT Build 10:75c5e0d8537d 427 }
Azure.IoT Build 7:07bc440836b3 428
AzureIoTClient 20:8dec76e7ba34 429 if (transport_state->cbs.sasl_mechanism != NULL)
Azure.IoT Build 10:75c5e0d8537d 430 {
AzureIoTClient 20:8dec76e7ba34 431 saslmechanism_destroy(transport_state->cbs.sasl_mechanism);
AzureIoTClient 20:8dec76e7ba34 432 transport_state->cbs.sasl_mechanism = NULL;
Azure.IoT Build 10:75c5e0d8537d 433 }
Azure.IoT Build 7:07bc440836b3 434
Azure.IoT Build 10:75c5e0d8537d 435 if (transport_state->tls_io != NULL)
Azure.IoT Build 10:75c5e0d8537d 436 {
AzureIoTClient 20:8dec76e7ba34 437 /*before destroying, we shall save its options for later use*/
AzureIoTClient 20:8dec76e7ba34 438 transport_state->xioOptions = xio_retrieveoptions(transport_state->tls_io);
AzureIoTClient 20:8dec76e7ba34 439 if (transport_state->xioOptions == NULL)
AzureIoTClient 20:8dec76e7ba34 440 {
AzureIoTClient 20:8dec76e7ba34 441 LogError("unable to retrieve xio_retrieveoptions");
AzureIoTClient 20:8dec76e7ba34 442 }
Azure.IoT Build 10:75c5e0d8537d 443 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_034: [IoTHubTransportAMQP_Destroy shall destroy the AMQP TLS I/O transport.]
Azure.IoT Build 10:75c5e0d8537d 444 xio_destroy(transport_state->tls_io);
Azure.IoT Build 10:75c5e0d8537d 445 transport_state->tls_io = NULL;
Azure.IoT Build 10:75c5e0d8537d 446 }
Azure.IoT Build 7:07bc440836b3 447 }
Azure.IoT Build 7:07bc440836b3 448
Azure.IoT Build 7:07bc440836b3 449 static void on_amqp_management_state_changed(void* context, AMQP_MANAGEMENT_STATE new_amqp_management_state, AMQP_MANAGEMENT_STATE previous_amqp_management_state)
Azure.IoT Build 7:07bc440836b3 450 {
Azure.IoT Build 10:75c5e0d8537d 451 (void)previous_amqp_management_state;
Azure.IoT Build 10:75c5e0d8537d 452 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)context;
Azure.IoT Build 11:62d7b956e76e 453
Azure.IoT Build 10:75c5e0d8537d 454 if (transport_state != NULL)
Azure.IoT Build 7:07bc440836b3 455 {
Azure.IoT Build 7:07bc440836b3 456 transport_state->connection_state = new_amqp_management_state;
Azure.IoT Build 7:07bc440836b3 457 }
Azure.IoT Build 7:07bc440836b3 458 }
Azure.IoT Build 7:07bc440836b3 459
AzureIoTClient 13:a4af7c301e02 460 static void on_connection_io_error(void* context)
AzureIoTClient 13:a4af7c301e02 461 {
AzureIoTClient 16:a49121e2300b 462 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)context;
AzureIoTClient 13:a4af7c301e02 463
AzureIoTClient 16:a49121e2300b 464 if (transport_state != NULL)
AzureIoTClient 16:a49121e2300b 465 {
AzureIoTClient 16:a49121e2300b 466 transport_state->connection_state = AMQP_MANAGEMENT_STATE_ERROR;
AzureIoTClient 16:a49121e2300b 467 }
AzureIoTClient 13:a4af7c301e02 468 }
AzureIoTClient 13:a4af7c301e02 469
Azure.IoT Build 7:07bc440836b3 470 static int establishConnection(AMQP_TRANSPORT_INSTANCE* transport_state)
Azure.IoT Build 7:07bc440836b3 471 {
Azure.IoT Build 7:07bc440836b3 472 int result;
Azure.IoT Build 7:07bc440836b3 473
Azure.IoT Build 7:07bc440836b3 474 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_110: [IoTHubTransportAMQP_DoWork shall create the TLS IO using transport_state->io_transport_provider callback function]
Azure.IoT Build 7:07bc440836b3 475 if (transport_state->tls_io == NULL &&
Azure.IoT Build 11:62d7b956e76e 476 (transport_state->tls_io = transport_state->tls_io_transport_provider(STRING_c_str(transport_state->iotHubHostFqdn), transport_state->iotHubPort)) == NULL)
Azure.IoT Build 7:07bc440836b3 477 {
Azure.IoT Build 7:07bc440836b3 478 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_136: [If transport_state->io_transport_provider_callback fails, IoTHubTransportAMQP_DoWork shall fail and return immediately]
Azure.IoT Build 7:07bc440836b3 479 result = RESULT_FAILURE;
AzureIoTClient 13:a4af7c301e02 480 LogError("Failed to obtain a TLS I/O transport layer.");
Azure.IoT Build 7:07bc440836b3 481 }
Azure.IoT Build 7:07bc440836b3 482 else
Azure.IoT Build 7:07bc440836b3 483 {
AzureIoTClient 20:8dec76e7ba34 484 /*in the case when a tls_io_transport has been created, replay its options*/
AzureIoTClient 20:8dec76e7ba34 485 if (transport_state->xioOptions != NULL)
AzureIoTClient 4:57e049bce51e 486 {
AzureIoTClient 20:8dec76e7ba34 487 if (OptionHandler_FeedOptions(transport_state->xioOptions, transport_state->tls_io) != 0)
Azure.IoT Build 7:07bc440836b3 488 {
AzureIoTClient 20:8dec76e7ba34 489 LogError("unable to replay options to TLS"); /*pessimistically hope TLS will fail, be recreated and options re-given*/
Azure.IoT Build 7:07bc440836b3 490 }
Azure.IoT Build 7:07bc440836b3 491 else
Azure.IoT Build 7:07bc440836b3 492 {
AzureIoTClient 20:8dec76e7ba34 493 /*everything is fine, forget the saved options...*/
AzureIoTClient 20:8dec76e7ba34 494 OptionHandler_Destroy(transport_state->xioOptions);
AzureIoTClient 20:8dec76e7ba34 495 transport_state->xioOptions = NULL;
AzureIoTClient 4:57e049bce51e 496 }
AzureIoTClient 4:57e049bce51e 497 }
AzureIoTClient 20:8dec76e7ba34 498
AzureIoTClient 20:8dec76e7ba34 499 switch (transport_state->credential.credentialType)
AzureIoTClient 20:8dec76e7ba34 500 {
AzureIoTClient 20:8dec76e7ba34 501 case (DEVICE_KEY):
AzureIoTClient 20:8dec76e7ba34 502 case (DEVICE_SAS_TOKEN):
AzureIoTClient 20:8dec76e7ba34 503 {
AzureIoTClient 20:8dec76e7ba34 504 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_056: [IoTHubTransportAMQP_DoWork shall create the SASL mechanism using AMQP's saslmechanism_create() API]
AzureIoTClient 20:8dec76e7ba34 505 if ((transport_state->cbs.sasl_mechanism = saslmechanism_create(saslmssbcbs_get_interface(), NULL)) == NULL)
AzureIoTClient 20:8dec76e7ba34 506 {
AzureIoTClient 20:8dec76e7ba34 507 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_057: [If saslmechanism_create() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately]
AzureIoTClient 20:8dec76e7ba34 508 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 509 LogError("Failed to create a SASL mechanism.");
AzureIoTClient 20:8dec76e7ba34 510 }
AzureIoTClient 20:8dec76e7ba34 511 else
AzureIoTClient 20:8dec76e7ba34 512 {
AzureIoTClient 20:8dec76e7ba34 513 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_060: [IoTHubTransportAMQP_DoWork shall create the SASL I / O layer using the xio_create() C Shared Utility API]
AzureIoTClient 20:8dec76e7ba34 514 SASLCLIENTIO_CONFIG sasl_client_config;
AzureIoTClient 20:8dec76e7ba34 515 sasl_client_config.sasl_mechanism = transport_state->cbs.sasl_mechanism;
AzureIoTClient 20:8dec76e7ba34 516 sasl_client_config.underlying_io = transport_state->tls_io;
AzureIoTClient 20:8dec76e7ba34 517 if ((transport_state->cbs.sasl_io = xio_create(saslclientio_get_interface_description(), &sasl_client_config)) == NULL)
AzureIoTClient 20:8dec76e7ba34 518 {
AzureIoTClient 20:8dec76e7ba34 519 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_061: [If xio_create() fails creating the SASL I/O layer, IoTHubTransportAMQP_DoWork shall fail and return immediately]
AzureIoTClient 20:8dec76e7ba34 520 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 521 LogError("Failed to create a SASL I/O layer.");
AzureIoTClient 20:8dec76e7ba34 522 }
AzureIoTClient 20:8dec76e7ba34 523 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_062: [IoTHubTransportAMQP_DoWork shall create the connection with the IoT service using connection_create2() AMQP API, passing the SASL I/O layer, IoT Hub FQDN and container ID as parameters (pass NULL for callbacks)]
AzureIoTClient 20:8dec76e7ba34 524 else if ((transport_state->connection = connection_create2(transport_state->cbs.sasl_io, STRING_c_str(transport_state->iotHubHostFqdn), DEFAULT_CONTAINER_ID, NULL, NULL, NULL, NULL, on_connection_io_error, (void*)transport_state)) == NULL)
AzureIoTClient 20:8dec76e7ba34 525 {
AzureIoTClient 20:8dec76e7ba34 526 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_063: [If connection_create2() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately.]
AzureIoTClient 20:8dec76e7ba34 527 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 528 LogError("Failed to create the AMQP connection.");
AzureIoTClient 20:8dec76e7ba34 529 }
AzureIoTClient 20:8dec76e7ba34 530 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_137: [IoTHubTransportAMQP_DoWork shall create the AMQP session session_create() AMQP API, passing the connection instance as parameter]
AzureIoTClient 20:8dec76e7ba34 531 else if ((transport_state->session = session_create(transport_state->connection, NULL, NULL)) == NULL)
AzureIoTClient 20:8dec76e7ba34 532 {
AzureIoTClient 20:8dec76e7ba34 533 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_138 : [If session_create() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately]
AzureIoTClient 20:8dec76e7ba34 534 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 535 LogError("Failed to create the AMQP session.");
AzureIoTClient 20:8dec76e7ba34 536 }
AzureIoTClient 20:8dec76e7ba34 537 else
AzureIoTClient 20:8dec76e7ba34 538 {
AzureIoTClient 20:8dec76e7ba34 539 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_065: [IoTHubTransportAMQP_DoWork shall apply a default value of UINT_MAX for the parameter 'AMQP incoming window']
AzureIoTClient 20:8dec76e7ba34 540 if (session_set_incoming_window(transport_state->session, (uint32_t)DEFAULT_INCOMING_WINDOW_SIZE) != 0)
AzureIoTClient 20:8dec76e7ba34 541 {
AzureIoTClient 20:8dec76e7ba34 542 LogError("Failed to set the AMQP incoming window size.");
AzureIoTClient 20:8dec76e7ba34 543 }
AzureIoTClient 20:8dec76e7ba34 544
AzureIoTClient 20:8dec76e7ba34 545 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_115: [IoTHubTransportAMQP_DoWork shall apply a default value of 100 for the parameter 'AMQP outgoing window']
AzureIoTClient 20:8dec76e7ba34 546 if (session_set_outgoing_window(transport_state->session, DEFAULT_OUTGOING_WINDOW_SIZE) != 0)
AzureIoTClient 20:8dec76e7ba34 547 {
AzureIoTClient 20:8dec76e7ba34 548 LogError("Failed to set the AMQP outgoing window size.");
AzureIoTClient 20:8dec76e7ba34 549 }
AzureIoTClient 20:8dec76e7ba34 550
AzureIoTClient 20:8dec76e7ba34 551 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_066: [IoTHubTransportAMQP_DoWork shall establish the CBS connection using the cbs_create() AMQP API]
AzureIoTClient 20:8dec76e7ba34 552 if ((transport_state->cbs.cbs = cbs_create(transport_state->session, on_amqp_management_state_changed, NULL)) == NULL)
AzureIoTClient 20:8dec76e7ba34 553 {
AzureIoTClient 20:8dec76e7ba34 554 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_067: [If cbs_create() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately]
AzureIoTClient 20:8dec76e7ba34 555 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 556 LogError("Failed to create the CBS connection.");
AzureIoTClient 20:8dec76e7ba34 557 }
AzureIoTClient 20:8dec76e7ba34 558 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_139: [IoTHubTransportAMQP_DoWork shall open the CBS connection using the cbs_open() AMQP API]
AzureIoTClient 20:8dec76e7ba34 559 else if (cbs_open(transport_state->cbs.cbs) != 0)
AzureIoTClient 20:8dec76e7ba34 560 {
AzureIoTClient 20:8dec76e7ba34 561 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_140: [If cbs_open() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately]
AzureIoTClient 20:8dec76e7ba34 562 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 563 LogError("Failed to open the connection with CBS.");
AzureIoTClient 20:8dec76e7ba34 564 }
AzureIoTClient 22:8b70cf813f25 565 else if (getSecondsSinceEpoch(&transport_state->connection_establish_time) != RESULT_OK)
AzureIoTClient 22:8b70cf813f25 566 {
AzureIoTClient 22:8b70cf813f25 567 LogError("Failed setting the connection establish time.");
AzureIoTClient 22:8b70cf813f25 568 result = RESULT_FAILURE;
AzureIoTClient 22:8b70cf813f25 569 }
AzureIoTClient 20:8dec76e7ba34 570 else
AzureIoTClient 20:8dec76e7ba34 571 {
AzureIoTClient 20:8dec76e7ba34 572 transport_state->cbs.cbs_state = CBS_STATE_IDLE;
AzureIoTClient 20:8dec76e7ba34 573 connection_set_trace(transport_state->connection, transport_state->is_trace_on);
AzureIoTClient 21:32a1746384ba 574 (void)xio_setoption(transport_state->cbs.sasl_io, OPTION_LOG_TRACE, &transport_state->is_trace_on);
AzureIoTClient 20:8dec76e7ba34 575 result = RESULT_OK;
AzureIoTClient 20:8dec76e7ba34 576 }
AzureIoTClient 20:8dec76e7ba34 577 }
AzureIoTClient 20:8dec76e7ba34 578 }
AzureIoTClient 20:8dec76e7ba34 579 break;
AzureIoTClient 20:8dec76e7ba34 580 }
AzureIoTClient 20:8dec76e7ba34 581 case(X509):
AzureIoTClient 20:8dec76e7ba34 582 {
AzureIoTClient 20:8dec76e7ba34 583 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_006: [ IoTHubTransportAMQP_DoWork shall not establish a CBS connection. ]*/
AzureIoTClient 20:8dec76e7ba34 584 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_005: [ IoTHubTransportAMQP_DoWork shall create the connection with the IoT service using connection_create2() AMQP API, passing the TLS I/O layer, IoT Hub FQDN and container ID as parameters (pass NULL for callbacks) ]*/
AzureIoTClient 20:8dec76e7ba34 585 if ((transport_state->connection = connection_create2(transport_state->tls_io, STRING_c_str(transport_state->iotHubHostFqdn), DEFAULT_CONTAINER_ID, NULL, NULL, NULL, NULL, on_connection_io_error, (void*)transport_state)) == NULL)
AzureIoTClient 20:8dec76e7ba34 586 {
AzureIoTClient 20:8dec76e7ba34 587 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_063: [If connection_create2() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately.]
AzureIoTClient 20:8dec76e7ba34 588 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 589 LogError("Failed to create the AMQP connection.");
AzureIoTClient 20:8dec76e7ba34 590 }
AzureIoTClient 20:8dec76e7ba34 591 else
AzureIoTClient 20:8dec76e7ba34 592 {
AzureIoTClient 20:8dec76e7ba34 593 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_137: [IoTHubTransportAMQP_DoWork shall create the AMQP session session_create() AMQP API, passing the connection instance as parameter]
AzureIoTClient 20:8dec76e7ba34 594 if ((transport_state->session = session_create(transport_state->connection, NULL, NULL)) == NULL)
AzureIoTClient 20:8dec76e7ba34 595 {
AzureIoTClient 20:8dec76e7ba34 596 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_138 : [If session_create() fails, IoTHubTransportAMQP_DoWork shall fail and return immediately]
AzureIoTClient 20:8dec76e7ba34 597 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 598 LogError("Failed to create the AMQP session.");
AzureIoTClient 20:8dec76e7ba34 599 }
AzureIoTClient 20:8dec76e7ba34 600 else
AzureIoTClient 20:8dec76e7ba34 601 {
AzureIoTClient 20:8dec76e7ba34 602 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_065: [IoTHubTransportAMQP_DoWork shall apply a default value of UINT_MAX for the parameter 'AMQP incoming window']
AzureIoTClient 20:8dec76e7ba34 603 if (session_set_incoming_window(transport_state->session, (uint32_t)DEFAULT_INCOMING_WINDOW_SIZE) != 0)
AzureIoTClient 20:8dec76e7ba34 604 {
AzureIoTClient 20:8dec76e7ba34 605 LogError("Failed to set the AMQP incoming window size.");
AzureIoTClient 20:8dec76e7ba34 606 }
AzureIoTClient 20:8dec76e7ba34 607
AzureIoTClient 20:8dec76e7ba34 608 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_115: [IoTHubTransportAMQP_DoWork shall apply a default value of 100 for the parameter 'AMQP outgoing window']
AzureIoTClient 20:8dec76e7ba34 609 if (session_set_outgoing_window(transport_state->session, DEFAULT_OUTGOING_WINDOW_SIZE) != 0)
AzureIoTClient 20:8dec76e7ba34 610 {
AzureIoTClient 20:8dec76e7ba34 611 LogError("Failed to set the AMQP outgoing window size.");
AzureIoTClient 20:8dec76e7ba34 612 }
AzureIoTClient 20:8dec76e7ba34 613
AzureIoTClient 22:8b70cf813f25 614 if (getSecondsSinceEpoch(&transport_state->connection_establish_time) != RESULT_OK)
AzureIoTClient 22:8b70cf813f25 615 {
AzureIoTClient 22:8b70cf813f25 616 LogError("Failed setting the connection establish time.");
AzureIoTClient 22:8b70cf813f25 617 result = RESULT_FAILURE;
AzureIoTClient 22:8b70cf813f25 618 }
AzureIoTClient 22:8b70cf813f25 619 else
AzureIoTClient 22:8b70cf813f25 620 {
AzureIoTClient 20:8dec76e7ba34 621 connection_set_trace(transport_state->connection, transport_state->is_trace_on);
AzureIoTClient 21:32a1746384ba 622 (void)xio_setoption(transport_state->tls_io, OPTION_LOG_TRACE, &transport_state->is_trace_on);
AzureIoTClient 20:8dec76e7ba34 623 result = RESULT_OK;
AzureIoTClient 22:8b70cf813f25 624 }
AzureIoTClient 20:8dec76e7ba34 625 }
AzureIoTClient 20:8dec76e7ba34 626 }
AzureIoTClient 20:8dec76e7ba34 627 break;
AzureIoTClient 20:8dec76e7ba34 628 }
AzureIoTClient 20:8dec76e7ba34 629 default:
AzureIoTClient 20:8dec76e7ba34 630 {
AzureIoTClient 20:8dec76e7ba34 631 LogError("internal error: unexpected enum value for transport_state->credential.credentialType = %d", transport_state->credential.credentialType);
AzureIoTClient 20:8dec76e7ba34 632 result = RESULT_FAILURE;
AzureIoTClient 20:8dec76e7ba34 633 break;
AzureIoTClient 20:8dec76e7ba34 634 }
AzureIoTClient 20:8dec76e7ba34 635 }/*switch*/
AzureIoTClient 4:57e049bce51e 636 }
Azure.IoT Build 7:07bc440836b3 637
Azure.IoT Build 7:07bc440836b3 638 if (result == RESULT_FAILURE)
Azure.IoT Build 7:07bc440836b3 639 {
Azure.IoT Build 7:07bc440836b3 640 destroyConnection(transport_state);
Azure.IoT Build 7:07bc440836b3 641 }
Azure.IoT Build 7:07bc440836b3 642
Azure.IoT Build 7:07bc440836b3 643 return result;
AzureIoTClient 4:57e049bce51e 644 }
AzureIoTClient 4:57e049bce51e 645
AzureIoTClient 19:ea016664011a 646 static int handSASTokenToCbs(AMQP_TRANSPORT_INSTANCE* transport_state, STRING_HANDLE sasToken, size_t sas_token_create_time)
AzureIoTClient 19:ea016664011a 647 {
AzureIoTClient 19:ea016664011a 648 int result;
AzureIoTClient 20:8dec76e7ba34 649 if (cbs_put_token(transport_state->cbs.cbs, CBS_AUDIENCE, STRING_c_str(transport_state->devicesPath), STRING_c_str(sasToken), on_put_token_complete, transport_state) != RESULT_OK)
AzureIoTClient 19:ea016664011a 650 {
AzureIoTClient 19:ea016664011a 651 LogError("Failed applying new SAS token to CBS.");
AzureIoTClient 19:ea016664011a 652 result = __LINE__;
AzureIoTClient 19:ea016664011a 653 }
AzureIoTClient 19:ea016664011a 654 else
AzureIoTClient 19:ea016664011a 655 {
AzureIoTClient 20:8dec76e7ba34 656 transport_state->cbs.cbs_state = CBS_STATE_AUTH_IN_PROGRESS;
AzureIoTClient 20:8dec76e7ba34 657 transport_state->cbs.current_sas_token_create_time = sas_token_create_time;
AzureIoTClient 19:ea016664011a 658 result = RESULT_OK;
AzureIoTClient 19:ea016664011a 659 }
AzureIoTClient 19:ea016664011a 660 return result;
AzureIoTClient 19:ea016664011a 661 }
AzureIoTClient 19:ea016664011a 662
Azure.IoT Build 7:07bc440836b3 663 static int startAuthentication(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 664 {
Azure.IoT Build 10:75c5e0d8537d 665 int result;
AzureIoTClient 22:8b70cf813f25 666 size_t currentTimeInSeconds;
Azure.IoT Build 11:62d7b956e76e 667
AzureIoTClient 22:8b70cf813f25 668 if (getSecondsSinceEpoch(&currentTimeInSeconds) != RESULT_OK)
AzureIoTClient 22:8b70cf813f25 669 {
AzureIoTClient 22:8b70cf813f25 670 LogError("Failed getting current time to compute the SAS token creation time.");
AzureIoTClient 22:8b70cf813f25 671 result = __LINE__;
AzureIoTClient 22:8b70cf813f25 672 }
AzureIoTClient 22:8b70cf813f25 673 else
AzureIoTClient 22:8b70cf813f25 674 {
AzureIoTClient 22:8b70cf813f25 675 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_083: [SAS tokens expiration time shall be calculated using the number of seconds since Epoch UTC (Jan 1st 1970 00h00m00s000 GMT) to now (GMT), plus the 'sas_token_lifetime'.]
AzureIoTClient 22:8b70cf813f25 676 size_t new_expiry_time = currentTimeInSeconds + (transport_state->cbs.sas_token_lifetime / 1000);
Azure.IoT Build 7:07bc440836b3 677
AzureIoTClient 22:8b70cf813f25 678 STRING_HANDLE newSASToken;
AzureIoTClient 14:8e8e42008807 679
AzureIoTClient 22:8b70cf813f25 680 switch (transport_state->credential.credentialType)
AzureIoTClient 22:8b70cf813f25 681 {
AzureIoTClient 22:8b70cf813f25 682 default:
AzureIoTClient 22:8b70cf813f25 683 {
AzureIoTClient 22:8b70cf813f25 684 result = __LINE__;
AzureIoTClient 22:8b70cf813f25 685 LogError("internal error, unexpected enum value transport_state->credential.credentialType=%d", transport_state->credential.credentialType);
AzureIoTClient 22:8b70cf813f25 686 break;
AzureIoTClient 22:8b70cf813f25 687 }
AzureIoTClient 22:8b70cf813f25 688 case DEVICE_KEY:
AzureIoTClient 22:8b70cf813f25 689 {
AzureIoTClient 22:8b70cf813f25 690 newSASToken = SASToken_Create(transport_state->credential.credential.deviceKey, transport_state->devicesPath, transport_state->cbs.sasTokenKeyName, new_expiry_time);
AzureIoTClient 22:8b70cf813f25 691 if (newSASToken == NULL)
AzureIoTClient 22:8b70cf813f25 692 {
AzureIoTClient 22:8b70cf813f25 693 LogError("Could not generate a new SAS token for the CBS.");
AzureIoTClient 22:8b70cf813f25 694 result = RESULT_FAILURE;
AzureIoTClient 22:8b70cf813f25 695 }
AzureIoTClient 22:8b70cf813f25 696 else
AzureIoTClient 22:8b70cf813f25 697 {
AzureIoTClient 22:8b70cf813f25 698 if (handSASTokenToCbs(transport_state, newSASToken, currentTimeInSeconds) != 0)
AzureIoTClient 22:8b70cf813f25 699 {
AzureIoTClient 22:8b70cf813f25 700 LogError("unable to handSASTokenToCbs");
AzureIoTClient 22:8b70cf813f25 701 result = RESULT_FAILURE;
AzureIoTClient 22:8b70cf813f25 702 }
AzureIoTClient 22:8b70cf813f25 703 else
AzureIoTClient 22:8b70cf813f25 704 {
AzureIoTClient 22:8b70cf813f25 705 result = RESULT_OK;
AzureIoTClient 22:8b70cf813f25 706 }
AzureIoTClient 19:ea016664011a 707
AzureIoTClient 22:8b70cf813f25 708 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_145: [Each new SAS token created shall be deleted from memory immediately after sending it to CBS]
AzureIoTClient 22:8b70cf813f25 709 STRING_delete(newSASToken);
AzureIoTClient 22:8b70cf813f25 710 }
AzureIoTClient 22:8b70cf813f25 711 break;
AzureIoTClient 22:8b70cf813f25 712 }
AzureIoTClient 22:8b70cf813f25 713 case DEVICE_SAS_TOKEN:
AzureIoTClient 22:8b70cf813f25 714 {
AzureIoTClient 22:8b70cf813f25 715 newSASToken = STRING_clone(transport_state->credential.credential.deviceSasToken);
AzureIoTClient 22:8b70cf813f25 716 if (newSASToken == NULL)
AzureIoTClient 22:8b70cf813f25 717 {
AzureIoTClient 22:8b70cf813f25 718 LogError("Could not generate a new SAS token for the CBS.");
AzureIoTClient 22:8b70cf813f25 719 result = RESULT_FAILURE;
AzureIoTClient 22:8b70cf813f25 720 }
AzureIoTClient 22:8b70cf813f25 721 else
AzureIoTClient 22:8b70cf813f25 722 {
AzureIoTClient 22:8b70cf813f25 723 if (handSASTokenToCbs(transport_state, newSASToken, currentTimeInSeconds) != 0)
AzureIoTClient 22:8b70cf813f25 724 {
AzureIoTClient 22:8b70cf813f25 725 LogError("unable to handSASTokenToCbs");
AzureIoTClient 22:8b70cf813f25 726 result = RESULT_FAILURE;
AzureIoTClient 22:8b70cf813f25 727 }
AzureIoTClient 22:8b70cf813f25 728 else
AzureIoTClient 22:8b70cf813f25 729 {
AzureIoTClient 22:8b70cf813f25 730 result = RESULT_OK;
AzureIoTClient 22:8b70cf813f25 731 }
AzureIoTClient 19:ea016664011a 732
AzureIoTClient 22:8b70cf813f25 733 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_145: [Each new SAS token created shall be deleted from memory immediately after sending it to CBS]
AzureIoTClient 22:8b70cf813f25 734 STRING_delete(newSASToken);
AzureIoTClient 22:8b70cf813f25 735 }
AzureIoTClient 22:8b70cf813f25 736 break;
AzureIoTClient 22:8b70cf813f25 737 }
AzureIoTClient 22:8b70cf813f25 738 }
AzureIoTClient 22:8b70cf813f25 739 }
AzureIoTClient 4:57e049bce51e 740 return result;
AzureIoTClient 4:57e049bce51e 741 }
AzureIoTClient 4:57e049bce51e 742
Azure.IoT Build 7:07bc440836b3 743 static int verifyAuthenticationTimeout(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 744 {
AzureIoTClient 22:8b70cf813f25 745 int result;
AzureIoTClient 22:8b70cf813f25 746 size_t currentTimeInSeconds;
AzureIoTClient 22:8b70cf813f25 747 if (getSecondsSinceEpoch(&currentTimeInSeconds) != RESULT_OK)
AzureIoTClient 22:8b70cf813f25 748 {
AzureIoTClient 22:8b70cf813f25 749 LogError("Failed getting the current time to verify if the SAS token needs to be refreshed.");
AzureIoTClient 22:8b70cf813f25 750 result = RESULT_TIMEOUT; // Fail safe.
AzureIoTClient 22:8b70cf813f25 751 }
AzureIoTClient 22:8b70cf813f25 752 else
AzureIoTClient 22:8b70cf813f25 753 {
AzureIoTClient 22:8b70cf813f25 754 result = ((currentTimeInSeconds - transport_state->cbs.current_sas_token_create_time) * 1000 >= transport_state->cbs.cbs_request_timeout) ? RESULT_TIMEOUT : RESULT_OK;
AzureIoTClient 22:8b70cf813f25 755 }
AzureIoTClient 22:8b70cf813f25 756 return result;
Azure.IoT Build 7:07bc440836b3 757 }
AzureIoTClient 4:57e049bce51e 758
Azure.IoT Build 7:07bc440836b3 759 static void attachDeviceClientTypeToLink(LINK_HANDLE link)
Azure.IoT Build 7:07bc440836b3 760 {
Azure.IoT Build 10:75c5e0d8537d 761 fields attach_properties;
Azure.IoT Build 10:75c5e0d8537d 762 AMQP_VALUE deviceClientTypeKeyName;
Azure.IoT Build 10:75c5e0d8537d 763 AMQP_VALUE deviceClientTypeValue;
Azure.IoT Build 7:07bc440836b3 764 int result;
Azure.IoT Build 7:07bc440836b3 765
Azure.IoT Build 7:07bc440836b3 766 //
Azure.IoT Build 7:07bc440836b3 767 // Attempt to add the device client type string to the attach properties.
Azure.IoT Build 7:07bc440836b3 768 // If this doesn't happen, well, this isn't that important. We can operate
Azure.IoT Build 7:07bc440836b3 769 // without this property. It's worth noting that even though we are going
Azure.IoT Build 7:07bc440836b3 770 // on, the reasons any of these operations fail don't bode well for the
Azure.IoT Build 7:07bc440836b3 771 // actual upcoming attach.
Azure.IoT Build 7:07bc440836b3 772 //
Azure.IoT Build 7:07bc440836b3 773
Azure.IoT Build 7:07bc440836b3 774 // Codes_SRS_IOTHUBTRANSPORTAMQP_06_187: [If IotHubTransportAMQP_DoWork fails to create an attach properties map and assign that map to the link the function will STILL proceed with the attempt to create the message sender.]
Azure.IoT Build 7:07bc440836b3 775
Azure.IoT Build 7:07bc440836b3 776 if ((attach_properties = amqpvalue_create_map()) == NULL)
AzureIoTClient 4:57e049bce51e 777 {
AzureIoTClient 13:a4af7c301e02 778 LogError("Failed to create the map for device client type.");
AzureIoTClient 4:57e049bce51e 779 }
Azure.IoT Build 10:75c5e0d8537d 780 else
Azure.IoT Build 7:07bc440836b3 781 {
Azure.IoT Build 10:75c5e0d8537d 782 if ((deviceClientTypeKeyName = amqpvalue_create_symbol("com.microsoft:client-version")) == NULL)
Azure.IoT Build 10:75c5e0d8537d 783 {
AzureIoTClient 13:a4af7c301e02 784 LogError("Failed to create the key name for the device client type.");
Azure.IoT Build 10:75c5e0d8537d 785 }
Azure.IoT Build 10:75c5e0d8537d 786 else
Azure.IoT Build 10:75c5e0d8537d 787 {
Azure.IoT Build 10:75c5e0d8537d 788 if ((deviceClientTypeValue = amqpvalue_create_string(CLIENT_DEVICE_TYPE_PREFIX CLIENT_DEVICE_BACKSLASH IOTHUB_SDK_VERSION)) == NULL)
Azure.IoT Build 10:75c5e0d8537d 789 {
AzureIoTClient 13:a4af7c301e02 790 LogError("Failed to create the key value for the device client type.");
Azure.IoT Build 10:75c5e0d8537d 791 }
Azure.IoT Build 10:75c5e0d8537d 792 else
Azure.IoT Build 10:75c5e0d8537d 793 {
Azure.IoT Build 10:75c5e0d8537d 794 if ((result = amqpvalue_set_map_value(attach_properties, deviceClientTypeKeyName, deviceClientTypeValue)) != 0)
Azure.IoT Build 10:75c5e0d8537d 795 {
AzureIoTClient 13:a4af7c301e02 796 LogError("Failed to set the property map for the device client type. Error code is: %d", result);
Azure.IoT Build 10:75c5e0d8537d 797 }
Azure.IoT Build 10:75c5e0d8537d 798 else if ((result = link_set_attach_properties(link, attach_properties)) != 0)
Azure.IoT Build 10:75c5e0d8537d 799 {
AzureIoTClient 13:a4af7c301e02 800 LogError("Unable to attach the device client type to the link properties. Error code is: %d", result);
Azure.IoT Build 10:75c5e0d8537d 801 }
Azure.IoT Build 10:75c5e0d8537d 802
Azure.IoT Build 10:75c5e0d8537d 803 amqpvalue_destroy(deviceClientTypeValue);
Azure.IoT Build 10:75c5e0d8537d 804 }
Azure.IoT Build 10:75c5e0d8537d 805
Azure.IoT Build 10:75c5e0d8537d 806 amqpvalue_destroy(deviceClientTypeKeyName);
Azure.IoT Build 10:75c5e0d8537d 807 }
Azure.IoT Build 10:75c5e0d8537d 808
Azure.IoT Build 10:75c5e0d8537d 809 amqpvalue_destroy(attach_properties);
AzureIoTClient 4:57e049bce51e 810 }
Azure.IoT Build 7:07bc440836b3 811 }
Azure.IoT Build 7:07bc440836b3 812
Azure.IoT Build 10:75c5e0d8537d 813 static void destroyEventSender(AMQP_TRANSPORT_INSTANCE* transport_state)
Azure.IoT Build 7:07bc440836b3 814 {
Azure.IoT Build 7:07bc440836b3 815 if (transport_state->message_sender != NULL)
Azure.IoT Build 7:07bc440836b3 816 {
Azure.IoT Build 7:07bc440836b3 817 messagesender_destroy(transport_state->message_sender);
Azure.IoT Build 7:07bc440836b3 818 transport_state->message_sender = NULL;
Azure.IoT Build 7:07bc440836b3 819
Azure.IoT Build 7:07bc440836b3 820 link_destroy(transport_state->sender_link);
Azure.IoT Build 7:07bc440836b3 821 transport_state->sender_link = NULL;
AzureIoTClient 4:57e049bce51e 822 }
AzureIoTClient 4:57e049bce51e 823 }
AzureIoTClient 4:57e049bce51e 824
AzureIoTClient 13:a4af7c301e02 825 void on_event_sender_state_changed(void* context, MESSAGE_SENDER_STATE new_state, MESSAGE_SENDER_STATE previous_state)
AzureIoTClient 13:a4af7c301e02 826 {
AzureIoTClient 21:32a1746384ba 827 if (context != NULL)
AzureIoTClient 21:32a1746384ba 828 {
AzureIoTClient 21:32a1746384ba 829 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)context;
AzureIoTClient 20:8dec76e7ba34 830
AzureIoTClient 21:32a1746384ba 831 if (transport_state->is_trace_on)
AzureIoTClient 21:32a1746384ba 832 {
AzureIoTClient 21:32a1746384ba 833 LogInfo("Event sender state changed [%d->%d]", previous_state, new_state);
AzureIoTClient 21:32a1746384ba 834 }
AzureIoTClient 20:8dec76e7ba34 835
AzureIoTClient 21:32a1746384ba 836 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_192: [If a message sender instance changes its state to MESSAGE_SENDER_STATE_ERROR (first transition only) the connection retry logic shall be triggered]
AzureIoTClient 21:32a1746384ba 837 if (new_state != previous_state && new_state == MESSAGE_SENDER_STATE_ERROR)
AzureIoTClient 21:32a1746384ba 838 {
AzureIoTClient 21:32a1746384ba 839 transport_state->connection_state = AMQP_MANAGEMENT_STATE_ERROR;
AzureIoTClient 21:32a1746384ba 840 }
AzureIoTClient 21:32a1746384ba 841 }
AzureIoTClient 13:a4af7c301e02 842 }
AzureIoTClient 13:a4af7c301e02 843
Azure.IoT Build 7:07bc440836b3 844 static int createEventSender(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 845 {
Azure.IoT Build 7:07bc440836b3 846 int result = RESULT_FAILURE;
Azure.IoT Build 7:07bc440836b3 847
Azure.IoT Build 7:07bc440836b3 848 if (transport_state->message_sender == NULL)
AzureIoTClient 4:57e049bce51e 849 {
Azure.IoT Build 7:07bc440836b3 850 AMQP_VALUE source = NULL;
Azure.IoT Build 7:07bc440836b3 851 AMQP_VALUE target = NULL;
Azure.IoT Build 7:07bc440836b3 852
Azure.IoT Build 10:75c5e0d8537d 853 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_068: [IoTHubTransportAMQP_DoWork shall create the AMQP link for sending messages using 'source' as "ingress", target as the IoT hub FQDN, link name as "sender-link" and role as 'role_sender']
Azure.IoT Build 7:07bc440836b3 854 if ((source = messaging_create_source(MESSAGE_SENDER_SOURCE_ADDRESS)) == NULL)
AzureIoTClient 4:57e049bce51e 855 {
AzureIoTClient 13:a4af7c301e02 856 LogError("Failed creating AMQP messaging source attribute.");
AzureIoTClient 4:57e049bce51e 857 }
Azure.IoT Build 7:07bc440836b3 858 else if ((target = messaging_create_target(STRING_c_str(transport_state->targetAddress))) == NULL)
AzureIoTClient 4:57e049bce51e 859 {
AzureIoTClient 13:a4af7c301e02 860 LogError("Failed creating AMQP messaging target attribute.");
Azure.IoT Build 7:07bc440836b3 861 }
Azure.IoT Build 7:07bc440836b3 862 else if ((transport_state->sender_link = link_create(transport_state->session, MESSAGE_SENDER_LINK_NAME, role_sender, source, target)) == NULL)
Azure.IoT Build 7:07bc440836b3 863 {
Azure.IoT Build 7:07bc440836b3 864 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_069: [If IoTHubTransportAMQP_DoWork fails to create the AMQP link for sending messages, the function shall fail and return immediately, flagging the connection to be re-stablished]
AzureIoTClient 13:a4af7c301e02 865 LogError("Failed creating AMQP link for message sender.");
AzureIoTClient 4:57e049bce51e 866 }
AzureIoTClient 4:57e049bce51e 867 else
AzureIoTClient 4:57e049bce51e 868 {
Azure.IoT Build 10:75c5e0d8537d 869 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_119: [IoTHubTransportAMQP_DoWork shall apply a default value of 65536 for the parameter 'Link MAX message size']
Azure.IoT Build 7:07bc440836b3 870 if (link_set_max_message_size(transport_state->sender_link, MESSAGE_SENDER_MAX_LINK_SIZE) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 871 {
AzureIoTClient 13:a4af7c301e02 872 LogError("Failed setting AMQP link max message size.");
Azure.IoT Build 7:07bc440836b3 873 }
Azure.IoT Build 7:07bc440836b3 874
Azure.IoT Build 7:07bc440836b3 875 attachDeviceClientTypeToLink(transport_state->sender_link);
Azure.IoT Build 7:07bc440836b3 876
Azure.IoT Build 7:07bc440836b3 877 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_070: [IoTHubTransportAMQP_DoWork shall create the AMQP message sender using messagesender_create() AMQP API]
AzureIoTClient 21:32a1746384ba 878 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_191: [IoTHubTransportAMQP_DoWork shall create each AMQP message sender tracking its state changes with a callback function]
Azure.IoT Build 18:239d162e3607 879 if ((transport_state->message_sender = messagesender_create(transport_state->sender_link, on_event_sender_state_changed, (void*)transport_state)) == NULL)
Azure.IoT Build 7:07bc440836b3 880 {
Azure.IoT Build 7:07bc440836b3 881 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_071: [IoTHubTransportAMQP_DoWork shall fail and return immediately if the AMQP message sender instance fails to be created, flagging the connection to be re-established]
AzureIoTClient 13:a4af7c301e02 882 LogError("Could not allocate AMQP message sender");
Azure.IoT Build 7:07bc440836b3 883 }
Azure.IoT Build 7:07bc440836b3 884 else
Azure.IoT Build 7:07bc440836b3 885 {
Azure.IoT Build 7:07bc440836b3 886 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_072: [IoTHubTransportAMQP_DoWork shall open the AMQP message sender using messagesender_open() AMQP API]
Azure.IoT Build 7:07bc440836b3 887 if (messagesender_open(transport_state->message_sender) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 888 {
Azure.IoT Build 7:07bc440836b3 889 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_073: [IoTHubTransportAMQP_DoWork shall fail and return immediately if the AMQP message sender instance fails to be opened, flagging the connection to be re-established]
AzureIoTClient 13:a4af7c301e02 890 LogError("Failed opening the AMQP message sender.");
Azure.IoT Build 7:07bc440836b3 891 }
Azure.IoT Build 7:07bc440836b3 892 else
Azure.IoT Build 7:07bc440836b3 893 {
Azure.IoT Build 7:07bc440836b3 894 result = RESULT_OK;
Azure.IoT Build 7:07bc440836b3 895 }
Azure.IoT Build 7:07bc440836b3 896 }
AzureIoTClient 4:57e049bce51e 897 }
Azure.IoT Build 7:07bc440836b3 898
Azure.IoT Build 7:07bc440836b3 899 if (source != NULL)
Azure.IoT Build 7:07bc440836b3 900 amqpvalue_destroy(source);
Azure.IoT Build 7:07bc440836b3 901 if (target != NULL)
Azure.IoT Build 7:07bc440836b3 902 amqpvalue_destroy(target);
AzureIoTClient 4:57e049bce51e 903 }
Azure.IoT Build 11:62d7b956e76e 904
Azure.IoT Build 7:07bc440836b3 905 return result;
AzureIoTClient 4:57e049bce51e 906 }
Azure.IoT Build 7:07bc440836b3 907
Azure.IoT Build 7:07bc440836b3 908 static int destroyMessageReceiver(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 909 {
Azure.IoT Build 7:07bc440836b3 910 int result = RESULT_FAILURE;
Azure.IoT Build 7:07bc440836b3 911
Azure.IoT Build 7:07bc440836b3 912 if (transport_state->message_receiver != NULL)
AzureIoTClient 4:57e049bce51e 913 {
Azure.IoT Build 7:07bc440836b3 914 if (messagereceiver_close(transport_state->message_receiver) != RESULT_OK)
AzureIoTClient 4:57e049bce51e 915 {
AzureIoTClient 13:a4af7c301e02 916 LogError("Failed closing the AMQP message receiver.");
Azure.IoT Build 7:07bc440836b3 917 }
Azure.IoT Build 7:07bc440836b3 918
Azure.IoT Build 7:07bc440836b3 919 messagereceiver_destroy(transport_state->message_receiver);
Azure.IoT Build 7:07bc440836b3 920
Azure.IoT Build 7:07bc440836b3 921 transport_state->message_receiver = NULL;
Azure.IoT Build 7:07bc440836b3 922
Azure.IoT Build 7:07bc440836b3 923 link_destroy(transport_state->receiver_link);
Azure.IoT Build 7:07bc440836b3 924
Azure.IoT Build 7:07bc440836b3 925 transport_state->receiver_link = NULL;
Azure.IoT Build 7:07bc440836b3 926
Azure.IoT Build 7:07bc440836b3 927 result = RESULT_OK;
Azure.IoT Build 7:07bc440836b3 928 }
Azure.IoT Build 7:07bc440836b3 929
Azure.IoT Build 7:07bc440836b3 930 return result;
Azure.IoT Build 7:07bc440836b3 931 }
Azure.IoT Build 7:07bc440836b3 932
AzureIoTClient 20:8dec76e7ba34 933 void on_message_receiver_state_changed(const void* context, MESSAGE_RECEIVER_STATE new_state, MESSAGE_RECEIVER_STATE previous_state)
AzureIoTClient 20:8dec76e7ba34 934 {
AzureIoTClient 21:32a1746384ba 935 if (context != NULL)
AzureIoTClient 21:32a1746384ba 936 {
AzureIoTClient 21:32a1746384ba 937 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)context;
AzureIoTClient 20:8dec76e7ba34 938
AzureIoTClient 21:32a1746384ba 939 if (transport_state->is_trace_on)
AzureIoTClient 21:32a1746384ba 940 {
AzureIoTClient 21:32a1746384ba 941 LogInfo("Message receiver state changed [%d->%d]", previous_state, new_state);
AzureIoTClient 21:32a1746384ba 942 }
AzureIoTClient 20:8dec76e7ba34 943
AzureIoTClient 21:32a1746384ba 944 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_190: [If a message_receiver instance changes its state to MESSAGE_RECEIVER_STATE_ERROR (first transition only) the connection retry logic shall be triggered]
AzureIoTClient 21:32a1746384ba 945 if (new_state != previous_state && new_state == MESSAGE_RECEIVER_STATE_ERROR)
AzureIoTClient 21:32a1746384ba 946 {
AzureIoTClient 21:32a1746384ba 947 transport_state->connection_state = AMQP_MANAGEMENT_STATE_ERROR;
AzureIoTClient 21:32a1746384ba 948 }
AzureIoTClient 21:32a1746384ba 949 }
AzureIoTClient 20:8dec76e7ba34 950 }
AzureIoTClient 20:8dec76e7ba34 951
Azure.IoT Build 7:07bc440836b3 952 static int createMessageReceiver(AMQP_TRANSPORT_INSTANCE* transport_state, IOTHUB_CLIENT_LL_HANDLE iothub_client_handle)
Azure.IoT Build 7:07bc440836b3 953 {
Azure.IoT Build 7:07bc440836b3 954 int result = RESULT_FAILURE;
Azure.IoT Build 7:07bc440836b3 955
AzureIoTClient 14:8e8e42008807 956 if (transport_state->message_receiver == NULL)
Azure.IoT Build 7:07bc440836b3 957 {
Azure.IoT Build 7:07bc440836b3 958 AMQP_VALUE source = NULL;
Azure.IoT Build 7:07bc440836b3 959 AMQP_VALUE target = NULL;
Azure.IoT Build 7:07bc440836b3 960
Azure.IoT Build 10:75c5e0d8537d 961 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_074: [IoTHubTransportAMQP_DoWork shall create the AMQP link for receiving messages using 'source' as messageReceiveAddress, target as the "ingress-rx", link name as "receiver-link" and role as 'role_receiver']
Azure.IoT Build 7:07bc440836b3 962 if ((source = messaging_create_source(STRING_c_str(transport_state->messageReceiveAddress))) == NULL)
Azure.IoT Build 7:07bc440836b3 963 {
AzureIoTClient 13:a4af7c301e02 964 LogError("Failed creating AMQP message receiver source attribute.");
Azure.IoT Build 7:07bc440836b3 965 }
Azure.IoT Build 7:07bc440836b3 966 else if ((target = messaging_create_target(MESSAGE_RECEIVER_TARGET_ADDRESS)) == NULL)
Azure.IoT Build 7:07bc440836b3 967 {
AzureIoTClient 13:a4af7c301e02 968 LogError("Failed creating AMQP message receiver target attribute.");
Azure.IoT Build 7:07bc440836b3 969 }
Azure.IoT Build 7:07bc440836b3 970 else if ((transport_state->receiver_link = link_create(transport_state->session, MESSAGE_RECEIVER_LINK_NAME, role_receiver, source, target)) == NULL)
Azure.IoT Build 7:07bc440836b3 971 {
Azure.IoT Build 7:07bc440836b3 972 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_075: [If IoTHubTransportAMQP_DoWork fails to create the AMQP link for receiving messages, the function shall fail and return immediately, flagging the connection to be re-stablished]
AzureIoTClient 13:a4af7c301e02 973 LogError("Failed creating AMQP link for message receiver.");
Azure.IoT Build 7:07bc440836b3 974 }
Azure.IoT Build 7:07bc440836b3 975 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_076: [IoTHubTransportAMQP_DoWork shall set the receiver link settle mode as receiver_settle_mode_first]
Azure.IoT Build 7:07bc440836b3 976 else if (link_set_rcv_settle_mode(transport_state->receiver_link, receiver_settle_mode_first) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 977 {
Azure.IoT Build 7:07bc440836b3 978 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_141: [If IoTHubTransportAMQP_DoWork fails to set the settle mode on the AMQP link for receiving messages, the function shall fail and return immediately, flagging the connection to be re-stablished]
AzureIoTClient 13:a4af7c301e02 979 LogError("Failed setting AMQP link settle mode for message receiver.");
AzureIoTClient 4:57e049bce51e 980 }
AzureIoTClient 4:57e049bce51e 981 else
AzureIoTClient 4:57e049bce51e 982 {
Azure.IoT Build 10:75c5e0d8537d 983 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_119: [IoTHubTransportAMQP_DoWork shall apply a default value of 65536 for the parameter 'Link MAX message size']
Azure.IoT Build 7:07bc440836b3 984 if (link_set_max_message_size(transport_state->receiver_link, MESSAGE_RECEIVER_MAX_LINK_SIZE) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 985 {
AzureIoTClient 13:a4af7c301e02 986 LogError("Failed setting AMQP link max message size for message receiver.");
Azure.IoT Build 7:07bc440836b3 987 }
Azure.IoT Build 7:07bc440836b3 988
Azure.IoT Build 7:07bc440836b3 989 attachDeviceClientTypeToLink(transport_state->receiver_link);
AzureIoTClient 4:57e049bce51e 990
Azure.IoT Build 7:07bc440836b3 991 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_077: [IoTHubTransportAMQP_DoWork shall create the AMQP message receiver using messagereceiver_create() AMQP API]
AzureIoTClient 21:32a1746384ba 992 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_189: [IoTHubTransportAMQP_DoWork shall create each AMQP message_receiver tracking its state changes with a callback function]
AzureIoTClient 20:8dec76e7ba34 993 if ((transport_state->message_receiver = messagereceiver_create(transport_state->receiver_link, on_message_receiver_state_changed, (void*)transport_state)) == NULL)
Azure.IoT Build 7:07bc440836b3 994 {
Azure.IoT Build 7:07bc440836b3 995 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_078: [IoTHubTransportAMQP_DoWork shall fail and return immediately if the AMQP message receiver instance fails to be created, flagging the connection to be re-established]
AzureIoTClient 13:a4af7c301e02 996 LogError("Could not allocate AMQP message receiver.");
Azure.IoT Build 7:07bc440836b3 997 }
Azure.IoT Build 7:07bc440836b3 998 else
AzureIoTClient 4:57e049bce51e 999 {
Azure.IoT Build 7:07bc440836b3 1000 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_079: [IoTHubTransportAMQP_DoWork shall open the AMQP message receiver using messagereceiver_open() AMQP API, passing a callback function for handling C2D incoming messages]
Azure.IoT Build 10:75c5e0d8537d 1001 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_123: [IoTHubTransportAMQP_DoWork shall create each AMQP message_receiver passing the 'on_message_received' as the callback function]
Azure.IoT Build 7:07bc440836b3 1002 if (messagereceiver_open(transport_state->message_receiver, on_message_received, (const void*)iothub_client_handle) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 1003 {
Azure.IoT Build 7:07bc440836b3 1004 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_080: [IoTHubTransportAMQP_DoWork shall fail and return immediately if the AMQP message receiver instance fails to be opened, flagging the connection to be re-established]
AzureIoTClient 13:a4af7c301e02 1005 LogError("Failed opening the AMQP message receiver.");
Azure.IoT Build 7:07bc440836b3 1006 }
Azure.IoT Build 7:07bc440836b3 1007 else
Azure.IoT Build 7:07bc440836b3 1008 {
Azure.IoT Build 7:07bc440836b3 1009 result = RESULT_OK;
Azure.IoT Build 7:07bc440836b3 1010 }
AzureIoTClient 4:57e049bce51e 1011 }
AzureIoTClient 4:57e049bce51e 1012 }
Azure.IoT Build 7:07bc440836b3 1013
Azure.IoT Build 7:07bc440836b3 1014 if (source != NULL)
Azure.IoT Build 7:07bc440836b3 1015 amqpvalue_destroy(source);
Azure.IoT Build 7:07bc440836b3 1016 if (target != NULL)
Azure.IoT Build 7:07bc440836b3 1017 amqpvalue_destroy(target);
AzureIoTClient 4:57e049bce51e 1018 }
Azure.IoT Build 7:07bc440836b3 1019
Azure.IoT Build 7:07bc440836b3 1020 return result;
AzureIoTClient 4:57e049bce51e 1021 }
AzureIoTClient 4:57e049bce51e 1022
Azure.IoT Build 7:07bc440836b3 1023 static int sendPendingEvents(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 4:57e049bce51e 1024 {
Azure.IoT Build 7:07bc440836b3 1025 int result = RESULT_OK;
Azure.IoT Build 10:75c5e0d8537d 1026 IOTHUB_MESSAGE_LIST* message;
Azure.IoT Build 7:07bc440836b3 1027
Azure.IoT Build 7:07bc440836b3 1028 while ((message = getNextEventToSend(transport_state)) != NULL)
AzureIoTClient 4:57e049bce51e 1029 {
Azure.IoT Build 7:07bc440836b3 1030 result = RESULT_FAILURE;
Azure.IoT Build 11:62d7b956e76e 1031
Azure.IoT Build 12:841a4c36bd36 1032 MESSAGE_HANDLE amqp_message = NULL;
Azure.IoT Build 7:07bc440836b3 1033 bool is_message_error = false;
Azure.IoT Build 7:07bc440836b3 1034
Azure.IoT Build 10:75c5e0d8537d 1035 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_086: [IoTHubTransportAMQP_DoWork shall move queued events to an "in-progress" list right before processing them for sending]
AzureIoTClient 16:a49121e2300b 1036 trackEventInProgress(message, transport_state);
Azure.IoT Build 12:841a4c36bd36 1037
AzureIoTClient 23:2c6779675a01 1038 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_193: [IoTHubTransportAMQP_DoWork shall get a MESSAGE_HANDLE instance out of the event's IOTHUB_MESSAGE_HANDLE instance by using message_create_from_iothub_message().]
AzureIoTClient 23:2c6779675a01 1039 if ((result = message_create_from_iothub_message(message->messageHandle, &amqp_message)) != RESULT_OK)
AzureIoTClient 23:2c6779675a01 1040 {
AzureIoTClient 23:2c6779675a01 1041 LogError("Failed creating AMQP message (error=%d).", result);
AzureIoTClient 23:2c6779675a01 1042 result = __LINE__;
AzureIoTClient 23:2c6779675a01 1043 is_message_error = true;
AzureIoTClient 23:2c6779675a01 1044 }
AzureIoTClient 23:2c6779675a01 1045 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_097: [IoTHubTransportAMQP_DoWork shall pass the MESSAGE_HANDLE intance to uAMQP for sending (along with on_message_send_complete callback) using messagesender_send()]
AzureIoTClient 23:2c6779675a01 1046 else if (messagesender_send(transport_state->message_sender, amqp_message, on_message_send_complete, message) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 1047 {
AzureIoTClient 23:2c6779675a01 1048 LogError("Failed sending the AMQP message.");
AzureIoTClient 23:2c6779675a01 1049 result = __LINE__;
AzureIoTClient 4:57e049bce51e 1050 }
AzureIoTClient 4:57e049bce51e 1051 else
AzureIoTClient 4:57e049bce51e 1052 {
AzureIoTClient 23:2c6779675a01 1053 result = RESULT_OK;
Azure.IoT Build 7:07bc440836b3 1054 }
Azure.IoT Build 7:07bc440836b3 1055
AzureIoTClient 23:2c6779675a01 1056 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_194: [IoTHubTransportAMQP_DoWork shall destroy the MESSAGE_HANDLE instance after messagesender_send() is invoked.]
Azure.IoT Build 7:07bc440836b3 1057 if (amqp_message != NULL)
Azure.IoT Build 7:07bc440836b3 1058 {
Azure.IoT Build 7:07bc440836b3 1059 // It can be destroyed because AMQP keeps a clone of the message.
Azure.IoT Build 7:07bc440836b3 1060 message_destroy(amqp_message);
Azure.IoT Build 7:07bc440836b3 1061 }
Azure.IoT Build 7:07bc440836b3 1062
Azure.IoT Build 7:07bc440836b3 1063 if (result != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 1064 {
Azure.IoT Build 12:841a4c36bd36 1065 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_088: [If IoTHubMessage_GetByteArray() fails, IoTHubTransportAMQP_DoWork shall remove the event from the in-progress list and invoke the upper layer callback reporting the error]
Azure.IoT Build 12:841a4c36bd36 1066 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_091: [If IoTHubMessage_GetString() fails, IoTHubTransportAMQP_DoWork shall remove the event from the in-progress list and invoke the upper layer callback reporting the error]
Azure.IoT Build 12:841a4c36bd36 1067 if (is_message_error)
AzureIoTClient 5:8d58d20699dd 1068 {
Azure.IoT Build 12:841a4c36bd36 1069 on_message_send_complete(message, MESSAGE_SEND_ERROR);
AzureIoTClient 5:8d58d20699dd 1070 }
AzureIoTClient 4:57e049bce51e 1071 else
AzureIoTClient 4:57e049bce51e 1072 {
AzureIoTClient 23:2c6779675a01 1073 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_111: [If message_create_from_iothub_message() fails, IoTHubTransportAMQP_DoWork notify the failure, roll back the event to waitToSend list and return]
Azure.IoT Build 12:841a4c36bd36 1074 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_112: [If message_add_body_amqp_data() fails, IoTHubTransportAMQP_DoWork notify the failure, roll back the event to waitToSent list and return]
AzureIoTClient 23:2c6779675a01 1075 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_113: [If messagesender_send() fails, IoTHubTransportAMQP_DoWork notify the failure, roll back the event to waitToSend list and return]
Azure.IoT Build 12:841a4c36bd36 1076 rollEventBackToWaitList(message, transport_state);
Azure.IoT Build 12:841a4c36bd36 1077 break;
AzureIoTClient 4:57e049bce51e 1078 }
AzureIoTClient 4:57e049bce51e 1079 }
AzureIoTClient 4:57e049bce51e 1080 }
Azure.IoT Build 7:07bc440836b3 1081
Azure.IoT Build 7:07bc440836b3 1082 return result;
Azure.IoT Build 7:07bc440836b3 1083 }
Azure.IoT Build 7:07bc440836b3 1084
Azure.IoT Build 7:07bc440836b3 1085 static bool isSasTokenRefreshRequired(AMQP_TRANSPORT_INSTANCE* transport_state)
Azure.IoT Build 7:07bc440836b3 1086 {
AzureIoTClient 22:8b70cf813f25 1087 bool result;
AzureIoTClient 22:8b70cf813f25 1088 size_t currentTimeInSeconds;
AzureIoTClient 19:ea016664011a 1089 if (transport_state->credential.credentialType == DEVICE_SAS_TOKEN)
AzureIoTClient 16:a49121e2300b 1090 {
AzureIoTClient 22:8b70cf813f25 1091 result = false;
AzureIoTClient 16:a49121e2300b 1092 }
AzureIoTClient 22:8b70cf813f25 1093 else if (getSecondsSinceEpoch(&currentTimeInSeconds) != RESULT_OK)
AzureIoTClient 22:8b70cf813f25 1094 {
AzureIoTClient 22:8b70cf813f25 1095 LogError("Failed getting the current time to verify if the SAS token needs to be refreshed.");
AzureIoTClient 22:8b70cf813f25 1096 result = true; // Fail safe.
AzureIoTClient 22:8b70cf813f25 1097 }
AzureIoTClient 16:a49121e2300b 1098 else
AzureIoTClient 16:a49121e2300b 1099 {
AzureIoTClient 22:8b70cf813f25 1100 result = ((currentTimeInSeconds - transport_state->cbs.current_sas_token_create_time) >= (transport_state->cbs.sas_token_refresh_time / 1000)) ? true : false;
AzureIoTClient 20:8dec76e7ba34 1101 }
AzureIoTClient 22:8b70cf813f25 1102
AzureIoTClient 22:8b70cf813f25 1103 return result;
AzureIoTClient 14:8e8e42008807 1104 }
Azure.IoT Build 7:07bc440836b3 1105
Azure.IoT Build 7:07bc440836b3 1106 static void prepareForConnectionRetry(AMQP_TRANSPORT_INSTANCE* transport_state)
Azure.IoT Build 7:07bc440836b3 1107 {
AzureIoTClient 16:a49121e2300b 1108 destroyMessageReceiver(transport_state);
AzureIoTClient 16:a49121e2300b 1109 destroyEventSender(transport_state);
Azure.IoT Build 7:07bc440836b3 1110 destroyConnection(transport_state);
AzureIoTClient 16:a49121e2300b 1111 transport_state->connection_state = AMQP_MANAGEMENT_STATE_IDLE;
Azure.IoT Build 7:07bc440836b3 1112 rollEventsBackToWaitList(transport_state);
AzureIoTClient 4:57e049bce51e 1113 }
AzureIoTClient 4:57e049bce51e 1114
Azure.IoT Build 7:07bc440836b3 1115
AzureIoTClient 19:ea016664011a 1116 static void credential_destroy(AMQP_TRANSPORT_INSTANCE* transport_state)
AzureIoTClient 19:ea016664011a 1117 {
AzureIoTClient 19:ea016664011a 1118 switch (transport_state->credential.credentialType)
AzureIoTClient 19:ea016664011a 1119 {
AzureIoTClient 20:8dec76e7ba34 1120 default:
AzureIoTClient 20:8dec76e7ba34 1121 {
AzureIoTClient 20:8dec76e7ba34 1122 LogError("internal error: unexpected enum value transport_state->credential.credentialType=%d", transport_state->credential.credentialType);
AzureIoTClient 20:8dec76e7ba34 1123 break;
AzureIoTClient 20:8dec76e7ba34 1124 }
AzureIoTClient 20:8dec76e7ba34 1125 case (CREDENTIAL_NOT_BUILD):
AzureIoTClient 20:8dec76e7ba34 1126 {
AzureIoTClient 20:8dec76e7ba34 1127 /*nothing to do*/
AzureIoTClient 20:8dec76e7ba34 1128 break;
AzureIoTClient 20:8dec76e7ba34 1129 }
AzureIoTClient 20:8dec76e7ba34 1130 case(X509):
AzureIoTClient 20:8dec76e7ba34 1131 {
AzureIoTClient 20:8dec76e7ba34 1132 /*nothing to do here, x509certificate and x509privatekey are both NULL*/
AzureIoTClient 20:8dec76e7ba34 1133 break;
AzureIoTClient 20:8dec76e7ba34 1134 }
AzureIoTClient 20:8dec76e7ba34 1135 case(DEVICE_KEY):
AzureIoTClient 20:8dec76e7ba34 1136 {
AzureIoTClient 20:8dec76e7ba34 1137 STRING_delete(transport_state->credential.credential.deviceKey);
AzureIoTClient 20:8dec76e7ba34 1138 break;
AzureIoTClient 20:8dec76e7ba34 1139 }
AzureIoTClient 20:8dec76e7ba34 1140 case(DEVICE_SAS_TOKEN):
AzureIoTClient 20:8dec76e7ba34 1141 {
AzureIoTClient 20:8dec76e7ba34 1142 STRING_delete(transport_state->credential.credential.deviceSasToken);
AzureIoTClient 20:8dec76e7ba34 1143 break;
AzureIoTClient 20:8dec76e7ba34 1144 }
AzureIoTClient 19:ea016664011a 1145 }
AzureIoTClient 19:ea016664011a 1146 }
AzureIoTClient 19:ea016664011a 1147
Azure.IoT Build 7:07bc440836b3 1148 // API functions
Azure.IoT Build 7:07bc440836b3 1149
Azure.IoT Build 11:62d7b956e76e 1150 static TRANSPORT_LL_HANDLE IoTHubTransportAMQP_Create(const IOTHUBTRANSPORT_CONFIG* config)
AzureIoTClient 4:57e049bce51e 1151 {
Azure.IoT Build 7:07bc440836b3 1152 AMQP_TRANSPORT_INSTANCE* transport_state = NULL;
Azure.IoT Build 10:75c5e0d8537d 1153 size_t deviceIdLength;
AzureIoTClient 4:57e049bce51e 1154
Azure.IoT Build 7:07bc440836b3 1155 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_005: [If parameter config (or its fields) is NULL then IoTHubTransportAMQP_Create shall fail and return NULL.]
Azure.IoT Build 7:07bc440836b3 1156 if (config == NULL || config->upperConfig == NULL || config->waitingToSend == NULL)
Azure.IoT Build 7:07bc440836b3 1157 {
AzureIoTClient 13:a4af7c301e02 1158 LogError("IoTHub AMQP client transport null configuration parameter.");
Azure.IoT Build 7:07bc440836b3 1159 }
Azure.IoT Build 7:07bc440836b3 1160 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_006: [IoTHubTransportAMQP_Create shall fail and return NULL if any fields of the config structure are NULL.]
AzureIoTClient 14:8e8e42008807 1161 // Codes_SRS_IOTHUBTRANSPORTAMQP_03_001: [IoTHubTransportAMQP_Create shall fail and return NULL if both deviceKey & deviceSasToken fields are NOT NULL.]
Azure.IoT Build 7:07bc440836b3 1162 else if (config->upperConfig->protocol == NULL)
Azure.IoT Build 7:07bc440836b3 1163 {
AzureIoTClient 13:a4af7c301e02 1164 LogError("Invalid configuration (NULL protocol detected)");
Azure.IoT Build 7:07bc440836b3 1165 }
Azure.IoT Build 7:07bc440836b3 1166 else if (config->upperConfig->deviceId == NULL)
Azure.IoT Build 7:07bc440836b3 1167 {
AzureIoTClient 13:a4af7c301e02 1168 LogError("Invalid configuration (NULL deviceId detected)");
Azure.IoT Build 7:07bc440836b3 1169 }
AzureIoTClient 14:8e8e42008807 1170 else if (config->upperConfig->deviceKey != NULL && config->upperConfig->deviceSasToken != NULL)
AzureIoTClient 14:8e8e42008807 1171 {
AzureIoTClient 14:8e8e42008807 1172 LogError("Invalid configuration (Both deviceKey and deviceSasToken are defined)");
Azure.IoT Build 7:07bc440836b3 1173 }
Azure.IoT Build 7:07bc440836b3 1174 else if (config->upperConfig->iotHubName == NULL)
Azure.IoT Build 7:07bc440836b3 1175 {
AzureIoTClient 13:a4af7c301e02 1176 LogError("Invalid configuration (NULL iotHubName detected)");
AzureIoTClient 4:57e049bce51e 1177 }
Azure.IoT Build 7:07bc440836b3 1178 else if (config->upperConfig->iotHubSuffix == NULL)
Azure.IoT Build 7:07bc440836b3 1179 {
AzureIoTClient 13:a4af7c301e02 1180 LogError("Invalid configuration (NULL iotHubSuffix detected)");
Azure.IoT Build 7:07bc440836b3 1181 }
Azure.IoT Build 7:07bc440836b3 1182 else if (!config->waitingToSend)
AzureIoTClient 4:57e049bce51e 1183 {
AzureIoTClient 13:a4af7c301e02 1184 LogError("Invalid configuration (NULL waitingToSend list detected)");
Azure.IoT Build 7:07bc440836b3 1185 }
Azure.IoT Build 7:07bc440836b3 1186 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_008: [IoTHubTransportAMQP_Create shall fail and return NULL if any config field of type string is zero length.]
Azure.IoT Build 7:07bc440836b3 1187 else if ((deviceIdLength = strlen(config->upperConfig->deviceId)) == 0 ||
Azure.IoT Build 7:07bc440836b3 1188 (strlen(config->upperConfig->iotHubName) == 0) ||
Azure.IoT Build 7:07bc440836b3 1189 (strlen(config->upperConfig->iotHubSuffix) == 0))
Azure.IoT Build 7:07bc440836b3 1190 {
AzureIoTClient 16:a49121e2300b 1191 LogError("Zero-length config parameter (deviceId, iotHubName or iotHubSuffix)");
Azure.IoT Build 7:07bc440836b3 1192 }
AzureIoTClient 16:a49121e2300b 1193 else if ((config->upperConfig->deviceKey != NULL) && (strlen(config->upperConfig->deviceKey) == 0))
AzureIoTClient 16:a49121e2300b 1194 {
AzureIoTClient 16:a49121e2300b 1195 LogError("Zero-length config parameter (deviceKey)");
AzureIoTClient 16:a49121e2300b 1196 }
AzureIoTClient 16:a49121e2300b 1197 else if ((config->upperConfig->deviceSasToken != NULL) && (strlen(config->upperConfig->deviceSasToken) == 0))
AzureIoTClient 16:a49121e2300b 1198 {
AzureIoTClient 16:a49121e2300b 1199 LogError("Zero-length config parameter (deviceSasToken)");
AzureIoTClient 16:a49121e2300b 1200 }
Azure.IoT Build 7:07bc440836b3 1201 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_007: [IoTHubTransportAMQP_Create shall fail and return NULL if the deviceId length is greater than 128.]
Azure.IoT Build 7:07bc440836b3 1202 else if (deviceIdLength > 128U)
Azure.IoT Build 7:07bc440836b3 1203 {
AzureIoTClient 13:a4af7c301e02 1204 LogError("deviceId is too long");
Azure.IoT Build 7:07bc440836b3 1205 }
Azure.IoT Build 7:07bc440836b3 1206 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_134: [IoTHubTransportAMQP_Create shall fail and return NULL if the combined length of config->iotHubName and config->iotHubSuffix exceeds 254 bytes (RFC1035)]
Azure.IoT Build 7:07bc440836b3 1207 else if ((strlen(config->upperConfig->iotHubName) + strlen(config->upperConfig->iotHubSuffix)) > (RFC1035_MAX_FQDN_LENGTH - 1))
Azure.IoT Build 7:07bc440836b3 1208 {
AzureIoTClient 13:a4af7c301e02 1209 LogError("The lengths of iotHubName and iotHubSuffix together exceed the maximum FQDN length allowed (RFC 1035)");
AzureIoTClient 4:57e049bce51e 1210 }
AzureIoTClient 4:57e049bce51e 1211 else
AzureIoTClient 4:57e049bce51e 1212 {
Azure.IoT Build 10:75c5e0d8537d 1213 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_009: [IoTHubTransportAMQP_Create shall fail and return NULL if memory allocation of the transport's internal state structure fails.]
Azure.IoT Build 7:07bc440836b3 1214 transport_state = (AMQP_TRANSPORT_INSTANCE*)malloc(sizeof(AMQP_TRANSPORT_INSTANCE));
AzureIoTClient 4:57e049bce51e 1215
Azure.IoT Build 7:07bc440836b3 1216 if (transport_state == NULL)
AzureIoTClient 4:57e049bce51e 1217 {
AzureIoTClient 13:a4af7c301e02 1218 LogError("Could not allocate AMQP transport state");
AzureIoTClient 4:57e049bce51e 1219 }
AzureIoTClient 4:57e049bce51e 1220 else
AzureIoTClient 4:57e049bce51e 1221 {
AzureIoTClient 19:ea016664011a 1222 bool cleanup_required = false;
AzureIoTClient 19:ea016664011a 1223
Azure.IoT Build 7:07bc440836b3 1224 transport_state->iotHubHostFqdn = NULL;
Azure.IoT Build 7:07bc440836b3 1225 transport_state->iotHubPort = DEFAULT_IOTHUB_AMQP_PORT;
Azure.IoT Build 7:07bc440836b3 1226 transport_state->devicesPath = NULL;
Azure.IoT Build 7:07bc440836b3 1227 transport_state->messageReceiveAddress = NULL;
Azure.IoT Build 7:07bc440836b3 1228 transport_state->targetAddress = NULL;
Azure.IoT Build 7:07bc440836b3 1229 transport_state->waitingToSend = config->waitingToSend;
Azure.IoT Build 7:07bc440836b3 1230 transport_state->connection = NULL;
Azure.IoT Build 7:07bc440836b3 1231 transport_state->connection_state = AMQP_MANAGEMENT_STATE_IDLE;
Azure.IoT Build 7:07bc440836b3 1232 transport_state->connection_establish_time = 0;
Azure.IoT Build 7:07bc440836b3 1233 transport_state->iothub_client_handle = NULL;
Azure.IoT Build 7:07bc440836b3 1234 transport_state->receive_messages = false;
Azure.IoT Build 7:07bc440836b3 1235 transport_state->message_receiver = NULL;
Azure.IoT Build 7:07bc440836b3 1236 transport_state->message_sender = NULL;
Azure.IoT Build 7:07bc440836b3 1237 transport_state->receiver_link = NULL;
Azure.IoT Build 7:07bc440836b3 1238 transport_state->sender_link = NULL;
Azure.IoT Build 7:07bc440836b3 1239 transport_state->session = NULL;
Azure.IoT Build 7:07bc440836b3 1240 transport_state->tls_io = NULL;
Azure.IoT Build 10:75c5e0d8537d 1241 transport_state->tls_io_transport_provider = getTLSIOTransport;
Azure.IoT Build 10:75c5e0d8537d 1242 transport_state->isRegistered = false;
AzureIoTClient 16:a49121e2300b 1243 transport_state->is_trace_on = false;
Azure.IoT Build 7:07bc440836b3 1244
AzureIoTClient 20:8dec76e7ba34 1245 transport_state->cbs.cbs = NULL;
AzureIoTClient 20:8dec76e7ba34 1246 transport_state->cbs.sasTokenKeyName = NULL;
AzureIoTClient 20:8dec76e7ba34 1247 transport_state->cbs.cbs_state = CBS_STATE_IDLE;
AzureIoTClient 20:8dec76e7ba34 1248 transport_state->cbs.current_sas_token_create_time = 0;
AzureIoTClient 20:8dec76e7ba34 1249 transport_state->cbs.sasl_io = NULL;
AzureIoTClient 20:8dec76e7ba34 1250 transport_state->cbs.sasl_mechanism = NULL;
AzureIoTClient 20:8dec76e7ba34 1251
AzureIoTClient 20:8dec76e7ba34 1252 transport_state->xioOptions = NULL;
AzureIoTClient 20:8dec76e7ba34 1253
Azure.IoT Build 7:07bc440836b3 1254 transport_state->waitingToSend = config->waitingToSend;
Azure.IoT Build 7:07bc440836b3 1255 DList_InitializeListHead(&transport_state->inProgress);
Azure.IoT Build 7:07bc440836b3 1256
AzureIoTClient 19:ea016664011a 1257 transport_state->credential.credentialType = CREDENTIAL_NOT_BUILD;
AzureIoTClient 19:ea016664011a 1258
AzureIoTClient 24:834cf977abcf 1259 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_010: [If config->upperConfig->protocolGatewayHostName is NULL, IoTHubTransportAMQP_Create shall create an immutable string, referred to as iotHubHostFqdn, from the following pieces: config->iotHubName + "." + config->iotHubSuffix.]
AzureIoTClient 24:834cf977abcf 1260 // Codes_SRS_IOTHUBTRANSPORTAMQP_20_001: [If config->upperConfig->protocolGatewayHostName is not NULL, IoTHubTransportAMQP_Create shall use it as iotHubHostFqdn]
AzureIoTClient 24:834cf977abcf 1261 if ((transport_state->iotHubHostFqdn = (config->upperConfig->protocolGatewayHostName != NULL ? STRING_construct(config->upperConfig->protocolGatewayHostName) : concat3Params(config->upperConfig->iotHubName, ".", config->upperConfig->iotHubSuffix))) == NULL)
AzureIoTClient 4:57e049bce51e 1262 {
AzureIoTClient 13:a4af7c301e02 1263 LogError("Failed to set transport_state->iotHubHostFqdn.");
Azure.IoT Build 7:07bc440836b3 1264 cleanup_required = true;
AzureIoTClient 4:57e049bce51e 1265 }
Azure.IoT Build 10:75c5e0d8537d 1266 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_012: [IoTHubTransportAMQP_Create shall create an immutable string, referred to as devicesPath, from the following parts: host_fqdn + "/devices/" + deviceId.]
Azure.IoT Build 7:07bc440836b3 1267 else if ((transport_state->devicesPath = concat3Params(STRING_c_str(transport_state->iotHubHostFqdn), "/devices/", config->upperConfig->deviceId)) == NULL)
AzureIoTClient 4:57e049bce51e 1268 {
Azure.IoT Build 7:07bc440836b3 1269 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_013: [If creating devicesPath fails for any reason then IoTHubTransportAMQP_Create shall fail and return NULL.]
AzureIoTClient 13:a4af7c301e02 1270 LogError("Failed to allocate transport_state->devicesPath.");
Azure.IoT Build 7:07bc440836b3 1271 cleanup_required = true;
Azure.IoT Build 7:07bc440836b3 1272 }
Azure.IoT Build 7:07bc440836b3 1273 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_014: [IoTHubTransportAMQP_Create shall create an immutable string, referred to as targetAddress, from the following parts: "amqps://" + devicesPath + "/messages/events".]
Azure.IoT Build 7:07bc440836b3 1274 else if ((transport_state->targetAddress = concat3Params("amqps://", STRING_c_str(transport_state->devicesPath), "/messages/events")) == NULL)
Azure.IoT Build 7:07bc440836b3 1275 {
Azure.IoT Build 7:07bc440836b3 1276 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_015: [If creating the targetAddress fails for any reason then IoTHubTransportAMQP_Create shall fail and return NULL.]
AzureIoTClient 13:a4af7c301e02 1277 LogError("Failed to allocate transport_state->targetAddress.");
Azure.IoT Build 7:07bc440836b3 1278 cleanup_required = true;
Azure.IoT Build 7:07bc440836b3 1279 }
Azure.IoT Build 7:07bc440836b3 1280 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_053: [IoTHubTransportAMQP_Create shall define the source address for receiving messages as "amqps://" + devicesPath + "/messages/devicebound", stored in the transport handle as messageReceiveAddress]
Azure.IoT Build 7:07bc440836b3 1281 else if ((transport_state->messageReceiveAddress = concat3Params("amqps://", STRING_c_str(transport_state->devicesPath), "/messages/devicebound")) == NULL)
Azure.IoT Build 7:07bc440836b3 1282 {
Azure.IoT Build 7:07bc440836b3 1283 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_054: [If creating the messageReceiveAddress fails for any reason then IoTHubTransportAMQP_Create shall fail and return NULL.]
AzureIoTClient 13:a4af7c301e02 1284 LogError("Failed to allocate transport_state->messageReceiveAddress.");
Azure.IoT Build 7:07bc440836b3 1285 cleanup_required = true;
Azure.IoT Build 7:07bc440836b3 1286 }
AzureIoTClient 20:8dec76e7ba34 1287 else
Azure.IoT Build 7:07bc440836b3 1288 {
AzureIoTClient 19:ea016664011a 1289 if (config->upperConfig->deviceSasToken != NULL)
AzureIoTClient 19:ea016664011a 1290 {
AzureIoTClient 20:8dec76e7ba34 1291 /*only SAS token specified*/
AzureIoTClient 20:8dec76e7ba34 1292 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_016: [IoTHubTransportAMQP_Create shall initialize handle->sasTokenKeyName with a zero-length STRING_HANDLE instance.]
AzureIoTClient 20:8dec76e7ba34 1293 if ((transport_state->cbs.sasTokenKeyName = STRING_new()) == NULL)
AzureIoTClient 19:ea016664011a 1294 {
AzureIoTClient 20:8dec76e7ba34 1295 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_017: [If IoTHubTransportAMQP_Create fails to initialize handle->sasTokenKeyName with a zero-length STRING the function shall fail and return NULL.]
AzureIoTClient 20:8dec76e7ba34 1296 LogError("Failed to allocate transport_state->sasTokenKeyName.");
AzureIoTClient 19:ea016664011a 1297 cleanup_required = true;
AzureIoTClient 19:ea016664011a 1298 }
AzureIoTClient 19:ea016664011a 1299 else
AzureIoTClient 19:ea016664011a 1300 {
AzureIoTClient 19:ea016664011a 1301 transport_state->credential.credential.deviceSasToken = STRING_construct(config->upperConfig->deviceSasToken);
AzureIoTClient 19:ea016664011a 1302 if (transport_state->credential.credential.deviceSasToken == NULL)
AzureIoTClient 19:ea016664011a 1303 {
AzureIoTClient 19:ea016664011a 1304 LogError("unable to STRING_construct for deviceSasToken");
AzureIoTClient 19:ea016664011a 1305 cleanup_required = true;
AzureIoTClient 19:ea016664011a 1306 }
AzureIoTClient 19:ea016664011a 1307 else
AzureIoTClient 19:ea016664011a 1308 {
AzureIoTClient 19:ea016664011a 1309 transport_state->credential.credentialType = DEVICE_SAS_TOKEN;
AzureIoTClient 19:ea016664011a 1310 }
AzureIoTClient 19:ea016664011a 1311 }
AzureIoTClient 20:8dec76e7ba34 1312
AzureIoTClient 19:ea016664011a 1313 }
AzureIoTClient 19:ea016664011a 1314 else
AzureIoTClient 19:ea016664011a 1315 {
AzureIoTClient 19:ea016664011a 1316 /*when deviceSasToken == NULL*/
AzureIoTClient 19:ea016664011a 1317 if (config->upperConfig->deviceKey != NULL)
AzureIoTClient 19:ea016664011a 1318 {
AzureIoTClient 19:ea016664011a 1319 /*it is device key*/
AzureIoTClient 20:8dec76e7ba34 1320 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_016: [IoTHubTransportAMQP_Create shall initialize handle->sasTokenKeyName with a zero-length STRING_HANDLE instance.]
AzureIoTClient 20:8dec76e7ba34 1321 if ((transport_state->cbs.sasTokenKeyName = STRING_new()) == NULL)
AzureIoTClient 19:ea016664011a 1322 {
AzureIoTClient 20:8dec76e7ba34 1323 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_017: [If IoTHubTransportAMQP_Create fails to initialize handle->sasTokenKeyName with a zero-length STRING the function shall fail and return NULL.]
AzureIoTClient 20:8dec76e7ba34 1324 LogError("Failed to allocate transport_state->sasTokenKeyName.");
AzureIoTClient 19:ea016664011a 1325 cleanup_required = true;
AzureIoTClient 19:ea016664011a 1326 }
AzureIoTClient 19:ea016664011a 1327 else
AzureIoTClient 19:ea016664011a 1328 {
AzureIoTClient 20:8dec76e7ba34 1329 transport_state->credential.credential.deviceKey = STRING_construct(config->upperConfig->deviceKey);
AzureIoTClient 20:8dec76e7ba34 1330 if (transport_state->credential.credential.deviceKey == NULL)
AzureIoTClient 20:8dec76e7ba34 1331 {
AzureIoTClient 20:8dec76e7ba34 1332 LogError("unable to STRING_construct for a deviceKey");
AzureIoTClient 20:8dec76e7ba34 1333 cleanup_required = true;
AzureIoTClient 20:8dec76e7ba34 1334 }
AzureIoTClient 20:8dec76e7ba34 1335 else
AzureIoTClient 20:8dec76e7ba34 1336 {
AzureIoTClient 20:8dec76e7ba34 1337 transport_state->credential.credentialType = DEVICE_KEY;
AzureIoTClient 20:8dec76e7ba34 1338 }
AzureIoTClient 19:ea016664011a 1339 }
AzureIoTClient 19:ea016664011a 1340 }
AzureIoTClient 19:ea016664011a 1341 else
AzureIoTClient 19:ea016664011a 1342 {
AzureIoTClient 20:8dec76e7ba34 1343 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_004: [ If both deviceKey and deviceSasToken fields are NULL then IoTHubTransportAMQP_Create shall assume a x509 authentication. ]*/
AzureIoTClient 19:ea016664011a 1344 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_003: [ IoTHubTransportAMQP_Register shall assume a x509 authentication mechanism when both deviceKey and deviceSasToken are NULL. ]*/
AzureIoTClient 19:ea016664011a 1345 /*when both SAS token AND devicekey are NULL*/
AzureIoTClient 19:ea016664011a 1346 transport_state->credential.credentialType = X509;
AzureIoTClient 19:ea016664011a 1347 transport_state->credential.credential.x509credential.x509certificate = NULL;
AzureIoTClient 19:ea016664011a 1348 transport_state->credential.credential.x509credential.x509privatekey = NULL;
AzureIoTClient 19:ea016664011a 1349 }
AzureIoTClient 19:ea016664011a 1350 }
AzureIoTClient 19:ea016664011a 1351
AzureIoTClient 20:8dec76e7ba34 1352 if (transport_state->credential.credentialType != CREDENTIAL_NOT_BUILD)
AzureIoTClient 19:ea016664011a 1353 {
AzureIoTClient 19:ea016664011a 1354 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_020: [IoTHubTransportAMQP_Create shall set parameter transport_state->sas_token_lifetime with the default value of 3600000 (milliseconds).]
AzureIoTClient 20:8dec76e7ba34 1355 transport_state->cbs.sas_token_lifetime = DEFAULT_SAS_TOKEN_LIFETIME_MS;
AzureIoTClient 19:ea016664011a 1356
AzureIoTClient 19:ea016664011a 1357 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_128: [IoTHubTransportAMQP_Create shall set parameter transport_state->sas_token_refresh_time with the default value of sas_token_lifetime/2 (milliseconds).]
AzureIoTClient 20:8dec76e7ba34 1358 transport_state->cbs.sas_token_refresh_time = transport_state->cbs.sas_token_lifetime / 2;
AzureIoTClient 19:ea016664011a 1359
AzureIoTClient 19:ea016664011a 1360 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_129 : [IoTHubTransportAMQP_Create shall set parameter transport_state->cbs_request_timeout with the default value of 30000 (milliseconds).]
AzureIoTClient 20:8dec76e7ba34 1361 transport_state->cbs.cbs_request_timeout = DEFAULT_CBS_REQUEST_TIMEOUT_MS;
AzureIoTClient 19:ea016664011a 1362 }
AzureIoTClient 20:8dec76e7ba34 1363
Azure.IoT Build 7:07bc440836b3 1364 }
AzureIoTClient 19:ea016664011a 1365
AzureIoTClient 19:ea016664011a 1366 if (cleanup_required)
Azure.IoT Build 7:07bc440836b3 1367 {
AzureIoTClient 19:ea016664011a 1368 credential_destroy(transport_state);
AzureIoTClient 20:8dec76e7ba34 1369 if (transport_state->cbs.sasTokenKeyName != NULL)
AzureIoTClient 20:8dec76e7ba34 1370 STRING_delete(transport_state->cbs.sasTokenKeyName);
AzureIoTClient 19:ea016664011a 1371 if (transport_state->targetAddress != NULL)
AzureIoTClient 19:ea016664011a 1372 STRING_delete(transport_state->targetAddress);
AzureIoTClient 19:ea016664011a 1373 if (transport_state->messageReceiveAddress != NULL)
AzureIoTClient 19:ea016664011a 1374 STRING_delete(transport_state->messageReceiveAddress);
AzureIoTClient 19:ea016664011a 1375 if (transport_state->devicesPath != NULL)
AzureIoTClient 19:ea016664011a 1376 STRING_delete(transport_state->devicesPath);
AzureIoTClient 19:ea016664011a 1377 if (transport_state->iotHubHostFqdn != NULL)
AzureIoTClient 19:ea016664011a 1378 STRING_delete(transport_state->iotHubHostFqdn);
Azure.IoT Build 7:07bc440836b3 1379
AzureIoTClient 19:ea016664011a 1380 free(transport_state);
AzureIoTClient 19:ea016664011a 1381 transport_state = NULL;
AzureIoTClient 4:57e049bce51e 1382 }
AzureIoTClient 4:57e049bce51e 1383 }
AzureIoTClient 4:57e049bce51e 1384 }
Azure.IoT Build 7:07bc440836b3 1385
Azure.IoT Build 7:07bc440836b3 1386 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_023: [If IoTHubTransportAMQP_Create succeeds it shall return a non-NULL pointer to the structure that represents the transport.]
Azure.IoT Build 7:07bc440836b3 1387 return transport_state;
AzureIoTClient 4:57e049bce51e 1388 }
AzureIoTClient 4:57e049bce51e 1389
Azure.IoT Build 11:62d7b956e76e 1390 static void IoTHubTransportAMQP_Destroy(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 4:57e049bce51e 1391 {
Azure.IoT Build 7:07bc440836b3 1392 if (handle != NULL)
Azure.IoT Build 7:07bc440836b3 1393 {
Azure.IoT Build 7:07bc440836b3 1394 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
Azure.IoT Build 11:62d7b956e76e 1395
Azure.IoT Build 7:07bc440836b3 1396 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_024: [IoTHubTransportAMQP_Destroy shall destroy the AMQP message_sender.]
Azure.IoT Build 7:07bc440836b3 1397 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_029 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP link.]
Azure.IoT Build 7:07bc440836b3 1398 destroyEventSender(transport_state);
Azure.IoT Build 7:07bc440836b3 1399
Azure.IoT Build 7:07bc440836b3 1400 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_025: [IoTHubTransportAMQP_Destroy shall destroy the AMQP message_receiver.]
Azure.IoT Build 7:07bc440836b3 1401 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_029 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP link.]
Azure.IoT Build 7:07bc440836b3 1402 destroyMessageReceiver(transport_state);
Azure.IoT Build 7:07bc440836b3 1403
Azure.IoT Build 7:07bc440836b3 1404 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_027 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP cbs instance]
Azure.IoT Build 7:07bc440836b3 1405 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_030 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP session.]
Azure.IoT Build 7:07bc440836b3 1406 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_031 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP connection.]
Azure.IoT Build 7:07bc440836b3 1407 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_032 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP SASL I / O transport.]
Azure.IoT Build 7:07bc440836b3 1408 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_033 : [IoTHubTransportAMQP_Destroy shall destroy the AMQP SASL mechanism.]
Azure.IoT Build 7:07bc440836b3 1409 destroyConnection(transport_state);
Azure.IoT Build 7:07bc440836b3 1410
Azure.IoT Build 7:07bc440836b3 1411 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_035 : [IoTHubTransportAMQP_Destroy shall delete its internally - set parameters(deviceKey, targetAddress, devicesPath, sasTokenKeyName).]
Azure.IoT Build 7:07bc440836b3 1412 STRING_delete(transport_state->targetAddress);
Azure.IoT Build 7:07bc440836b3 1413 STRING_delete(transport_state->messageReceiveAddress);
AzureIoTClient 20:8dec76e7ba34 1414 STRING_delete(transport_state->cbs.sasTokenKeyName);
AzureIoTClient 19:ea016664011a 1415 credential_destroy(transport_state);
Azure.IoT Build 7:07bc440836b3 1416 STRING_delete(transport_state->devicesPath);
Azure.IoT Build 7:07bc440836b3 1417 STRING_delete(transport_state->iotHubHostFqdn);
Azure.IoT Build 7:07bc440836b3 1418
Azure.IoT Build 7:07bc440836b3 1419 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_036 : [IoTHubTransportAMQP_Destroy shall return the remaining items in inProgress to waitingToSend list.]
Azure.IoT Build 7:07bc440836b3 1420 rollEventsBackToWaitList(transport_state);
Azure.IoT Build 7:07bc440836b3 1421
AzureIoTClient 20:8dec76e7ba34 1422 if (transport_state->xioOptions != NULL)
AzureIoTClient 20:8dec76e7ba34 1423 {
AzureIoTClient 20:8dec76e7ba34 1424 OptionHandler_Destroy(transport_state->xioOptions);
AzureIoTClient 20:8dec76e7ba34 1425 }
AzureIoTClient 20:8dec76e7ba34 1426
Azure.IoT Build 7:07bc440836b3 1427 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_150: [IoTHubTransportAMQP_Destroy shall destroy the transport instance]
Azure.IoT Build 7:07bc440836b3 1428 free(transport_state);
Azure.IoT Build 7:07bc440836b3 1429 }
Azure.IoT Build 7:07bc440836b3 1430 }
Azure.IoT Build 7:07bc440836b3 1431
Azure.IoT Build 11:62d7b956e76e 1432 static void IoTHubTransportAMQP_DoWork(TRANSPORT_LL_HANDLE handle, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle)
Azure.IoT Build 7:07bc440836b3 1433 {
Azure.IoT Build 7:07bc440836b3 1434 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_051: [IoTHubTransportAMQP_DoWork shall fail and return immediately if the transport handle parameter is NULL]
AzureIoTClient 4:57e049bce51e 1435 if (handle == NULL)
AzureIoTClient 4:57e049bce51e 1436 {
AzureIoTClient 13:a4af7c301e02 1437 LogError("IoTHubClient DoWork failed: transport handle parameter is NULL.");
Azure.IoT Build 7:07bc440836b3 1438 }
Azure.IoT Build 7:07bc440836b3 1439 // Codes_[IoTHubTransportAMQP_DoWork shall fail and return immediately if the client handle parameter is NULL]
Azure.IoT Build 7:07bc440836b3 1440 else if (iotHubClientHandle == NULL)
Azure.IoT Build 7:07bc440836b3 1441 {
AzureIoTClient 13:a4af7c301e02 1442 LogError("IoTHubClient DoWork failed: client handle parameter is NULL.");
AzureIoTClient 4:57e049bce51e 1443 }
AzureIoTClient 4:57e049bce51e 1444 else
AzureIoTClient 4:57e049bce51e 1445 {
Azure.IoT Build 7:07bc440836b3 1446 bool trigger_connection_retry = false;
Azure.IoT Build 7:07bc440836b3 1447 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
Azure.IoT Build 7:07bc440836b3 1448
Azure.IoT Build 7:07bc440836b3 1449 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_147: [IoTHubTransportAMQP_DoWork shall save a reference to the client handle in transport_state->iothub_client_handle]
Azure.IoT Build 7:07bc440836b3 1450 transport_state->iothub_client_handle = iotHubClientHandle;
Azure.IoT Build 7:07bc440836b3 1451
AzureIoTClient 16:a49121e2300b 1452 if (transport_state->connection != NULL &&
AzureIoTClient 16:a49121e2300b 1453 transport_state->connection_state == AMQP_MANAGEMENT_STATE_ERROR)
AzureIoTClient 16:a49121e2300b 1454 {
AzureIoTClient 16:a49121e2300b 1455 LogError("An error occured on AMQP connection. The connection will be restablished.");
AzureIoTClient 16:a49121e2300b 1456 trigger_connection_retry = true;
AzureIoTClient 16:a49121e2300b 1457 }
Azure.IoT Build 7:07bc440836b3 1458 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_055: [If the transport handle has a NULL connection, IoTHubTransportAMQP_DoWork shall instantiate and initialize the AMQP components and establish the connection]
AzureIoTClient 13:a4af7c301e02 1459 else if (transport_state->connection == NULL &&
Azure.IoT Build 7:07bc440836b3 1460 establishConnection(transport_state) != RESULT_OK)
Azure.IoT Build 7:07bc440836b3 1461 {
AzureIoTClient 13:a4af7c301e02 1462 LogError("AMQP transport failed to establish connection with service.");
Azure.IoT Build 7:07bc440836b3 1463 trigger_connection_retry = true;
Azure.IoT Build 7:07bc440836b3 1464 }
AzureIoTClient 20:8dec76e7ba34 1465 else
Azure.IoT Build 7:07bc440836b3 1466 {
AzureIoTClient 20:8dec76e7ba34 1467 switch(transport_state->credential.credentialType)
Azure.IoT Build 7:07bc440836b3 1468 {
AzureIoTClient 20:8dec76e7ba34 1469 case(DEVICE_KEY):
AzureIoTClient 20:8dec76e7ba34 1470 case(DEVICE_SAS_TOKEN):
AzureIoTClient 20:8dec76e7ba34 1471 {
AzureIoTClient 20:8dec76e7ba34 1472 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_081: [IoTHubTransportAMQP_DoWork shall put a new SAS token if the one has not been out already, or if the previous one failed to be put due to timeout of cbs_put_token().]
AzureIoTClient 20:8dec76e7ba34 1473 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_082: [IoTHubTransportAMQP_DoWork shall refresh the SAS token if the current token has been used for more than 'sas_token_refresh_time' milliseconds]
AzureIoTClient 20:8dec76e7ba34 1474 if ((transport_state->cbs.cbs_state == CBS_STATE_IDLE || isSasTokenRefreshRequired(transport_state)) &&
AzureIoTClient 20:8dec76e7ba34 1475 startAuthentication(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1476 {
AzureIoTClient 20:8dec76e7ba34 1477 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_146: [If the SAS token fails to be sent to CBS (cbs_put_token), IoTHubTransportAMQP_DoWork shall fail and exit immediately]
AzureIoTClient 20:8dec76e7ba34 1478 LogError("Failed authenticating AMQP connection within CBS.");
AzureIoTClient 20:8dec76e7ba34 1479 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1480 }
AzureIoTClient 20:8dec76e7ba34 1481 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_084: [IoTHubTransportAMQP_DoWork shall wait for 'cbs_request_timeout' milliseconds for the cbs_put_token() to complete before failing due to timeout]
AzureIoTClient 20:8dec76e7ba34 1482 else if (transport_state->cbs.cbs_state == CBS_STATE_AUTH_IN_PROGRESS &&
AzureIoTClient 20:8dec76e7ba34 1483 verifyAuthenticationTimeout(transport_state) == RESULT_TIMEOUT)
AzureIoTClient 20:8dec76e7ba34 1484 {
AzureIoTClient 20:8dec76e7ba34 1485 LogError("AMQP transport authentication timed out.");
AzureIoTClient 20:8dec76e7ba34 1486 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1487 }
AzureIoTClient 20:8dec76e7ba34 1488 else if (transport_state->cbs.cbs_state == CBS_STATE_AUTHENTICATED)
AzureIoTClient 20:8dec76e7ba34 1489 {
AzureIoTClient 20:8dec76e7ba34 1490 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_121: [IoTHubTransportAMQP_DoWork shall create an AMQP message_receiver if transport_state->message_receive is NULL and transport_state->receive_messages is true]
AzureIoTClient 20:8dec76e7ba34 1491 if (transport_state->receive_messages == true &&
AzureIoTClient 20:8dec76e7ba34 1492 transport_state->message_receiver == NULL &&
AzureIoTClient 20:8dec76e7ba34 1493 createMessageReceiver(transport_state, iotHubClientHandle) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1494 {
AzureIoTClient 20:8dec76e7ba34 1495 LogError("Failed creating AMQP transport message receiver.");
AzureIoTClient 20:8dec76e7ba34 1496 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1497 }
AzureIoTClient 20:8dec76e7ba34 1498 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_122: [IoTHubTransportAMQP_DoWork shall destroy the transport_state->message_receiver (and set it to NULL) if it exists and transport_state->receive_messages is false]
AzureIoTClient 20:8dec76e7ba34 1499 else if (transport_state->receive_messages == false &&
AzureIoTClient 20:8dec76e7ba34 1500 transport_state->message_receiver != NULL &&
AzureIoTClient 20:8dec76e7ba34 1501 destroyMessageReceiver(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1502 {
AzureIoTClient 20:8dec76e7ba34 1503 LogError("Failed destroying AMQP transport message receiver.");
AzureIoTClient 20:8dec76e7ba34 1504 }
Azure.IoT Build 7:07bc440836b3 1505
AzureIoTClient 20:8dec76e7ba34 1506 if (transport_state->message_sender == NULL &&
AzureIoTClient 20:8dec76e7ba34 1507 createEventSender(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1508 {
AzureIoTClient 20:8dec76e7ba34 1509 LogError("Failed creating AMQP transport event sender.");
AzureIoTClient 20:8dec76e7ba34 1510 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1511 }
AzureIoTClient 20:8dec76e7ba34 1512 else if (sendPendingEvents(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1513 {
AzureIoTClient 20:8dec76e7ba34 1514 LogError("AMQP transport failed sending events.");
AzureIoTClient 20:8dec76e7ba34 1515 }
AzureIoTClient 20:8dec76e7ba34 1516 }
AzureIoTClient 20:8dec76e7ba34 1517 break;
AzureIoTClient 20:8dec76e7ba34 1518 }
AzureIoTClient 20:8dec76e7ba34 1519 case (X509):
AzureIoTClient 20:8dec76e7ba34 1520 {
AzureIoTClient 20:8dec76e7ba34 1521 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_121: [IoTHubTransportAMQP_DoWork shall create an AMQP message_receiver if transport_state->message_receive is NULL and transport_state->receive_messages is true]
AzureIoTClient 20:8dec76e7ba34 1522 if (transport_state->receive_messages == true &&
AzureIoTClient 20:8dec76e7ba34 1523 transport_state->message_receiver == NULL &&
AzureIoTClient 20:8dec76e7ba34 1524 createMessageReceiver(transport_state, iotHubClientHandle) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1525 {
AzureIoTClient 20:8dec76e7ba34 1526 LogError("Failed creating AMQP transport message receiver.");
AzureIoTClient 20:8dec76e7ba34 1527 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1528 }
AzureIoTClient 20:8dec76e7ba34 1529 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_122: [IoTHubTransportAMQP_DoWork shall destroy the transport_state->message_receiver (and set it to NULL) if it exists and transport_state->receive_messages is false]
AzureIoTClient 20:8dec76e7ba34 1530 else if (transport_state->receive_messages == false &&
AzureIoTClient 20:8dec76e7ba34 1531 transport_state->message_receiver != NULL &&
AzureIoTClient 20:8dec76e7ba34 1532 destroyMessageReceiver(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1533 {
AzureIoTClient 20:8dec76e7ba34 1534 LogError("Failed destroying AMQP transport message receiver.");
AzureIoTClient 20:8dec76e7ba34 1535 }
AzureIoTClient 20:8dec76e7ba34 1536
AzureIoTClient 20:8dec76e7ba34 1537 if (transport_state->message_sender == NULL &&
AzureIoTClient 20:8dec76e7ba34 1538 createEventSender(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1539 {
AzureIoTClient 20:8dec76e7ba34 1540 LogError("Failed creating AMQP transport event sender.");
AzureIoTClient 20:8dec76e7ba34 1541 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1542 }
AzureIoTClient 20:8dec76e7ba34 1543 else if (sendPendingEvents(transport_state) != RESULT_OK)
AzureIoTClient 20:8dec76e7ba34 1544 {
AzureIoTClient 20:8dec76e7ba34 1545 LogError("AMQP transport failed sending events.");
AzureIoTClient 20:8dec76e7ba34 1546 }
AzureIoTClient 20:8dec76e7ba34 1547 break;
AzureIoTClient 20:8dec76e7ba34 1548 }
AzureIoTClient 20:8dec76e7ba34 1549 default:
AzureIoTClient 20:8dec76e7ba34 1550 {
AzureIoTClient 20:8dec76e7ba34 1551 LogError("internal error: unexpected enum value : transport_state->credential.credentialType = %d", transport_state->credential.credentialType);
AzureIoTClient 20:8dec76e7ba34 1552 trigger_connection_retry = true;
AzureIoTClient 20:8dec76e7ba34 1553 }
AzureIoTClient 20:8dec76e7ba34 1554 }/*switch*/
Azure.IoT Build 7:07bc440836b3 1555 }
Azure.IoT Build 7:07bc440836b3 1556
Azure.IoT Build 7:07bc440836b3 1557 if (trigger_connection_retry)
Azure.IoT Build 7:07bc440836b3 1558 {
Azure.IoT Build 7:07bc440836b3 1559 prepareForConnectionRetry(transport_state);
Azure.IoT Build 7:07bc440836b3 1560 }
Azure.IoT Build 7:07bc440836b3 1561 else
Azure.IoT Build 7:07bc440836b3 1562 {
Azure.IoT Build 7:07bc440836b3 1563 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_103: [IoTHubTransportAMQP_DoWork shall invoke connection_dowork() on AMQP for triggering sending and receiving messages]
Azure.IoT Build 7:07bc440836b3 1564 connection_dowork(transport_state->connection);
Azure.IoT Build 7:07bc440836b3 1565 }
Azure.IoT Build 7:07bc440836b3 1566 }
Azure.IoT Build 7:07bc440836b3 1567 }
Azure.IoT Build 7:07bc440836b3 1568
AzureIoTClient 14:8e8e42008807 1569 static int IoTHubTransportAMQP_Subscribe(TRANSPORT_LL_HANDLE handle)
Azure.IoT Build 7:07bc440836b3 1570 {
Azure.IoT Build 7:07bc440836b3 1571 int result;
Azure.IoT Build 11:62d7b956e76e 1572
Azure.IoT Build 7:07bc440836b3 1573 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_037: [IoTHubTransportAMQP_Subscribe shall fail if the transport handle parameter received is NULL.]
Azure.IoT Build 7:07bc440836b3 1574 if (handle == NULL)
Azure.IoT Build 7:07bc440836b3 1575 {
AzureIoTClient 13:a4af7c301e02 1576 LogError("Invalid handle to IoTHubClient AMQP transport.");
Azure.IoT Build 7:07bc440836b3 1577 result = __LINE__;
Azure.IoT Build 7:07bc440836b3 1578 }
Azure.IoT Build 7:07bc440836b3 1579 else
Azure.IoT Build 7:07bc440836b3 1580 {
Azure.IoT Build 7:07bc440836b3 1581 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_038: [IoTHubTransportAMQP_Subscribe shall set transport_handle->receive_messages to true and return success code.]
Azure.IoT Build 7:07bc440836b3 1582 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
Azure.IoT Build 7:07bc440836b3 1583 transport_state->receive_messages = true;
AzureIoTClient 4:57e049bce51e 1584 result = 0;
AzureIoTClient 4:57e049bce51e 1585 }
Azure.IoT Build 7:07bc440836b3 1586
AzureIoTClient 4:57e049bce51e 1587 return result;
AzureIoTClient 4:57e049bce51e 1588 }
AzureIoTClient 4:57e049bce51e 1589
AzureIoTClient 14:8e8e42008807 1590 static void IoTHubTransportAMQP_Unsubscribe(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 4:57e049bce51e 1591 {
Azure.IoT Build 7:07bc440836b3 1592 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_039: [IoTHubTransportAMQP_Unsubscribe shall fail if the transport handle parameter received is NULL.]
Azure.IoT Build 7:07bc440836b3 1593 if (handle == NULL)
AzureIoTClient 4:57e049bce51e 1594 {
AzureIoTClient 13:a4af7c301e02 1595 LogError("Invalid handle to IoTHubClient AMQP transport.");
Azure.IoT Build 7:07bc440836b3 1596 }
Azure.IoT Build 7:07bc440836b3 1597 else
Azure.IoT Build 7:07bc440836b3 1598 {
Azure.IoT Build 7:07bc440836b3 1599 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_040: [IoTHubTransportAMQP_Unsubscribe shall set transport_handle->receive_messages to false and return success code.]
Azure.IoT Build 7:07bc440836b3 1600 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
Azure.IoT Build 7:07bc440836b3 1601 transport_state->receive_messages = false;
AzureIoTClient 4:57e049bce51e 1602 }
AzureIoTClient 4:57e049bce51e 1603 }
AzureIoTClient 4:57e049bce51e 1604
Azure.IoT Build 10:75c5e0d8537d 1605 static IOTHUB_CLIENT_RESULT IoTHubTransportAMQP_GetSendStatus(IOTHUB_DEVICE_HANDLE handle, IOTHUB_CLIENT_STATUS *iotHubClientStatus)
AzureIoTClient 4:57e049bce51e 1606 {
AzureIoTClient 4:57e049bce51e 1607 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 4:57e049bce51e 1608
Azure.IoT Build 7:07bc440836b3 1609 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_041: [IoTHubTransportAMQP_GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL parameter.]
AzureIoTClient 4:57e049bce51e 1610 if (handle == NULL)
AzureIoTClient 4:57e049bce51e 1611 {
AzureIoTClient 4:57e049bce51e 1612 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 13:a4af7c301e02 1613 LogError("Invalid handle to IoTHubClient AMQP transport instance.");
AzureIoTClient 4:57e049bce51e 1614 }
AzureIoTClient 4:57e049bce51e 1615 else if (iotHubClientStatus == NULL)
AzureIoTClient 4:57e049bce51e 1616 {
AzureIoTClient 4:57e049bce51e 1617 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 13:a4af7c301e02 1618 LogError("Invalid pointer to output parameter IOTHUB_CLIENT_STATUS.");
AzureIoTClient 4:57e049bce51e 1619 }
AzureIoTClient 4:57e049bce51e 1620 else
AzureIoTClient 4:57e049bce51e 1621 {
Azure.IoT Build 7:07bc440836b3 1622 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 4:57e049bce51e 1623
Azure.IoT Build 7:07bc440836b3 1624 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_043: [IoTHubTransportAMQP_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.]
Azure.IoT Build 7:07bc440836b3 1625 if (!DList_IsListEmpty(transport_state->waitingToSend) || !DList_IsListEmpty(&(transport_state->inProgress)))
AzureIoTClient 4:57e049bce51e 1626 {
AzureIoTClient 4:57e049bce51e 1627 *iotHubClientStatus = IOTHUB_CLIENT_SEND_STATUS_BUSY;
AzureIoTClient 4:57e049bce51e 1628 }
Azure.IoT Build 7:07bc440836b3 1629 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_042: [IoTHubTransportAMQP_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 4:57e049bce51e 1630 else
AzureIoTClient 4:57e049bce51e 1631 {
AzureIoTClient 4:57e049bce51e 1632 *iotHubClientStatus = IOTHUB_CLIENT_SEND_STATUS_IDLE;
AzureIoTClient 4:57e049bce51e 1633 }
AzureIoTClient 4:57e049bce51e 1634
AzureIoTClient 4:57e049bce51e 1635 result = IOTHUB_CLIENT_OK;
AzureIoTClient 4:57e049bce51e 1636 }
AzureIoTClient 4:57e049bce51e 1637
AzureIoTClient 4:57e049bce51e 1638 return result;
AzureIoTClient 4:57e049bce51e 1639 }
AzureIoTClient 4:57e049bce51e 1640
Azure.IoT Build 11:62d7b956e76e 1641 static IOTHUB_CLIENT_RESULT IoTHubTransportAMQP_SetOption(TRANSPORT_LL_HANDLE handle, const char* option, const void* value)
AzureIoTClient 4:57e049bce51e 1642 {
AzureIoTClient 4:57e049bce51e 1643 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 4:57e049bce51e 1644
Azure.IoT Build 7:07bc440836b3 1645 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_044: [If handle parameter is NULL then IoTHubTransportAMQP_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.]
Azure.IoT Build 7:07bc440836b3 1646 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_045: [If parameter optionName is NULL then IoTHubTransportAMQP_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.]
Azure.IoT Build 7:07bc440836b3 1647 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_046: [If parameter value is NULL then IoTHubTransportAMQP_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.]
AzureIoTClient 5:8d58d20699dd 1648 if (
AzureIoTClient 5:8d58d20699dd 1649 (handle == NULL) ||
AzureIoTClient 5:8d58d20699dd 1650 (option == NULL) ||
AzureIoTClient 5:8d58d20699dd 1651 (value == NULL)
AzureIoTClient 5:8d58d20699dd 1652 )
AzureIoTClient 5:8d58d20699dd 1653 {
AzureIoTClient 5:8d58d20699dd 1654 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 13:a4af7c301e02 1655 LogError("Invalid parameter (NULL) passed to AMQP transport SetOption()");
AzureIoTClient 5:8d58d20699dd 1656 }
AzureIoTClient 5:8d58d20699dd 1657 else
AzureIoTClient 5:8d58d20699dd 1658 {
Azure.IoT Build 7:07bc440836b3 1659 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 4:57e049bce51e 1660
Azure.IoT Build 10:75c5e0d8537d 1661 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_048: [IotHubTransportAMQP_SetOption shall save and apply the value if the option name is "sas_token_lifetime", returning IOTHUB_CLIENT_OK]
AzureIoTClient 21:32a1746384ba 1662 if (strcmp(OPTION_SAS_TOKEN_LIFETIME, option) == 0)
Azure.IoT Build 10:75c5e0d8537d 1663 {
AzureIoTClient 20:8dec76e7ba34 1664 transport_state->cbs.sas_token_lifetime = *((size_t*)value);
Azure.IoT Build 10:75c5e0d8537d 1665 result = IOTHUB_CLIENT_OK;
Azure.IoT Build 10:75c5e0d8537d 1666 }
Azure.IoT Build 10:75c5e0d8537d 1667 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_049: [IotHubTransportAMQP_SetOption shall save and apply the value if the option name is "sas_token_refresh_time", returning IOTHUB_CLIENT_OK]
AzureIoTClient 21:32a1746384ba 1668 else if (strcmp(OPTION_SAS_TOKEN_REFRESH_TIME, option) == 0)
Azure.IoT Build 10:75c5e0d8537d 1669 {
AzureIoTClient 20:8dec76e7ba34 1670 transport_state->cbs.sas_token_refresh_time = *((size_t*)value);
Azure.IoT Build 10:75c5e0d8537d 1671 result = IOTHUB_CLIENT_OK;
Azure.IoT Build 10:75c5e0d8537d 1672 }
Azure.IoT Build 10:75c5e0d8537d 1673 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_148: [IotHubTransportAMQP_SetOption shall save and apply the value if the option name is "cbs_request_timeout", returning IOTHUB_CLIENT_OK]
AzureIoTClient 21:32a1746384ba 1674 else if (strcmp(OPTION_CBS_REQUEST_TIMEOUT, option) == 0)
Azure.IoT Build 10:75c5e0d8537d 1675 {
AzureIoTClient 20:8dec76e7ba34 1676 transport_state->cbs.cbs_request_timeout = *((size_t*)value);
Azure.IoT Build 10:75c5e0d8537d 1677 result = IOTHUB_CLIENT_OK;
Azure.IoT Build 10:75c5e0d8537d 1678 }
AzureIoTClient 21:32a1746384ba 1679 else if (strcmp(OPTION_LOG_TRACE, option) == 0)
AzureIoTClient 16:a49121e2300b 1680 {
AzureIoTClient 19:ea016664011a 1681 transport_state->is_trace_on = *((bool*)value);
AzureIoTClient 16:a49121e2300b 1682 if (transport_state->connection != NULL)
AzureIoTClient 16:a49121e2300b 1683 {
AzureIoTClient 16:a49121e2300b 1684 connection_set_trace(transport_state->connection, transport_state->is_trace_on);
AzureIoTClient 16:a49121e2300b 1685 }
AzureIoTClient 16:a49121e2300b 1686 result = IOTHUB_CLIENT_OK;
AzureIoTClient 16:a49121e2300b 1687 }
AzureIoTClient 20:8dec76e7ba34 1688 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_007: [ If optionName is x509certificate and the authentication method is not x509 then IoTHubTransportAMQP_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
AzureIoTClient 21:32a1746384ba 1689 else if ((strcmp(OPTION_X509_CERT, option) == 0) && (transport_state->credential.credentialType != X509))
AzureIoTClient 20:8dec76e7ba34 1690 {
AzureIoTClient 20:8dec76e7ba34 1691 LogError("x509certificate specified, but authentication method is not x509");
AzureIoTClient 20:8dec76e7ba34 1692 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 20:8dec76e7ba34 1693 }
AzureIoTClient 20:8dec76e7ba34 1694 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_008: [ If optionName is x509privatekey and the authentication method is not x509 then IoTHubTransportAMQP_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
AzureIoTClient 21:32a1746384ba 1695 else if ((strcmp(OPTION_X509_PRIVATE_KEY, option) == 0) && (transport_state->credential.credentialType != X509))
AzureIoTClient 20:8dec76e7ba34 1696 {
AzureIoTClient 20:8dec76e7ba34 1697 LogError("x509privatekey specified, but authentication method is not x509");
AzureIoTClient 20:8dec76e7ba34 1698 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 20:8dec76e7ba34 1699 }
Azure.IoT Build 11:62d7b956e76e 1700 // Codes_SRS_IOTHUBTRANSPORTAMQP_09_047: [If the option name does not match one of the options handled by this module, then IoTHubTransportAMQP_SetOption shall get the handle to the XIO and invoke the xio_setoption passing down the option name and value parameters.]
Azure.IoT Build 10:75c5e0d8537d 1701 else
Azure.IoT Build 10:75c5e0d8537d 1702 {
Azure.IoT Build 11:62d7b956e76e 1703 if (transport_state->tls_io == NULL &&
Azure.IoT Build 11:62d7b956e76e 1704 (transport_state->tls_io = transport_state->tls_io_transport_provider(STRING_c_str(transport_state->iotHubHostFqdn), transport_state->iotHubPort)) == NULL)
Azure.IoT Build 11:62d7b956e76e 1705 {
Azure.IoT Build 11:62d7b956e76e 1706 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 13:a4af7c301e02 1707 LogError("Failed to obtain a TLS I/O transport layer.");
Azure.IoT Build 11:62d7b956e76e 1708 }
Azure.IoT Build 11:62d7b956e76e 1709 else
Azure.IoT Build 11:62d7b956e76e 1710 {
AzureIoTClient 20:8dec76e7ba34 1711 /*in the case when a tls_io_transport has been created, replay its options*/
AzureIoTClient 20:8dec76e7ba34 1712 if (transport_state->xioOptions != NULL)
AzureIoTClient 20:8dec76e7ba34 1713 {
AzureIoTClient 20:8dec76e7ba34 1714 if (OptionHandler_FeedOptions(transport_state->xioOptions, transport_state->tls_io) != 0)
AzureIoTClient 20:8dec76e7ba34 1715 {
AzureIoTClient 20:8dec76e7ba34 1716 LogError("unable to replay options to TLS"); /*pessimistically hope TLS will fail, be recreated and options re-given*/
AzureIoTClient 20:8dec76e7ba34 1717 }
AzureIoTClient 20:8dec76e7ba34 1718 else
AzureIoTClient 20:8dec76e7ba34 1719 {
AzureIoTClient 20:8dec76e7ba34 1720 /*everything is fine, forget the saved options...*/
AzureIoTClient 20:8dec76e7ba34 1721 OptionHandler_Destroy(transport_state->xioOptions);
AzureIoTClient 20:8dec76e7ba34 1722 transport_state->xioOptions = NULL;
AzureIoTClient 20:8dec76e7ba34 1723 }
AzureIoTClient 20:8dec76e7ba34 1724 }
AzureIoTClient 20:8dec76e7ba34 1725
AzureIoTClient 19:ea016664011a 1726 /* Codes_SRS_IOTHUBTRANSPORTAMQP_03_001: [If xio_setoption fails, IoTHubTransportAMQP_SetOption shall return IOTHUB_CLIENT_ERROR.] */
Azure.IoT Build 11:62d7b956e76e 1727 if (xio_setoption(transport_state->tls_io, option, value) == 0)
Azure.IoT Build 11:62d7b956e76e 1728 {
Azure.IoT Build 11:62d7b956e76e 1729 result = IOTHUB_CLIENT_OK;
Azure.IoT Build 11:62d7b956e76e 1730 }
Azure.IoT Build 11:62d7b956e76e 1731 else
Azure.IoT Build 11:62d7b956e76e 1732 {
Azure.IoT Build 11:62d7b956e76e 1733 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 20:8dec76e7ba34 1734 LogError("Invalid option (%s) passed to IoTHubTransportAMQP_SetOption", option);
Azure.IoT Build 11:62d7b956e76e 1735 }
Azure.IoT Build 11:62d7b956e76e 1736 }
Azure.IoT Build 10:75c5e0d8537d 1737 }
Azure.IoT Build 10:75c5e0d8537d 1738 }
AzureIoTClient 4:57e049bce51e 1739
AzureIoTClient 4:57e049bce51e 1740 return result;
AzureIoTClient 4:57e049bce51e 1741 }
AzureIoTClient 4:57e049bce51e 1742
AzureIoTClient 14:8e8e42008807 1743 static IOTHUB_DEVICE_HANDLE IoTHubTransportAMQP_Register(TRANSPORT_LL_HANDLE handle, const IOTHUB_DEVICE_CONFIG* device, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, PDLIST_ENTRY waitingToSend)
Azure.IoT Build 10:75c5e0d8537d 1744 {
AzureIoTClient 22:8b70cf813f25 1745 #ifdef NO_LOGGING
AzureIoTClient 22:8b70cf813f25 1746 UNUSED(iotHubClientHandle);
AzureIoTClient 22:8b70cf813f25 1747 #endif
AzureIoTClient 22:8b70cf813f25 1748
Azure.IoT Build 10:75c5e0d8537d 1749 IOTHUB_DEVICE_HANDLE result;
AzureIoTClient 19:ea016664011a 1750 // Codes_SRS_IOTHUBTRANSPORTAMQP_17_001: [IoTHubTransportAMQP_Register shall return NULL if device, or waitingToSend are NULL.]
AzureIoTClient 19:ea016664011a 1751 // Codes_SRS_IOTHUBTRANSPORTAMQP_17_005: [IoTHubTransportAMQP_Register shall return NULL if the TRANSPORT_LL_HANDLE is NULL.]
AzureIoTClient 16:a49121e2300b 1752 if ((handle == NULL) || (device == NULL) || (waitingToSend == NULL))
Azure.IoT Build 10:75c5e0d8537d 1753 {
AzureIoTClient 19:ea016664011a 1754 LogError("invalid parameter TRANSPORT_LL_HANDLE handle=%p, const IOTHUB_DEVICE_CONFIG* device=%p, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle=%p, PDLIST_ENTRY waitingToSend=%p",
AzureIoTClient 19:ea016664011a 1755 handle, device, iotHubClientHandle, waitingToSend);
Azure.IoT Build 10:75c5e0d8537d 1756 result = NULL;
Azure.IoT Build 10:75c5e0d8537d 1757 }
Azure.IoT Build 10:75c5e0d8537d 1758 else
Azure.IoT Build 10:75c5e0d8537d 1759 {
Azure.IoT Build 10:75c5e0d8537d 1760 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)handle;
Azure.IoT Build 10:75c5e0d8537d 1761
AzureIoTClient 19:ea016664011a 1762 // Codes_SRS_IOTHUBTRANSPORTAMQP_03_002: [IoTHubTransportAMQP_Register shall return NULL if deviceId is NULL.**]
AzureIoTClient 19:ea016664011a 1763 if (device->deviceId == NULL)
AzureIoTClient 16:a49121e2300b 1764 {
AzureIoTClient 19:ea016664011a 1765 LogError("invalid parameter device->deviceId was NULL");
AzureIoTClient 16:a49121e2300b 1766 result = NULL;
AzureIoTClient 16:a49121e2300b 1767 }
AzureIoTClient 19:ea016664011a 1768 // Codes_SRS_IOTHUBTRANSPORTAMQP_03_003: [IoTHubTransportAMQP_Register shall return NULL if both deviceKey and deviceSasToken are not NULL.]
AzureIoTClient 20:8dec76e7ba34 1769 else if ((device->deviceSasToken != NULL) && (device->deviceKey != NULL))
AzureIoTClient 16:a49121e2300b 1770 {
AzureIoTClient 19:ea016664011a 1771 LogError("invalid parameter both device->deviceSasToken and device->deviceKey were NULL");
AzureIoTClient 16:a49121e2300b 1772 result = NULL;
AzureIoTClient 16:a49121e2300b 1773 }
AzureIoTClient 16:a49121e2300b 1774 else
AzureIoTClient 16:a49121e2300b 1775 {
AzureIoTClient 16:a49121e2300b 1776 STRING_HANDLE devicesPath = concat3Params(STRING_c_str(transport_state->iotHubHostFqdn), "/devices/", device->deviceId);
AzureIoTClient 19:ea016664011a 1777 if (devicesPath == NULL)
AzureIoTClient 19:ea016664011a 1778 {
AzureIoTClient 16:a49121e2300b 1779 LogError("Could not create devicesPath");
Azure.IoT Build 10:75c5e0d8537d 1780 result = NULL;
Azure.IoT Build 10:75c5e0d8537d 1781 }
Azure.IoT Build 10:75c5e0d8537d 1782 else
Azure.IoT Build 10:75c5e0d8537d 1783 {
AzureIoTClient 19:ea016664011a 1784 // Codes_SRS_IOTHUBTRANSPORTAMQP_17_002: [IoTHubTransportAMQP_Register shall return NULL if deviceId or deviceKey do not match the deviceId and deviceKey passed in during IoTHubTransportAMQP_Create.]
AzureIoTClient 19:ea016664011a 1785 if (strcmp(STRING_c_str(transport_state->devicesPath), STRING_c_str(devicesPath)) != 0)
Azure.IoT Build 10:75c5e0d8537d 1786 {
AzureIoTClient 19:ea016664011a 1787 LogError("Attemping to add new device to AMQP transport, not allowed.");
AzureIoTClient 19:ea016664011a 1788 result = NULL;
AzureIoTClient 19:ea016664011a 1789 }
AzureIoTClient 19:ea016664011a 1790 else if ((transport_state->credential.credentialType == DEVICE_KEY) && strcmp(STRING_c_str(transport_state->credential.credential.deviceKey), device->deviceKey) != 0)
AzureIoTClient 19:ea016664011a 1791 {
AzureIoTClient 19:ea016664011a 1792 LogError("Attemping to add new device to AMQP transport, not allowed.");
Azure.IoT Build 10:75c5e0d8537d 1793 result = NULL;
Azure.IoT Build 10:75c5e0d8537d 1794 }
Azure.IoT Build 10:75c5e0d8537d 1795 else
Azure.IoT Build 10:75c5e0d8537d 1796 {
AzureIoTClient 19:ea016664011a 1797 if (transport_state->isRegistered == true)
AzureIoTClient 19:ea016664011a 1798 {
AzureIoTClient 19:ea016664011a 1799 LogError("Transport already has device registered by id: [%s]", device->deviceId);
AzureIoTClient 19:ea016664011a 1800 result = NULL;
AzureIoTClient 19:ea016664011a 1801 }
AzureIoTClient 19:ea016664011a 1802 else
AzureIoTClient 19:ea016664011a 1803 {
AzureIoTClient 19:ea016664011a 1804 transport_state->isRegistered = true;
AzureIoTClient 19:ea016664011a 1805 // Codes_SRS_IOTHUBTRANSPORTAMQP_17_003: [IoTHubTransportAMQP_Register shall return the TRANSPORT_LL_HANDLE as the IOTHUB_DEVICE_HANDLE.]
AzureIoTClient 19:ea016664011a 1806 result = (IOTHUB_DEVICE_HANDLE)handle;
AzureIoTClient 19:ea016664011a 1807 }
Azure.IoT Build 10:75c5e0d8537d 1808 }
AzureIoTClient 19:ea016664011a 1809 STRING_delete(devicesPath);
Azure.IoT Build 10:75c5e0d8537d 1810 }
Azure.IoT Build 10:75c5e0d8537d 1811 }
Azure.IoT Build 10:75c5e0d8537d 1812 }
Azure.IoT Build 10:75c5e0d8537d 1813
Azure.IoT Build 10:75c5e0d8537d 1814 return result;
Azure.IoT Build 10:75c5e0d8537d 1815 }
Azure.IoT Build 10:75c5e0d8537d 1816
AzureIoTClient 19:ea016664011a 1817 // Codes_SRS_IOTHUBTRANSPORTAMQP_17_004: [IoTHubTransportAMQP_Unregister shall return.]
Azure.IoT Build 12:841a4c36bd36 1818 static void IoTHubTransportAMQP_Unregister(IOTHUB_DEVICE_HANDLE deviceHandle)
Azure.IoT Build 10:75c5e0d8537d 1819 {
Azure.IoT Build 10:75c5e0d8537d 1820 if (deviceHandle != NULL)
Azure.IoT Build 10:75c5e0d8537d 1821 {
Azure.IoT Build 10:75c5e0d8537d 1822 AMQP_TRANSPORT_INSTANCE* transport_state = (AMQP_TRANSPORT_INSTANCE*)deviceHandle;
Azure.IoT Build 10:75c5e0d8537d 1823
Azure.IoT Build 10:75c5e0d8537d 1824 transport_state->isRegistered = false;
Azure.IoT Build 10:75c5e0d8537d 1825 }
Azure.IoT Build 10:75c5e0d8537d 1826 }
Azure.IoT Build 10:75c5e0d8537d 1827
AzureIoTClient 17:597443dc65a4 1828 static STRING_HANDLE IoTHubTransportAMQP_GetHostname(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 17:597443dc65a4 1829 {
AzureIoTClient 17:597443dc65a4 1830 STRING_HANDLE result;
AzureIoTClient 17:597443dc65a4 1831 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_001: [ If parameter handle is NULL then IoTHubTransportAMQP_GetHostname shall return NULL. ]*/
AzureIoTClient 17:597443dc65a4 1832 if (handle == NULL)
AzureIoTClient 17:597443dc65a4 1833 {
AzureIoTClient 17:597443dc65a4 1834 result = NULL;
AzureIoTClient 17:597443dc65a4 1835 }
AzureIoTClient 17:597443dc65a4 1836 else
AzureIoTClient 17:597443dc65a4 1837 {
AzureIoTClient 17:597443dc65a4 1838 /*Codes_SRS_IOTHUBTRANSPORTAMQP_02_002: [ Otherwise IoTHubTransportAMQP_GetHostname shall return a STRING_HANDLE for the hostname. ]*/
AzureIoTClient 17:597443dc65a4 1839 result = ((AMQP_TRANSPORT_INSTANCE*)(handle))->iotHubHostFqdn;
AzureIoTClient 17:597443dc65a4 1840 }
AzureIoTClient 17:597443dc65a4 1841 return result;
AzureIoTClient 17:597443dc65a4 1842 }
AzureIoTClient 17:597443dc65a4 1843
Azure.IoT Build 7:07bc440836b3 1844 static TRANSPORT_PROVIDER thisTransportProvider = {
AzureIoTClient 17:597443dc65a4 1845 IoTHubTransportAMQP_GetHostname,
Azure.IoT Build 11:62d7b956e76e 1846 IoTHubTransportAMQP_SetOption,
Azure.IoT Build 11:62d7b956e76e 1847 IoTHubTransportAMQP_Create,
Azure.IoT Build 11:62d7b956e76e 1848 IoTHubTransportAMQP_Destroy,
Azure.IoT Build 12:841a4c36bd36 1849 IoTHubTransportAMQP_Register,
Azure.IoT Build 12:841a4c36bd36 1850 IoTHubTransportAMQP_Unregister,
Azure.IoT Build 11:62d7b956e76e 1851 IoTHubTransportAMQP_Subscribe,
Azure.IoT Build 11:62d7b956e76e 1852 IoTHubTransportAMQP_Unsubscribe,
Azure.IoT Build 11:62d7b956e76e 1853 IoTHubTransportAMQP_DoWork,
Azure.IoT Build 7:07bc440836b3 1854 IoTHubTransportAMQP_GetSendStatus
AzureIoTClient 4:57e049bce51e 1855 };
AzureIoTClient 4:57e049bce51e 1856
AzureIoTClient 17:597443dc65a4 1857 extern const TRANSPORT_PROVIDER* AMQP_Protocol(void)
AzureIoTClient 4:57e049bce51e 1858 {
Azure.IoT Build 7:07bc440836b3 1859 return &thisTransportProvider;
AzureIoTClient 4:57e049bce51e 1860 }