source: azure_iot_hub_mbedtls/trunk/azure_iothub/iothub_client/src/iothub_client_core_ll.c@ 398

Last change on this file since 398 was 398, checked in by coas-nagasima, 5 years ago

mbedTLS版Azure IoT Hub接続サンプルのソースコードを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 146.5 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdint.h>
6#include <string.h>
7#include <errno.h>
8
9#include "azure_c_shared_utility/optimize_size.h"
10#include "azure_c_shared_utility/gballoc.h"
11#include "azure_c_shared_utility/string_tokenizer.h"
12#include "azure_c_shared_utility/doublylinkedlist.h"
13#include "azure_c_shared_utility/xlogging.h"
14#include "azure_c_shared_utility/tickcounter.h"
15#include "azure_c_shared_utility/constbuffer.h"
16#include "azure_c_shared_utility/platform.h"
17#include "azure_c_shared_utility/singlylinkedlist.h"
18#include "azure_c_shared_utility/shared_util_options.h"
19#include "azure_c_shared_utility/agenttime.h"
20
21#include "iothub_client_core_ll.h"
22#include "iothub_client_options.h"
23#include "iothub_client_version.h"
24#include "iothub_transport_ll.h"
25#include "internal/iothub_client_authorization.h"
26#include "internal/iothub_client_private.h"
27#include "internal/iothub_client_diagnostic.h"
28#include "internal/iothubtransport.h"
29
30#ifndef DONT_USE_UPLOADTOBLOB
31#include "internal/iothub_client_ll_uploadtoblob.h"
32#endif
33
34#ifdef USE_EDGE_MODULES
35#include "azure_c_shared_utility/envvariable.h"
36#include "azure_prov_client/iothub_security_factory.h"
37#include "internal/iothub_client_edge.h"
38#endif
39
40#define LOG_ERROR_RESULT LogError("result = %s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_RESULT, result));
41#define INDEFINITE_TIME ((time_t)(-1))
42
43MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_FILE_UPLOAD_RESULT, IOTHUB_CLIENT_FILE_UPLOAD_RESULT_VALUES);
44MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES);
45MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_RETRY_POLICY, IOTHUB_CLIENT_RETRY_POLICY_VALUES);
46MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_STATUS, IOTHUB_CLIENT_STATUS_VALUES);
47MU_DEFINE_ENUM_STRINGS(IOTHUB_IDENTITY_TYPE, IOTHUB_IDENTITY_TYPE_VALUE);
48MU_DEFINE_ENUM_STRINGS(IOTHUB_PROCESS_ITEM_RESULT, IOTHUB_PROCESS_ITEM_RESULT_VALUE);
49MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_IOTHUB_METHOD_STATUS, IOTHUB_CLIENT_IOTHUB_METHOD_STATUS_VALUES);
50MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_CONFIRMATION_RESULT, IOTHUB_CLIENT_CONFIRMATION_RESULT_VALUES);
51MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_CONNECTION_STATUS, IOTHUB_CLIENT_CONNECTION_STATUS_VALUES);
52MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_CONNECTION_STATUS_REASON, IOTHUB_CLIENT_CONNECTION_STATUS_REASON_VALUES);
53MU_DEFINE_ENUM_STRINGS(TRANSPORT_TYPE, TRANSPORT_TYPE_VALUES);
54MU_DEFINE_ENUM_STRINGS(DEVICE_TWIN_UPDATE_STATE, DEVICE_TWIN_UPDATE_STATE_VALUES);
55#ifndef DONT_USE_UPLOADTOBLOB
56MU_DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT_VALUES);
57#endif // DONT_USE_UPLOADTOBLOB
58
59#define CALLBACK_TYPE_VALUES \
60 CALLBACK_TYPE_NONE, \
61 CALLBACK_TYPE_SYNC, \
62 CALLBACK_TYPE_ASYNC
63
64MU_DEFINE_ENUM(CALLBACK_TYPE, CALLBACK_TYPE_VALUES)
65MU_DEFINE_ENUM_STRINGS(CALLBACK_TYPE, CALLBACK_TYPE_VALUES)
66
67typedef struct IOTHUB_METHOD_CALLBACK_DATA_TAG
68{
69 CALLBACK_TYPE type;
70 IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC callbackSync;
71 IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK callbackAsync;
72 void* userContextCallback;
73}IOTHUB_METHOD_CALLBACK_DATA;
74
75typedef struct IOTHUB_EVENT_CALLBACK_TAG
76{
77 STRING_HANDLE inputName;
78 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC callbackAsync;
79 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX callbackAsyncEx;
80 void* userContextCallback;
81 void* userContextCallbackEx;
82}IOTHUB_EVENT_CALLBACK;
83
84typedef struct IOTHUB_MESSAGE_CALLBACK_DATA_TAG
85{
86 CALLBACK_TYPE type;
87 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC callbackSync;
88 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX callbackAsync;
89 void* userContextCallback;
90}IOTHUB_MESSAGE_CALLBACK_DATA;
91
92typedef struct GET_TWIN_CONTEXT_TAG
93{
94 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK callback;
95 void* context;
96} GET_TWIN_CONTEXT;
97
98typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG
99{
100 DLIST_ENTRY waitingToSend;
101 DLIST_ENTRY iot_msg_queue;
102 DLIST_ENTRY iot_ack_queue;
103 TRANSPORT_LL_HANDLE transportHandle;
104 bool isSharedTransport;
105 IOTHUB_DEVICE_HANDLE deviceHandle;
106 TRANSPORT_PROVIDER_FIELDS;
107 IOTHUB_MESSAGE_CALLBACK_DATA messageCallback;
108 IOTHUB_METHOD_CALLBACK_DATA methodCallback;
109 IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK conStatusCallback;
110 void* conStatusUserContextCallback;
111 time_t lastMessageReceiveTime;
112 TICK_COUNTER_HANDLE tickCounter; /*shared tickcounter used to track message timeouts in waitingToSend list*/
113 tickcounter_ms_t currentMessageTimeout;
114 uint64_t current_device_twin_timeout;
115 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback;
116 void* deviceTwinContextCallback;
117 IOTHUB_CLIENT_RETRY_POLICY retryPolicy;
118 size_t retryTimeoutLimitInSeconds;
119#ifndef DONT_USE_UPLOADTOBLOB
120 IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE uploadToBlobHandle;
121#endif
122#ifdef USE_EDGE_MODULES
123 IOTHUB_CLIENT_EDGE_HANDLE methodHandle;
124#endif
125 uint32_t data_msg_id;
126 bool complete_twin_update_encountered;
127 IOTHUB_AUTHORIZATION_HANDLE authorization_module;
128 STRING_HANDLE product_info;
129 IOTHUB_DIAGNOSTIC_SETTING_DATA diagnostic_setting;
130 SINGLYLINKEDLIST_HANDLE event_callbacks; // List of IOTHUB_EVENT_CALLBACK's
131}IOTHUB_CLIENT_CORE_LL_HANDLE_DATA;
132
133static const char HOSTNAME_TOKEN[] = "HostName";
134static const char DEVICEID_TOKEN[] = "DeviceId";
135static const char X509_TOKEN[] = "x509";
136static const char X509_TOKEN_ONLY_ACCEPTABLE_VALUE[] = "true";
137static const char DEVICEKEY_TOKEN[] = "SharedAccessKey";
138static const char DEVICESAS_TOKEN[] = "SharedAccessSignature";
139static const char PROTOCOL_GATEWAY_HOST_TOKEN[] = "GatewayHostName";
140static const char MODULE_ID_TOKEN[] = "ModuleId";
141static const char PROVISIONING_TOKEN[] = "UseProvisioning";
142static const char PROVISIONING_ACCEPTABLE_VALUE[] = "true";
143
144
145#ifdef USE_EDGE_MODULES
146/*The following section should be moved to iothub_module_client_ll.c during impending refactor*/
147
148static const char* ENVIRONMENT_VAR_EDGEHUB_CONNECTIONSTRING = "EdgeHubConnectionString";
149static const char* ENVIRONMENT_VAR_EDGEHUB_CACERTIFICATEFILE = "EdgeModuleCACertificateFile";
150static const char* ENVIRONMENT_VAR_EDGEAUTHSCHEME = "IOTEDGE_AUTHSCHEME";
151static const char* ENVIRONMENT_VAR_EDGEDEVICEID = "IOTEDGE_DEVICEID";
152static const char* ENVIRONMENT_VAR_EDGEMODULEID = "IOTEDGE_MODULEID";
153static const char* ENVIRONMENT_VAR_EDGEHUBHOSTNAME = "IOTEDGE_IOTHUBHOSTNAME";
154static const char* ENVIRONMENT_VAR_EDGEGATEWAYHOST = "IOTEDGE_GATEWAYHOSTNAME";
155static const char* SAS_TOKEN_AUTH = "sasToken";
156
157
158typedef struct EDGE_ENVIRONMENT_VARIABLES_TAG
159{
160 const char* connection_string;
161 const char* ca_trusted_certificate_file;
162 const char* auth_scheme;
163 const char* device_id;
164 const char* iothub_name;
165 const char* iothub_suffix;
166 const char* gatewayhostname;
167 const char* module_id;
168 char* iothub_buffer;
169} EDGE_ENVIRONMENT_VARIABLES;
170
171
172static int retrieve_edge_environment_variabes(EDGE_ENVIRONMENT_VARIABLES *edge_environment_variables)
173{
174 int result;
175 const char* edgehubhostname;
176 char* edgehubhostname_separator;
177
178 if ((edge_environment_variables->connection_string = environment_get_variable(ENVIRONMENT_VAR_EDGEHUB_CONNECTIONSTRING)) != NULL)
179 {
180 if ((edge_environment_variables->ca_trusted_certificate_file = environment_get_variable(ENVIRONMENT_VAR_EDGEHUB_CACERTIFICATEFILE)) == NULL)
181 {
182 LogError("Environment variable %s is missing. When %s is set, it is required", ENVIRONMENT_VAR_EDGEHUB_CACERTIFICATEFILE, ENVIRONMENT_VAR_EDGEHUB_CONNECTIONSTRING);
183 result = MU_FAILURE;
184 }
185 else
186 {
187 // If we can read in the connection string and trusted certs, we're done.
188 result = 0;
189 }
190 }
191 else
192 {
193 // We're NOT using pre-configured EdgeConnection string / certificates. In this case, we use these environment variables when
194 // communicating to Edge service.
195 if ((edge_environment_variables->auth_scheme = environment_get_variable(ENVIRONMENT_VAR_EDGEAUTHSCHEME)) == NULL)
196 {
197 LogError("Environment %s not set", ENVIRONMENT_VAR_EDGEAUTHSCHEME);
198 result = MU_FAILURE;
199 }
200 else if (strcmp(edge_environment_variables->auth_scheme, SAS_TOKEN_AUTH) != 0)
201 {
202 LogError("Environment %s was set to %s, but only support for %s", ENVIRONMENT_VAR_EDGEAUTHSCHEME, edge_environment_variables->auth_scheme, SAS_TOKEN_AUTH);
203 result = MU_FAILURE;
204 }
205 else if ((edge_environment_variables->device_id = environment_get_variable(ENVIRONMENT_VAR_EDGEDEVICEID)) == NULL)
206 {
207 LogError("Environment %s not set", ENVIRONMENT_VAR_EDGEDEVICEID);
208 result = MU_FAILURE;
209 }
210 else if ((edgehubhostname = environment_get_variable(ENVIRONMENT_VAR_EDGEHUBHOSTNAME)) == NULL)
211 {
212 LogError("Environment %s not set", ENVIRONMENT_VAR_EDGEHUBHOSTNAME);
213 result = MU_FAILURE;
214 }
215 else if ((edge_environment_variables->gatewayhostname = environment_get_variable(ENVIRONMENT_VAR_EDGEGATEWAYHOST)) == NULL)
216 {
217 LogError("Environment %s not set", ENVIRONMENT_VAR_EDGEGATEWAYHOST);
218 result = MU_FAILURE;
219 }
220 else if ((edge_environment_variables->module_id = environment_get_variable(ENVIRONMENT_VAR_EDGEMODULEID)) == NULL)
221 {
222 LogError("Environment %s not set", ENVIRONMENT_VAR_EDGEMODULEID);
223 result = MU_FAILURE;
224 }
225 // Make a copy of just ENVIRONMENT_VAR_EDGEHUBHOSTNAME. We need to make changes in place (namely inserting a '\0')
226 // and can't do this with system environment variable safely.
227 else if (mallocAndStrcpy_s(&edge_environment_variables->iothub_buffer, edgehubhostname) != 0)
228 {
229 LogError("Unable to copy buffer");
230 result = MU_FAILURE;
231 }
232 else if ((edgehubhostname_separator = strchr(edge_environment_variables->iothub_buffer, '.')) == NULL)
233 {
234 LogError("Environment edgehub %s invalid, requires '.' separator", edge_environment_variables->iothub_buffer);
235 result = MU_FAILURE;
236 }
237 else if (*(edgehubhostname_separator + 1) == 0)
238 {
239 LogError("Environment edgehub %s invalid, no content after '.' separator", edge_environment_variables->iothub_buffer);
240 result = MU_FAILURE;
241 }
242 else
243 {
244 edge_environment_variables->iothub_name = edge_environment_variables->iothub_buffer;
245 *edgehubhostname_separator = 0;
246 edge_environment_variables->iothub_suffix = edgehubhostname_separator + 1;
247 result = 0;
248 }
249 }
250
251 return result;
252}
253
254IOTHUB_CLIENT_EDGE_HANDLE IoTHubClientCore_LL_GetEdgeHandle(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle)
255{
256 IOTHUB_CLIENT_EDGE_HANDLE result;
257 if (iotHubClientHandle != NULL)
258 {
259 result = iotHubClientHandle->methodHandle;
260 }
261 else
262 {
263 result = NULL;
264 }
265
266 return result;
267}
268#endif /* USE_EDGE_MODULES */
269
270static void setTransportProtocol(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData, TRANSPORT_PROVIDER* protocol)
271{
272 handleData->IoTHubTransport_SendMessageDisposition = protocol->IoTHubTransport_SendMessageDisposition;
273 handleData->IoTHubTransport_GetHostname = protocol->IoTHubTransport_GetHostname;
274 handleData->IoTHubTransport_SetOption = protocol->IoTHubTransport_SetOption;
275 handleData->IoTHubTransport_Create = protocol->IoTHubTransport_Create;
276 handleData->IoTHubTransport_Destroy = protocol->IoTHubTransport_Destroy;
277 handleData->IoTHubTransport_Register = protocol->IoTHubTransport_Register;
278 handleData->IoTHubTransport_Unregister = protocol->IoTHubTransport_Unregister;
279 handleData->IoTHubTransport_Subscribe = protocol->IoTHubTransport_Subscribe;
280 handleData->IoTHubTransport_Unsubscribe = protocol->IoTHubTransport_Unsubscribe;
281 handleData->IoTHubTransport_DoWork = protocol->IoTHubTransport_DoWork;
282 handleData->IoTHubTransport_SetRetryPolicy = protocol->IoTHubTransport_SetRetryPolicy;
283 handleData->IoTHubTransport_GetSendStatus = protocol->IoTHubTransport_GetSendStatus;
284 handleData->IoTHubTransport_ProcessItem = protocol->IoTHubTransport_ProcessItem;
285 handleData->IoTHubTransport_Subscribe_DeviceTwin = protocol->IoTHubTransport_Subscribe_DeviceTwin;
286 handleData->IoTHubTransport_Unsubscribe_DeviceTwin = protocol->IoTHubTransport_Unsubscribe_DeviceTwin;
287 handleData->IoTHubTransport_GetTwinAsync = protocol->IoTHubTransport_GetTwinAsync;
288 handleData->IoTHubTransport_Subscribe_DeviceMethod = protocol->IoTHubTransport_Subscribe_DeviceMethod;
289 handleData->IoTHubTransport_Unsubscribe_DeviceMethod = protocol->IoTHubTransport_Unsubscribe_DeviceMethod;
290 handleData->IoTHubTransport_DeviceMethod_Response = protocol->IoTHubTransport_DeviceMethod_Response;
291 handleData->IoTHubTransport_Subscribe_InputQueue = protocol->IoTHubTransport_Subscribe_InputQueue;
292 handleData->IoTHubTransport_Unsubscribe_InputQueue = protocol->IoTHubTransport_Unsubscribe_InputQueue;
293 handleData->IoTHubTransport_SetCallbackContext = protocol->IoTHubTransport_SetCallbackContext;
294}
295
296static bool is_event_equal(IOTHUB_EVENT_CALLBACK *event_callback, const char *input_name)
297{
298 bool result;
299
300 if (event_callback != NULL)
301 {
302 const char* event_input_name = STRING_c_str(event_callback->inputName);
303 if ((event_input_name != NULL) && (input_name != NULL))
304 {
305 // Matched the input queue name of a named handler
306 result = (strcmp(event_input_name, input_name) == 0);
307 }
308 else if ((input_name == NULL) && (event_input_name == NULL))
309 {
310 // Matched the default handler
311 result = true;
312 }
313 else
314 {
315 result = false;
316 }
317 }
318 else
319 {
320 result = false;
321 }
322 return result;
323}
324
325static bool is_event_equal_for_match(LIST_ITEM_HANDLE list_item, const void* match_context)
326{
327 return is_event_equal((IOTHUB_EVENT_CALLBACK*)singlylinkedlist_item_get_value(list_item), (const char*)match_context);
328}
329
330static void device_twin_data_destroy(IOTHUB_DEVICE_TWIN* client_item)
331{
332 CONSTBUFFER_DecRef(client_item->report_data_handle);
333 free(client_item);
334}
335
336static int create_edge_handle(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handle_data, const IOTHUB_CLIENT_CONFIG* config, const char* module_id)
337{
338 int result;
339 (void)config;
340 (void)module_id;
341#ifdef USE_EDGE_MODULES
342 /* There is no way to currently distinguish a regular module from a edge module, so this handle is created regardless of if appropriate.
343 However, as a gateway hostname is required in order to create an Edge Handle, we need to at least make sure that exists
344 in order to prevent errors.
345
346 The end result is that all edge modules will have an EdgeHandle, but only some non-edge modules will have it.
347 Regardless, non-edge modules will never be able to use the handle.
348 */
349 if (config->protocolGatewayHostName != NULL)
350 {
351 handle_data->methodHandle = IoTHubClient_EdgeHandle_Create(config, handle_data->authorization_module, module_id);
352
353 if (handle_data->methodHandle == NULL)
354 {
355 LogError("Unable to IoTHubModuleClient_LL_MethodHandle_Create");
356 result = MU_FAILURE;
357 }
358 else
359 {
360 result = 0;
361 }
362 }
363 else
364 {
365 result = 0;
366 }
367
368#else
369 (void)handle_data;
370 result = 0;
371#endif
372 return result;
373}
374
375static int create_blob_upload_module(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handle_data, const IOTHUB_CLIENT_CONFIG* config)
376{
377 int result;
378 (void)handle_data;
379 (void)config;
380#ifndef DONT_USE_UPLOADTOBLOB
381 handle_data->uploadToBlobHandle = IoTHubClient_LL_UploadToBlob_Create(config, handle_data->authorization_module);
382 if (handle_data->uploadToBlobHandle == NULL)
383 {
384 LogError("unable to IoTHubClientCore_LL_UploadToBlob_Create");
385 result = MU_FAILURE;
386 }
387 else
388 {
389 result = 0;
390 }
391#else
392 result = 0;
393#endif
394 return result;
395}
396
397static void destroy_blob_upload_module(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handle_data)
398{
399 (void)handle_data;
400#ifndef DONT_USE_UPLOADTOBLOB
401 /*Codes_SRS_IOTHUBCLIENT_LL_02_046: [ If creating the TICK_COUNTER_HANDLE fails then IoTHubClientCore_LL_Create shall fail and return NULL. ]*/
402 IoTHubClient_LL_UploadToBlob_Destroy(handle_data->uploadToBlobHandle);
403#endif
404}
405
406static void destroy_module_method_module(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handle_data)
407{
408 (void)handle_data;
409#ifdef USE_EDGE_MODULES
410 IoTHubClient_EdgeHandle_Destroy(handle_data->methodHandle);
411#endif
412}
413
414static bool invoke_message_callback(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData, MESSAGE_CALLBACK_INFO* messageData)
415{
416 bool result;
417 /* Codes_SRS_IOTHUBCLIENT_LL_09_004: [IoTHubClient_LL_GetLastMessageReceiveTime shall return lastMessageReceiveTime in localtime] */
418 handleData->lastMessageReceiveTime = get_time(NULL);
419
420 switch (handleData->messageCallback.type)
421 {
422 case CALLBACK_TYPE_NONE:
423 {
424 /*Codes_SRS_IOTHUBCLIENT_LL_02_032: [If the client is not subscribed to receive messages then IoTHubClient_LL_MessageCallback shall return false.] */
425 LogError("Invalid workflow - not currently set up to accept messages");
426 result = false;
427 break;
428 }
429 case CALLBACK_TYPE_SYNC:
430 {
431 /*Codes_SRS_IOTHUBCLIENT_LL_02_030: [If messageCallbackType is LEGACY then IoTHubClient_LL_MessageCallback shall invoke the last callback function (the parameter messageCallback to IoTHubClient_LL_SetMessageCallback) passing the message and the passed userContextCallback.]*/
432 IOTHUBMESSAGE_DISPOSITION_RESULT cb_result = handleData->messageCallback.callbackSync(messageData->messageHandle, handleData->messageCallback.userContextCallback);
433
434 /*Codes_SRS_IOTHUBCLIENT_LL_10_007: [If messageCallbackType is LEGACY then IoTHubClient_LL_MessageCallback shall send the message disposition as returned by the client to the underlying layer.] */
435 if (handleData->IoTHubTransport_SendMessageDisposition(messageData, cb_result) != IOTHUB_CLIENT_OK)
436 {
437 LogError("IoTHubTransport_SendMessageDisposition failed");
438 }
439 result = true;
440 break;
441 }
442 case CALLBACK_TYPE_ASYNC:
443 {
444 /* Codes_SRS_IOTHUBCLIENT_LL_10_009: [If messageCallbackType is ASYNC then IoTHubClient_LL_MessageCallback shall return what messageCallbacEx returns.] */
445 result = handleData->messageCallback.callbackAsync(messageData, handleData->messageCallback.userContextCallback);
446 if (!result)
447 {
448 LogError("messageCallbackEx failed");
449 }
450 break;
451 }
452 default:
453 {
454 LogError("Invalid state");
455 result = false;
456 break;
457 }
458 }
459
460 return result;
461}
462
463/*Codes_SRS_IOTHUBCLIENT_LL_10_032: ["product_info" - takes a char string as an argument to specify the product information(e.g. `"ProductName/ProductVersion"`). ]*/
464/*Codes_SRS_IOTHUBCLIENT_LL_10_034: ["product_info" - shall store the given string concatenated with the sdk information and the platform information in the form(ProductInfo DeviceSDKName / DeviceSDKVersion(OSName OSVersion; Architecture). ]*/
465static STRING_HANDLE make_product_info(const char* product)
466{
467 STRING_HANDLE result;
468 STRING_HANDLE pfi = platform_get_platform_info(PLATFORM_INFO_OPTION_DEFAULT);
469 if (pfi == NULL)
470 {
471 result = NULL;
472 }
473 else
474 {
475 if (product == NULL)
476 {
477 result = STRING_construct_sprintf("%s %s", CLIENT_DEVICE_TYPE_PREFIX CLIENT_DEVICE_BACKSLASH IOTHUB_SDK_VERSION, STRING_c_str(pfi));
478 }
479 else
480 {
481 result = STRING_construct_sprintf("%s %s %s", product, CLIENT_DEVICE_TYPE_PREFIX CLIENT_DEVICE_BACKSLASH IOTHUB_SDK_VERSION, STRING_c_str(pfi));
482 }
483 STRING_delete(pfi);
484 }
485 return result;
486}
487
488static void IoTHubClientCore_LL_SendComplete(PDLIST_ENTRY completed, IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* ctx)
489{
490 /*Codes_SRS_IOTHUBCLIENT_LL_02_022: [If parameter completed is NULL, or parameter handle is NULL then IoTHubClientCore_LL_SendBatch shall return.]*/
491 if (
492 (ctx == NULL) ||
493 (completed == NULL)
494 )
495 {
496 /*"shall return"*/
497 LogError("invalid arg");
498 }
499 else
500 {
501 /*Codes_SRS_IOTHUBCLIENT_LL_02_027: [If parameter result is IOTHUB_CLIENT_CONFIRMATION_ERROR then IoTHubClientCore_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.] */
502 /*Codes_SRS_IOTHUBCLIENT_LL_02_025: [If parameter result is IOTHUB_CLIENT_CONFIRMATION_OK then IoTHubClientCore_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.]*/
503 PDLIST_ENTRY oldest;
504 while ((oldest = DList_RemoveHeadList(completed)) != completed)
505 {
506 IOTHUB_MESSAGE_LIST* messageList = (IOTHUB_MESSAGE_LIST*)containingRecord(oldest, IOTHUB_MESSAGE_LIST, entry);
507 /*Codes_SRS_IOTHUBCLIENT_LL_02_026: [If any callback is NULL then there shall not be a callback call.]*/
508 if (messageList->callback != NULL)
509 {
510 messageList->callback(result, messageList->context);
511 }
512 IoTHubMessage_Destroy(messageList->messageHandle);
513 free(messageList);
514 }
515 }
516}
517
518static void IoTHubClientCore_LL_RetrievePropertyComplete(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* ctx)
519{
520 if (ctx == NULL)
521 {
522 /* Codes_SRS_IOTHUBCLIENT_LL_07_013: [ If handle is NULL then IoTHubClientCore_LL_RetrievePropertyComplete shall do nothing.] */
523 LogError("Invalid argument ctx NULL");
524 }
525 else
526 {
527 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
528 /* Codes_SRS_IOTHUBCLIENT_LL_07_014: [ If deviceTwinCallback is NULL then IoTHubClientCore_LL_RetrievePropertyComplete shall do nothing.] */
529 if (handleData->deviceTwinCallback)
530 {
531 /* 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 IoTHubClientCore_LL_RetrievePropertyComplete shall do nothing.] */
532 if (update_state == DEVICE_TWIN_UPDATE_COMPLETE)
533 {
534 handleData->complete_twin_update_encountered = true;
535 }
536 if (handleData->complete_twin_update_encountered)
537 {
538 /* Codes_SRS_IOTHUBCLIENT_LL_07_016: [ If deviceTwinCallback is set and DEVICE_TWIN_UPDATE_COMPLETE has been encountered then IoTHubClientCore_LL_RetrievePropertyComplete shall call deviceTwinCallback.] */
539 handleData->deviceTwinCallback(update_state, payLoad, size, handleData->deviceTwinContextCallback);
540 }
541 }
542 }
543}
544
545static void IoTHubClientCore_LL_ReportedStateComplete(uint32_t item_id, int status_code, void* ctx)
546{
547 /* Codes_SRS_IOTHUBCLIENT_LL_07_002: [ if handle or queue_handle are NULL then IoTHubClientCore_LL_ReportedStateComplete shall do nothing. ] */
548 if (ctx == NULL)
549 {
550 /*"shall return"*/
551 LogError("Invalid argument handle=%p", ctx);
552 }
553 else
554 {
555 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
556
557 /* Codes_SRS_IOTHUBCLIENT_LL_07_003: [ IoTHubClientCore_LL_ReportedStateComplete shall enumerate through the IOTHUB_DEVICE_TWIN structures in queue_handle. ]*/
558 DLIST_ENTRY* client_item = handleData->iot_ack_queue.Flink;
559 while (client_item != &(handleData->iot_ack_queue)) /*while we are not at the end of the list*/
560 {
561 PDLIST_ENTRY next_item = client_item->Flink;
562 IOTHUB_DEVICE_TWIN* queue_data = containingRecord(client_item, IOTHUB_DEVICE_TWIN, entry);
563 if (queue_data->item_id == item_id)
564 {
565 if (queue_data->reported_state_callback != NULL)
566 {
567 queue_data->reported_state_callback(status_code, queue_data->context);
568 }
569 /*Codes_SRS_IOTHUBCLIENT_LL_07_009: [ IoTHubClientCore_LL_ReportedStateComplete shall remove the IOTHUB_DEVICE_TWIN item from the ack queue.]*/
570 DList_RemoveEntryList(client_item);
571 device_twin_data_destroy(queue_data);
572 break;
573 }
574 client_item = next_item;
575 }
576 }
577}
578
579static void IoTHubClientCore_LL_ConnectionStatusCallBack(IOTHUB_CLIENT_CONNECTION_STATUS status, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* ctx)
580{
581 /*Codes_SRS_IOTHUBCLIENT_LL_25_113: [If parameter connectionStatus is NULL or parameter handle is NULL then IoTHubClientCore_LL_ConnectionStatusCallBack shall return.]*/
582 if (ctx == NULL)
583 {
584 /*"shall return"*/
585 LogError("invalid arg");
586 }
587 else
588 {
589 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
590
591 /*Codes_SRS_IOTHUBCLIENT_LL_25_114: [IoTHubClientCore_LL_ConnectionStatusCallBack shall call non-callback set by the user from IoTHubClientCore_LL_SetConnectionStatusCallback passing the status, reason and the passed userContextCallback.]*/
592 if (handleData->conStatusCallback != NULL)
593 {
594 handleData->conStatusCallback(status, reason, handleData->conStatusUserContextCallback);
595 }
596 }
597
598}
599
600static const char* IoTHubClientCore_LL_GetProductInfo(void* ctx)
601{
602 const char* result;
603 if (ctx == NULL)
604 {
605 result = NULL;
606 LogError("invalid argument ctx %p", ctx);
607 }
608 else
609 {
610 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* iothub_data = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
611 result = STRING_c_str(iothub_data->product_info);
612 }
613 return result;
614}
615
616static bool IoTHubClientCore_LL_MessageCallbackFromInput(MESSAGE_CALLBACK_INFO* messageData, void* ctx)
617{
618 bool result;
619 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
620
621 if ((handleData == NULL) || messageData == NULL)
622 {
623 // Codes_SRS_IOTHUBCLIENT_LL_31_137: [ If either parameter `handle` or `messageData` is `NULL` then `IoTHubClient_LL_MessageCallbackFromInput` shall return `false`.** ]
624 LogError("invalid argument: handle(%p), messageData(%p)", handleData, messageData);
625 result = false;
626 }
627 else if (messageData->messageHandle == NULL)
628 {
629 // Codes_SRS_IOTHUBCLIENT_LL_31_137: [ If either parameter `handle` or `messageData` is `NULL` then `IoTHubClient_LL_MessageCallbackFromInput` shall return `false`.** ]
630 LogError("invalid argument messageData->messageHandle(NULL)");
631 result = false;
632 }
633 else if (handleData->event_callbacks == NULL)
634 {
635 LogError("Callback from input called but no input specific callbacks registered");
636 result = false;
637 }
638 else
639 {
640 const char* inputName = IoTHubMessage_GetInputName(messageData->messageHandle);
641
642 LIST_ITEM_HANDLE item_handle = NULL;
643
644 item_handle = singlylinkedlist_find(handleData->event_callbacks, is_event_equal_for_match, (const void*)inputName);
645
646 if (item_handle == NULL)
647 {
648 // Codes_SRS_IOTHUBCLIENT_LL_31_138: [ If there is no registered handler for the inputName from `IoTHubMessage_GetInputName`, then `IoTHubClient_LL_MessageCallbackFromInput` shall attempt invoke the default handler handler.** ]
649 item_handle = singlylinkedlist_find(handleData->event_callbacks, is_event_equal_for_match, NULL);
650 }
651
652 if (item_handle == NULL)
653 {
654 LogError("Could not find callback (explicit or default) for input queue %s", inputName);
655 result = false;
656 }
657 else
658 {
659 IOTHUB_EVENT_CALLBACK* event_callback = (IOTHUB_EVENT_CALLBACK*)singlylinkedlist_item_get_value(item_handle);
660 if (NULL == event_callback)
661 {
662 LogError("singlylinkedlist_item_get_value for event_callback failed");
663 result = false;
664 }
665 else
666 {
667 // Codes_SRS_IOTHUBCLIENT_LL_09_004: [IoTHubClient_LL_GetLastMessageReceiveTime shall return lastMessageReceiveTime in localtime]
668 handleData->lastMessageReceiveTime = get_time(NULL);
669
670 if (event_callback->callbackAsyncEx != NULL)
671 {
672 // Codes_SRS_IOTHUBCLIENT_LL_31_139: [ `IoTHubClient_LL_MessageCallbackFromInput` shall the callback from the given inputName queue if it has been registered.** ]
673 result = event_callback->callbackAsyncEx(messageData, event_callback->userContextCallbackEx);
674 }
675 else
676 {
677 // Codes_SRS_IOTHUBCLIENT_LL_31_139: [ `IoTHubClient_LL_MessageCallbackFromInput` shall the callback from the given inputName queue if it has been registered.** ]
678 IOTHUBMESSAGE_DISPOSITION_RESULT cb_result = event_callback->callbackAsync(messageData->messageHandle, event_callback->userContextCallback);
679
680 // Codes_SRS_IOTHUBCLIENT_LL_31_140: [ `IoTHubClient_LL_MessageCallbackFromInput` shall send the message disposition as returned by the client to the underlying layer and return `true` if an input queue match is found.** ]
681 if (handleData->IoTHubTransport_SendMessageDisposition(messageData, cb_result) != IOTHUB_CLIENT_OK)
682 {
683 LogError("IoTHubTransport_SendMessageDisposition failed");
684 }
685 result = true;
686 }
687 }
688 }
689 }
690 return result;
691}
692
693static bool IoTHubClientCore_LL_MessageCallback(MESSAGE_CALLBACK_INFO* messageData, void* ctx)
694{
695 bool result;
696 if ((ctx == NULL) || messageData == NULL)
697 {
698 /*Codes_SRS_IOTHUBCLIENT_LL_02_029: [If parameter handle is NULL then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */
699 LogError("invalid argument: ctx(%p), messageData(%p)", ctx, messageData);
700 result = false;
701 }
702 else if (messageData->messageHandle == NULL)
703 {
704 /*Codes_SRS_IOTHUBCLIENT_LL_10_004: [If messageHandle field of paramger messageData is NULL then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */
705 LogError("invalid argument messageData->messageHandle(NULL)");
706 result = false;
707 }
708 else
709 {
710 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
711 return invoke_message_callback(handleData, messageData);
712 }
713 return result;
714}
715
716static int IoTHubClientCore_LL_DeviceMethodComplete(const char* method_name, const unsigned char* payLoad, size_t size, METHOD_HANDLE response_id, void* ctx)
717{
718 int result;
719 if (ctx == NULL)
720 {
721 /* Codes_SRS_IOTHUBCLIENT_LL_07_017: [ If handle or response is NULL then IoTHubClientCore_LL_DeviceMethodComplete shall return 500. ] */
722 LogError("Invalid argument ctx=%p", ctx);
723 result = MU_FAILURE;
724 }
725 else
726 {
727 /* Codes_SRS_IOTHUBCLIENT_LL_07_018: [ If deviceMethodCallback is not NULL IoTHubClientCore_LL_DeviceMethodComplete shall execute deviceMethodCallback and return the status. ] */
728 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)ctx;
729 switch (handleData->methodCallback.type)
730 {
731 case CALLBACK_TYPE_SYNC:
732 {
733 unsigned char* payload_resp = NULL;
734 size_t response_size = 0;
735 result = handleData->methodCallback.callbackSync(method_name, payLoad, size, &payload_resp, &response_size, handleData->methodCallback.userContextCallback);
736 /* Codes_SRS_IOTHUBCLIENT_LL_07_020: [ deviceMethodCallback shall build the BUFFER_HANDLE with the response payload from the IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC callback. ] */
737 if (payload_resp != NULL && response_size > 0)
738 {
739 result = handleData->IoTHubTransport_DeviceMethod_Response(handleData->deviceHandle, response_id, payload_resp, response_size, result);
740 }
741 else
742 {
743 result = MU_FAILURE;
744 }
745 if (payload_resp != NULL)
746 {
747 free(payload_resp);
748 }
749 break;
750 }
751 case CALLBACK_TYPE_ASYNC:
752 result = handleData->methodCallback.callbackAsync(method_name, payLoad, size, response_id, handleData->methodCallback.userContextCallback);
753 break;
754 default:
755 /* Codes_SRS_IOTHUBCLIENT_LL_07_019: [ If deviceMethodCallback is NULL IoTHubClientCore_LL_DeviceMethodComplete shall return 404. ] */
756 result = 0;
757 break;
758 }
759 }
760 return result;
761}
762
763static IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* initialize_iothub_client(const IOTHUB_CLIENT_CONFIG* client_config, const IOTHUB_CLIENT_DEVICE_CONFIG* device_config, bool use_dev_auth, const char* module_id)
764{
765 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* result;
766 srand((unsigned int)time(NULL));
767 STRING_HANDLE product_info = make_product_info(NULL);
768 if (product_info == NULL)
769 {
770 LogError("failed to initialize product info");
771 result = NULL;
772 }
773 else
774 {
775 result = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)malloc(sizeof(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA));
776 if (result == NULL)
777 {
778 LogError("failure allocating IOTHUB_CLIENT_CORE_LL_HANDLE_DATA");
779 STRING_delete(product_info);
780 }
781 else
782 {
783 IOTHUB_CLIENT_CONFIG actual_config;
784 const IOTHUB_CLIENT_CONFIG* config = NULL;
785 char* IoTHubName = NULL;
786 char* IoTHubSuffix = NULL;
787
788 memset(result, 0, sizeof(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA));
789 if (use_dev_auth)
790 {
791 if ((result->authorization_module = IoTHubClient_Auth_CreateFromDeviceAuth(client_config->deviceId, module_id)) == NULL)
792 {
793 LogError("Failed create authorization module");
794 free(result);
795 STRING_delete(product_info);
796 result = NULL;
797 }
798 }
799 else
800 {
801 const char* device_key;
802 const char* device_id;
803 const char* sas_token;
804 if (device_config == NULL)
805 {
806 device_key = client_config->deviceKey;
807 device_id = client_config->deviceId;
808 sas_token = client_config->deviceSasToken;
809 }
810 else
811 {
812 device_key = device_config->deviceKey;
813 device_id = device_config->deviceId;
814 sas_token = device_config->deviceSasToken;
815 }
816
817 /* Codes_SRS_IOTHUBCLIENT_LL_07_029: [ IoTHubClientCore_LL_Create shall create the Auth module with the device_key, device_id, and/or deviceSasToken values ] */
818 if ((result->authorization_module = IoTHubClient_Auth_Create(device_key, device_id, sas_token, module_id)) == NULL)
819 {
820 LogError("Failed create authorization module");
821 free(result);
822 STRING_delete(product_info);
823 result = NULL;
824 }
825 }
826
827 if (result != NULL)
828 {
829 TRANSPORT_CALLBACKS_INFO transport_cb;
830 memset(&transport_cb, 0, sizeof(TRANSPORT_CALLBACKS_INFO));
831 transport_cb.send_complete_cb = IoTHubClientCore_LL_SendComplete;
832 transport_cb.twin_retrieve_prop_complete_cb = IoTHubClientCore_LL_RetrievePropertyComplete;
833 transport_cb.twin_rpt_state_complete_cb = IoTHubClientCore_LL_ReportedStateComplete;
834 transport_cb.connection_status_cb = IoTHubClientCore_LL_ConnectionStatusCallBack;
835 transport_cb.prod_info_cb = IoTHubClientCore_LL_GetProductInfo;
836 transport_cb.msg_input_cb = IoTHubClientCore_LL_MessageCallbackFromInput;
837 transport_cb.msg_cb = IoTHubClientCore_LL_MessageCallback;
838 transport_cb.method_complete_cb = IoTHubClientCore_LL_DeviceMethodComplete;
839
840 if (client_config != NULL)
841 {
842 IOTHUBTRANSPORT_CONFIG lowerLayerConfig;
843 memset(&lowerLayerConfig, 0, sizeof(IOTHUBTRANSPORT_CONFIG));
844 /*Codes_SRS_IOTHUBCLIENT_LL_02_006: [IoTHubClientCore_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.]*/
845 lowerLayerConfig.upperConfig = client_config;
846 lowerLayerConfig.waitingToSend = &(result->waitingToSend);
847 lowerLayerConfig.auth_module_handle = result->authorization_module;
848 lowerLayerConfig.moduleId = module_id;
849
850 setTransportProtocol(result, (TRANSPORT_PROVIDER*)client_config->protocol());
851 if ((result->transportHandle = result->IoTHubTransport_Create(&lowerLayerConfig, &transport_cb, result)) == NULL)
852 {
853 /*Codes_SRS_IOTHUBCLIENT_LL_02_007: [If the underlaying layer _Create function fails them IoTHubClientCore_LL_Create shall fail and return NULL.] */
854 LogError("underlying transport failed");
855 destroy_blob_upload_module(result);
856 destroy_module_method_module(result);
857 tickcounter_destroy(result->tickCounter);
858 IoTHubClient_Auth_Destroy(result->authorization_module);
859 STRING_delete(product_info);
860 free(result);
861 result = NULL;
862 }
863 else
864 {
865 /*Codes_SRS_IOTHUBCLIENT_LL_02_008: [Otherwise, IoTHubClientCore_LL_Create shall succeed and return a non-NULL handle.] */
866 result->isSharedTransport = false;
867 config = client_config;
868 }
869 }
870 else
871 {
872 STRING_HANDLE transport_hostname = NULL;
873
874 result->transportHandle = device_config->transportHandle;
875 setTransportProtocol(result, (TRANSPORT_PROVIDER*)device_config->protocol());
876
877 if (result->IoTHubTransport_SetCallbackContext(result->transportHandle, result) != 0)
878 {
879 LogError("unable to set transport callbacks");
880 IoTHubClient_Auth_Destroy(result->authorization_module);
881 STRING_delete(product_info);
882 free(result);
883 result = NULL;
884 }
885 else if ((transport_hostname = result->IoTHubTransport_GetHostname(result->transportHandle)) == NULL)
886 {
887 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClientCore_LL_CreateWithTransport shall fail and return NULL. ]*/
888 LogError("unable to determine the transport IoTHub name");
889 IoTHubClient_Auth_Destroy(result->authorization_module);
890 STRING_delete(product_info);
891 free(result);
892 result = NULL;
893 }
894 else
895 {
896 const char* hostname = STRING_c_str(transport_hostname);
897 /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClientCore_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/
898 /*the first '.' says where the iothubname finishes*/
899 const char* whereIsDot = strchr(hostname, '.');
900 if (whereIsDot == NULL)
901 {
902 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClientCore_LL_CreateWithTransport shall fail and return NULL. ]*/
903 LogError("unable to determine the IoTHub name");
904 IoTHubClient_Auth_Destroy(result->authorization_module);
905 STRING_delete(product_info);
906 free(result);
907 result = NULL;
908 }
909 else
910 {
911 size_t suffix_len = strlen(whereIsDot);
912 /*Codes_SRS_IOTHUBCLIENT_LL_02_096: [ IoTHubClientCore_LL_CreateWithTransport shall create the data structures needed to instantiate a IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE. ]*/
913 IoTHubName = (char*)malloc(whereIsDot - hostname + 1);
914 if (IoTHubName == NULL)
915 {
916 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClientCore_LL_CreateWithTransport shall fail and return NULL. ]*/
917 LogError("unable to malloc");
918 IoTHubClient_Auth_Destroy(result->authorization_module);
919 STRING_delete(product_info);
920 free(result);
921 result = NULL;
922 }
923 else if ((IoTHubSuffix = (char*)malloc(suffix_len + 1)) == NULL)
924 {
925 /*Codes_SRS_IOTHUBCLIENT_LL_02_097: [ If creating the data structures fails or instantiating the IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE fails then IoTHubClientCore_LL_CreateWithTransport shall fail and return NULL. ]*/
926 LogError("unable to malloc");
927 IoTHubClient_Auth_Destroy(result->authorization_module);
928 STRING_delete(product_info);
929 free(result);
930 result = NULL;
931 }
932 else
933 {
934 memset(IoTHubName, 0, whereIsDot - hostname + 1);
935 (void)memcpy(IoTHubName, hostname, whereIsDot - hostname);
936 (void)strcpy(IoTHubSuffix, whereIsDot+1);
937
938 actual_config.deviceId = device_config->deviceId;
939 actual_config.deviceKey = device_config->deviceKey;
940 actual_config.deviceSasToken = device_config->deviceSasToken;
941 actual_config.iotHubName = IoTHubName;
942 actual_config.iotHubSuffix = IoTHubSuffix;
943 actual_config.protocol = NULL; /*irrelevant to IoTHubClientCore_LL_UploadToBlob*/
944 actual_config.protocolGatewayHostName = NULL; /*irrelevant to IoTHubClientCore_LL_UploadToBlob*/
945
946 config = &actual_config;
947
948 /*Codes_SRS_IOTHUBCLIENT_LL_02_008: [Otherwise, IoTHubClientCore_LL_Create shall succeed and return a non-NULL handle.] */
949 result->isSharedTransport = true;
950 }
951 }
952 }
953 STRING_delete(transport_hostname);
954 }
955 }
956 if (result != NULL)
957 {
958 if (create_blob_upload_module(result, config) != 0)
959 {
960 LogError("unable to create blob upload");
961 // Codes_SRS_IOTHUBCLIENT_LL_09_010: [ If any failure occurs `IoTHubClientCore_LL_Create` shall destroy the `transportHandle` only if it has created it ]
962 if (!result->isSharedTransport)
963 {
964 result->IoTHubTransport_Destroy(result->transportHandle);
965 }
966 destroy_blob_upload_module(result);
967 IoTHubClient_Auth_Destroy(result->authorization_module);
968 STRING_delete(product_info);
969 free(result);
970 result = NULL;
971 }
972 else if ((module_id != NULL) && create_edge_handle(result, config, module_id) != 0)
973 {
974 LogError("unable to create module method handle");
975 if (!result->isSharedTransport)
976 {
977 result->IoTHubTransport_Destroy(result->transportHandle);
978 }
979 destroy_blob_upload_module(result);
980 IoTHubClient_Auth_Destroy(result->authorization_module);
981 STRING_delete(product_info);
982 free(result);
983 result = NULL;
984 }
985 else
986 {
987 if ((result->tickCounter = tickcounter_create()) == NULL)
988 {
989 LogError("unable to get a tickcounter");
990 // Codes_SRS_IOTHUBCLIENT_LL_09_010: [ If any failure occurs `IoTHubClientCore_LL_Create` shall destroy the `transportHandle` only if it has created it ]
991 if (!result->isSharedTransport)
992 {
993 result->IoTHubTransport_Destroy(result->transportHandle);
994 }
995 destroy_blob_upload_module(result);
996 destroy_module_method_module(result);
997 IoTHubClient_Auth_Destroy(result->authorization_module);
998 STRING_delete(product_info);
999 free(result);
1000 result = NULL;
1001 }
1002 else
1003 {
1004 /*Codes_SRS_IOTHUBCLIENT_LL_02_004: [Otherwise IoTHubClientCore_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*.]*/
1005 DList_InitializeListHead(&(result->waitingToSend));
1006 DList_InitializeListHead(&(result->iot_msg_queue));
1007 DList_InitializeListHead(&(result->iot_ack_queue));
1008 result->messageCallback.type = CALLBACK_TYPE_NONE;
1009 result->lastMessageReceiveTime = INDEFINITE_TIME;
1010 result->data_msg_id = 1;
1011 result->product_info = product_info;
1012
1013 IOTHUB_DEVICE_CONFIG deviceConfig;
1014 deviceConfig.deviceId = config->deviceId;
1015 deviceConfig.deviceKey = config->deviceKey;
1016 deviceConfig.deviceSasToken = config->deviceSasToken;
1017 deviceConfig.authorization_module = result->authorization_module;
1018 deviceConfig.moduleId = module_id;
1019
1020 /*Codes_SRS_IOTHUBCLIENT_LL_17_008: [IoTHubClientCore_LL_Create shall call the transport _Register function with a populated structure of type IOTHUB_DEVICE_CONFIG and waitingToSend list.] */
1021 if ((result->deviceHandle = result->IoTHubTransport_Register(result->transportHandle, &deviceConfig, &(result->waitingToSend))) == NULL)
1022 {
1023 LogError("Registering device in transport failed");
1024 IoTHubClient_Auth_Destroy(result->authorization_module);
1025 // Codes_SRS_IOTHUBCLIENT_LL_09_010: [ If any failure occurs `IoTHubClientCore_LL_Create` shall destroy the `transportHandle` only if it has created it ]
1026 if (!result->isSharedTransport)
1027 {
1028 result->IoTHubTransport_Destroy(result->transportHandle);
1029 }
1030 destroy_blob_upload_module(result);
1031 destroy_module_method_module(result);
1032 tickcounter_destroy(result->tickCounter);
1033 STRING_delete(product_info);
1034 free(result);
1035 result = NULL;
1036 }
1037 else
1038 {
1039 /*Codes_SRS_IOTHUBCLIENT_LL_02_042: [ By default, messages shall not timeout. ]*/
1040 result->currentMessageTimeout = 0;
1041 result->current_device_twin_timeout = 0;
1042
1043 result->diagnostic_setting.currentMessageNumber = 0;
1044 result->diagnostic_setting.diagSamplingPercentage = 0;
1045 /*Codes_SRS_IOTHUBCLIENT_LL_25_124: [ `IoTHubClientCore_LL_Create` shall set the default retry policy as Exponential backoff with jitter and if succeed and return a `non-NULL` handle. ]*/
1046 if (IoTHubClientCore_LL_SetRetryPolicy(result, IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER, 0) != IOTHUB_CLIENT_OK)
1047 {
1048 LogError("Setting default retry policy in transport failed");
1049 result->IoTHubTransport_Unregister(result->deviceHandle);
1050 IoTHubClient_Auth_Destroy(result->authorization_module);
1051 // Codes_SRS_IOTHUBCLIENT_LL_09_010: [ If any failure occurs `IoTHubClientCore_LL_Create` shall destroy the `transportHandle` only if it has created it ]
1052 if (!result->isSharedTransport)
1053 {
1054 result->IoTHubTransport_Destroy(result->transportHandle);
1055 }
1056 destroy_blob_upload_module(result);
1057 destroy_module_method_module(result);
1058 tickcounter_destroy(result->tickCounter);
1059 STRING_delete(product_info);
1060 free(result);
1061 result = NULL;
1062 }
1063 }
1064 }
1065 }
1066 }
1067 if (IoTHubName)
1068 {
1069 free(IoTHubName);
1070 }
1071 if (IoTHubSuffix)
1072 {
1073 free(IoTHubSuffix);
1074 }
1075 }
1076 }
1077 return result;
1078}
1079
1080static uint32_t get_next_item_id(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData)
1081{
1082 if (handleData->data_msg_id+1 >= UINT32_MAX)
1083 {
1084 handleData->data_msg_id = 1;
1085 }
1086 else
1087 {
1088 handleData->data_msg_id++;
1089 }
1090 return handleData->data_msg_id;
1091}
1092
1093static IOTHUB_DEVICE_TWIN* dev_twin_data_create(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData, uint32_t id, const unsigned char* reportedState, size_t size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback, void* userContextCallback)
1094{
1095 IOTHUB_DEVICE_TWIN* result = (IOTHUB_DEVICE_TWIN*)malloc(sizeof(IOTHUB_DEVICE_TWIN) );
1096 if (result != NULL)
1097 {
1098 result->report_data_handle = CONSTBUFFER_Create(reportedState, size);
1099 if (result->report_data_handle == NULL)
1100 {
1101 LogError("Failure allocating reported state data");
1102 free(result);
1103 result = NULL;
1104 }
1105 else
1106 {
1107 result->item_id = id;
1108 result->ms_timesOutAfter = 0;
1109 result->context = userContextCallback;
1110 result->reported_state_callback = reportedStateCallback;
1111 result->client_handle = handleData;
1112 result->device_handle = handleData->deviceHandle;
1113 }
1114 }
1115 else
1116 {
1117 LogError("Failure allocating device twin information");
1118 }
1119 return result;
1120}
1121
1122static void on_get_device_twin_completed(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
1123{
1124 if (userContextCallback == NULL)
1125 {
1126 LogError("Invalid argument (userContextCallback=NULL)");
1127 }
1128 else
1129 {
1130 GET_TWIN_CONTEXT* getTwinCtx = (GET_TWIN_CONTEXT*)userContextCallback;
1131
1132 getTwinCtx->callback(update_state, payLoad, size, getTwinCtx->context);
1133
1134 free(getTwinCtx);
1135 }
1136}
1137
1138static void delete_event(IOTHUB_EVENT_CALLBACK* event_callback)
1139{
1140 STRING_delete(event_callback->inputName);
1141 free(event_callback->userContextCallbackEx);
1142 free(event_callback);
1143}
1144
1145static void delete_event_callback(const void* item, const void* action_context, bool* continue_processing)
1146{
1147 (void)action_context;
1148 delete_event((IOTHUB_EVENT_CALLBACK*)item);
1149 *continue_processing = true;
1150}
1151
1152static void delete_event_callback_list(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData)
1153{
1154 if (handleData->event_callbacks != NULL)
1155 {
1156 singlylinkedlist_foreach(handleData->event_callbacks, delete_event_callback, NULL);
1157 singlylinkedlist_destroy(handleData->event_callbacks);
1158 handleData->event_callbacks = NULL;
1159 }
1160}
1161
1162
1163IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientCore_LL_CreateFromDeviceAuth(const char* iothub_uri, const char* device_id, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
1164{
1165 IOTHUB_CLIENT_CORE_LL_HANDLE result;
1166 if (iothub_uri == NULL || protocol == NULL || device_id == NULL)
1167 {
1168 LogError("Input parameter is NULL: iothub_uri: %p protocol: %p device_id: %p", iothub_uri, protocol, device_id);
1169 result = NULL;
1170 }
1171 else
1172 {
1173#ifdef USE_PROV_MODULE
1174 IOTHUB_CLIENT_CONFIG* config = (IOTHUB_CLIENT_CONFIG*)malloc(sizeof(IOTHUB_CLIENT_CONFIG));
1175 if (config == NULL)
1176 {
1177 /* Codes_SRS_IOTHUBCLIENT_LL_12_012: [If the allocation failed IoTHubClientCore_LL_CreateFromConnectionString returns NULL] */
1178 LogError("Malloc failed");
1179 result = NULL;
1180 }
1181 else
1182 {
1183 const char* iterator;
1184 const char* initial;
1185 char* iothub_name = NULL;
1186 char* iothub_suffix = NULL;
1187
1188 memset(config, 0, sizeof(IOTHUB_CLIENT_CONFIG));
1189 config->protocol = protocol;
1190 config->deviceId = device_id;
1191
1192 // Find the iothub suffix
1193 initial = iterator = iothub_uri;
1194 while (iterator != NULL && *iterator != '\0')
1195 {
1196 if (*iterator == '.')
1197 {
1198 size_t length = iterator - initial;
1199 iothub_name = (char*)malloc(length + 1);
1200 if (iothub_name != NULL)
1201 {
1202 memset(iothub_name, 0, length + 1);
1203 memcpy(iothub_name, initial, length);
1204 config->iotHubName = iothub_name;
1205
1206 length = strlen(initial) - length - 1;
1207 iothub_suffix = (char*)malloc(length + 1);
1208 if (iothub_suffix != NULL)
1209 {
1210 memset(iothub_suffix, 0, length + 1);
1211 memcpy(iothub_suffix, iterator + 1, length);
1212 config->iotHubSuffix = iothub_suffix;
1213 break;
1214 }
1215 else
1216 {
1217 LogError("Failed to allocate iothub suffix");
1218 free(iothub_name);
1219 iothub_name = NULL;
1220 result = NULL;
1221 }
1222 }
1223 else
1224 {
1225 LogError("Failed to allocate iothub name");
1226 result = NULL;
1227 }
1228 }
1229 iterator++;
1230 }
1231
1232 if (config->iotHubName == NULL || config->iotHubSuffix == NULL)
1233 {
1234 LogError("initialize iothub client");
1235 result = NULL;
1236 }
1237 else
1238 {
1239 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = initialize_iothub_client(config, NULL, true, NULL);
1240 if (handleData == NULL)
1241 {
1242 LogError("initialize iothub client");
1243 result = NULL;
1244 }
1245 else
1246 {
1247 result = handleData;
1248 }
1249 }
1250
1251 free(iothub_name);
1252 free(iothub_suffix);
1253 free(config);
1254 }
1255#else
1256 LogError("HSM module is not included");
1257 result = NULL;
1258#endif
1259 }
1260 return result;
1261}
1262
1263IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientCore_LL_CreateFromConnectionString(const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
1264{
1265 IOTHUB_CLIENT_CORE_LL_HANDLE result;
1266
1267 /* Codes_SRS_IOTHUBCLIENT_LL_12_003: [IoTHubClientCore_LL_CreateFromConnectionString shall verify the input parameter and if it is NULL then return NULL] */
1268 if (connectionString == NULL)
1269 {
1270 LogError("Input parameter is NULL: connectionString");
1271 result = NULL;
1272 }
1273 else if (protocol == NULL)
1274 {
1275 LogError("Input parameter is NULL: protocol");
1276 result = NULL;
1277 }
1278 else
1279 {
1280 /* Codes_SRS_IOTHUBCLIENT_LL_12_004: [IoTHubClientCore_LL_CreateFromConnectionString shall allocate IOTHUB_CLIENT_CONFIG structure] */
1281 IOTHUB_CLIENT_CONFIG* config = (IOTHUB_CLIENT_CONFIG*) malloc(sizeof(IOTHUB_CLIENT_CONFIG));
1282 if (config == NULL)
1283 {
1284 /* Codes_SRS_IOTHUBCLIENT_LL_12_012: [If the allocation failed IoTHubClientCore_LL_CreateFromConnectionString returns NULL] */
1285 LogError("Malloc failed");
1286 result = NULL;
1287 }
1288 else
1289 {
1290 STRING_TOKENIZER_HANDLE tokenizer1 = NULL;
1291 STRING_HANDLE connString = NULL;
1292 STRING_HANDLE tokenString = NULL;
1293 STRING_HANDLE valueString = NULL;
1294 STRING_HANDLE hostNameString = NULL;
1295 STRING_HANDLE hostSuffixString = NULL;
1296 STRING_HANDLE deviceIdString = NULL;
1297 STRING_HANDLE deviceKeyString = NULL;
1298 STRING_HANDLE deviceSasTokenString = NULL;
1299 STRING_HANDLE protocolGateway = NULL;
1300 STRING_HANDLE moduleId = NULL;
1301
1302 memset(config, 0, sizeof(*config));
1303 config->protocol = protocol;
1304
1305 /* Codes_SRS_IOTHUBCLIENT_LL_04_002: [If it does not, it shall pass the protocolGatewayHostName NULL.] */
1306 config->protocolGatewayHostName = NULL;
1307
1308 if ((connString = STRING_construct(connectionString)) == NULL)
1309 {
1310 LogError("Error constructing connectiong String");
1311 result = NULL;
1312 }
1313 else if ((tokenizer1 = STRING_TOKENIZER_create(connString)) == NULL)
1314 {
1315 LogError("Error creating Tokenizer");
1316 result = NULL;
1317 }
1318 else if ((tokenString = STRING_new()) == NULL)
1319 {
1320 LogError("Error creating Token String");
1321 result = NULL;
1322 }
1323 else if ((valueString = STRING_new()) == NULL)
1324 {
1325 LogError("Error creating Value String");
1326 result = NULL;
1327 }
1328 else if ((hostNameString = STRING_new()) == NULL)
1329 {
1330 LogError("Error creating HostName String");
1331 result = NULL;
1332 }
1333 else if ((hostSuffixString = STRING_new()) == NULL)
1334 {
1335 LogError("Error creating HostSuffix String");
1336 result = NULL;
1337 }
1338 /* Codes_SRS_IOTHUBCLIENT_LL_12_005: [IoTHubClientCore_LL_CreateFromConnectionString shall try to parse the connectionString input parameter for the following structure: "Key1=value1;key2=value2;key3=value3..."] */
1339 /* Codes_SRS_IOTHUBCLIENT_LL_12_006: [IoTHubClientCore_LL_CreateFromConnectionString shall verify the existence of the following Key/Value pairs in the connection string: HostName, DeviceId, SharedAccessKey, SharedAccessSignature or x509] */
1340 else
1341 {
1342 int isx509found = 0;
1343 bool use_provisioning = false;
1344 while ((STRING_TOKENIZER_get_next_token(tokenizer1, tokenString, "=") == 0))
1345 {
1346 if (STRING_TOKENIZER_get_next_token(tokenizer1, valueString, ";") != 0)
1347 {
1348 LogError("Tokenizer error");
1349 break;
1350 }
1351 else
1352 {
1353 if (tokenString != NULL)
1354 {
1355 /* Codes_SRS_IOTHUBCLIENT_LL_12_010: [IoTHubClientCore_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] */
1356 const char* s_token = STRING_c_str(tokenString);
1357 if (strcmp(s_token, HOSTNAME_TOKEN) == 0)
1358 {
1359 /* Codes_SRS_IOTHUBCLIENT_LL_12_009: [IoTHubClientCore_LL_CreateFromConnectionString shall split the value of HostName to Name and Suffix using the first "." as a separator] */
1360 STRING_TOKENIZER_HANDLE tokenizer2 = NULL;
1361 if ((tokenizer2 = STRING_TOKENIZER_create(valueString)) == NULL)
1362 {
1363 LogError("Error creating Tokenizer");
1364 break;
1365 }
1366 else
1367 {
1368 /* Codes_SRS_IOTHUBCLIENT_LL_12_015: [If the string split failed, IoTHubClientCore_LL_CreateFromConnectionString returns NULL ] */
1369 if (STRING_TOKENIZER_get_next_token(tokenizer2, hostNameString, ".") != 0)
1370 {
1371 LogError("Tokenizer error");
1372 STRING_TOKENIZER_destroy(tokenizer2);
1373 break;
1374 }
1375 else
1376 {
1377 config->iotHubName = STRING_c_str(hostNameString);
1378 if (STRING_TOKENIZER_get_next_token(tokenizer2, hostSuffixString, ";") != 0)
1379 {
1380 LogError("Tokenizer error");
1381 STRING_TOKENIZER_destroy(tokenizer2);
1382 break;
1383 }
1384 else
1385 {
1386 config->iotHubSuffix = STRING_c_str(hostSuffixString);
1387 }
1388 }
1389 STRING_TOKENIZER_destroy(tokenizer2);
1390 }
1391 }
1392 else if (strcmp(s_token, DEVICEID_TOKEN) == 0)
1393 {
1394 deviceIdString = STRING_clone(valueString);
1395 if (deviceIdString != NULL)
1396 {
1397 config->deviceId = STRING_c_str(deviceIdString);
1398 }
1399 else
1400 {
1401 LogError("Failure cloning device id string");
1402 break;
1403 }
1404 }
1405 else if (strcmp(s_token, DEVICEKEY_TOKEN) == 0)
1406 {
1407 deviceKeyString = STRING_clone(valueString);
1408 if (deviceKeyString != NULL)
1409 {
1410 config->deviceKey = STRING_c_str(deviceKeyString);
1411 }
1412 else
1413 {
1414 LogError("Failure cloning device key string");
1415 break;
1416 }
1417 }
1418 else if (strcmp(s_token, DEVICESAS_TOKEN) == 0)
1419 {
1420 deviceSasTokenString = STRING_clone(valueString);
1421 if (deviceSasTokenString != NULL)
1422 {
1423 config->deviceSasToken = STRING_c_str(deviceSasTokenString);
1424 }
1425 else
1426 {
1427 LogError("Failure cloning device sasToken string");
1428 break;
1429 }
1430 }
1431 else if (strcmp(s_token, X509_TOKEN) == 0)
1432 {
1433 if (strcmp(STRING_c_str(valueString), X509_TOKEN_ONLY_ACCEPTABLE_VALUE) != 0)
1434 {
1435 LogError("x509 option has wrong value, the only acceptable one is \"true\"");
1436 break;
1437 }
1438 else
1439 {
1440 isx509found = 1;
1441 }
1442 }
1443 else if (strcmp(s_token, PROVISIONING_TOKEN) == 0)
1444 {
1445 if (strcmp(STRING_c_str(valueString), PROVISIONING_ACCEPTABLE_VALUE) != 0)
1446 {
1447 LogError("provisioning option has wrong value, the only acceptable one is \"true\"");
1448 break;
1449 }
1450 else
1451 {
1452 use_provisioning = 1;
1453 }
1454 }
1455
1456 /* Codes_SRS_IOTHUBCLIENT_LL_04_001: [IoTHubClientCore_LL_CreateFromConnectionString shall verify the existence of key/value pair GatewayHostName. If it does exist it shall pass the value to IoTHubClientCore_LL_Create API.] */
1457 else if (strcmp(s_token, PROTOCOL_GATEWAY_HOST_TOKEN) == 0)
1458 {
1459 protocolGateway = STRING_clone(valueString);
1460 if (protocolGateway != NULL)
1461 {
1462 config->protocolGatewayHostName = STRING_c_str(protocolGateway);
1463 }
1464 else
1465 {
1466 LogError("Failure cloning protocol Gateway Name");
1467 break;
1468 }
1469 }
1470 /*Codes_SRS_IOTHUBCLIENT_LL_31_126: [IoTHubClient_LL_CreateFromConnectionString shall optionally parse ModuleId, if present.] */
1471 else if (strcmp(s_token, MODULE_ID_TOKEN) == 0)
1472 {
1473 moduleId = STRING_clone(valueString);
1474 if (moduleId == NULL)
1475 {
1476 LogError("Failure cloning moduleId string");
1477 break;
1478 }
1479 }
1480 else
1481 {
1482 // If we get an unknown token, log it to error stream but do not cause a fatal error.
1483 LogError("Unknown token <%s> in connection string. Ignoring error and continuing to parse", s_token);
1484 }
1485 }
1486 }
1487 }
1488 /* parsing is done - check the result */
1489 if (config->iotHubName == NULL)
1490 {
1491 LogError("iotHubName is not found");
1492 result = NULL;
1493 }
1494 else if (config->iotHubSuffix == NULL)
1495 {
1496 LogError("iotHubSuffix is not found");
1497 result = NULL;
1498 }
1499 else if (config->deviceId == NULL)
1500 {
1501 LogError("deviceId is not found");
1502 result = NULL;
1503 }
1504 else if (!(
1505 ((!use_provisioning && !isx509found) && (config->deviceSasToken == NULL) ^ (config->deviceKey == NULL)) ||
1506 ((use_provisioning || isx509found) && (config->deviceSasToken == NULL) && (config->deviceKey == NULL))
1507 ))
1508 {
1509 LogError("invalid combination of x509, provisioning, deviceSasToken and deviceKey");
1510 result = NULL;
1511 }
1512 else
1513 {
1514 /* Codes_SRS_IOTHUBCLIENT_LL_12_011: [IoTHubClientCore_LL_CreateFromConnectionString shall call into the IoTHubClientCore_LL_Create API with the current structure and returns with the return value of it] */
1515 result = initialize_iothub_client(config, NULL, use_provisioning, STRING_c_str(moduleId));
1516 if (result == NULL)
1517 {
1518 LogError("IoTHubClientCore_LL_Create failed");
1519 }
1520 else
1521 {
1522 /*return as is*/
1523 }
1524 }
1525 }
1526 if (deviceSasTokenString != NULL)
1527 STRING_delete(deviceSasTokenString);
1528 if (deviceKeyString != NULL)
1529 STRING_delete(deviceKeyString);
1530 if (deviceIdString != NULL)
1531 STRING_delete(deviceIdString);
1532 if (hostSuffixString != NULL)
1533 STRING_delete(hostSuffixString);
1534 if (hostNameString != NULL)
1535 STRING_delete(hostNameString);
1536 if (valueString != NULL)
1537 STRING_delete(valueString);
1538 if (tokenString != NULL)
1539 STRING_delete(tokenString);
1540 if (connString != NULL)
1541 STRING_delete(connString);
1542 if (protocolGateway != NULL)
1543 STRING_delete(protocolGateway);
1544 if (moduleId != NULL)
1545 STRING_delete(moduleId);
1546
1547 if (tokenizer1 != NULL)
1548 STRING_TOKENIZER_destroy(tokenizer1);
1549
1550 free(config);
1551 }
1552 }
1553 return result;
1554}
1555
1556IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientCore_LL_CreateImpl(const IOTHUB_CLIENT_CONFIG* config, const char* module_id, bool use_dev_auth)
1557{
1558 IOTHUB_CLIENT_CORE_LL_HANDLE result;
1559 /*Codes_SRS_IOTHUBCLIENT_LL_02_001: [IoTHubClientCore_LL_Create shall return NULL if config parameter is NULL or protocol field is NULL.]*/
1560 if(
1561 (config == NULL) ||
1562 (config->protocol == NULL)
1563 )
1564 {
1565 result = NULL;
1566 LogError("invalid configuration (NULL detected)");
1567 }
1568 else
1569 {
1570 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = initialize_iothub_client(config, NULL, use_dev_auth, module_id);
1571 if (handleData == NULL)
1572 {
1573 LogError("initialize iothub client");
1574 result = NULL;
1575 }
1576 else
1577 {
1578 result = handleData;
1579 }
1580 }
1581
1582 return result;
1583}
1584
1585IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientCore_LL_Create(const IOTHUB_CLIENT_CONFIG* config)
1586{
1587 return IoTHubClientCore_LL_CreateImpl(config, NULL, false);
1588}
1589
1590#ifdef USE_EDGE_MODULES
1591IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientCore_LL_CreateFromEnvironment(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
1592{
1593 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* result;
1594 EDGE_ENVIRONMENT_VARIABLES edge_environment_variables;
1595
1596 memset(&edge_environment_variables, 0, sizeof(edge_environment_variables));
1597
1598 if (retrieve_edge_environment_variabes(&edge_environment_variables) != 0)
1599 {
1600 LogError("retrieve_edge_environment_variabes failed");
1601 result = NULL;
1602 }
1603 // The presence of a connection string environment variable means we use it, ignoring other settings
1604 else if (edge_environment_variables.connection_string != NULL)
1605 {
1606 if ((result = IoTHubClientCore_LL_CreateFromConnectionString(edge_environment_variables.connection_string, protocol)) == NULL)
1607 {
1608 LogError("IoTHubClientCore_LL_CreateFromConnectionString fails");
1609 }
1610 }
1611 else if (iothub_security_init(IOTHUB_SECURITY_TYPE_HTTP_EDGE) != 0)
1612 {
1613 LogError("iothub_security_init failed");
1614 result = NULL;
1615 }
1616 else
1617 {
1618 IOTHUB_CLIENT_CONFIG client_config;
1619
1620 memset(&client_config, 0, sizeof(client_config));
1621 client_config.protocol = protocol;
1622 client_config.deviceId = edge_environment_variables.device_id;
1623 client_config.iotHubName = edge_environment_variables.iothub_name;
1624 client_config.iotHubSuffix = edge_environment_variables.iothub_suffix;
1625 client_config.protocolGatewayHostName = edge_environment_variables.gatewayhostname;
1626
1627 if ((result = IoTHubClientCore_LL_CreateImpl(&client_config, edge_environment_variables.module_id, true)) == NULL)
1628 {
1629 LogError("IoTHubClientCore_LL_CreateImpl fails");
1630 }
1631 }
1632
1633 if (result != NULL)
1634 {
1635 // Because the Edge Hub almost always use self-signed certificates, we need to specify which certificates to trust. We need to do
1636 // this regardless of how we created the underlying IOTHUB_CLIENT_CORE_LL_HANDLE_DATA.
1637 IOTHUB_CLIENT_RESULT setTrustResult;
1638 char* trustedCertificate = IoTHubClient_Auth_Get_TrustBundle(result->authorization_module, edge_environment_variables.ca_trusted_certificate_file);
1639
1640 if (trustedCertificate == NULL)
1641 {
1642 LogError("IoTHubClient_Auth_Get_TrustBundle failed");
1643 IoTHubClientCore_LL_Destroy(result);
1644 result = NULL;
1645 }
1646 else if ((setTrustResult = IoTHubClientCore_LL_SetOption(result, OPTION_TRUSTED_CERT, trustedCertificate)) != IOTHUB_CLIENT_OK)
1647 {
1648 LogError("IoTHubClientCore_LL_SetOption failed, err = %d", setTrustResult);
1649 IoTHubClientCore_LL_Destroy(result);
1650 result = NULL;
1651 }
1652
1653 free(trustedCertificate);
1654 }
1655
1656 free(edge_environment_variables.iothub_buffer);
1657 return result;
1658}
1659#endif
1660
1661
1662IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientCore_LL_CreateWithTransport(const IOTHUB_CLIENT_DEVICE_CONFIG * config)
1663{
1664 IOTHUB_CLIENT_CORE_LL_HANDLE result;
1665 /*Codes_SRS_IOTHUBCLIENT_LL_17_001: [IoTHubClientCore_LL_CreateWithTransport shall return NULL if config parameter is NULL, or protocol field is NULL or transportHandle is NULL.]*/
1666 if (
1667 (config == NULL) ||
1668 (config->protocol == NULL) ||
1669 (config->transportHandle == NULL) ||
1670 /*Codes_SRS_IOTHUBCLIENT_LL_02_098: [ IoTHubClientCore_LL_CreateWithTransport shall fail and return NULL if both config->deviceKey AND config->deviceSasToken are NULL. ]*/
1671 ((config->deviceKey == NULL) && (config->deviceSasToken == NULL))
1672 )
1673 {
1674 result = NULL;
1675 LogError("invalid configuration (NULL detected)");
1676 }
1677 else
1678 {
1679 result = initialize_iothub_client(NULL, config, false, NULL);
1680 }
1681 return result;
1682}
1683
1684void IoTHubClientCore_LL_Destroy(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle)
1685{
1686 /*Codes_SRS_IOTHUBCLIENT_LL_02_009: [IoTHubClientCore_LL_Destroy shall do nothing if parameter iotHubClientHandle is NULL.]*/
1687 if (iotHubClientHandle != NULL)
1688 {
1689 PDLIST_ENTRY unsend;
1690 /*Codes_SRS_IOTHUBCLIENT_LL_17_010: [IoTHubClientCore_LL_Destroy shall call the underlaying layer's _Unregister function] */
1691 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
1692 handleData->IoTHubTransport_Unregister(handleData->deviceHandle);
1693 if (handleData->isSharedTransport == false)
1694 {
1695 /*Codes_SRS_IOTHUBCLIENT_LL_02_010: [If iotHubClientHandle was not created by IoTHubClientCore_LL_CreateWithTransport, IoTHubClientCore_LL_Destroy shall call the underlaying layer's _Destroy function.] */
1696 handleData->IoTHubTransport_Destroy(handleData->transportHandle);
1697 }
1698 /*if any, remove the items currently not send*/
1699 while ((unsend = DList_RemoveHeadList(&(handleData->waitingToSend))) != &(handleData->waitingToSend))
1700 {
1701 IOTHUB_MESSAGE_LIST* temp = containingRecord(unsend, IOTHUB_MESSAGE_LIST, entry);
1702 /*Codes_SRS_IOTHUBCLIENT_LL_02_033: [Otherwise, IoTHubClientCore_LL_Destroy shall complete all the event message callbacks that are in the waitingToSend list with the result IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY.] */
1703 if (temp->callback != NULL)
1704 {
1705 temp->callback(IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY, temp->context);
1706 }
1707 IoTHubMessage_Destroy(temp->messageHandle);
1708 free(temp);
1709 }
1710
1711 /* Codes_SRS_IOTHUBCLIENT_LL_07_007: [ IoTHubClientCore_LL_Destroy shall iterate the device twin queues and destroy any remaining items. ] */
1712 while ((unsend = DList_RemoveHeadList(&(handleData->iot_msg_queue))) != &(handleData->iot_msg_queue))
1713 {
1714 IOTHUB_DEVICE_TWIN* temp = containingRecord(unsend, IOTHUB_DEVICE_TWIN, entry);
1715 device_twin_data_destroy(temp);
1716 }
1717 while ((unsend = DList_RemoveHeadList(&(handleData->iot_ack_queue))) != &(handleData->iot_ack_queue))
1718 {
1719 IOTHUB_DEVICE_TWIN* temp = containingRecord(unsend, IOTHUB_DEVICE_TWIN, entry);
1720 device_twin_data_destroy(temp);
1721 }
1722
1723 /* Codes_SRS_IOTHUBCLIENT_LL_31_141: [ IoTHubClient_LL_Destroy shall iterate registered callbacks for input queues and destroy any remaining items. ] */
1724 delete_event_callback_list(handleData);
1725
1726 /*Codes_SRS_IOTHUBCLIENT_LL_17_011: [IoTHubClientCore_LL_Destroy shall free the resources allocated by IoTHubClient (if any).] */
1727 IoTHubClient_Auth_Destroy(handleData->authorization_module);
1728 tickcounter_destroy(handleData->tickCounter);
1729#ifndef DONT_USE_UPLOADTOBLOB
1730 IoTHubClient_LL_UploadToBlob_Destroy(handleData->uploadToBlobHandle);
1731#endif
1732#ifdef USE_EDGE_MODULES
1733 IoTHubClient_EdgeHandle_Destroy(handleData->methodHandle);
1734#endif
1735 STRING_delete(handleData->product_info);
1736 free(handleData);
1737 }
1738}
1739
1740/*Codes_SRS_IOTHUBCLIENT_LL_02_044: [ Messages already delivered to IoTHubClientCore_LL shall not have their timeouts modified by a new call to IoTHubClientCore_LL_SetOption. ]*/
1741/*returns 0 on success, any other value is error*/
1742static int attach_ms_timesOutAfter(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData, IOTHUB_MESSAGE_LIST *newEntry)
1743{
1744 int result;
1745 /*Codes_SRS_IOTHUBCLIENT_LL_02_043: [ Calling IoTHubClientCore_LL_SetOption with value set to "0" shall disable the timeout mechanism for all new messages. ]*/
1746 if (handleData->currentMessageTimeout == 0)
1747 {
1748 newEntry->ms_timesOutAfter = 0; /*do not timeout*/
1749 newEntry->message_timeout_value = 0;
1750 result = 0;
1751 }
1752 else
1753 {
1754 /*Codes_SRS_IOTHUBCLIENT_LL_02_039: [ "messageTimeout" - once IoTHubClientCore_LL_SendEventAsync is called the message shall timeout after value miliseconds. Value is a pointer to a tickcounter_ms_t. ]*/
1755 if (tickcounter_get_current_ms(handleData->tickCounter, &newEntry->ms_timesOutAfter) != 0)
1756 {
1757 result = MU_FAILURE;
1758 LogError("unable to get the current relative tickcount");
1759 }
1760 else
1761 {
1762 newEntry->message_timeout_value = handleData->currentMessageTimeout;
1763 result = 0;
1764 }
1765 }
1766 return result;
1767}
1768
1769IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SendEventAsync(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback)
1770{
1771 IOTHUB_CLIENT_RESULT result;
1772 /*Codes_SRS_IOTHUBCLIENT_LL_02_011: [IoTHubClientCore_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle or eventMessageHandle is NULL.]*/
1773 if (
1774 (iotHubClientHandle == NULL) ||
1775 (eventMessageHandle == NULL) ||
1776 /*Codes_SRS_IOTHUBCLIENT_LL_02_012: [IoTHubClientCore_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter eventConfirmationCallback is NULL and userContextCallback is not NULL.] */
1777 ((eventConfirmationCallback == NULL) && (userContextCallback != NULL))
1778 )
1779 {
1780 result = IOTHUB_CLIENT_INVALID_ARG;
1781 LOG_ERROR_RESULT;
1782 }
1783 else
1784 {
1785 IOTHUB_MESSAGE_LIST *newEntry = (IOTHUB_MESSAGE_LIST*)malloc(sizeof(IOTHUB_MESSAGE_LIST));
1786 if (newEntry == NULL)
1787 {
1788 result = IOTHUB_CLIENT_ERROR;
1789 LOG_ERROR_RESULT;
1790 }
1791 else
1792 {
1793 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
1794
1795 if (attach_ms_timesOutAfter(handleData, newEntry) != 0)
1796 {
1797 result = IOTHUB_CLIENT_ERROR;
1798 LOG_ERROR_RESULT;
1799 free(newEntry);
1800 }
1801 else
1802 {
1803 /*Codes_SRS_IOTHUBCLIENT_LL_02_013: [IoTHubClientCore_LL_SendEventAsync shall add the DLIST waitingToSend a new record cloning the information from eventMessageHandle, eventConfirmationCallback, userContextCallback.]*/
1804 if ((newEntry->messageHandle = IoTHubMessage_Clone(eventMessageHandle)) == NULL)
1805 {
1806 result = IOTHUB_CLIENT_ERROR;
1807 free(newEntry);
1808 LOG_ERROR_RESULT;
1809 }
1810 else if (IoTHubClient_Diagnostic_AddIfNecessary(&handleData->diagnostic_setting, newEntry->messageHandle) != 0)
1811 {
1812 /*Codes_SRS_IOTHUBCLIENT_LL_02_014: [If cloning and/or adding the information/diagnostic fails for any reason, IoTHubClientCore_LL_SendEventAsync shall fail and return IOTHUB_CLIENT_ERROR.] */
1813 result = IOTHUB_CLIENT_ERROR;
1814 IoTHubMessage_Destroy(newEntry->messageHandle);
1815 free(newEntry);
1816 LOG_ERROR_RESULT;
1817 }
1818 else
1819 {
1820 /*Codes_SRS_IOTHUBCLIENT_LL_02_013: [IoTHubClientCore_LL_SendEventAsync shall add the DLIST waitingToSend a new record cloning the information from eventMessageHandle, eventConfirmationCallback, userContextCallback.]*/
1821 newEntry->callback = eventConfirmationCallback;
1822 newEntry->context = userContextCallback;
1823 DList_InsertTailList(&(iotHubClientHandle->waitingToSend), &(newEntry->entry));
1824 /*Codes_SRS_IOTHUBCLIENT_LL_02_015: [Otherwise IoTHubClientCore_LL_SendEventAsync shall succeed and return IOTHUB_CLIENT_OK.] */
1825 result = IOTHUB_CLIENT_OK;
1826 }
1827 }
1828 }
1829 }
1830 return result;
1831}
1832
1833IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetMessageCallback(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback, void* userContextCallback)
1834{
1835 IOTHUB_CLIENT_RESULT result;
1836 if (iotHubClientHandle == NULL)
1837 {
1838 /*Codes_SRS_IOTHUBCLIENT_LL_02_016: [IoTHubClientCore_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.] */
1839 LogError("Invalid argument - iotHubClientHandle is NULL");
1840 result = IOTHUB_CLIENT_INVALID_ARG;
1841 }
1842 else
1843 {
1844 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
1845 if (messageCallback == NULL)
1846 {
1847 if (handleData->messageCallback.type == CALLBACK_TYPE_NONE)
1848 {
1849 /*Codes_SRS_IOTHUBCLIENT_LL_10_010: [If parameter messageCallback is NULL and the _SetMessageCallback had not been called to subscribe for messages, then IoTHubClientCore_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR.] */
1850 LogError("not currently set to accept or process incoming messages.");
1851 result = IOTHUB_CLIENT_ERROR;
1852 }
1853 else if (handleData->messageCallback.type == CALLBACK_TYPE_ASYNC)
1854 {
1855 /*Codes_SRS_IOTHUBCLIENT_LL_10_010: [If parameter messageCallback is NULL and the _SetMessageCallback had not been called to subscribe for messages, then IoTHubClientCore_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR.] */
1856 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetMessageCallback_Ex function.");
1857 result = IOTHUB_CLIENT_ERROR;
1858 }
1859 else
1860 {
1861 /*Codes_SRS_IOTHUBCLIENT_LL_02_019: [If parameter messageCallback is NULL then IoTHubClientCore_LL_SetMessageCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */
1862 handleData->IoTHubTransport_Unsubscribe(handleData->deviceHandle);
1863 handleData->messageCallback.type = CALLBACK_TYPE_NONE;
1864 handleData->messageCallback.callbackSync = NULL;
1865 handleData->messageCallback.callbackAsync = NULL;
1866 handleData->messageCallback.userContextCallback = NULL;
1867 result = IOTHUB_CLIENT_OK;
1868 }
1869 }
1870 else
1871 {
1872 if (handleData->messageCallback.type == CALLBACK_TYPE_ASYNC)
1873 {
1874 /* Codes_SRS_IOTHUBCLIENT_LL_10_011: [If parameter messageCallback is non-NULL and the _SetMessageCallback_Ex had been used to susbscribe for messages, then IoTHubClientCore_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR.] */
1875 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetMessageCallback_Ex function before subscribing with MessageCallback.");
1876 result = IOTHUB_CLIENT_ERROR;
1877 }
1878 else
1879 {
1880 if (handleData->IoTHubTransport_Subscribe(handleData->deviceHandle) == 0)
1881 {
1882 /*Codes_SRS_IOTHUBCLIENT_LL_02_017: [If parameter messageCallback is non-NULL then IoTHubClientCore_LL_SetMessageCallback shall call the underlying layer's _Subscribe function.]*/
1883 handleData->messageCallback.type = CALLBACK_TYPE_SYNC;
1884 handleData->messageCallback.callbackSync = messageCallback;
1885 handleData->messageCallback.userContextCallback = userContextCallback;
1886 result = IOTHUB_CLIENT_OK;
1887 }
1888 else
1889 {
1890 /*Codes_SRS_IOTHUBCLIENT_LL_02_018: [If the underlying layer's _Subscribe function fails, then IoTHubClientCore_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR. Otherwise IoTHubClientCore_LL_SetMessageCallback shall succeed and return IOTHUB_CLIENT_OK.]*/
1891 LogError("IoTHubTransport_Subscribe failed");
1892 handleData->messageCallback.type = CALLBACK_TYPE_NONE;
1893 handleData->messageCallback.callbackSync = NULL;
1894 handleData->messageCallback.callbackAsync = NULL;
1895 handleData->messageCallback.userContextCallback = NULL;
1896 result = IOTHUB_CLIENT_ERROR;
1897 }
1898 }
1899 }
1900 }
1901 return result;
1902}
1903
1904IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetMessageCallback_Ex(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX messageCallback, void* userContextCallback)
1905{
1906 IOTHUB_CLIENT_RESULT result;
1907 if (iotHubClientHandle == NULL)
1908 {
1909 /*Codes_SRS_IOTHUBCLIENT_LL_10_021: [IoTHubClientCore_LL_SetMessageCallback_Ex shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.]*/
1910 LogError("Invalid argument - iotHubClientHandle is NULL");
1911 result = IOTHUB_CLIENT_INVALID_ARG;
1912 }
1913 else
1914 {
1915 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
1916 if (messageCallback == NULL)
1917 {
1918 if (handleData->messageCallback.type == CALLBACK_TYPE_NONE)
1919 {
1920 /*Codes_SRS_IOTHUBCLIENT_LL_10_018: [If parameter messageCallback is NULL and IoTHubClientCore_LL_SetMessageCallback_Ex had not been used to subscribe for messages, then IoTHubClientCore_LL_SetMessageCallback_Ex shall fail and return IOTHUB_CLIENT_ERROR.] */
1921 LogError("not currently set to accept or process incoming messages.");
1922 result = IOTHUB_CLIENT_ERROR;
1923 }
1924 else if (handleData->messageCallback.type == CALLBACK_TYPE_SYNC)
1925 {
1926 /*Codes_SRS_IOTHUBCLIENT_LL_10_019: [If parameter messageCallback is NULL and IoTHubClientCore_LL_SetMessageCallback had been used to subscribe for messages, then IoTHubClientCore_LL_SetMessageCallback_Ex shall fail and return IOTHUB_CLIENT_ERROR.] */
1927 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetMessageCallback function.");
1928 result = IOTHUB_CLIENT_ERROR;
1929 }
1930 else
1931 {
1932 /*Codes_SRS_IOTHUBCLIENT_LL_10_023: [If parameter messageCallback is NULL then IoTHubClientCore_LL_SetMessageCallback_Ex shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */
1933 handleData->IoTHubTransport_Unsubscribe(handleData->deviceHandle);
1934 handleData->messageCallback.type = CALLBACK_TYPE_NONE;
1935 handleData->messageCallback.callbackSync = NULL;
1936 handleData->messageCallback.callbackAsync = NULL;
1937 handleData->messageCallback.userContextCallback = NULL;
1938 result = IOTHUB_CLIENT_OK;
1939 }
1940 }
1941 else
1942 {
1943 if (handleData->messageCallback.type == CALLBACK_TYPE_SYNC)
1944 {
1945 /*Codes_SRS_IOTHUBCLIENT_LL_10_020: [If parameter messageCallback is non-NULL, and IoTHubClientCore_LL_SetMessageCallback had been used to subscribe for messages, then IoTHubClientCore_LL_SetMessageCallback_Ex shall fail and return IOTHUB_CLIENT_ERROR.] */
1946 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_MessageCallbackEx function before subscribing with MessageCallback.");
1947 result = IOTHUB_CLIENT_ERROR;
1948 }
1949 else
1950 {
1951 if (handleData->IoTHubTransport_Subscribe(handleData->deviceHandle) == 0)
1952 {
1953 /*Codes_SRS_IOTHUBCLIENT_LL_10_024: [If parameter messageCallback is non-NULL then IoTHubClientCore_LL_SetMessageCallback_Ex shall call the underlying layer's _Subscribe function.]*/
1954 handleData->messageCallback.type = CALLBACK_TYPE_ASYNC;
1955 handleData->messageCallback.callbackAsync = messageCallback;
1956 handleData->messageCallback.userContextCallback = userContextCallback;
1957 result = IOTHUB_CLIENT_OK;
1958 }
1959 else
1960 {
1961 /*Codes_SRS_IOTHUBCLIENT_LL_10_025: [If the underlying layer's _Subscribe function fails, then IoTHubClientCore_LL_SetMessageCallback_Ex shall fail and return IOTHUB_CLIENT_ERROR. Otherwise IoTHubClientCore_LL_SetMessageCallback_Ex shall succeed and return IOTHUB_CLIENT_OK.] */
1962 LogError("IoTHubTransport_Subscribe failed");
1963 handleData->messageCallback.type = CALLBACK_TYPE_NONE;
1964 handleData->messageCallback.callbackSync = NULL;
1965 handleData->messageCallback.callbackAsync = NULL;
1966 handleData->messageCallback.userContextCallback = NULL;
1967 result = IOTHUB_CLIENT_ERROR;
1968 }
1969 }
1970 }
1971 }
1972 return result;
1973}
1974
1975IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SendMessageDisposition(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, MESSAGE_CALLBACK_INFO* message_data, IOTHUBMESSAGE_DISPOSITION_RESULT disposition)
1976{
1977 IOTHUB_CLIENT_RESULT result;
1978 if ((iotHubClientHandle == NULL) || (message_data == NULL))
1979 {
1980 /*Codes_SRS_IOTHUBCLIENT_LL_10_026: [IoTHubClientCore_LL_SendMessageDisposition shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.]*/
1981 LogError("Invalid argument handle=%p, message=%p", iotHubClientHandle, message_data);
1982 result = IOTHUB_CLIENT_INVALID_ARG;
1983 }
1984 else
1985 {
1986 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
1987 /*Codes_SRS_IOTHUBCLIENT_LL_10_027: [IoTHubClientCore_LL_SendMessageDisposition shall return the result from calling the underlying layer's _Send_Message_Disposition.]*/
1988 result = handleData->IoTHubTransport_SendMessageDisposition(message_data, disposition);
1989 }
1990 return result;
1991}
1992
1993static void DoTimeouts(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData)
1994{
1995 tickcounter_ms_t nowTick;
1996 if (tickcounter_get_current_ms(handleData->tickCounter, &nowTick) != 0)
1997 {
1998 LogError("unable to get the current ms, timeouts will not be processed");
1999 }
2000 else
2001 {
2002 DLIST_ENTRY* currentItemInWaitingToSend = handleData->waitingToSend.Flink;
2003 while (currentItemInWaitingToSend != &(handleData->waitingToSend)) /*while we are not at the end of the list*/
2004 {
2005 IOTHUB_MESSAGE_LIST* fullEntry = containingRecord(currentItemInWaitingToSend, IOTHUB_MESSAGE_LIST, entry);
2006 /*Codes_SRS_IOTHUBCLIENT_LL_02_041: [ If more than value miliseconds have passed since the call to IoTHubClientCore_LL_SendEventAsync then the message callback shall be called with a status code of IOTHUB_CLIENT_CONFIRMATION_TIMEOUT. ]*/
2007 if ((fullEntry->ms_timesOutAfter != 0) && ((nowTick - fullEntry->ms_timesOutAfter) > fullEntry->message_timeout_value))
2008 {
2009 PDLIST_ENTRY theNext = currentItemInWaitingToSend->Flink; /*need to save the next item, because the below operations are destructive*/
2010 DList_RemoveEntryList(currentItemInWaitingToSend);
2011 if (fullEntry->callback != NULL)
2012 {
2013 fullEntry->callback(IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT, fullEntry->context);
2014 }
2015 IoTHubMessage_Destroy(fullEntry->messageHandle); /*because it has been cloned*/
2016 free(fullEntry);
2017 currentItemInWaitingToSend = theNext;
2018 }
2019 else
2020 {
2021 currentItemInWaitingToSend = currentItemInWaitingToSend->Flink;
2022 }
2023 }
2024 }
2025}
2026
2027void IoTHubClientCore_LL_DoWork(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle)
2028{
2029 /*Codes_SRS_IOTHUBCLIENT_LL_02_020: [If parameter iotHubClientHandle is NULL then IoTHubClientCore_LL_DoWork shall not perform any action.] */
2030 if (iotHubClientHandle != NULL)
2031 {
2032 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2033 DoTimeouts(handleData);
2034
2035 /*Codes_SRS_IOTHUBCLIENT_LL_07_008: [ IoTHubClientCore_LL_DoWork shall iterate the message queue and execute the underlying transports IoTHubTransport_ProcessItem function for each item. ] */
2036 DLIST_ENTRY* client_item = handleData->iot_msg_queue.Flink;
2037 while (client_item != &(handleData->iot_msg_queue)) /*while we are not at the end of the list*/
2038 {
2039 PDLIST_ENTRY next_item = client_item->Flink;
2040
2041 IOTHUB_DEVICE_TWIN* queue_data = containingRecord(client_item, IOTHUB_DEVICE_TWIN, entry);
2042 IOTHUB_IDENTITY_INFO identity_info;
2043 identity_info.device_twin = queue_data;
2044 IOTHUB_PROCESS_ITEM_RESULT process_results = handleData->IoTHubTransport_ProcessItem(handleData->transportHandle, IOTHUB_TYPE_DEVICE_TWIN, &identity_info);
2045 if (process_results == IOTHUB_PROCESS_CONTINUE || process_results == IOTHUB_PROCESS_NOT_CONNECTED)
2046 {
2047 /*Codes_SRS_IOTHUBCLIENT_LL_07_010: [ If 'IoTHubTransport_ProcessItem' returns IOTHUB_PROCESS_CONTINUE or IOTHUB_PROCESS_NOT_CONNECTED IoTHubClientCore_LL_DoWork shall continue on to call the underlaying layer's _DoWork function. ]*/
2048 break;
2049 }
2050 else
2051 {
2052 DList_RemoveEntryList(client_item);
2053 if (process_results == IOTHUB_PROCESS_OK)
2054 {
2055 /*Codes_SRS_IOTHUBCLIENT_LL_07_011: [ If 'IoTHubTransport_ProcessItem' returns IOTHUB_PROCESS_OK IoTHubClientCore_LL_DoWork shall add the IOTHUB_DEVICE_TWIN to the ack queue. ]*/
2056 DList_InsertTailList(&(iotHubClientHandle->iot_ack_queue), &(queue_data->entry));
2057 }
2058 else
2059 {
2060 /*Codes_SRS_IOTHUBCLIENT_LL_07_012: [ If 'IoTHubTransport_ProcessItem' returns any other value IoTHubClientCore_LL_DoWork shall destroy the IOTHUB_DEVICE_TWIN item. ]*/
2061 LogError("Failure queue processing item");
2062 device_twin_data_destroy(queue_data);
2063 }
2064 }
2065 // Move along to the next item
2066 client_item = next_item;
2067 }
2068
2069 /*Codes_SRS_IOTHUBCLIENT_LL_02_021: [Otherwise, IoTHubClientCore_LL_DoWork shall invoke the underlaying layer's _DoWork function.]*/
2070 handleData->IoTHubTransport_DoWork(handleData->transportHandle);
2071 }
2072}
2073
2074IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_GetSendStatus(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_STATUS *iotHubClientStatus)
2075{
2076 IOTHUB_CLIENT_RESULT result;
2077
2078 /* Codes_SRS_IOTHUBCLIENT_09_007: [IoTHubClient_GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL parameter] */
2079 if (iotHubClientHandle == NULL || iotHubClientStatus == NULL)
2080 {
2081 result = IOTHUB_CLIENT_INVALID_ARG;
2082 LOG_ERROR_RESULT;
2083 }
2084 else
2085 {
2086 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2087
2088 /* 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] */
2089 /* 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] */
2090 result = handleData->IoTHubTransport_GetSendStatus(handleData->deviceHandle, iotHubClientStatus);
2091 }
2092
2093 return result;
2094}
2095
2096IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetConnectionStatusCallback(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connectionStatusCallback, void * userContextCallback)
2097{
2098 IOTHUB_CLIENT_RESULT result;
2099 /*Codes_SRS_IOTHUBCLIENT_LL_25_111: [IoTHubClientCore_LL_SetConnectionStatusCallback shall return IOTHUB_CLIENT_INVALID_ARG if called with NULL parameter iotHubClientHandle**]** */
2100 if (iotHubClientHandle == NULL)
2101 {
2102 result = IOTHUB_CLIENT_INVALID_ARG;
2103 LOG_ERROR_RESULT;
2104 }
2105 else
2106 {
2107 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2108 /*Codes_SRS_IOTHUBCLIENT_LL_25_112: [IoTHubClientCore_LL_SetConnectionStatusCallback shall return IOTHUB_CLIENT_OK and save the callback and userContext as a member of the handle.] */
2109 handleData->conStatusCallback = connectionStatusCallback;
2110 handleData->conStatusUserContextCallback = userContextCallback;
2111 result = IOTHUB_CLIENT_OK;
2112 }
2113
2114 return result;
2115}
2116
2117IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetRetryPolicy(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY retryPolicy, size_t retryTimeoutLimitInSeconds)
2118{
2119 IOTHUB_CLIENT_RESULT result;
2120 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2121
2122 /* Codes_SRS_IOTHUBCLIENT_LL_25_116: [If iotHubClientHandle, retryPolicy or retryTimeoutLimitinSeconds is NULL, IoTHubClientCore_LL_GetRetryPolicy shall return IOTHUB_CLIENT_INVALID_ARG]*/
2123 if (handleData == NULL)
2124 {
2125 result = IOTHUB_CLIENT_INVALID_ARG;
2126 LOG_ERROR_RESULT;
2127 }
2128 else
2129 {
2130 if (handleData->transportHandle == NULL)
2131 {
2132 result = IOTHUB_CLIENT_ERROR;
2133 LOG_ERROR_RESULT;
2134 }
2135 else
2136 {
2137 if (handleData->IoTHubTransport_SetRetryPolicy(handleData->transportHandle, retryPolicy, retryTimeoutLimitInSeconds) != 0)
2138 {
2139 result = IOTHUB_CLIENT_ERROR;
2140 LOG_ERROR_RESULT;
2141 }
2142 else
2143 {
2144 /* Codes_SRS_IOTHUBCLIENT_LL_25_118: [IoTHubClientCore_LL_SetRetryPolicy shall save connection retry policies specified by the user to retryPolicy in struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA] */
2145 /* Codes_SRS_IOTHUBCLIENT_LL_25_119: [IoTHubClientCore_LL_SetRetryPolicy shall save retryTimeoutLimitInSeconds in seconds to retryTimeout in struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA] */
2146 handleData->retryPolicy = retryPolicy;
2147 handleData->retryTimeoutLimitInSeconds = retryTimeoutLimitInSeconds;
2148 result = IOTHUB_CLIENT_OK;
2149 }
2150 }
2151 }
2152 return result;
2153}
2154
2155IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_GetRetryPolicy(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY* retryPolicy, size_t* retryTimeoutLimitInSeconds)
2156{
2157 IOTHUB_CLIENT_RESULT result;
2158
2159 /* Codes_SRS_IOTHUBCLIENT_LL_09_001: [IoTHubClientCore_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INVALID_ARG if any of the arguments is NULL] */
2160 if (iotHubClientHandle == NULL || retryPolicy == NULL || retryTimeoutLimitInSeconds == NULL)
2161 {
2162 LogError("Invalid parameter IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle = %p, IOTHUB_CLIENT_RETRY_POLICY* retryPolicy = %p, size_t* retryTimeoutLimitInSeconds = %p", iotHubClientHandle, retryPolicy, retryTimeoutLimitInSeconds);
2163 result = IOTHUB_CLIENT_INVALID_ARG;
2164 }
2165 else
2166 {
2167 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2168
2169 *retryPolicy = handleData->retryPolicy;
2170 *retryTimeoutLimitInSeconds = handleData->retryTimeoutLimitInSeconds;
2171 result = IOTHUB_CLIENT_OK;
2172 }
2173
2174 return result;
2175}
2176
2177IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_GetLastMessageReceiveTime(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, time_t* lastMessageReceiveTime)
2178{
2179 IOTHUB_CLIENT_RESULT result;
2180 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2181
2182 /* Codes_SRS_IOTHUBCLIENT_LL_09_001: [IoTHubClientCore_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INVALID_ARG if any of the arguments is NULL] */
2183 if (handleData == NULL || lastMessageReceiveTime == NULL)
2184 {
2185 result = IOTHUB_CLIENT_INVALID_ARG;
2186 LOG_ERROR_RESULT;
2187 }
2188 else
2189 {
2190 /* Codes_SRS_IOTHUBCLIENT_LL_09_002: [IoTHubClientCore_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INDEFINITE_TIME - and not set 'lastMessageReceiveTime' - if it is unable to provide the time for the last commands] */
2191 if (handleData->lastMessageReceiveTime == INDEFINITE_TIME)
2192 {
2193 result = IOTHUB_CLIENT_INDEFINITE_TIME;
2194 LOG_ERROR_RESULT;
2195 }
2196 else
2197 {
2198 /* Codes_SRS_IOTHUBCLIENT_LL_09_003: [IoTHubClientCore_LL_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_OK if it wrote in the lastMessageReceiveTime the time when the last command was received] */
2199 /* Codes_SRS_IOTHUBCLIENT_LL_09_004: [IoTHubClientCore_LL_GetLastMessageReceiveTime shall return lastMessageReceiveTime in localtime] */
2200 *lastMessageReceiveTime = handleData->lastMessageReceiveTime;
2201 result = IOTHUB_CLIENT_OK;
2202 }
2203 }
2204
2205 return result;
2206}
2207
2208IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetOption(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* optionName, const void* value)
2209{
2210
2211 IOTHUB_CLIENT_RESULT result;
2212 /*Codes_SRS_IOTHUBCLIENT_LL_02_034: [If iotHubClientHandle is NULL then IoTHubClientCore_LL_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.]*/
2213 /*Codes_SRS_IOTHUBCLIENT_LL_02_035: [If optionName is NULL then IoTHubClientCore_LL_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */
2214 /*Codes_SRS_IOTHUBCLIENT_LL_02_036: [If value is NULL then IoTHubClientCore_LL_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */
2215 if (
2216 (iotHubClientHandle == NULL) ||
2217 (optionName == NULL) ||
2218 (value == NULL)
2219 )
2220 {
2221 result = IOTHUB_CLIENT_INVALID_ARG;
2222 LogError("invalid argument (NULL)");
2223 }
2224 else
2225 {
2226 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2227
2228 /*Codes_SRS_IOTHUBCLIENT_LL_02_039: [ "messageTimeout" - once IoTHubClientCore_LL_SendEventAsync is called the message shall timeout after value miliseconds. Value is a pointer to a tickcounter_ms_t. ]*/
2229 if (strcmp(optionName, OPTION_MESSAGE_TIMEOUT) == 0)
2230 {
2231 /*this is an option handled by IoTHubClientCore_LL*/
2232 /*Codes_SRS_IOTHUBCLIENT_LL_02_043: [ Calling IoTHubClientCore_LL_SetOption with value set to "0" shall disable the timeout mechanism for all new messages. ]*/
2233 handleData->currentMessageTimeout = *(const tickcounter_ms_t*)value;
2234 result = IOTHUB_CLIENT_OK;
2235 }
2236 else if (strcmp(optionName, OPTION_PRODUCT_INFO) == 0)
2237 {
2238 /*Codes_SRS_IOTHUBCLIENT_LL_10_033: [repeat calls with "product_info" will erase the previously set product information if applicatble. ]*/
2239 if (handleData->product_info != NULL)
2240 {
2241 STRING_delete(handleData->product_info);
2242 handleData->product_info = NULL;
2243 }
2244
2245 /*Codes_SRS_IOTHUBCLIENT_LL_10_035: [If string concatenation fails, `IoTHubClientCore_LL_SetOption` shall return `IOTHUB_CLIENT_ERRROR`. Otherwise, `IOTHUB_CLIENT_OK` shall be returned. ]*/
2246 handleData->product_info = make_product_info((const char*)value);
2247 if (handleData->product_info == NULL)
2248 {
2249 LogError("STRING_construct_sprintf failed");
2250 result = IOTHUB_CLIENT_ERROR;
2251 }
2252 else
2253 {
2254 result = IOTHUB_CLIENT_OK;
2255 }
2256 }
2257 else if (strcmp(optionName, OPTION_DIAGNOSTIC_SAMPLING_PERCENTAGE) == 0)
2258 {
2259 uint32_t percentage = *(uint32_t*)value;
2260 if (percentage > 100)
2261 {
2262 /*Codes_SRS_IOTHUBCLIENT_LL_10_036: [Calling IoTHubClientCore_LL_SetOption with value > 100 shall return `IOTHUB_CLIENT_ERRROR`. ]*/
2263 LogError("The value of diag_sampling_percentage is out of range [0, 100]: %u", percentage);
2264 result = IOTHUB_CLIENT_ERROR;
2265 }
2266 else
2267 {
2268 /*Codes_SRS_IOTHUBCLIENT_LL_10_037: [Calling IoTHubClientCore_LL_SetOption with value between [0, 100] shall return `IOTHUB_CLIENT_OK`. ]*/
2269 handleData->diagnostic_setting.diagSamplingPercentage = percentage;
2270 handleData->diagnostic_setting.currentMessageNumber = 0;
2271 result = IOTHUB_CLIENT_OK;
2272 }
2273 }
2274 else if ((strcmp(optionName, OPTION_BLOB_UPLOAD_TIMEOUT_SECS) == 0) || (strcmp(optionName, OPTION_CURL_VERBOSE) == 0))
2275 {
2276#ifndef DONT_USE_UPLOADTOBLOB
2277 // This option just gets passed down into IoTHubClientCore_LL_UploadToBlob
2278 /*Codes_SRS_IOTHUBCLIENT_LL_30_010: [ blob_xfr_timeout - IoTHubClientCore_LL_SetOption shall pass this option to IoTHubClient_UploadToBlob_SetOption and return its result. ]*/
2279 result = IoTHubClient_LL_UploadToBlob_SetOption(handleData->uploadToBlobHandle, optionName, value);
2280 if(result != IOTHUB_CLIENT_OK)
2281 {
2282 LogError("unable to IoTHubClientCore_LL_UploadToBlob_SetOption, result=%d", result);
2283 }
2284#else
2285 LogError("%s option being set with DONT_USE_UPLOADTOBLOB compiler switch", optionName);
2286 result = IOTHUB_CLIENT_ERROR;
2287#endif /*DONT_USE_UPLOADTOBLOB*/
2288 }
2289 // OPTION_SAS_TOKEN_REFRESH_TIME is, but may be updated in the future
2290 // if this becomes necessary
2291 else if (strcmp(optionName, OPTION_SAS_TOKEN_REFRESH_TIME) == 0 || strcmp(optionName, OPTION_SAS_TOKEN_LIFETIME) == 0)
2292 {
2293 if (IoTHubClient_Auth_Set_SasToken_Expiry(handleData->authorization_module, *(size_t*)value) != 0)
2294 {
2295 LogError("Failed setting the Token Expiry time");
2296 result = IOTHUB_CLIENT_ERROR;
2297 }
2298 else
2299 {
2300 result = IOTHUB_CLIENT_OK;
2301 }
2302 }
2303 else
2304 {
2305 // This section is unusual for SetOption calls because it attempts to pass unhandled options
2306 // to two downstream targets (IoTHubTransport_SetOption and IoTHubClientCore_LL_UploadToBlob_SetOption) instead of one.
2307
2308 /*Codes_SRS_IOTHUBCLIENT_LL_30_011: [ IoTHubClientCore_LL_SetOption shall always pass unhandled options to Transport_SetOption. ]*/
2309 /*Codes_SRS_IOTHUBCLIENT_LL_30_012: [ If Transport_SetOption fails, IoTHubClientCore_LL_SetOption shall return that failure code. ]*/
2310 result = handleData->IoTHubTransport_SetOption(handleData->transportHandle, optionName, value);
2311 if(result != IOTHUB_CLIENT_OK)
2312 {
2313 LogError("unable to IoTHubTransport_SetOption");
2314 }
2315#ifndef DONT_USE_UPLOADTOBLOB
2316 else
2317 {
2318 /*Codes_SRS_IOTHUBCLIENT_LL_30_013: [ If the DONT_USE_UPLOADTOBLOB compiler switch is undefined, IoTHubClientCore_LL_SetOption shall pass unhandled options to IoTHubClient_UploadToBlob_SetOption and ignore the result. ]*/
2319 (void)IoTHubClient_LL_UploadToBlob_SetOption(handleData->uploadToBlobHandle, optionName, value);
2320 }
2321#endif /*DONT_USE_UPLOADTOBLOB*/
2322 }
2323 }
2324 return result;
2325}
2326
2327IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetDeviceTwinCallback(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
2328{
2329 IOTHUB_CLIENT_RESULT result;
2330 /* Codes_SRS_IOTHUBCLIENT_LL_10_001: [ IoTHubClientCore_LL_SetDeviceTwinCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.] */
2331 if (iotHubClientHandle == NULL)
2332 {
2333 result = IOTHUB_CLIENT_INVALID_ARG;
2334 LogError("Invalid argument specified iothubClientHandle=%p", iotHubClientHandle);
2335 }
2336 else
2337 {
2338 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2339 if (deviceTwinCallback == NULL)
2340 {
2341 /* Codes_SRS_IOTHUBCLIENT_LL_10_006: [ If deviceTwinCallback is NULL, then IoTHubClientCore_LL_SetDeviceTwinCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */
2342 handleData->IoTHubTransport_Unsubscribe_DeviceTwin(handleData->transportHandle);
2343 handleData->deviceTwinCallback = NULL;
2344 result = IOTHUB_CLIENT_OK;
2345 }
2346 else
2347 {
2348 /* Codes_SRS_IOTHUBCLIENT_LL_10_002: [ If deviceTwinCallback is not NULL, then IoTHubClientCore_LL_SetDeviceTwinCallback shall call the underlying layer's _Subscribe function.] */
2349 if (handleData->IoTHubTransport_Subscribe_DeviceTwin(handleData->transportHandle) == 0)
2350 {
2351 handleData->deviceTwinCallback = deviceTwinCallback;
2352 handleData->deviceTwinContextCallback = userContextCallback;
2353 /* Codes_SRS_IOTHUBCLIENT_LL_10_005: [ Otherwise IoTHubClientCore_LL_SetDeviceTwinCallback shall succeed and return IOTHUB_CLIENT_OK.] */
2354 result = IOTHUB_CLIENT_OK;
2355 }
2356 else
2357 {
2358 /* Codes_SRS_IOTHUBCLIENT_LL_10_003: [ If the underlying layer's _Subscribe function fails, then IoTHubClientCore_LL_SetDeviceTwinCallback shall fail and return IOTHUB_CLIENT_ERROR.] */
2359 result = IOTHUB_CLIENT_ERROR;
2360 }
2361 }
2362 }
2363 return result;
2364}
2365
2366IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SendReportedState(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const unsigned char* reportedState, size_t size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback, void* userContextCallback)
2367{
2368 IOTHUB_CLIENT_RESULT result;
2369 /* Codes_SRS_IOTHUBCLIENT_LL_10_012: [ IoTHubClientCore_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL. ] */
2370 /* Codes_SRS_IOTHUBCLIENT_LL_10_013: [ IoTHubClientCore_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter reportedState is NULL] */
2371 /* Codes_SRS_IOTHUBCLIENT_LL_07_005: [ IoTHubClientCore_LL_SendReportedState shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter size is equal to 0. ] */
2372 if (iotHubClientHandle == NULL || (reportedState == NULL || size == 0) )
2373 {
2374 result = IOTHUB_CLIENT_INVALID_ARG;
2375 LogError("Invalid argument specified iothubClientHandle=%p, reportedState=%p, size=%lu", iotHubClientHandle, reportedState, (unsigned long)size);
2376 }
2377 else
2378 {
2379 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2380 /* Codes_SRS_IOTHUBCLIENT_LL_10_014: [IoTHubClientCore_LL_SendReportedState shall construct and queue the reported a Device_Twin structure for transmition by the underlying transport.] */
2381 IOTHUB_DEVICE_TWIN* client_data = dev_twin_data_create(handleData, get_next_item_id(handleData), reportedState, size, reportedStateCallback, userContextCallback);
2382 if (client_data == NULL)
2383 {
2384 /* Codes_SRS_IOTHUBCLIENT_LL_10_015: [If any error is encountered IoTHubClientCore_LL_SendReportedState shall return IOTHUB_CLIENT_ERROR.] */
2385 LogError("Failure constructing device twin data");
2386 result = IOTHUB_CLIENT_ERROR;
2387 }
2388 else
2389 {
2390 if (handleData->IoTHubTransport_Subscribe_DeviceTwin(handleData->transportHandle) != 0)
2391 {
2392 LogError("Failure adding device twin data to queue");
2393 device_twin_data_destroy(client_data);
2394 result = IOTHUB_CLIENT_ERROR;
2395 }
2396 else
2397 {
2398 /* Codes_SRS_IOTHUBCLIENT_LL_07_001: [ IoTHubClientCore_LL_SendReportedState shall queue the constructed reportedState data to be consumed by the targeted transport. ] */
2399 DList_InsertTailList(&(iotHubClientHandle->iot_msg_queue), &(client_data->entry));
2400
2401 /* Codes_SRS_IOTHUBCLIENT_LL_10_016: [ Otherwise IoTHubClientCore_LL_SendReportedState shall succeed and return IOTHUB_CLIENT_OK.] */
2402 result = IOTHUB_CLIENT_OK;
2403 }
2404 }
2405 }
2406 return result;
2407}
2408
2409IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_GetTwinAsync(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
2410{
2411 IOTHUB_CLIENT_RESULT result;
2412
2413 // Codes_SRS_IOTHUBCLIENT_LL_09_011: [ If `iotHubClientHandle` or `deviceTwinCallback` are `NULL`, `IoTHubClientCore_LL_GetTwinAsync` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]
2414 if (iotHubClientHandle == NULL || deviceTwinCallback == NULL)
2415 {
2416 LogError("Invalid argument iothubClientHandle=%p, deviceTwinCallback=%p", iotHubClientHandle, deviceTwinCallback);
2417 result = IOTHUB_CLIENT_INVALID_ARG;
2418 }
2419 else
2420 {
2421 if (iotHubClientHandle->IoTHubTransport_Subscribe_DeviceTwin(iotHubClientHandle->transportHandle) != 0)
2422 {
2423 LogError("Failure adding device twin data to queue");
2424 result = IOTHUB_CLIENT_ERROR;
2425 }
2426 else
2427 {
2428 GET_TWIN_CONTEXT* getTwinCtx;
2429
2430 if ((getTwinCtx = (GET_TWIN_CONTEXT*)malloc(sizeof(GET_TWIN_CONTEXT))) == NULL)
2431 {
2432 LogError("Failed creating get-twin context");
2433 result = IOTHUB_CLIENT_ERROR;
2434 }
2435 else
2436 {
2437 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2438
2439 getTwinCtx->callback = deviceTwinCallback;
2440 getTwinCtx->context = userContextCallback;
2441
2442 // Codes_SRS_IOTHUBCLIENT_LL_09_012: [ IoTHubClientCore_LL_GetTwinAsync shall invoke IoTHubTransport_GetTwinAsync, passing `on_device_twin_report_received` and the user data as context ]
2443 if (handleData->IoTHubTransport_GetTwinAsync(handleData->deviceHandle, on_get_device_twin_completed, getTwinCtx) != IOTHUB_CLIENT_OK)
2444 {
2445 // Codes_SRS_IOTHUBCLIENT_LL_09_013: [ If IoTHubTransport_GetTwinAsync fails, `IoTHubClientCore_LL_GetTwinAsync` shall fail and return `IOTHUB_CLIENT_ERROR`. ]
2446 LogError("Failed getting device twin document");
2447 free(getTwinCtx);
2448 result = IOTHUB_CLIENT_ERROR;
2449 }
2450 else
2451 {
2452 // Codes_SRS_IOTHUBCLIENT_LL_09_014: [ If no errors occur IoTHubClientCore_LL_GetTwinAsync shall return `IOTHUB_CLIENT_OK`. ]
2453 handleData->complete_twin_update_encountered = true;
2454 result = IOTHUB_CLIENT_OK;
2455 }
2456 }
2457 }
2458 }
2459
2460 return result;
2461}
2462
2463
2464IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetDeviceMethodCallback(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC deviceMethodCallback, void* userContextCallback)
2465{
2466 IOTHUB_CLIENT_RESULT result;
2467
2468 /*Codes_SRS_IOTHUBCLIENT_LL_12_017: [ IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL. ] */
2469 if (iotHubClientHandle == NULL)
2470 {
2471 result = IOTHUB_CLIENT_INVALID_ARG;
2472 LOG_ERROR_RESULT;
2473 }
2474 else
2475 {
2476 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2477 if (deviceMethodCallback == NULL)
2478 {
2479 if (handleData->methodCallback.type == CALLBACK_TYPE_NONE)
2480 {
2481 /* Codes_SRS_IOTHUBCLIENT_LL_10_029: [ If deviceMethodCallback is NULL and the client is not subscribed to receive method calls, IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ] */
2482 LogError("not currently set to accept or process incoming messages.");
2483 result = IOTHUB_CLIENT_ERROR;
2484 }
2485 else if (handleData->methodCallback.type == CALLBACK_TYPE_ASYNC)
2486 {
2487 /* Codes_SRS_IOTHUBCLIENT_LL_10_028: [If the user has subscribed using IoTHubClientCore_LL_SetDeviceMethodCallback_Ex, IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ] */
2488 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetDeviceMethodCallback_Ex function.");
2489 result = IOTHUB_CLIENT_ERROR;
2490 }
2491 else
2492 {
2493 /*Codes_SRS_IOTHUBCLIENT_LL_02_019: [If parameter messageCallback is NULL then IoTHubClientCore_LL_SetMessageCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */
2494 /*Codes_SRS_IOTHUBCLIENT_LL_12_018: [If deviceMethodCallback is NULL, then IoTHubClientCore_LL_SetDeviceMethodCallback shall call the underlying layer's IoTHubTransport_Unsubscribe_DeviceMethod function and return IOTHUB_CLIENT_OK. ] */
2495 /*Codes_SRS_IOTHUBCLIENT_LL_12_022: [ Otherwise IoTHubClientCore_LL_SetDeviceMethodCallback shall succeed and return IOTHUB_CLIENT_OK. ]*/
2496 handleData->IoTHubTransport_Unsubscribe_DeviceMethod(handleData->deviceHandle);
2497 handleData->methodCallback.type = CALLBACK_TYPE_NONE;
2498 handleData->methodCallback.callbackSync = NULL;
2499 handleData->methodCallback.userContextCallback = NULL;
2500 result = IOTHUB_CLIENT_OK;
2501 }
2502 }
2503 else
2504 {
2505 if (handleData->methodCallback.type == CALLBACK_TYPE_ASYNC)
2506 {
2507 /* Codes_SRS_IOTHUBCLIENT_LL_10_028: [If the user has subscribed using IoTHubClientCore_LL_SetDeviceMethodCallback_Ex, IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ] */
2508 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetDeviceMethodCallback_Ex function before subscribing with IoTHubClientCore_LL_SetDeviceMethodCallback.");
2509 result = IOTHUB_CLIENT_ERROR;
2510 }
2511 else
2512 {
2513 /*Codes_SRS_IOTHUBCLIENT_LL_12_019: [ If deviceMethodCallback is not NULL, then IoTHubClientCore_LL_SetDeviceMethodCallback shall call the underlying layer's IoTHubTransport_Subscribe_DeviceMethod function. ]*/
2514 if (handleData->IoTHubTransport_Subscribe_DeviceMethod(handleData->deviceHandle) == 0)
2515 {
2516 /*Codes_SRS_IOTHUBCLIENT_LL_12_022: [ Otherwise IoTHubClientCore_LL_SetDeviceMethodCallback shall succeed and return IOTHUB_CLIENT_OK. ]*/
2517 handleData->methodCallback.type = CALLBACK_TYPE_SYNC;
2518 handleData->methodCallback.callbackSync = deviceMethodCallback;
2519 handleData->methodCallback.callbackAsync = NULL;
2520 handleData->methodCallback.userContextCallback = userContextCallback;
2521 result = IOTHUB_CLIENT_OK;
2522 }
2523 else
2524 {
2525 /*Codes_SRS_IOTHUBCLIENT_LL_12_020: [ If the underlying layer's IoTHubTransport_Subscribe_DeviceMethod function fails, then IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2526 /*Codes_SRS_IOTHUBCLIENT_LL_12_021: [ If adding the information fails for any reason, IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2527 LogError("IoTHubTransport_Subscribe_DeviceMethod failed");
2528 handleData->methodCallback.type = CALLBACK_TYPE_NONE;
2529 handleData->methodCallback.callbackAsync = NULL;
2530 handleData->methodCallback.callbackSync = NULL;
2531 handleData->methodCallback.userContextCallback = NULL;
2532 result = IOTHUB_CLIENT_ERROR;
2533 }
2534 }
2535 }
2536 }
2537 return result;
2538}
2539
2540IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetDeviceMethodCallback_Ex(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK inboundDeviceMethodCallback, void* userContextCallback)
2541{
2542 IOTHUB_CLIENT_RESULT result;
2543 /* Codes_SRS_IOTHUBCLIENT_LL_07_021: [ If handle is NULL then IoTHubClientCore_LL_SetDeviceMethodCallback_Ex shall return IOTHUB_CLIENT_INVALID_ARG.] */
2544 if (iotHubClientHandle == NULL)
2545 {
2546 result = IOTHUB_CLIENT_INVALID_ARG;
2547 LOG_ERROR_RESULT;
2548 }
2549 else
2550 {
2551 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2552 if (inboundDeviceMethodCallback == NULL)
2553 {
2554 if (handleData->methodCallback.type == CALLBACK_TYPE_NONE)
2555 {
2556 /* Codes_SRS_IOTHUBCLIENT_LL_10_030: [ If deviceMethodCallback is NULL and the client is not subscribed to receive method calls, IoTHubClientCore_LL_SetDeviceMethodCallback shall fail and return IOTHUB_CLIENT_ERROR. ] */
2557 LogError("not currently set to accept or process incoming messages.");
2558 result = IOTHUB_CLIENT_ERROR;
2559 }
2560 else if (handleData->methodCallback.type == CALLBACK_TYPE_SYNC)
2561 {
2562 /* Codes_SRS_IOTHUBCLIENT_LL_10_031: [If the user has subscribed using IoTHubClientCore_LL_SetDeviceMethodCallback, IoTHubClientCore_LL_SetDeviceMethodCallback_Ex shall fail and return IOTHUB_CLIENT_ERROR. ] */
2563 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetDeviceMethodCallback function.");
2564 result = IOTHUB_CLIENT_ERROR;
2565 }
2566 else
2567 {
2568 /* Codes_SRS_IOTHUBCLIENT_LL_07_022: [ If inboundDeviceMethodCallback is NULL then IoTHubClientCore_LL_SetDeviceMethodCallback_Ex shall call the underlying layer's IoTHubTransport_Unsubscribe_DeviceMethod function and return IOTHUB_CLIENT_OK.] */
2569 handleData->IoTHubTransport_Unsubscribe_DeviceMethod(handleData->deviceHandle);
2570 handleData->methodCallback.type = CALLBACK_TYPE_NONE;
2571 handleData->methodCallback.callbackAsync = NULL;
2572 handleData->methodCallback.userContextCallback = NULL;
2573 result = IOTHUB_CLIENT_OK;
2574 }
2575 }
2576 else
2577 {
2578 if (handleData->methodCallback.type == CALLBACK_TYPE_SYNC)
2579 {
2580 /* Codes_SRS_IOTHUBCLIENT_LL_10_031: [If the user has subscribed using IoTHubClientCore_LL_SetDeviceMethodCallback, IoTHubClientCore_LL_SetDeviceMethodCallback_Ex shall fail and return IOTHUB_CLIENT_ERROR. ] */
2581 LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClientCore_LL_SetDeviceMethodCallback function before subscribing with IoTHubClientCore_LL_SetDeviceMethodCallback_Ex.");
2582 result = IOTHUB_CLIENT_ERROR;
2583 }
2584 else
2585 {
2586 /* Codes_SRS_IOTHUBCLIENT_LL_07_023: [ If inboundDeviceMethodCallback is non-NULL then IoTHubClientCore_LL_SetDeviceMethodCallback_Ex shall call the underlying layer's IoTHubTransport_Subscribe_DeviceMethod function.]*/
2587 if (handleData->IoTHubTransport_Subscribe_DeviceMethod(handleData->deviceHandle) == 0)
2588 {
2589 handleData->methodCallback.type = CALLBACK_TYPE_ASYNC;
2590 handleData->methodCallback.callbackAsync = inboundDeviceMethodCallback;
2591 handleData->methodCallback.callbackSync = NULL;
2592 handleData->methodCallback.userContextCallback = userContextCallback;
2593 result = IOTHUB_CLIENT_OK;
2594 }
2595 else
2596 {
2597 /* Codes_SRS_IOTHUBCLIENT_LL_07_025: [ If any error is encountered then IoTHubClientCore_LL_SetDeviceMethodCallback_Ex shall return IOTHUB_CLIENT_ERROR.] */
2598 LogError("IoTHubTransport_Subscribe_DeviceMethod failed");
2599 handleData->methodCallback.type = CALLBACK_TYPE_NONE;
2600 handleData->methodCallback.callbackAsync = NULL;
2601 handleData->methodCallback.callbackSync = NULL;
2602 handleData->methodCallback.userContextCallback = NULL;
2603 result = IOTHUB_CLIENT_ERROR;
2604 }
2605 }
2606 }
2607 }
2608 return result;
2609}
2610
2611IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_DeviceMethodResponse(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, METHOD_HANDLE methodId, const unsigned char* response, size_t response_size, int status_response)
2612{
2613 IOTHUB_CLIENT_RESULT result;
2614 /* Codes_SRS_IOTHUBCLIENT_LL_07_026: [ If handle or methodId is NULL then IoTHubClientCore_LL_DeviceMethodResponse shall return IOTHUB_CLIENT_INVALID_ARG.] */
2615 if (iotHubClientHandle == NULL || methodId == NULL)
2616 {
2617 result = IOTHUB_CLIENT_INVALID_ARG;
2618 LOG_ERROR_RESULT;
2619 }
2620 else
2621 {
2622 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2623 /* Codes_SRS_IOTHUBCLIENT_LL_07_027: [ IoTHubClientCore_LL_DeviceMethodResponse shall call the IoTHubTransport_DeviceMethod_Response transport function.] */
2624 if (handleData->IoTHubTransport_DeviceMethod_Response(handleData->deviceHandle, methodId, response, response_size, status_response) != 0)
2625 {
2626 LogError("IoTHubTransport_DeviceMethod_Response failed");
2627 result = IOTHUB_CLIENT_ERROR;
2628 }
2629 else
2630 {
2631 result = IOTHUB_CLIENT_OK;
2632 }
2633 }
2634 return result;
2635}
2636
2637#ifndef DONT_USE_UPLOADTOBLOB
2638IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_UploadToBlob(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* destinationFileName, const unsigned char* source, size_t size)
2639{
2640 IOTHUB_CLIENT_RESULT result;
2641 /*Codes_SRS_IOTHUBCLIENT_LL_02_061: [ If iotHubClientHandle is NULL then IoTHubClientCore_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
2642 /*Codes_SRS_IOTHUBCLIENT_LL_02_062: [ If destinationFileName is NULL then IoTHubClientCore_LL_UploadToBlob shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
2643 /*Codes_SRS_IOTHUBCLIENT_LL_02_063: [ If `source` is `NULL` and size is greater than 0 then `IoTHubClientCore_LL_UploadToBlob` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2644 if (
2645 (iotHubClientHandle == NULL) ||
2646 (destinationFileName == NULL) ||
2647 ((source == NULL) && (size >0))
2648 )
2649 {
2650 LogError("invalid parameters IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle=%p, const char* destinationFileName=%s, const unsigned char* source=%p, size_t size=%lu", iotHubClientHandle, destinationFileName, source, (unsigned long)size);
2651 result = IOTHUB_CLIENT_INVALID_ARG;
2652 }
2653 else
2654 {
2655 result = IoTHubClient_LL_UploadToBlob_Impl(iotHubClientHandle->uploadToBlobHandle, destinationFileName, source, size);
2656 }
2657 return result;
2658}
2659
2660typedef struct UPLOAD_MULTIPLE_BLOCKS_WRAPPER_CONTEXT_TAG
2661{
2662 IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback;
2663 void* context;
2664} UPLOAD_MULTIPLE_BLOCKS_WRAPPER_CONTEXT;
2665
2666
2667static IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_RESULT uploadMultipleBlocksCallbackWrapper(IOTHUB_CLIENT_FILE_UPLOAD_RESULT result, unsigned char const ** data, size_t* size, void* context)
2668{
2669 UPLOAD_MULTIPLE_BLOCKS_WRAPPER_CONTEXT* wrapperContext = (UPLOAD_MULTIPLE_BLOCKS_WRAPPER_CONTEXT*)context;
2670 wrapperContext->getDataCallback(result, data, size, wrapperContext->context);
2671 return IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_OK;
2672}
2673
2674IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_UploadMultipleBlocksToBlob(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback, void* context)
2675{
2676 IOTHUB_CLIENT_RESULT result;
2677 /*Codes_SRS_IOTHUBCLIENT_LL_99_005: [ If `iotHubClientHandle` is `NULL` then `IoTHubClientCore_LL_UploadMultipleBlocksToBlob(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2678 /*Codes_SRS_IOTHUBCLIENT_LL_99_006: [ If `destinationFileName` is `NULL` then `IoTHubClientCore_LL_UploadMultipleBlocksToBlob(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2679 /*Codes_SRS_IOTHUBCLIENT_LL_99_007: [ If `getDataCallback` is `NULL` then `IoTHubClientCore_LL_UploadMultipleBlocksToBlob(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2680 if (
2681 (iotHubClientHandle == NULL) ||
2682 (destinationFileName == NULL) ||
2683 (getDataCallback == NULL)
2684 )
2685 {
2686 LogError("invalid parameters IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle=%p, const char* destinationFileName=%p, getDataCallback=%p", iotHubClientHandle, destinationFileName, getDataCallback);
2687 result = IOTHUB_CLIENT_INVALID_ARG;
2688 }
2689 else
2690 {
2691 UPLOAD_MULTIPLE_BLOCKS_WRAPPER_CONTEXT uploadMultipleBlocksWrapperContext;
2692 uploadMultipleBlocksWrapperContext.getDataCallback = getDataCallback;
2693 uploadMultipleBlocksWrapperContext.context = context;
2694
2695 result = IoTHubClient_LL_UploadMultipleBlocksToBlob_Impl(iotHubClientHandle->uploadToBlobHandle, destinationFileName, uploadMultipleBlocksCallbackWrapper, &uploadMultipleBlocksWrapperContext);
2696 }
2697 return result;
2698}
2699
2700IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context)
2701{
2702 IOTHUB_CLIENT_RESULT result;
2703 /*Codes_SRS_IOTHUBCLIENT_LL_99_005: [ If `iotHubClientHandle` is `NULL` then `IoTHubClientCore_LL_UploadMultipleBlocksToBlob(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2704 /*Codes_SRS_IOTHUBCLIENT_LL_99_006: [ If `destinationFileName` is `NULL` then `IoTHubClientCore_LL_UploadMultipleBlocksToBlob(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2705 /*Codes_SRS_IOTHUBCLIENT_LL_99_007: [ If `getDataCallback` is `NULL` then `IoTHubClientCore_LL_UploadMultipleBlocksToBlob(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2706 if (
2707 (iotHubClientHandle == NULL) ||
2708 (destinationFileName == NULL) ||
2709 (getDataCallbackEx == NULL)
2710 )
2711 {
2712 LogError("invalid parameters IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle=%p, destinationFileName=%p, getDataCallbackEx=%p", iotHubClientHandle, destinationFileName, getDataCallbackEx);
2713 result = IOTHUB_CLIENT_INVALID_ARG;
2714 }
2715 else
2716 {
2717 result = IoTHubClient_LL_UploadMultipleBlocksToBlob_Impl(iotHubClientHandle->uploadToBlobHandle, destinationFileName, getDataCallbackEx, context);
2718 }
2719 return result;
2720}
2721#endif // DONT_USE_UPLOADTOBLOB
2722
2723IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SendEventToOutputAsync(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, const char* outputName, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback)
2724{
2725 IOTHUB_CLIENT_RESULT result;
2726
2727 if ((iotHubClientHandle == NULL) || (outputName == NULL) || (eventMessageHandle == NULL) || ((eventConfirmationCallback == NULL) && (userContextCallback != NULL)))
2728 {
2729 // Codes_SRS_IOTHUBCLIENT_LL_31_127: [ If `iotHubClientHandle`, `outputName`, or `eventConfirmationCallback` is `NULL`, `IoTHubClient_LL_SendEventToOutputAsync` shall return `IOTHUB_CLIENT_INVALID_ARG`. ]
2730 LogError("Invalid argument (iotHubClientHandle=%p, outputName=%p, eventMessageHandle=%p)", iotHubClientHandle, outputName, eventMessageHandle);
2731 result = IOTHUB_CLIENT_INVALID_ARG;
2732 }
2733 else
2734 {
2735 // Codes_SRS_IOTHUBCLIENT_LL_31_128: [ `IoTHubClient_LL_SendEventToOutputAsync` shall set the outputName of the message to send. ]
2736 if (IoTHubMessage_SetOutputName(eventMessageHandle, outputName) != IOTHUB_MESSAGE_OK)
2737 {
2738 LogError("IoTHubMessage_SetOutputName failed");
2739 result = IOTHUB_CLIENT_ERROR;
2740 }
2741 // Codes_SRS_IOTHUBCLIENT_LL_31_129: [ `IoTHubClient_LL_SendEventToOutputAsync` shall invoke `IoTHubClient_LL_SendEventAsync` to send the message. ]
2742 else if ((result = IoTHubClientCore_LL_SendEventAsync(iotHubClientHandle, eventMessageHandle, eventConfirmationCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
2743 {
2744 LogError("Call into IoTHubClient_LL_SendEventAsync failed, result=%d", result);
2745 }
2746 }
2747
2748 return result;
2749}
2750
2751
2752static IOTHUB_CLIENT_RESULT create_event_handler_callback(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData, const char* inputName, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC callbackSync, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX callbackSyncEx, void* userContextCallback, void* userContextCallbackEx, size_t userContextCallbackExLength)
2753{
2754 IOTHUB_CLIENT_RESULT result = IOTHUB_CLIENT_ERROR;
2755 bool add_to_list = false;
2756
2757 if ((handleData->event_callbacks == NULL) && ((handleData->event_callbacks = singlylinkedlist_create()) == NULL))
2758 {
2759 LogError("Could not allocate linked list for callbacks");
2760 result = IOTHUB_CLIENT_ERROR;
2761 }
2762 else
2763 {
2764 IOTHUB_EVENT_CALLBACK* event_callback = NULL;
2765 LIST_ITEM_HANDLE item_handle = singlylinkedlist_find(handleData->event_callbacks, is_event_equal_for_match, (const void*)inputName);
2766 if (item_handle == NULL)
2767 {
2768 // Codes_SRS_IOTHUBCLIENT_LL_31_134: [ `IoTHubClient_LL_SetInputMessageCallback` shall allocate a callback handle to associate callbacks from the transport => client if `inputName` isn't already present in the callback list. ]
2769 event_callback = (IOTHUB_EVENT_CALLBACK*)malloc(sizeof(IOTHUB_EVENT_CALLBACK));
2770 if (event_callback == NULL)
2771 {
2772 LogError("Could not allocate IOTHUB_EVENT_CALLBACK");
2773 result = IOTHUB_CLIENT_ERROR;
2774 }
2775 else
2776 {
2777 memset(event_callback, 0, sizeof(*event_callback));
2778 add_to_list = true;
2779 }
2780 }
2781 else
2782 {
2783 // Codes_SRS_IOTHUBCLIENT_LL_31_135: [ `IoTHubClient_LL_SetInputMessageCallback` shall reuse the existing callback handle if `inputName` is already present in the callback list. ]
2784 event_callback = (IOTHUB_EVENT_CALLBACK*)singlylinkedlist_item_get_value(item_handle);
2785 if (event_callback == NULL)
2786 {
2787 LogError("singlylinkedlist_item_get_value failed looking up event callback");
2788 }
2789 }
2790
2791 if (event_callback != NULL)
2792 {
2793 if ((inputName != NULL) && (event_callback->inputName == NULL))
2794 {
2795 event_callback->inputName = STRING_construct(inputName);
2796 }
2797
2798 if ((inputName == NULL) || (event_callback->inputName != NULL))
2799 {
2800 event_callback->callbackAsync = callbackSync;
2801 event_callback->callbackAsyncEx = callbackSyncEx;
2802
2803 free(event_callback->userContextCallbackEx);
2804 event_callback->userContextCallbackEx = NULL;
2805
2806 if (userContextCallbackEx == NULL)
2807 {
2808 event_callback->userContextCallback = userContextCallback;
2809 }
2810
2811 if ((userContextCallbackEx != NULL) &&
2812 (NULL == (event_callback->userContextCallbackEx = malloc(userContextCallbackExLength))))
2813 {
2814 LogError("Unable to allocate userContextCallback");
2815 delete_event(event_callback);
2816 result = IOTHUB_CLIENT_ERROR;
2817 }
2818 else if ((add_to_list == true) && (NULL == singlylinkedlist_add(handleData->event_callbacks, event_callback)))
2819 {
2820 LogError("Unable to add eventCallback to list");
2821 delete_event(event_callback);
2822 result = IOTHUB_CLIENT_ERROR;
2823 }
2824 else
2825 {
2826 if (userContextCallbackEx != NULL)
2827 {
2828 // Codes_SRS_IOTHUBCLIENT_LL_31_141: [`IoTHubClient_LL_SetInputMessageCallbackEx` shall copy the data passed in extended context. ]
2829 memcpy(event_callback->userContextCallbackEx, userContextCallbackEx, userContextCallbackExLength);
2830 }
2831 result = IOTHUB_CLIENT_OK;
2832 }
2833 }
2834 else
2835 {
2836 delete_event(event_callback);
2837 result = IOTHUB_CLIENT_ERROR;
2838 }
2839 }
2840 }
2841
2842 return result;
2843}
2844
2845static IOTHUB_CLIENT_RESULT remove_event_unsubscribe_if_needed(IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData, const char* inputName)
2846{
2847 IOTHUB_CLIENT_RESULT result;
2848
2849 LIST_ITEM_HANDLE item_handle = singlylinkedlist_find(handleData->event_callbacks, is_event_equal_for_match, (const void*)inputName);
2850 if (item_handle == NULL)
2851 {
2852 // Codes_SRS_IOTHUBCLIENT_LL_31_132: [ If `eventHandlerCallback` is NULL, `IoTHubClient_LL_SetInputMessageCallback` shall return `IOTHUB_CLIENT_ERROR` if the `inputName` is not present. ]
2853 LogError("Input name %s was not present", inputName);
2854 result = IOTHUB_CLIENT_ERROR;
2855 }
2856 else
2857 {
2858 IOTHUB_EVENT_CALLBACK* event_callback = (IOTHUB_EVENT_CALLBACK*)singlylinkedlist_item_get_value(item_handle);
2859 if (event_callback == NULL)
2860 {
2861 LogError("singlylinkedlist_item_get_value failed");
2862 result = IOTHUB_CLIENT_ERROR;
2863 }
2864 else
2865 {
2866 delete_event(event_callback);
2867 // Codes_SRS_IOTHUBCLIENT_LL_31_131: [ If `eventHandlerCallback` is NULL, `IoTHubClient_LL_SetInputMessageCallback` shall remove the `inputName` from its callback list if present. ]
2868 if (singlylinkedlist_remove(handleData->event_callbacks, item_handle) != 0)
2869 {
2870 LogError("singlylinkedlist_remove failed");
2871 result = IOTHUB_CLIENT_ERROR;
2872 }
2873 else
2874 {
2875 if (singlylinkedlist_get_head_item(handleData->event_callbacks) == NULL)
2876 {
2877 // Codes_SRS_IOTHUBCLIENT_LL_31_133: [ If `eventHandlerCallback` is NULL, `IoTHubClient_LL_SetInputMessageCallback` shall invoke `IoTHubTransport_Unsubscribe_InputQueue` if this was the last input callback. ]
2878 handleData->IoTHubTransport_Unsubscribe_InputQueue(handleData);
2879 }
2880 result = IOTHUB_CLIENT_OK;
2881 }
2882 }
2883 }
2884
2885 return result;
2886}
2887
2888
2889IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetInputMessageCallbackImpl(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* inputName, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC eventHandlerCallback, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX eventHandlerCallbackEx, void *userContextCallback, void *userContextCallbackEx, size_t userContextCallbackExLength)
2890{
2891 IOTHUB_CLIENT_RESULT result;
2892
2893 if (iotHubClientHandle == NULL)
2894 {
2895 // Codes_SRS_IOTHUBCLIENT_LL_31_130: [ If `iotHubClientHandle` or `inputName` is NULL, `IoTHubClient_LL_SetInputMessageCallback` shall return IOTHUB_CLIENT_INVALID_ARG. ]
2896 LogError("Invalid argument - iotHubClientHandle=%p, inputName=%p", iotHubClientHandle, inputName);
2897 result = IOTHUB_CLIENT_INVALID_ARG;
2898 }
2899 else
2900 {
2901 IOTHUB_CLIENT_CORE_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_CORE_LL_HANDLE_DATA*)iotHubClientHandle;
2902 if ((eventHandlerCallback == NULL) && (eventHandlerCallbackEx == NULL))
2903 {
2904 result = (IOTHUB_CLIENT_RESULT)remove_event_unsubscribe_if_needed(handleData, inputName);
2905 }
2906 else
2907 {
2908 bool registered_with_transport_handler = (handleData->event_callbacks != NULL) && (singlylinkedlist_get_head_item(handleData->event_callbacks) != NULL);
2909 if ((result = (IOTHUB_CLIENT_RESULT)create_event_handler_callback(handleData, inputName, eventHandlerCallback, eventHandlerCallbackEx, userContextCallback, userContextCallbackEx, userContextCallbackExLength)) != IOTHUB_CLIENT_OK)
2910 {
2911 LogError("create_event_handler_callback call failed, error = %d", result);
2912 }
2913 // Codes_SRS_IOTHUBCLIENT_LL_31_136: [ `IoTHubClient_LL_SetInputMessageCallback` shall invoke `IoTHubTransport_Subscribe_InputQueue` if this is the first callback being registered. ]
2914 else if (!registered_with_transport_handler && (handleData->IoTHubTransport_Subscribe_InputQueue(handleData->deviceHandle) != 0))
2915 {
2916 LogError("IoTHubTransport_Subscribe_InputQueue failed");
2917 delete_event_callback_list(handleData);
2918 result = IOTHUB_CLIENT_ERROR;
2919 }
2920 else
2921 {
2922 result = IOTHUB_CLIENT_OK;
2923 }
2924 }
2925 }
2926 return result;
2927
2928}
2929
2930IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetInputMessageCallbackEx(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* inputName, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX eventHandlerCallbackEx, void *userContextCallbackEx, size_t userContextCallbackExLength)
2931{
2932 return IoTHubClientCore_LL_SetInputMessageCallbackImpl(iotHubClientHandle, inputName, NULL, eventHandlerCallbackEx, NULL, userContextCallbackEx, userContextCallbackExLength);
2933}
2934
2935IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_SetInputMessageCallback(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* inputName, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC eventHandlerCallback, void* userContextCallback)
2936{
2937 return IoTHubClientCore_LL_SetInputMessageCallbackImpl(iotHubClientHandle, inputName, eventHandlerCallback, NULL, userContextCallback, NULL, 0);
2938}
2939
2940int IoTHubClientCore_LL_GetTransportCallbacks(TRANSPORT_CALLBACKS_INFO* transport_cb)
2941{
2942 int result;
2943 if (transport_cb == NULL)
2944 {
2945 LogError("Invalid parameter transport callback can not be NULL");
2946 result = MU_FAILURE;
2947 }
2948 else
2949 {
2950 transport_cb->send_complete_cb = IoTHubClientCore_LL_SendComplete;
2951 transport_cb->twin_retrieve_prop_complete_cb = IoTHubClientCore_LL_RetrievePropertyComplete;
2952 transport_cb->twin_rpt_state_complete_cb = IoTHubClientCore_LL_ReportedStateComplete;
2953 transport_cb->connection_status_cb = IoTHubClientCore_LL_ConnectionStatusCallBack;
2954 transport_cb->prod_info_cb = IoTHubClientCore_LL_GetProductInfo;
2955 transport_cb->msg_input_cb = IoTHubClientCore_LL_MessageCallbackFromInput;
2956 transport_cb->msg_cb = IoTHubClientCore_LL_MessageCallback;
2957 transport_cb->method_complete_cb = IoTHubClientCore_LL_DeviceMethodComplete;
2958 result = 0;
2959 }
2960 return result;
2961}
2962
2963#ifdef USE_EDGE_MODULES
2964/* These should be replaced during iothub_client refactor */
2965IOTHUB_CLIENT_RESULT IoTHubClientCore_LL_GenericMethodInvoke(IOTHUB_CLIENT_CORE_LL_HANDLE iotHubClientHandle, const char* deviceId, const char* moduleId, const char* methodName, const char* methodPayload, unsigned int timeout, int* responseStatus, unsigned char** responsePayload, size_t* responsePayloadSize)
2966{
2967 IOTHUB_CLIENT_RESULT result;
2968 if (iotHubClientHandle != NULL)
2969 {
2970 if (moduleId != NULL)
2971 {
2972 result = IoTHubClient_Edge_ModuleMethodInvoke(iotHubClientHandle->methodHandle, deviceId, moduleId, methodName, methodPayload, timeout, responseStatus, responsePayload, responsePayloadSize);
2973 }
2974 else
2975 {
2976 result = IoTHubClient_Edge_DeviceMethodInvoke(iotHubClientHandle->methodHandle, deviceId, methodName, methodPayload, timeout, responseStatus, responsePayload, responsePayloadSize);
2977
2978 }
2979 }
2980 else
2981 {
2982 result = IOTHUB_CLIENT_INVALID_ARG;
2983 }
2984 return result;
2985}
2986#endif
2987
2988/*end*/
2989
Note: See TracBrowser for help on using the repository browser.