source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/iothub_client/src/iothub_client_core_ll.c@ 464

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

WolfSSLとAzure IoT SDKを更新

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