Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: azure_umqtt_c iothub_mqtt_transport mbed-rtos mbed wolfSSL Socket lwip-eth lwip-sys lwip
iothub_client_ll.c
00001 // Copyright (c) Microsoft. All rights reserved. 00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 00003 00004 #include <stdlib.h> 00005 #ifdef _CRTDBG_MAP_ALLOC 00006 #include <crtdbg.h> 00007 #endif 00008 #include <string.h> 00009 #include "azure_c_shared_utility/gballoc.h" 00010 #include "azure_c_shared_utility/string_tokenizer.h" 00011 #include "azure_c_shared_utility/doublylinkedlist.h" 00012 #include "azure_c_shared_utility/xlogging.h" 00013 #include "azure_c_shared_utility/tickcounter.h" 00014 #include "azure_c_shared_utility/constbuffer.h" 00015 00016 #include "iothub_client_ll.h" 00017 #include "iothub_client_private.h" 00018 #include "iothub_client_version.h" 00019 #include "iothub_transport_ll.h" 00020 #include <stdint.h> 00021 00022 #ifndef DONT_USE_UPLOADTOBLOB 00023 #include "iothub_client_ll_uploadtoblob.h" 00024 #endif 00025 00026 #define LOG_ERROR_RESULT LogError("result = %s", ENUM_TO_STRING(IOTHUB_CLIENT_RESULT, result)); 00027 #define INDEFINITE_TIME ((time_t)(-1)) 00028 00029 DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES); 00030 DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_CONFIRMATION_RESULT, IOTHUB_CLIENT_CONFIRMATION_RESULT_VALUES); 00031 00032 typedef struct IOTHUB_CLIENT_LL_HANDLE_DATA_TAG 00033 { 00034 DLIST_ENTRY waitingToSend; 00035 DLIST_ENTRY iot_msg_queue; 00036 DLIST_ENTRY iot_ack_queue; 00037 TRANSPORT_LL_HANDLE transportHandle; 00038 bool isSharedTransport; 00039 IOTHUB_DEVICE_HANDLE deviceHandle; 00040 TRANSPORT_PROVIDER_FIELDS; 00041 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback; 00042 void* messageUserContextCallback; 00043 IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK conStatusCallback; 00044 void* conStatusUserContextCallback; 00045 time_t lastMessageReceiveTime; 00046 TICK_COUNTER_HANDLE tickCounter; /*shared tickcounter used to track message timeouts in waitingToSend list*/ 00047 uint64_t currentMessageTimeout; 00048 uint64_t current_device_twin_timeout; 00049 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback; 00050 void* deviceTwinContextCallback; 00051 IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC deviceMethodCallback; 00052 void* deviceMethodUserContextCallback; 00053 IOTHUB_CLIENT_RETRY_POLICY retryPolicy; 00054 size_t retryTimeoutLimitInSeconds; 00055 #ifndef DONT_USE_UPLOADTOBLOB 00056 IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE uploadToBlobHandle; 00057 #endif 00058 uint32_t data_msg_id; 00059 bool complete_twin_update_encountered; 00060 }IOTHUB_CLIENT_LL_HANDLE_DATA; 00061 00062 static const char HOSTNAME_TOKEN[] = "HostName"; 00063 static const char DEVICEID_TOKEN[] = "DeviceId"; 00064 static const char X509_TOKEN[] = "x509"; 00065 static const char X509_TOKEN_ONLY_ACCEPTABLE_VALUE[] = "true"; 00066 static const char DEVICEKEY_TOKEN[] = "SharedAccessKey"; 00067 static const char DEVICESAS_TOKEN[] = "SharedAccessSignature"; 00068 static const char PROTOCOL_GATEWAY_HOST[] = "GatewayHostName"; 00069 00070 static void device_twin_data_destroy(IOTHUB_DEVICE_TWIN* client_item) 00071 { 00072 CONSTBUFFER_Destroy(client_item->report_data_handle); 00073 free(client_item); 00074 } 00075 00076 static uint32_t get_next_item_id(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData) 00077 { 00078 if (handleData->data_msg_id+1 >= UINT32_MAX) 00079 { 00080 handleData->data_msg_id = 1; 00081 } 00082 else 00083 { 00084 handleData->data_msg_id++; 00085 } 00086 return handleData->data_msg_id; 00087 } 00088 00089 static IOTHUB_DEVICE_TWIN* dev_twin_data_create(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData, uint32_t id, const unsigned char* reportedState, size_t size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback, void* userContextCallback) 00090 { 00091 IOTHUB_DEVICE_TWIN* result = (IOTHUB_DEVICE_TWIN*)malloc(sizeof(IOTHUB_DEVICE_TWIN) ); 00092 if (result != NULL) 00093 { 00094 result->report_data_handle = CONSTBUFFER_Create(reportedState, size); 00095 if (result->report_data_handle == NULL) 00096 { 00097 LogError("Failure allocating reported state data"); 00098 free(result); 00099 result = NULL; 00100 } 00101 else if (tickcounter_get_current_ms(handleData->tickCounter, &result->ms_timesOutAfter) != 0) 00102 { 00103 LogError("Failure getting tickcount info"); 00104 CONSTBUFFER_Destroy(result->report_data_handle); 00105 free(result); 00106 result = NULL; 00107 } 00108 else 00109 { 00110 result->item_id = id; 00111 result->ms_timesOutAfter = 0; 00112 result->context = userContextCallback; 00113 result->reported_state_callback = reportedStateCallback; 00114 } 00115 } 00116 else 00117 { 00118 LogError("Failure allocating device twin information"); 00119 } 00120 return result; 00121 } 00122 00123 IOTHUB_CLIENT_LL_HANDLE IoTHubClient_LL_CreateFromConnectionString(const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) 00124 { 00125 IOTHUB_CLIENT_LL_HANDLE result; 00126 00127 /*Codes_SRS_IOTHUBCLIENT_LL_05_001: [IoTHubClient_LL_CreateFromConnectionString shall obtain the version string by a call to IoTHubClient_GetVersionString.]*/ 00128 /*Codes_SRS_IOTHUBCLIENT_LL_05_002: [IoTHubClient_LL_CreateFromConnectionString shall print the version string to standard output.]*/ 00129 LogInfo("IoT Hub SDK for C, version %s", IoTHubClient_GetVersionString()); 00130 00131 /* Codes_SRS_IOTHUBCLIENT_LL_12_003: [IoTHubClient_LL_CreateFromConnectionString shall verify the input parameter and if it is NULL then return NULL] */ 00132 if (connectionString == NULL) 00133 { 00134 LogError("Input parameter is NULL: connectionString"); 00135 result = NULL; 00136 } 00137 else if (protocol == NULL) 00138 { 00139 LogError("Input parameter is NULL: protocol"); 00140 result = NULL; 00141 } 00142 else 00143 { 00144 /* Codes_SRS_IOTHUBCLIENT_LL_12_004: [IoTHubClient_LL_CreateFromConnectionString shall allocate IOTHUB_CLIENT_CONFIG structure] */ 00145 IOTHUB_CLIENT_CONFIG* config = (IOTHUB_CLIENT_CONFIG*) malloc(sizeof(IOTHUB_CLIENT_CONFIG)); 00146 if (config == NULL) 00147 { 00148 /* Codes_SRS_IOTHUBCLIENT_LL_12_012: [If the allocation failed IoTHubClient_LL_CreateFromConnectionString returns NULL] */ 00149 LogError("Malloc failed"); 00150 result = NULL; 00151 } 00152 else 00153 { 00154 STRING_TOKENIZER_HANDLE tokenizer1 = NULL; 00155 STRING_HANDLE connString = NULL; 00156 STRING_HANDLE tokenString = NULL; 00157 STRING_HANDLE valueString = NULL; 00158 STRING_HANDLE hostNameString = NULL; 00159 STRING_HANDLE hostSuffixString = NULL; 00160 STRING_HANDLE deviceIdString = NULL; 00161 STRING_HANDLE deviceKeyString = NULL; 00162 STRING_HANDLE deviceSasTokenString = NULL; 00163 STRING_HANDLE protocolGateway = NULL; 00164 00165 config->protocol = protocol; 00166 00167 config->iotHubName = NULL; 00168 config->iotHubSuffix = NULL; 00169 config->deviceId = NULL; 00170 config->deviceKey = NULL; 00171 config->deviceSasToken = NULL; 00172 00173 /* Codes_SRS_IOTHUBCLIENT_LL_04_002: [If it does not, it shall pass the protocolGatewayHostName NULL.] */ 00174 config->protocolGatewayHostName = NULL; 00175 00176 if ((connString = STRING_construct(connectionString)) == NULL) 00177 { 00178 LogError("Error constructing connectiong String"); 00179 result = NULL; 00180 } 00181 else if ((tokenizer1 = STRING_TOKENIZER_create(connString)) == NULL) 00182 { 00183 LogError("Error creating Tokenizer"); 00184 result = NULL; 00185 } 00186 else if ((tokenString = STRING_new()) == NULL) 00187 { 00188 LogError("Error creating Token String"); 00189 result = NULL; 00190 } 00191 else if ((valueString = STRING_new()) == NULL) 00192 { 00193 LogError("Error creating Value String"); 00194 result = NULL; 00195 } 00196 else if ((hostNameString = STRING_new()) == NULL) 00197 { 00198 LogError("Error creating HostName String"); 00199 result = NULL; 00200 } 00201 else if ((hostSuffixString = STRING_new()) == NULL) 00202 { 00203 LogError("Error creating HostSuffix String"); 00204 result = NULL; 00205 } 00206 /* Codes_SRS_IOTHUBCLIENT_LL_12_005: [IoTHubClient_LL_CreateFromConnectionString shall try to parse the connectionString input parameter for the following structure: "Key1=value1;key2=value2;key3=value3..."] */ 00207 /* Codes_SRS_IOTHUBCLIENT_LL_12_006: [IoTHubClient_LL_CreateFromConnectionString shall verify the existence of the following Key/Value pairs in the connection string: HostName, DeviceId, SharedAccessKey, SharedAccessSignature or x509] */ 00208 else 00209 { 00210 int isx509found = 0; 00211 while ((STRING_TOKENIZER_get_next_token(tokenizer1, tokenString, "=") == 0)) 00212 { 00213 if (STRING_TOKENIZER_get_next_token(tokenizer1, valueString, ";") != 0) 00214 { 00215 LogError("Tokenizer error"); 00216 break; 00217 } 00218 else 00219 { 00220 if (tokenString != NULL) 00221 { 00222 /* Codes_SRS_IOTHUBCLIENT_LL_12_010: [IoTHubClient_LL_CreateFromConnectionString shall fill up the IOTHUB_CLIENT_CONFIG structure using the following mapping: iotHubName = Name, iotHubSuffix = Suffix, deviceId = DeviceId, deviceKey = SharedAccessKey or deviceSasToken = SharedAccessSignature] */ 00223 const char* s_token = STRING_c_str(tokenString); 00224 if (strcmp(s_token, HOSTNAME_TOKEN) == 0) 00225 { 00226 /* Codes_SRS_IOTHUBCLIENT_LL_12_009: [IoTHubClient_LL_CreateFromConnectionString shall split the value of HostName to Name and Suffix using the first "." as a separator] */ 00227 STRING_TOKENIZER_HANDLE tokenizer2 = NULL; 00228 if ((tokenizer2 = STRING_TOKENIZER_create(valueString)) == NULL) 00229 { 00230 LogError("Error creating Tokenizer"); 00231 break; 00232 } 00233 else 00234 { 00235 /* Codes_SRS_IOTHUBCLIENT_LL_12_015: [If the string split failed, IoTHubClient_LL_CreateFromConnectionString returns NULL ] */ 00236 if (STRING_TOKENIZER_get_next_token(tokenizer2, hostNameString, ".") != 0) 00237 { 00238 LogError("Tokenizer error"); 00239 STRING_TOKENIZER_destroy(tokenizer2); 00240 break; 00241 } 00242 else 00243 { 00244 config->iotHubName = STRING_c_str(hostNameString); 00245 if (STRING_TOKENIZER_get_next_token(tokenizer2, hostSuffixString, ";") != 0) 00246 { 00247 LogError("Tokenizer error"); 00248 STRING_TOKENIZER_destroy(tokenizer2); 00249 break; 00250 } 00251 else 00252 { 00253 config->iotHubSuffix = STRING_c_str(hostSuffixString); 00254 } 00255 } 00256 STRING_TOKENIZER_destroy(tokenizer2); 00257 } 00258 } 00259 else if (strcmp(s_token, DEVICEID_TOKEN) == 0) 00260 { 00261 deviceIdString = STRING_clone(valueString); 00262 if (deviceIdString != NULL) 00263 { 00264 config->deviceId = STRING_c_str(deviceIdString); 00265 } 00266 else 00267 { 00268 LogError("Failure cloning device id string"); 00269 break; 00270 } 00271 } 00272 else if (strcmp(s_token, DEVICEKEY_TOKEN) == 0) 00273 { 00274 deviceKeyString = STRING_clone(valueString); 00275 if (deviceKeyString != NULL) 00276 { 00277 config->deviceKey = STRING_c_str(deviceKeyString); 00278 } 00279 else 00280 { 00281 LogError("Failure cloning device key string"); 00282 break; 00283 } 00284 } 00285 else if (strcmp(s_token, DEVICESAS_TOKEN) == 0) 00286 { 00287 deviceSasTokenString = STRING_clone(valueString); 00288 if (deviceSasTokenString != NULL) 00289 { 00290 config->deviceSasToken = STRING_c_str(deviceSasTokenString); 00291 } 00292 else 00293 { 00294 LogError("Failure cloning device sasToken string"); 00295 break; 00296 } 00297 } 00298 else if (strcmp(s_token, X509_TOKEN) == 0) 00299 { 00300 if (strcmp(STRING_c_str(valueString), X509_TOKEN_ONLY_ACCEPTABLE_VALUE) != 0) 00301 { 00302 LogError("x509 option has wrong value, the only acceptable one is \"true\""); 00303 break; 00304 } 00305 else 00306 { 00307 isx509found = 1; 00308 } 00309 } 00310 /* Codes_SRS_IOTHUBCLIENT_LL_04_001: [IoTHubClient_LL_CreateFromConnectionString shall verify the existence of key/value pair GatewayHostName. If it does exist it shall pass the value to IoTHubClient_LL_Create API.] */ 00311 else if (strcmp(s_token, PROTOCOL_GATEWAY_HOST) == 0) 00312 { 00313 protocolGateway = STRING_clone(valueString); 00314 if (protocolGateway != NULL) 00315 { 00316 config->protocolGatewayHostName = STRING_c_str(protocolGateway); 00317 } 00318 else 00319 { 00320 LogError("Failure cloning protocol Gateway Name"); 00321 break; 00322 } 00323 } 00324 } 00325 } 00326 } 00327 /* parsing is done - check the result */ 00328 if (config->iotHubName == NULL) 00329 { 00330 LogError("iotHubName is not found"); 00331 result = NULL; 00332 } 00333 else if (config->iotHubSuffix == NULL) 00334 { 00335 LogError("iotHubSuffix is not found"); 00336 result = NULL; 00337 } 00338 else if (config->deviceId == NULL) 00339 { 00340 LogError("deviceId is not found"); 00341 result = NULL; 00342 } 00343 else if (!( 00344 ((!isx509found) && (config->deviceSasToken == NULL) ^ (config->deviceKey == NULL)) || 00345 ((isx509found) && (config->deviceSasToken == NULL) && (config->deviceKey == NULL)) 00346 )) 00347 { 00348 LogError("invalid combination of x509, deviceSasToken and deviceKey"); 00349 result = NULL; 00350 } 00351 else 00352 { 00353 /* Codes_SRS_IOTHUBCLIENT_LL_12_011: [IoTHubClient_LL_CreateFromConnectionString shall call into the IoTHubClient_LL_Create API with the current structure and returns with the return value of it] */ 00354 00355 result = IoTHubClient_LL_Create(config); 00356 if (result == NULL) 00357 { 00358 LogError("IoTHubClient_LL_Create failed"); 00359 } 00360 else 00361 { 00362 /*return as is*/ 00363 } 00364 } 00365 } 00366 if (deviceSasTokenString != NULL) 00367 STRING_delete(deviceSasTokenString); 00368 if (deviceKeyString != NULL) 00369 STRING_delete(deviceKeyString); 00370 if (deviceIdString != NULL) 00371 STRING_delete(deviceIdString); 00372 if (hostSuffixString != NULL) 00373 STRING_delete(hostSuffixString); 00374 if (hostNameString != NULL) 00375 STRING_delete(hostNameString); 00376 if (valueString != NULL) 00377 STRING_delete(valueString); 00378 if (tokenString != NULL) 00379 STRING_delete(tokenString); 00380 if (connString != NULL) 00381 STRING_delete(connString); 00382 if (protocolGateway != NULL) 00383 STRING_delete(protocolGateway); 00384 00385 if (tokenizer1 != NULL) 00386 STRING_TOKENIZER_destroy(tokenizer1); 00387 00388 free(config); 00389 } 00390 } 00391 return result; 00392 } 00393 00394 static void setTransportProtocol(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData, TRANSPORT_PROVIDER* protocol) 00395 { 00396 handleData->IoTHubTransport_GetHostname = protocol->IoTHubTransport_GetHostname; 00397 handleData->IoTHubTransport_SetOption = protocol->IoTHubTransport_SetOption; 00398 handleData->IoTHubTransport_Create = protocol->IoTHubTransport_Create; 00399 handleData->IoTHubTransport_Destroy = protocol->IoTHubTransport_Destroy; 00400 handleData->IoTHubTransport_Register = protocol->IoTHubTransport_Register; 00401 handleData->IoTHubTransport_Unregister = protocol->IoTHubTransport_Unregister; 00402 handleData->IoTHubTransport_Subscribe = protocol->IoTHubTransport_Subscribe; 00403 handleData->IoTHubTransport_Unsubscribe = protocol->IoTHubTransport_Unsubscribe; 00404 handleData->IoTHubTransport_DoWork = protocol->IoTHubTransport_DoWork; 00405 handleData->IoTHubTransport_SetRetryPolicy = protocol->IoTHubTransport_SetRetryPolicy; 00406 handleData->IoTHubTransport_GetSendStatus = protocol->IoTHubTransport_GetSendStatus; 00407 handleData->IoTHubTransport_ProcessItem = protocol->IoTHubTransport_ProcessItem; 00408 handleData->IoTHubTransport_Subscribe_DeviceTwin = protocol->IoTHubTransport_Subscribe_DeviceTwin; 00409 handleData->IoTHubTransport_Unsubscribe_DeviceTwin = protocol->IoTHubTransport_Unsubscribe_DeviceTwin; 00410 handleData->IoTHubTransport_Subscribe_DeviceMethod = protocol->IoTHubTransport_Subscribe_DeviceMethod; 00411 handleData->IoTHubTransport_Unsubscribe_DeviceMethod = protocol->IoTHubTransport_Unsubscribe_DeviceMethod; 00412 } 00413 00414 IOTHUB_CLIENT_LL_HANDLE IoTHubClient_LL_Create(const IOTHUB_CLIENT_CONFIG* config) 00415 { 00416 IOTHUB_CLIENT_LL_HANDLE result; 00417 /*Codes_SRS_IOTHUBCLIENT_LL_02_001: [IoTHubClient_LL_Create shall return NULL if config parameter is NULL or protocol field is NULL.]*/ 00418 if( 00419 (config == NULL) || 00420 (config->protocol == NULL) 00421 ) 00422 { 00423 result = NULL; 00424 LogError("invalid configuration (NULL detected)"); 00425 } 00426 else 00427 { 00428 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)malloc(sizeof(IOTHUB_CLIENT_LL_HANDLE_DATA)); 00429 if (handleData == NULL) 00430 { 00431 LogError("malloc failed"); 00432 result = NULL; 00433 } 00434 else 00435 { 00436 #ifndef DONT_USE_UPLOADTOBLOB 00437 /*Codes_SRS_IOTHUBCLIENT_LL_02_094: [ IoTHubClient_LL_Create shall create a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE from IOTHUB_CLIENT_CONFIG. ]*/ 00438 /*Codes_SRS_IOTHUBCLIENT_LL_02_092: [ IoTHubClient_LL_CreateFromConnectionString shall create a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE from IOTHUB_CLIENT_CONFIG. ]*/ 00439 handleData->uploadToBlobHandle = IoTHubClient_LL_UploadToBlob_Create(config); 00440 if (handleData->uploadToBlobHandle == NULL) 00441 { 00442 /*Codes_SRS_IOTHUBCLIENT_LL_02_093: [ If creating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateFromConnectionString shall fail and return NULL. ]*/ 00443 /*Codes_SRS_IOTHUBCLIENT_LL_02_095: [ If creating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_Create shall fail and return NULL. ]*/ 00444 LogError("unable to IoTHubClient_LL_UploadToBlob_Create"); 00445 free(handleData); 00446 result = NULL; 00447 } 00448 else 00449 #endif 00450 { 00451 /*Codes_SRS_IOTHUBCLIENT_LL_02_045: [ Otherwise IoTHubClient_LL_Create shall create a new TICK_COUNTER_HANDLE ]*/ 00452 if ((handleData->tickCounter = tickcounter_create()) == NULL) 00453 { 00454 #ifndef DONT_USE_UPLOADTOBLOB 00455 /*Codes_SRS_IOTHUBCLIENT_LL_02_046: [ If creating the TICK_COUNTER_HANDLE fails then IoTHubClient_LL_Create shall fail and return NULL. ]*/ 00456 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); 00457 #endif 00458 LogError("unable to get a tickcounter"); 00459 free(handleData); 00460 result = NULL; 00461 } 00462 else 00463 { 00464 /*Codes_SRS_IOTHUBCLIENT_LL_02_004: [Otherwise IoTHubClient_LL_Create shall initialize a new DLIST (further called "waitingToSend") containing records with fields of the following types: IOTHUB_MESSAGE_HANDLE, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, void*.]*/ 00465 IOTHUBTRANSPORT_CONFIG lowerLayerConfig; 00466 DList_InitializeListHead(&(handleData->waitingToSend)); 00467 DList_InitializeListHead(&(handleData->iot_msg_queue)); 00468 DList_InitializeListHead(&(handleData->iot_ack_queue)); 00469 setTransportProtocol(handleData, (TRANSPORT_PROVIDER*)config->protocol()); 00470 handleData->messageCallback = NULL; 00471 handleData->messageUserContextCallback = NULL; 00472 handleData->deviceTwinCallback = NULL; 00473 handleData->deviceTwinContextCallback = NULL; 00474 handleData->deviceMethodCallback = NULL; 00475 handleData->deviceMethodUserContextCallback = NULL; 00476 handleData->lastMessageReceiveTime = INDEFINITE_TIME; 00477 handleData->data_msg_id = 1; 00478 handleData->complete_twin_update_encountered = false; 00479 handleData->conStatusCallback = NULL; 00480 handleData->conStatusUserContextCallback = NULL; 00481 handleData->lastMessageReceiveTime = INDEFINITE_TIME; 00482 00483 /*Codes_SRS_IOTHUBCLIENT_LL_02_006: [IoTHubClient_LL_Create shall populate a structure of type IOTHUBTRANSPORT_CONFIG with the information from config parameter and the previous DLIST and shall pass that to the underlying layer _Create function.]*/ 00484 lowerLayerConfig.upperConfig = config; 00485 lowerLayerConfig.waitingToSend = &(handleData->waitingToSend); 00486 /*Codes_SRS_IOTHUBCLIENT_LL_02_007: [If the underlaying layer _Create function fails them IoTHubClient_LL_Create shall fail and return NULL.] */ 00487 if ((handleData->transportHandle = handleData->IoTHubTransport_Create(&lowerLayerConfig)) == NULL) 00488 { 00489 LogError("underlying transport failed"); 00490 #ifndef DONT_USE_UPLOADTOBLOB 00491 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); 00492 #endif 00493 tickcounter_destroy(handleData->tickCounter); 00494 free(handleData); 00495 result = NULL; 00496 } 00497 else 00498 { 00499 IOTHUB_DEVICE_CONFIG deviceConfig; 00500 00501 deviceConfig.deviceId = config->deviceId; 00502 deviceConfig.deviceKey = config->deviceKey; 00503 deviceConfig.deviceSasToken = config->deviceSasToken; 00504 00505 /*Codes_SRS_IOTHUBCLIENT_LL_17_008: [IoTHubClient_LL_Create shall call the transport _Register function with a populated structure of type IOTHUB_DEVICE_CONFIG and waitingToSend list.] */ 00506 if ((handleData->deviceHandle = handleData->IoTHubTransport_Register(handleData->transportHandle, &deviceConfig, handleData, &(handleData->waitingToSend))) == NULL) 00507 { 00508 /*Codes_SRS_IOTHUBCLIENT_LL_17_009: [If the _Register function fails, this function shall fail and return NULL.]*/ 00509 LogError("Registering device in transport failed"); 00510 handleData->IoTHubTransport_Destroy(handleData->transportHandle); 00511 #ifndef DONT_USE_UPLOADTOBLOB 00512 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); 00513 #endif 00514 tickcounter_destroy(handleData->tickCounter); 00515 free(handleData); 00516 result = NULL; 00517 } 00518 else 00519 { 00520 /*Codes_SRS_IOTHUBCLIENT_LL_02_008: [Otherwise, IoTHubClient_LL_Create shall succeed and return a non-NULL handle.] */ 00521 handleData->isSharedTransport = false; 00522 /*Codes_SRS_IOTHUBCLIENT_LL_02_042: [ By default, messages shall not timeout. ]*/ 00523 handleData->currentMessageTimeout = 0; 00524 handleData->current_device_twin_timeout = 0; 00525 result = handleData; 00526 /*Codes_SRS_IOTHUBCLIENT_LL_25_124: [ `IoTHubClient_LL_Create` shall set the default retry policy as Exponential backoff with jitter and if succeed and return a `non-NULL` handle. ]*/ 00527 if (IoTHubClient_LL_SetRetryPolicy(handleData, IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER, 0) != IOTHUB_CLIENT_OK) 00528 { 00529 LogError("Setting default retry policy in transport failed"); 00530 IoTHubClient_LL_Destroy(handleData); 00531 result = NULL; 00532 } 00533 } 00534 } 00535 } 00536 } 00537 } 00538 } 00539 00540 return result; 00541 } 00542 00543 IOTHUB_CLIENT_LL_HANDLE IoTHubClient_LL_CreateWithTransport(const IOTHUB_CLIENT_DEVICE_CONFIG * config) 00544 { 00545 IOTHUB_CLIENT_LL_HANDLE result; 00546 /*Codes_SRS_IOTHUBCLIENT_LL_17_001: [IoTHubClient_LL_CreateWithTransport shall return NULL if config parameter is NULL, or protocol field is NULL or transportHandle is NULL.]*/ 00547 if ( 00548 (config == NULL) || 00549 (config->protocol == NULL) || 00550 (config->transportHandle == NULL) || 00551 /*Codes_SRS_IOTHUBCLIENT_LL_02_098: [ IoTHubClient_LL_CreateWithTransport shall fail and return NULL if both config->deviceKey AND config->deviceSasToken are NULL. ]*/ 00552 ((config->deviceKey == NULL) && (config->deviceSasToken == NULL)) 00553 ) 00554 { 00555 result = NULL; 00556 LogError("invalid configuration (NULL detected)"); 00557 } 00558 else 00559 { 00560 /*Codes_SRS_IOTHUBCLIENT_LL_17_002: [IoTHubClient_LL_CreateWithTransport shall allocate data for the IOTHUB_CLIENT_LL_HANDLE.]*/ 00561 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)malloc(sizeof(IOTHUB_CLIENT_LL_HANDLE_DATA)); 00562 if (handleData == NULL) 00563 { 00564 /*Codes_SRS_IOTHUBCLIENT_LL_17_003: [If allocation fails, the function shall fail and return NULL.] */ 00565 LogError("malloc failed"); 00566 result = NULL; 00567 } 00568 else 00569 { 00570 handleData->transportHandle = config->transportHandle; 00571 setTransportProtocol(handleData, (TRANSPORT_PROVIDER*)config->protocol()); 00572 00573 #ifndef DONT_USE_UPLOADTOBLOB 00574 const char* hostname = STRING_c_str(handleData->IoTHubTransport_GetHostname(handleData->transportHandle)); 00575 /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClient_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/ 00576 /*the first '.' says where the iothubname finishes*/ 00577 const char* whereIsDot = strchr(hostname, '.'); 00578 if (whereIsDot == NULL) 00579 { 00580 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateWithTransport shall fail and return NULL. ]*/ 00581 LogError("unable to determine the IoTHub name"); 00582 free(handleData); 00583 result = NULL; 00584 } 00585 else 00586 { 00587 /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClient_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/ 00588 char* IoTHubName = (char*) malloc(whereIsDot - hostname + 1); 00589 if (IoTHubName == NULL) 00590 { 00591 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateWithTransport shall fail and return NULL. ]*/ 00592 LogError("unable to malloc"); 00593 free(handleData); 00594 result = NULL; 00595 } 00596 else 00597 { 00598 const char* IotHubSuffix = whereIsDot + 1; 00599 memcpy(IoTHubName, hostname, whereIsDot - hostname); 00600 IoTHubName[whereIsDot - hostname ] = '\0'; 00601 00602 IOTHUB_CLIENT_CONFIG temp; 00603 temp.deviceId = config->deviceId; 00604 temp.deviceKey = config->deviceKey; 00605 temp.deviceSasToken = config->deviceSasToken; 00606 temp.iotHubName = IoTHubName; 00607 temp.iotHubSuffix = IotHubSuffix; 00608 temp.protocol = NULL; /*irrelevant to IoTHubClient_LL_UploadToBlob*/ 00609 temp.protocolGatewayHostName = NULL; /*irrelevant to IoTHubClient_LL_UploadToBlob*/ 00610 00611 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClient_LL_CreateWithTransport shall fail and return NULL. ]*/ 00612 handleData->uploadToBlobHandle = IoTHubClient_LL_UploadToBlob_Create(&temp); 00613 if (handleData->uploadToBlobHandle == NULL) 00614 { 00615 /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClient_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/ 00616 LogError("unable to IoTHubClient_LL_UploadToBlob_Create"); 00617 free(handleData); 00618 result = NULL; 00619 } 00620 else 00621 #endif 00622 { 00623 /*Codes_SRS_IOTHUBCLIENT_LL_02_047: [ IoTHubClient_LL_CreateWithTransport shall create a TICK_COUNTER_HANDLE. ]*/ 00624 if ((handleData->tickCounter = tickcounter_create()) == NULL) 00625 { 00626 /*Codes_SRS_IOTHUBCLIENT_LL_02_048: [ If creating the handle fails, then IoTHubClient_LL_CreateWithTransport shall fail and return NULL ]*/ 00627 LogError("unable to get a tickcounter"); 00628 #ifndef DONT_USE_UPLOADTOBLOB 00629 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); 00630 #endif 00631 free(handleData); 00632 result = NULL; 00633 } 00634 else 00635 { 00636 /*Codes_SRS_IOTHUBCLIENT_LL_17_004: [IoTHubClient_LL_CreateWithTransport shall initialize a new DLIST (further called "waitingToSend") containing records with fields of the following types: IOTHUB_MESSAGE_HANDLE, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK, void*.]*/ 00637 DList_InitializeListHead(&(handleData->waitingToSend)); 00638 DList_InitializeListHead(&(handleData->iot_msg_queue)); 00639 DList_InitializeListHead(&(handleData->iot_ack_queue)); 00640 handleData->messageCallback = NULL; 00641 handleData->messageUserContextCallback = NULL; 00642 handleData->deviceTwinCallback = NULL; 00643 handleData->deviceTwinContextCallback = NULL; 00644 handleData->deviceMethodCallback = NULL; 00645 handleData->deviceMethodUserContextCallback = NULL; 00646 handleData->lastMessageReceiveTime = INDEFINITE_TIME; 00647 handleData->data_msg_id = 1; 00648 handleData->complete_twin_update_encountered = false; 00649 00650 IOTHUB_DEVICE_CONFIG deviceConfig; 00651 00652 deviceConfig.deviceId = config->deviceId; 00653 deviceConfig.deviceKey = config->deviceKey; 00654 deviceConfig.deviceSasToken = config->deviceSasToken; 00655 00656 /*Codes_SRS_IOTHUBCLIENT_LL_17_006: [IoTHubClient_LL_CreateWithTransport shall call the transport _Register function with the IOTHUB_DEVICE_CONFIG populated structure and waitingToSend list.]*/ 00657 if ((handleData->deviceHandle = handleData->IoTHubTransport_Register(config->transportHandle, &deviceConfig, handleData, &(handleData->waitingToSend))) == NULL) 00658 { 00659 /*Codes_SRS_IOTHUBCLIENT_LL_17_007: [If the _Register function fails, this function shall fail and return NULL.]*/ 00660 LogError("Registering device in transport failed"); 00661 #ifndef DONT_USE_UPLOADTOBLOB 00662 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); 00663 #endif 00664 tickcounter_destroy(handleData->tickCounter); 00665 free(handleData); 00666 result = NULL; 00667 } 00668 else 00669 { 00670 /*Codes_SRS_IOTHUBCLIENT_LL_17_005: [IoTHubClient_LL_CreateWithTransport shall save the transport handle and mark this transport as shared.]*/ 00671 handleData->isSharedTransport = true; 00672 /*Codes_SRS_IOTHUBCLIENT_LL_02_042: [ By default, messages shall not timeout. ]*/ 00673 handleData->currentMessageTimeout = 0; 00674 handleData->current_device_twin_timeout = 0; 00675 result = handleData; 00676 /*Codes_SRS_IOTHUBCLIENT_LL_25_125: [ `IoTHubClient_LL_CreateWithTransport` shall set the default retry policy as Exponential backoff with jitter and if succeed and return a `non-NULL` handle. ]*/ 00677 if (IoTHubClient_LL_SetRetryPolicy(handleData, IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER, 0) != IOTHUB_CLIENT_OK) 00678 { 00679 LogError("Setting default retry policy in transport failed"); 00680 IoTHubClient_LL_Destroy(handleData); 00681 result = NULL; 00682 } 00683 } 00684 } 00685 } 00686 #ifndef DONT_USE_UPLOADTOBLOB 00687 free(IoTHubName); 00688 } 00689 } 00690 #endif 00691 } 00692 } 00693 00694 return result; 00695 } 00696 00697 void IoTHubClient_LL_Destroy(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle) 00698 { 00699 /*Codes_SRS_IOTHUBCLIENT_LL_02_009: [IoTHubClient_LL_Destroy shall do nothing if parameter iotHubClientHandle is NULL.]*/ 00700 if (iotHubClientHandle != NULL) 00701 { 00702 PDLIST_ENTRY unsend; 00703 /*Codes_SRS_IOTHUBCLIENT_LL_17_010: [IoTHubClient_LL_Destroy shall call the underlaying layer's _Unregister function] */ 00704 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 00705 handleData->IoTHubTransport_Unregister(handleData->deviceHandle); 00706 if (handleData->isSharedTransport == false) 00707 { 00708 /*Codes_SRS_IOTHUBCLIENT_LL_02_010: [If iotHubClientHandle was not created by IoTHubClient_LL_CreateWithTransport, IoTHubClient_LL_Destroy shall call the underlaying layer's _Destroy function.] */ 00709 handleData->IoTHubTransport_Destroy(handleData->transportHandle); 00710 } 00711 /*if any, remove the items currently not send*/ 00712 while ((unsend = DList_RemoveHeadList(&(handleData->waitingToSend))) != &(handleData->waitingToSend)) 00713 { 00714 IOTHUB_MESSAGE_LIST* temp = containingRecord(unsend, IOTHUB_MESSAGE_LIST, entry); 00715 /*Codes_SRS_IOTHUBCLIENT_LL_02_033: [Otherwise, IoTHubClient_LL_Destroy shall complete all the event message callbacks that are in the waitingToSend list with the result IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY.] */ 00716 if (temp->callback != NULL) 00717 { 00718 temp->callback(IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY, temp->context); 00719 } 00720 IoTHubMessage_Destroy(temp->messageHandle); 00721 free(temp); 00722 } 00723 00724 /* Codes_SRS_IOTHUBCLIENT_LL_07_007: [ IoTHubClient_LL_Destroy shall iterate the device twin queues and destroy any remaining items. ] */ 00725 while ((unsend = DList_RemoveHeadList(&(handleData->iot_msg_queue))) != &(handleData->iot_msg_queue)) 00726 { 00727 IOTHUB_DEVICE_TWIN* temp = containingRecord(unsend, IOTHUB_DEVICE_TWIN, entry); 00728 device_twin_data_destroy(temp); 00729 } 00730 while ((unsend = DList_RemoveHeadList(&(handleData->iot_ack_queue))) != &(handleData->iot_ack_queue)) 00731 { 00732 IOTHUB_DEVICE_TWIN* temp = containingRecord(unsend, IOTHUB_DEVICE_TWIN, entry); 00733 device_twin_data_destroy(temp); 00734 } 00735 00736 /*Codes_SRS_IOTHUBCLIENT_LL_17_011: [IoTHubClient_LL_Destroy shall free the resources allocated by IoTHubClient (if any).] */ 00737 tickcounter_destroy(handleData->tickCounter); 00738 #ifndef DONT_USE_UPLOADTOBLOB 00739 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle); 00740 #endif 00741 free(handleData); 00742 } 00743 } 00744 00745 /*Codes_SRS_IOTHUBCLIENT_LL_02_044: [ Messages already delivered to IoTHubClient_LL shall not have their timeouts modified by a new call to IoTHubClient_LL_SetOption. ]*/ 00746 /*returns 0 on success, any other value is error*/ 00747 static int attach_ms_timesOutAfter(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData, IOTHUB_MESSAGE_LIST *newEntry) 00748 { 00749 int result; 00750 /*Codes_SRS_IOTHUBCLIENT_LL_02_043: [ Calling IoTHubClient_LL_SetOption with value set to "0" shall disable the timeout mechanism for all new messages. ]*/ 00751 if (handleData->currentMessageTimeout == 0) 00752 { 00753 newEntry->ms_timesOutAfter = 0; /*do not timeout*/ 00754 result = 0; 00755 } 00756 else 00757 { 00758 /*Codes_SRS_IOTHUBCLIENT_LL_02_039: [ "messageTimeout" - once IoTHubClient_LL_SendEventAsync is called the message shall timeout after value miliseconds. Value is a pointer to a uint64. ]*/ 00759 if (tickcounter_get_current_ms(handleData->tickCounter, &newEntry->ms_timesOutAfter) != 0) 00760 { 00761 result = __LINE__; 00762 LogError("unable to get the current relative tickcount"); 00763 } 00764 else 00765 { 00766 newEntry->ms_timesOutAfter += handleData->currentMessageTimeout; 00767 result = 0; 00768 } 00769 } 00770 return result; 00771 } 00772 00773 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SendEventAsync(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback) 00774 { 00775 IOTHUB_CLIENT_RESULT result; 00776 /*Codes_SRS_IOTHUBCLIENT_LL_02_011: [IoTHubClient_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle or eventMessageHandle is NULL.]*/ 00777 if ( 00778 (iotHubClientHandle == NULL) || 00779 (eventMessageHandle == NULL) || 00780 /*Codes_SRS_IOTHUBCLIENT_LL_02_012: [IoTHubClient_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter eventConfirmationCallback is NULL and userContextCallback is not NULL.] */ 00781 ((eventConfirmationCallback == NULL) && (userContextCallback != NULL)) 00782 ) 00783 { 00784 result = IOTHUB_CLIENT_INVALID_ARG; 00785 LOG_ERROR_RESULT; 00786 } 00787 else 00788 { 00789 IOTHUB_MESSAGE_LIST *newEntry = (IOTHUB_MESSAGE_LIST*)malloc(sizeof(IOTHUB_MESSAGE_LIST)); 00790 if (newEntry == NULL) 00791 { 00792 result = IOTHUB_CLIENT_ERROR; 00793 LOG_ERROR_RESULT; 00794 } 00795 else 00796 { 00797 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 00798 00799 if (attach_ms_timesOutAfter(handleData, newEntry) != 0) 00800 { 00801 result = IOTHUB_CLIENT_ERROR; 00802 LOG_ERROR_RESULT; 00803 free(newEntry); 00804 } 00805 else 00806 { 00807 /*Codes_SRS_IOTHUBCLIENT_LL_02_013: [IoTHubClient_SendEventAsync shall add the DLIST waitingToSend a new record cloning the information from eventMessageHandle, eventConfirmationCallback, userContextCallback.]*/ 00808 if ((newEntry->messageHandle = IoTHubMessage_Clone(eventMessageHandle)) == NULL) 00809 { 00810 /*Codes_SRS_IOTHUBCLIENT_LL_02_014: [If cloning and/or adding the information fails for any reason, IoTHubClient_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_ERROR.] */ 00811 result = IOTHUB_CLIENT_ERROR; 00812 free(newEntry); 00813 LOG_ERROR_RESULT; 00814 } 00815 else 00816 { 00817 /*Codes_SRS_IOTHUBCLIENT_LL_02_013: [IoTHubClient_SendEventAsync shall add the DLIST waitingToSend a new record cloning the information from eventMessageHandle, eventConfirmationCallback, userContextCallback.]*/ 00818 newEntry->callback = eventConfirmationCallback; 00819 newEntry->context = userContextCallback; 00820 DList_InsertTailList(&(iotHubClientHandle->waitingToSend), &(newEntry->entry)); 00821 /*Codes_SRS_IOTHUBCLIENT_LL_02_015: [Otherwise IoTHubClient_LL_SendEventAsync shall succeed and return IOTHUB_CLIENT_OK.] */ 00822 result = IOTHUB_CLIENT_OK; 00823 } 00824 } 00825 } 00826 } 00827 return result; 00828 } 00829 00830 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetMessageCallback(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback, void* userContextCallback) 00831 { 00832 IOTHUB_CLIENT_RESULT result; 00833 /*Codes_SRS_IOTHUBCLIENT_LL_02_016: [IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.] */ 00834 if (iotHubClientHandle == NULL) 00835 { 00836 result = IOTHUB_CLIENT_INVALID_ARG; 00837 LOG_ERROR_RESULT; 00838 } 00839 else 00840 { 00841 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 00842 if (messageCallback == NULL) 00843 { 00844 /*Codes_SRS_IOTHUBCLIENT_LL_02_019: [If parameter messageCallback is NULL then IoTHubClient_LL_SetMessageCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */ 00845 handleData->IoTHubTransport_Unsubscribe(handleData->deviceHandle); 00846 handleData->messageCallback = NULL; 00847 handleData->messageUserContextCallback = NULL; 00848 result = IOTHUB_CLIENT_OK; 00849 } 00850 else 00851 { 00852 /*Codes_SRS_IOTHUBCLIENT_LL_02_017: [If parameter messageCallback is non-NULL then IoTHubClient_LL_SetMessageCallback shall call the underlying layer's _Subscribe function.]*/ 00853 if (handleData->IoTHubTransport_Subscribe(handleData->deviceHandle) == 0) 00854 { 00855 handleData->messageCallback = messageCallback; 00856 handleData->messageUserContextCallback = userContextCallback; 00857 result = IOTHUB_CLIENT_OK; 00858 } 00859 else 00860 { 00861 handleData->messageCallback = NULL; 00862 handleData->messageUserContextCallback = NULL; 00863 /*Codes_SRS_IOTHUBCLIENT_LL_02_018: [If the underlying layer's _Subscribe function fails, then IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR. Otherwise IoTHubClient_LL_SetMessageCallback shall succeed and return IOTHUB_CLIENT_OK.]*/ 00864 result = IOTHUB_CLIENT_ERROR; 00865 } 00866 } 00867 } 00868 00869 return result; 00870 } 00871 00872 static void DoTimeouts(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData) 00873 { 00874 uint64_t nowTick; 00875 if (tickcounter_get_current_ms(handleData->tickCounter, &nowTick) != 0) 00876 { 00877 LogError("unable to get the current ms, timeouts will not be processed"); 00878 } 00879 else 00880 { 00881 DLIST_ENTRY* currentItemInWaitingToSend = handleData->waitingToSend.Flink; 00882 while (currentItemInWaitingToSend != &(handleData->waitingToSend)) /*while we are not at the end of the list*/ 00883 { 00884 IOTHUB_MESSAGE_LIST* fullEntry = containingRecord(currentItemInWaitingToSend, IOTHUB_MESSAGE_LIST, entry); 00885 /*Codes_SRS_IOTHUBCLIENT_LL_02_041: [ If more than value miliseconds have passed since the call to IoTHubClient_LL_SendEventAsync then the message callback shall be called with a status code of IOTHUB_CLIENT_CONFIRMATION_TIMEOUT. ]*/ 00886 if ((fullEntry->ms_timesOutAfter != 0) && (fullEntry->ms_timesOutAfter < nowTick)) 00887 { 00888 PDLIST_ENTRY theNext = currentItemInWaitingToSend->Flink; /*need to save the next item, because the below operations are destructive*/ 00889 DList_RemoveEntryList(currentItemInWaitingToSend); 00890 if (fullEntry->callback != NULL) 00891 { 00892 fullEntry->callback(IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT, fullEntry->context); 00893 } 00894 IoTHubMessage_Destroy(fullEntry->messageHandle); /*because it has been cloned*/ 00895 free(fullEntry); 00896 currentItemInWaitingToSend = theNext; 00897 } 00898 else 00899 { 00900 currentItemInWaitingToSend = currentItemInWaitingToSend->Flink; 00901 } 00902 } 00903 } 00904 } 00905 00906 void IoTHubClient_LL_DoWork(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle) 00907 { 00908 /*Codes_SRS_IOTHUBCLIENT_LL_02_020: [If parameter iotHubClientHandle is NULL then IoTHubClient_LL_DoWork shall not perform any action.] */ 00909 if (iotHubClientHandle != NULL) 00910 { 00911 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 00912 DoTimeouts(handleData); 00913 00914 /*Codes_SRS_IOTHUBCLIENT_LL_07_008: [ IoTHubClient_LL_DoWork shall iterate the message queue and execute the underlying transports IoTHubTransport_ProcessItem function for each item. ] */ 00915 DLIST_ENTRY* client_item = handleData->iot_msg_queue.Flink; 00916 while (client_item != &(handleData->iot_msg_queue)) /*while we are not at the end of the list*/ 00917 { 00918 PDLIST_ENTRY next_item = client_item->Flink; 00919 00920 IOTHUB_DEVICE_TWIN* queue_data = containingRecord(client_item, IOTHUB_DEVICE_TWIN, entry); 00921 IOTHUB_IDENTITY_INFO identity_info; 00922 identity_info.device_twin = queue_data; 00923 IOTHUB_PROCESS_ITEM_RESULT process_results = handleData->IoTHubTransport_ProcessItem(handleData->transportHandle, IOTHUB_TYPE_DEVICE_TWIN, &identity_info); 00924 if (process_results == IOTHUB_PROCESS_CONTINUE || process_results == IOTHUB_PROCESS_NOT_CONNECTED) 00925 { 00926 /*Codes_SRS_IOTHUBCLIENT_LL_07_010: [ If 'IoTHubTransport_ProcessItem' returns IOTHUB_PROCESS_CONTINUE or IOTHUB_PROCESS_NOT_CONNECTED IoTHubClient_LL_DoWork shall continue on to call the underlaying layer's _DoWork function. ]*/ 00927 break; 00928 } 00929 else 00930 { 00931 DList_RemoveEntryList(client_item); 00932 if (process_results == IOTHUB_PROCESS_OK) 00933 { 00934 /*Codes_SRS_IOTHUBCLIENT_LL_07_011: [ If 'IoTHubTransport_ProcessItem' returns IOTHUB_PROCESS_OK IoTHubClient_LL_DoWork shall add the IOTHUB_DEVICE_TWIN to the ack queue. ]*/ 00935 DList_InsertTailList(&(iotHubClientHandle->iot_ack_queue), &(queue_data->entry)); 00936 } 00937 else 00938 { 00939 /*Codes_SRS_IOTHUBCLIENT_LL_07_012: [ If 'IoTHubTransport_ProcessItem' returns any other value IoTHubClient_LL_DoWork shall destroy the IOTHUB_DEVICE_TWIN item. ]*/ 00940 LogError("Failure queue processing item"); 00941 device_twin_data_destroy(queue_data); 00942 } 00943 } 00944 // Move along to the next item 00945 client_item = next_item; 00946 } 00947 00948 /*Codes_SRS_IOTHUBCLIENT_LL_02_021: [Otherwise, IoTHubClient_LL_DoWork shall invoke the underlaying layer's _DoWork function.]*/ 00949 handleData->IoTHubTransport_DoWork(handleData->transportHandle, iotHubClientHandle); 00950 } 00951 } 00952 00953 IOTHUB_CLIENT_RESULT IoTHubClient_LL_GetSendStatus(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_STATUS *iotHubClientStatus) 00954 { 00955 IOTHUB_CLIENT_RESULT result; 00956 00957 /* Codes_SRS_IOTHUBCLIENT_09_007: [IoTHubClient_GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL parameter] */ 00958 if (iotHubClientHandle == NULL || iotHubClientStatus == NULL) 00959 { 00960 result = IOTHUB_CLIENT_INVALID_ARG; 00961 LOG_ERROR_RESULT; 00962 } 00963 else 00964 { 00965 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 00966 00967 /* Codes_SRS_IOTHUBCLIENT_09_008: [IoTHubClient_GetSendStatus shall return IOTHUB_CLIENT_OK and status IOTHUB_CLIENT_SEND_STATUS_IDLE if there is currently no items to be sent] */ 00968 /* Codes_SRS_IOTHUBCLIENT_09_009: [IoTHubClient_GetSendStatus shall return IOTHUB_CLIENT_OK and status IOTHUB_CLIENT_SEND_STATUS_BUSY if there are currently items to be sent] */ 00969 result = handleData->IoTHubTransport_GetSendStatus(handleData->deviceHandle, iotHubClientStatus); 00970 } 00971 00972 return result; 00973 } 00974 00975 void IoTHubClient_LL_SendComplete(IOTHUB_CLIENT_LL_HANDLE handle, PDLIST_ENTRY completed, IOTHUB_CLIENT_CONFIRMATION_RESULT result) 00976 { 00977 /*Codes_SRS_IOTHUBCLIENT_LL_02_022: [If parameter completed is NULL, or parameter handle is NULL then IoTHubClient_LL_SendBatch shall return.]*/ 00978 if ( 00979 (handle == NULL) || 00980 (completed == NULL) 00981 ) 00982 { 00983 /*"shall return"*/ 00984 LogError("invalid arg"); 00985 } 00986 else 00987 { 00988 /*Codes_SRS_IOTHUBCLIENT_LL_02_027: [If parameter result is IOTHUB_CLIENT_CONFIRMATION_ERROR then IoTHubClient_LL_SendComplete shall call all the non-NULL callbacks with the result parameter set to IOTHUB_CLIENT_CONFIRMATION_ERROR and the context set to the context passed originally in the SendEventAsync call.] */ 00989 /*Codes_SRS_IOTHUBCLIENT_LL_02_025: [If parameter result is IOTHUB_CLIENT_CONFIRMATION_OK then IoTHubClient_LL_SendComplete shall call all the non-NULL callbacks with the result parameter set to IOTHUB_CLIENT_CONFIRMATION_OK and the context set to the context passed originally in the SendEventAsync call.]*/ 00990 PDLIST_ENTRY oldest; 00991 while ((oldest = DList_RemoveHeadList(completed)) != completed) 00992 { 00993 IOTHUB_MESSAGE_LIST* messageList = (IOTHUB_MESSAGE_LIST*)containingRecord(oldest, IOTHUB_MESSAGE_LIST, entry); 00994 /*Codes_SRS_IOTHUBCLIENT_LL_02_026: [If any callback is NULL then there shall not be a callback call.]*/ 00995 if (messageList->callback != NULL) 00996 { 00997 messageList->callback(result, messageList->context); 00998 } 00999 IoTHubMessage_Destroy(messageList->messageHandle); 01000 free(messageList); 01001 } 01002 } 01003 } 01004 01005 int IoTHubClient_LL_DeviceMethodComplete(IOTHUB_CLIENT_LL_HANDLE handle, const char* method_name, const unsigned char* payLoad, size_t size, BUFFER_HANDLE response) 01006 { 01007 int result; 01008 if (handle == NULL || response == NULL) 01009 { 01010 /* Codes_SRS_IOTHUBCLIENT_LL_07_017: [ If handle or response is NULL then IoTHubClient_LL_DeviceMethodComplete shall return 500. ] */ 01011 LogError("Invalid argument handle=%p", handle); 01012 result = 500; 01013 } 01014 else 01015 { 01016 /* Codes_SRS_IOTHUBCLIENT_LL_07_018: [ If deviceMethodCallback is not NULL IoTHubClient_LL_DeviceMethodComplete shall execute deviceMethodCallback and return the status. ] */ 01017 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)handle; 01018 if (handleData->deviceMethodCallback) 01019 { 01020 unsigned char* payload_resp = NULL; 01021 size_t resp_size = 0; 01022 result = handleData->deviceMethodCallback(method_name, payLoad, size, &payload_resp, &resp_size, handleData->deviceMethodUserContextCallback); 01023 /* Codes_SRS_IOTHUBCLIENT_LL_07_020: [ deviceMethodCallback shall buil the BUFFER_HANDLE with the response payload from the IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC callback. ] */ 01024 if (payload_resp != NULL && resp_size > 0) 01025 { 01026 if (BUFFER_build(response, payload_resp, resp_size) != 0) 01027 { 01028 result = 500; 01029 } 01030 } 01031 if (payload_resp != NULL) 01032 { 01033 free(payload_resp); 01034 } 01035 } 01036 else 01037 { 01038 /* Codes_SRS_IOTHUBCLIENT_LL_07_019: [ If deviceMethodCallback is NULL IoTHubClient_LL_DeviceMethodComplete shall return 404. ] */ 01039 result = 404; 01040 } 01041 } 01042 return result; 01043 } 01044 01045 void IoTHubClient_LL_RetrievePropertyComplete(IOTHUB_CLIENT_LL_HANDLE handle, DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size) 01046 { 01047 if (handle == NULL) 01048 { 01049 /* Codes_SRS_IOTHUBCLIENT_LL_07_013: [ If handle is NULL then IoTHubClient_LL_RetrievePropertyComplete shall do nothing.] */ 01050 LogError("Invalid argument handle=%p", handle); 01051 } 01052 else 01053 { 01054 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)handle; 01055 /* Codes_SRS_IOTHUBCLIENT_LL_07_014: [ If deviceTwinCallback is NULL then IoTHubClient_LL_RetrievePropertyComplete shall do nothing.] */ 01056 if (handleData->deviceTwinCallback) 01057 { 01058 /* Codes_SRS_IOTHUBCLIENT_LL_07_015: [ If the the update_state parameter is DEVICE_TWIN_UPDATE_PARTIAL and a DEVICE_TWIN_UPDATE_COMPLETE has not been previously recieved then IoTHubClient_LL_RetrievePropertyComplete shall do nothing.] */ 01059 if (update_state == DEVICE_TWIN_UPDATE_COMPLETE) 01060 { 01061 handleData->complete_twin_update_encountered = true; 01062 } 01063 if (handleData->complete_twin_update_encountered) 01064 { 01065 /* Codes_SRS_IOTHUBCLIENT_LL_07_016: [ If deviceTwinCallback is set and DEVICE_TWIN_UPDATE_COMPLETE has been encountered then IoTHubClient_LL_RetrievePropertyComplete shall call deviceTwinCallback.] */ 01066 handleData->deviceTwinCallback(update_state, payLoad, size, handleData->deviceTwinContextCallback); 01067 } 01068 } 01069 } 01070 } 01071 01072 void IoTHubClient_LL_ReportedStateComplete(IOTHUB_CLIENT_LL_HANDLE handle, uint32_t item_id, int status_code) 01073 { 01074 /* Codes_SRS_IOTHUBCLIENT_LL_07_002: [ if handle or queue_handle are NULL then IoTHubClient_LL_ReportedStateComplete shall do nothing. ] */ 01075 if (handle == NULL) 01076 { 01077 /*"shall return"*/ 01078 LogError("Invalid argument handle=%p", handle); 01079 } 01080 else 01081 { 01082 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)handle; 01083 01084 /* Codes_SRS_IOTHUBCLIENT_LL_07_003: [ IoTHubClient_LL_ReportedStateComplete shall enumerate through the IOTHUB_DEVICE_TWIN structures in queue_handle. ]*/ 01085 DLIST_ENTRY* client_item = handleData->iot_ack_queue.Flink; 01086 while (client_item != &(handleData->iot_ack_queue)) /*while we are not at the end of the list*/ 01087 { 01088 PDLIST_ENTRY next_item = client_item->Flink; 01089 IOTHUB_DEVICE_TWIN* queue_data = containingRecord(client_item, IOTHUB_DEVICE_TWIN, entry); 01090 if (queue_data->item_id == item_id) 01091 { 01092 if (queue_data->reported_state_callback != NULL) 01093 { 01094 queue_data->reported_state_callback(status_code, queue_data->context); 01095 } 01096 /*Codes_SRS_IOTHUBCLIENT_LL_07_009: [ IoTHubClient_LL_ReportedStateComplete shall remove the IOTHUB_DEVICE_TWIN item from the ack queue.]*/ 01097 DList_RemoveEntryList(client_item); 01098 device_twin_data_destroy(queue_data); 01099 break; 01100 } 01101 client_item = next_item; 01102 } 01103 } 01104 } 01105 01106 IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubClient_LL_MessageCallback(IOTHUB_CLIENT_LL_HANDLE handle, IOTHUB_MESSAGE_HANDLE message) 01107 { 01108 int result; 01109 /*Codes_SRS_IOTHUBCLIENT_LL_02_029: [If parameter handle is NULL then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */ 01110 if (handle == NULL) 01111 { 01112 LogError("invalid argument"); 01113 result = IOTHUBMESSAGE_ABANDONED; 01114 } 01115 else 01116 { 01117 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)handle; 01118 01119 /* Codes_SRS_IOTHUBCLIENT_LL_09_004: [IoTHubClient_LL_GetLastMessageReceiveTime shall return lastMessageReceiveTime in localtime] */ 01120 handleData->lastMessageReceiveTime = get_time(NULL); 01121 01122 /*Codes_SRS_IOTHUBCLIENT_LL_02_030: [IoTHubClient_LL_MessageCallback shall invoke the last callback function (the parameter messageCallback to IoTHubClient_LL_SetMessageCallback) passing the message and the passed userContextCallback.]*/ 01123 if (handleData->messageCallback != NULL) 01124 { 01125 result = handleData->messageCallback(message, handleData->messageUserContextCallback); 01126 } 01127 else 01128 { 01129 /*Codes_SRS_IOTHUBCLIENT_LL_02_032: [If the last callback function was NULL, then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */ 01130 LogError("user callback was NULL"); 01131 result = IOTHUBMESSAGE_ABANDONED; 01132 } 01133 } 01134 /*Codes_SRS_IOTHUBCLIENT_LL_02_031: [Then IoTHubClient_LL_MessageCallback shall return what the user function returns.]*/ 01135 return (IOTHUBMESSAGE_DISPOSITION_RESULT) result; 01136 } 01137 01138 void IotHubClient_LL_ConnectionStatusCallBack(IOTHUB_CLIENT_LL_HANDLE handle, IOTHUB_CLIENT_CONNECTION_STATUS status, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason) 01139 { 01140 /*Codes_SRS_IOTHUBCLIENT_LL_25_113: [If parameter connectionStatus is NULL or parameter handle is NULL then IotHubClient_LL_ConnectionStatusCallBack shall return.]*/ 01141 if (handle == NULL) 01142 { 01143 /*"shall return"*/ 01144 LogError("invalid arg"); 01145 } 01146 else 01147 { 01148 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)handle; 01149 01150 /*Codes_SRS_IOTHUBCLIENT_LL_25_114: [IotHubClient_LL_ConnectionStatusCallBack shall call non-callback set by the user from IoTHubClient_LL_SetConnectionStatusCallback passing the status, reason and the passed userContextCallback.]*/ 01151 if (handleData->conStatusCallback != NULL) 01152 { 01153 handleData->conStatusCallback(status, reason, handleData->conStatusUserContextCallback); 01154 } 01155 } 01156 01157 } 01158 01159 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetConnectionStatusCallback(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connectionStatusCallback, void * userContextCallback) 01160 { 01161 IOTHUB_CLIENT_RESULT result; 01162 /*Codes_SRS_IOTHUBCLIENT_LL_25_111: [IoTHubClient_LL_SetConnectionStatusCallback shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL parameter iotHubClientHandle**]** */ 01163 if (iotHubClientHandle == NULL) 01164 { 01165 result = IOTHUB_CLIENT_INVALID_ARG; 01166 LOG_ERROR_RESULT; 01167 } 01168 else 01169 { 01170 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01171 /*Codes_SRS_IOTHUBCLIENT_LL_25_112: [IoTHubClient_LL_SetConnectionStatusCallback shall return IOTHUB_CLIENT_OK and save the callback and userContext as a member of the handle.] */ 01172 handleData->conStatusCallback = connectionStatusCallback; 01173 handleData->conStatusUserContextCallback = userContextCallback; 01174 result = IOTHUB_CLIENT_OK; 01175 } 01176 01177 return result; 01178 } 01179 01180 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetRetryPolicy(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY retryPolicy, size_t retryTimeoutLimitInSeconds) 01181 { 01182 IOTHUB_CLIENT_RESULT result; 01183 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01184 01185 /* Codes_SRS_IOTHUBCLIENT_LL_25_116: [**IoTHubClient_LL_SetRetryPolicy shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL iotHubClientHandle]*/ 01186 if (handleData == NULL) 01187 { 01188 result = IOTHUB_CLIENT_INVALID_ARG; 01189 LOG_ERROR_RESULT; 01190 } 01191 else 01192 { 01193 if (handleData->transportHandle == NULL) 01194 { 01195 result = IOTHUB_CLIENT_ERROR; 01196 LOG_ERROR_RESULT; 01197 } 01198 else 01199 { 01200 if (handleData->IoTHubTransport_SetRetryPolicy(handleData->transportHandle, retryPolicy, retryTimeoutLimitInSeconds) != 0) 01201 { 01202 result = IOTHUB_CLIENT_ERROR; 01203 LOG_ERROR_RESULT; 01204 } 01205 else 01206 { 01207 /*Codes_SRS_IOTHUBCLIENT_LL_25_118: [**IoTHubClient_LL_SetRetryPolicy shall save connection retry policies specified by the user to retryPolicy in struct IOTHUB_CLIENT_LL_HANDLE_DATA]*/ 01208 /*Codes_SRS_IOTHUBCLIENT_LL_25_119: [**IoTHubClient_LL_SetRetryPolicy shall save retryTimeoutLimitInSeconds in seconds to retryTimeout in struct IOTHUB_CLIENT_LL_HANDLE_DATA]*/ 01209 handleData->retryPolicy = retryPolicy; 01210 handleData->retryTimeoutLimitInSeconds = retryTimeoutLimitInSeconds; 01211 result = IOTHUB_CLIENT_OK; 01212 } 01213 } 01214 } 01215 return result; 01216 } 01217 01218 IOTHUB_CLIENT_RESULT IoTHubClient_LL_GetRetryPolicy(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY* retryPolicy, size_t* retryTimeoutLimitInSeconds) 01219 { 01220 IOTHUB_CLIENT_RESULT result = IOTHUB_CLIENT_OK; 01221 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01222 01223 /* Codes_SRS_IOTHUBCLIENT_LL_09_001: [IoTHubClient_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INVALID_ARG if any of the arguments is NULL] */ 01224 if (handleData == NULL || retryPolicy == NULL || retryTimeoutLimitInSeconds == NULL) 01225 { 01226 result = IOTHUB_CLIENT_INVALID_ARG; 01227 LOG_ERROR_RESULT; 01228 } 01229 else 01230 { 01231 *retryPolicy = handleData->retryPolicy; 01232 *retryTimeoutLimitInSeconds = handleData->retryTimeoutLimitInSeconds; 01233 result = IOTHUB_CLIENT_OK; 01234 } 01235 01236 return result; 01237 } 01238 01239 IOTHUB_CLIENT_RESULT IoTHubClient_LL_GetLastMessageReceiveTime(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, time_t* lastMessageReceiveTime) 01240 { 01241 IOTHUB_CLIENT_RESULT result; 01242 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01243 01244 /* Codes_SRS_IOTHUBCLIENT_LL_09_001: [IoTHubClient_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INVALID_ARG if any of the arguments is NULL] */ 01245 if (handleData == NULL || lastMessageReceiveTime == NULL) 01246 { 01247 result = IOTHUB_CLIENT_INVALID_ARG; 01248 LOG_ERROR_RESULT; 01249 } 01250 else 01251 { 01252 /* Codes_SRS_IOTHUBCLIENT_LL_09_002: [IoTHubClient_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INDEFINITE_TIME - and not set 'lastMessageReceiveTime' - if it is unable to provide the time for the last commands] */ 01253 if (handleData->lastMessageReceiveTime == INDEFINITE_TIME) 01254 { 01255 result = IOTHUB_CLIENT_INDEFINITE_TIME; 01256 LOG_ERROR_RESULT; 01257 } 01258 else 01259 { 01260 /* Codes_SRS_IOTHUBCLIENT_LL_09_003: [IoTHubClient_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_OK if it wrote in the lastMessageReceiveTime the time when the last command was received] */ 01261 /* Codes_SRS_IOTHUBCLIENT_LL_09_004: [IoTHubClient_LL_GetLastMessageReceiveTime shall return lastMessageReceiveTime in localtime] */ 01262 *lastMessageReceiveTime = handleData->lastMessageReceiveTime; 01263 result = IOTHUB_CLIENT_OK; 01264 } 01265 } 01266 01267 return result; 01268 } 01269 01270 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetOption(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const char* optionName, const void* value) 01271 { 01272 01273 IOTHUB_CLIENT_RESULT result; 01274 /*Codes_SRS_IOTHUBCLIENT_LL_02_034: [If iotHubClientHandle is NULL then IoTHubClient_LL_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.]*/ 01275 /*Codes_SRS_IOTHUBCLIENT_LL_02_035: [If optionName is NULL then IoTHubClient_LL_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */ 01276 /*Codes_SRS_IOTHUBCLIENT_LL_02_036: [If value is NULL then IoTHubClient_LL_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */ 01277 if ( 01278 (iotHubClientHandle == NULL) || 01279 (optionName == NULL) || 01280 (value == NULL) 01281 ) 01282 { 01283 result = IOTHUB_CLIENT_INVALID_ARG; 01284 LogError("invalid argument (NULL)"); 01285 } 01286 else 01287 { 01288 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01289 01290 /*Codes_SRS_IOTHUBCLIENT_LL_02_039: [ "messageTimeout" - once IoTHubClient_LL_SendEventAsync is called the message shall timeout after value miliseconds. Value is a pointer to a uint64. ]*/ 01291 if (strcmp(optionName, "messageTimeout") == 0) 01292 { 01293 /*this is an option handled by IoTHubClient_LL*/ 01294 /*Codes_SRS_IOTHUBCLIENT_LL_02_043: [ Calling IoTHubClient_LL_SetOption with value set to "0" shall disable the timeout mechanism for all new messages. ]*/ 01295 handleData->currentMessageTimeout = *(const uint64_t*)value; 01296 result = IOTHUB_CLIENT_OK; 01297 } 01298 else 01299 { 01300 01301 /*Codes_SRS_IOTHUBCLIENT_LL_02_099: [ IoTHubClient_LL_SetOption shall return according to the table below ]*/ 01302 IOTHUB_CLIENT_RESULT uploadToBlob_result; 01303 #ifndef DONT_USE_UPLOADTOBLOB 01304 uploadToBlob_result = IoTHubClient_LL_UploadToBlob_SetOption(handleData->uploadToBlobHandle, optionName, value); 01305 if(uploadToBlob_result == IOTHUB_CLIENT_ERROR) 01306 { 01307 LogError("unable to IoTHubClient_LL_UploadToBlob_SetOption"); 01308 result = IOTHUB_CLIENT_ERROR; 01309 } 01310 #else 01311 uploadToBlob_result = IOTHUB_CLIENT_INVALID_ARG; /*harmless value (IOTHUB_CLIENT_INVALID_ARG)in the case when uploadtoblob is not compiled in, otherwise whatever IoTHubClient_LL_UploadToBlob_SetOption returned*/ 01312 #endif /*DONT_USE_UPLOADTOBLOB*/ 01313 01314 01315 result = 01316 /*based on uploadToBlob_result value this is what happens:*/ 01317 /*IOTHUB_CLIENT_INVALID_ARG always returns what IoTHubTransport_SetOption returns*/ 01318 /*IOTHUB_CLIENT_ERROR always returns IOTHUB_CLIENT_ERROR */ 01319 /*IOTHUB_CLIENT_OK returns OK 01320 IOTHUB_CLIENT_OK if IoTHubTransport_SetOption returns OK or INVALID_ARG 01321 IOTHUB_CLIENT_ERROR if IoTHubTransport_SetOption returns ERROR*/ 01322 01323 (uploadToBlob_result == IOTHUB_CLIENT_INVALID_ARG) ? handleData->IoTHubTransport_SetOption(handleData->transportHandle, optionName, value) : 01324 (uploadToBlob_result == IOTHUB_CLIENT_ERROR) ? IOTHUB_CLIENT_ERROR : 01325 (handleData->IoTHubTransport_SetOption(handleData->transportHandle, optionName, value) == IOTHUB_CLIENT_ERROR) ? IOTHUB_CLIENT_ERROR : IOTHUB_CLIENT_OK; 01326 01327 if (result != IOTHUB_CLIENT_OK) 01328 { 01329 LogError("underlying transport failed, returned = %s", ENUM_TO_STRING(IOTHUB_CLIENT_RESULT, result)); 01330 } 01331 } 01332 } 01333 return result; 01334 } 01335 01336 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetDeviceTwinCallback(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback) 01337 { 01338 IOTHUB_CLIENT_RESULT result; 01339 /* Codes_SRS_IOTHUBCLIENT_LL_10_001: [ IoTHubClient_LL_SetDeviceTwinCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.] */ 01340 if (iotHubClientHandle == NULL) 01341 { 01342 result = IOTHUB_CLIENT_INVALID_ARG; 01343 LogError("Invalid argument specified iothubClientHandle=%p", iotHubClientHandle); 01344 } 01345 else 01346 { 01347 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01348 if (deviceTwinCallback == NULL) 01349 { 01350 /* Codes_SRS_IOTHUBCLIENT_LL_10_006: [ If deviceTwinCallback is NULL, then IoTHubClient_LL_SetDeviceTwinCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */ 01351 handleData->IoTHubTransport_Unsubscribe_DeviceTwin(handleData->transportHandle); 01352 handleData->deviceTwinCallback = NULL; 01353 result = IOTHUB_CLIENT_OK; 01354 } 01355 else 01356 { 01357 /* Codes_SRS_IOTHUBCLIENT_LL_10_002: [ If deviceTwinCallback is not NULL, then IoTHubClient_LL_SetDeviceTwinCallback shall call the underlying layer's _Subscribe function.] */ 01358 if (handleData->IoTHubTransport_Subscribe_DeviceTwin(handleData->transportHandle) == 0) 01359 { 01360 handleData->deviceTwinCallback = deviceTwinCallback; 01361 handleData->deviceTwinContextCallback = userContextCallback; 01362 /* Codes_SRS_IOTHUBCLIENT_LL_10_005: [ Otherwise IoTHubClient_LL_SetDeviceTwinCallback shall succeed and return IOTHUB_CLIENT_OK.] */ 01363 result = IOTHUB_CLIENT_OK; 01364 } 01365 else 01366 { 01367 /* Codes_SRS_IOTHUBCLIENT_LL_10_003: [ If the underlying layer's _Subscribe function fails, then IoTHubClient_LL_SetDeviceTwinCallback shall fail and return IOTHUB_CLIENT_ERROR.] */ 01368 result = IOTHUB_CLIENT_ERROR; 01369 } 01370 } 01371 } 01372 return result; 01373 } 01374 01375 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SendReportedState(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const unsigned char* reportedState, size_t size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback, void* userContextCallback) 01376 { 01377 IOTHUB_CLIENT_RESULT result; 01378 /* Codes_SRS_IOTHUBCLIENT_LL_10_012: [ IoTHubClient_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL. ] */ 01379 /* Codes_SRS_IOTHUBCLIENT_LL_10_013: [ IoTHubClient_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter reportedState is NULL] */ 01380 /* Codes_SRS_IOTHUBCLIENT_LL_07_005: [ IoTHubClient_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter size is equal to 0. ] */ 01381 if (iotHubClientHandle == NULL || (reportedState == NULL || size == 0) ) 01382 { 01383 result = IOTHUB_CLIENT_INVALID_ARG; 01384 LogError("Invalid argument specified iothubClientHandle=%p, reportedState=%p, size=%zu", iotHubClientHandle, reportedState, size); 01385 } 01386 else 01387 { 01388 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01389 /* Codes_SRS_IOTHUBCLIENT_LL_10_014: [IoTHubClient_LL_SendReportedState shall construct and queue the reported a Device_Twin structure for transmition by the underlying transport.] */ 01390 IOTHUB_DEVICE_TWIN* client_data = dev_twin_data_create(handleData, get_next_item_id(handleData), reportedState, size, reportedStateCallback, userContextCallback); 01391 if (client_data == NULL) 01392 { 01393 /* Codes_SRS_IOTHUBCLIENT_LL_10_015: [If any error is encountered IoTHubClient_LL_SendReportedState shall return IOTHUB_CLIENT_ERROR.] */ 01394 LogError("Failure constructing device twin data"); 01395 result = IOTHUB_CLIENT_ERROR; 01396 } 01397 else 01398 { 01399 if (handleData->IoTHubTransport_Subscribe_DeviceTwin(handleData->transportHandle) != 0) 01400 { 01401 LogError("Failure adding device twin data to queue"); 01402 device_twin_data_destroy(client_data); 01403 result = IOTHUB_CLIENT_ERROR; 01404 } 01405 else 01406 { 01407 /* Codes_SRS_IOTHUBCLIENT_LL_07_001: [ IoTHubClient_LL_SendReportedState shall queue the constructed reportedState data to be consumed by the targeted transport. ] */ 01408 DList_InsertTailList(&(iotHubClientHandle->iot_msg_queue), &(client_data->entry)); 01409 01410 /* Codes_SRS_IOTHUBCLIENT_LL_10_016: [ Otherwise IoTHubClient_LL_SendReportedState shall succeed and return IOTHUB_CLIENT_OK.] */ 01411 result = IOTHUB_CLIENT_OK; 01412 } 01413 } 01414 } 01415 return result; 01416 } 01417 01418 IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetDeviceMethodCallback(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC deviceMethodCallback, void* userContextCallback) 01419 { 01420 IOTHUB_CLIENT_RESULT result; 01421 01422 /*Codes_SRS_IOTHUBCLIENT_LL_12_017: [ IoTHubClient_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL. ] */ 01423 if (iotHubClientHandle == NULL) 01424 { 01425 result = IOTHUB_CLIENT_INVALID_ARG; 01426 LOG_ERROR_RESULT; 01427 } 01428 else 01429 { 01430 IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; 01431 if (deviceMethodCallback == NULL) 01432 { 01433 /*Codes_SRS_IOTHUBCLIENT_LL_12_018: [If deviceMethodCallback is NULL, then IoTHubClient_LL_SetDeviceMethodCallback shall call the underlying layer's IoTHubTransport_Unsubscribe_DeviceMethod function and return IOTHUB_CLIENT_OK. ] */ 01434 /*Codes_SRS_IOTHUBCLIENT_LL_12_022: [ Otherwise IoTHubClient_LL_SetDeviceMethodCallback shall succeed and return IOTHUB_CLIENT_OK. ]*/ 01435 handleData->IoTHubTransport_Unsubscribe_DeviceMethod(handleData->transportHandle); 01436 handleData->deviceMethodCallback = NULL; 01437 result = IOTHUB_CLIENT_OK; 01438 } 01439 else 01440 { 01441 /*Codes_SRS_IOTHUBCLIENT_LL_12_019: [ If deviceMethodCallback is not NULL, then IoTHubClient_LL_SetDeviceMethodCallback shall call the underlying layer's IoTHubTransport_Subscribe_DeviceMethod function. ]*/ 01442 if (handleData->IoTHubTransport_Subscribe_DeviceMethod(handleData->deviceHandle) == 0) 01443 { 01444 /*Codes_SRS_IOTHUBCLIENT_LL_12_022: [ Otherwise IoTHubClient_LL_SetDeviceMethodCallback shall succeed and return IOTHUB_CLIENT_OK. ]*/ 01445 handleData->deviceMethodCallback = deviceMethodCallback; 01446 handleData->deviceMethodUserContextCallback = userContextCallback; 01447 result = IOTHUB_CLIENT_OK; 01448 } 01449 else 01450 { 01451 /*Codes_SRS_IOTHUBCLIENT_LL_12_020: [ If the underlying layer's IoTHubTransport_Subscribe_DeviceMethod function fails, then IoTHubClient_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ]*/ 01452 /*Codes_SRS_IOTHUBCLIENT_LL_12_021: [ If adding the information fails for any reason, IoTHubClient_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ]*/ 01453 result = IOTHUB_CLIENT_ERROR; 01454 } 01455 } 01456 } 01457 return result; 01458 } 01459 01460 #ifndef DONT_USE_UPLOADTOBLOB 01461 IOTHUB_CLIENT_RESULT IoTHubClient_LL_UploadToBlob(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const char* destinationFileName, const unsigned char* source, size_t size) 01462 { 01463 IOTHUB_CLIENT_RESULT result; 01464 /*Codes_SRS_IOTHUBCLIENT_LL_02_061: [ If iotHubClientHandle is NULL then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/ 01465 /*Codes_SRS_IOTHUBCLIENT_LL_02_062: [ If destinationFileName is NULL then IoTHubClient_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/ 01466 if ( 01467 (iotHubClientHandle == NULL) || 01468 (destinationFileName == NULL) || 01469 ((source == NULL) && (size >0)) 01470 ) 01471 { 01472 LogError("invalid parameters IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle=%p, const char* destinationFileName=%s, const unsigned char* source=%p, size_t size=%zu", iotHubClientHandle, destinationFileName, source, size); 01473 result = IOTHUB_CLIENT_INVALID_ARG; 01474 } 01475 else 01476 { 01477 result = IoTHubClient_LL_UploadToBlob_Impl(iotHubClientHandle->uploadToBlobHandle, destinationFileName, source, size); 01478 } 01479 return result; 01480 } 01481 #endif
Generated on Wed Jul 13 2022 07:19:04 by
1.7.2