source: azure_iot_hub_riscv/trunk/azure_iot_sdk/iothub_client/src/iothub_client_core.c@ 453

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

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 128.7 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 "umock_c/umock_c_prod.h"
6#include "azure_c_shared_utility/gballoc.h"
7
8#include <signal.h>
9#include <stddef.h>
10#include "azure_c_shared_utility/optimize_size.h"
11#include "azure_c_shared_utility/crt_abstractions.h"
12#include "iothub_client_core.h"
13#include "iothub_client_core_ll.h"
14#include "internal/iothubtransport.h"
15#include "internal/iothub_client_private.h"
16#include "internal/iothubtransport.h"
17#include "azure_c_shared_utility/threadapi.h"
18#include "azure_c_shared_utility/lock.h"
19#include "azure_c_shared_utility/xlogging.h"
20#include "azure_c_shared_utility/singlylinkedlist.h"
21#include "azure_c_shared_utility/vector.h"
22#include "iothub_client_options.h"
23#include "azure_c_shared_utility/tickcounter.h"
24#include "azure_c_shared_utility/agenttime.h"
25
26
27#define DO_WORK_FREQ_DEFAULT 1
28
29struct IOTHUB_QUEUE_CONTEXT_TAG;
30
31typedef struct IOTHUB_CLIENT_CORE_INSTANCE_TAG
32{
33 IOTHUB_CLIENT_CORE_LL_HANDLE IoTHubClientLLHandle;
34 TRANSPORT_HANDLE TransportHandle;
35 THREAD_HANDLE ThreadHandle;
36 LOCK_HANDLE LockHandle;
37 sig_atomic_t StopThread;
38 SINGLYLINKEDLIST_HANDLE httpWorkerThreadInfoList; /*list containing HTTPWORKER_THREAD_INFO*/
39 int created_with_transport_handle;
40 VECTOR_HANDLE saved_user_callback_list;
41 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK desired_state_callback;
42 IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connection_status_callback;
43 IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC device_method_callback;
44 IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK inbound_device_method_callback;
45 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC message_callback;
46 struct IOTHUB_QUEUE_CONTEXT_TAG* devicetwin_user_context;
47 struct IOTHUB_QUEUE_CONTEXT_TAG* connection_status_user_context;
48 struct IOTHUB_QUEUE_CONTEXT_TAG* message_user_context;
49 struct IOTHUB_QUEUE_CONTEXT_TAG* method_user_context;
50 tickcounter_ms_t do_work_freq_ms;
51 tickcounter_ms_t currentMessageTimeout;
52} IOTHUB_CLIENT_CORE_INSTANCE;
53
54typedef enum HTTPWORKER_THREAD_TYPE_TAG
55{
56 HTTPWORKER_THREAD_UPLOAD_TO_BLOB,
57 HTTPWORKER_THREAD_INVOKE_METHOD
58} HTTPWORKER_THREAD_TYPE;
59
60typedef struct UPLOADTOBLOB_SAVED_DATA_TAG
61{
62 unsigned char* source;
63 size_t size;
64 IOTHUB_CLIENT_FILE_UPLOAD_CALLBACK iotHubClientFileUploadCallback;
65}UPLOADTOBLOB_SAVED_DATA;
66
67typedef struct UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA_TAG
68{
69 IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback;
70 IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx;
71}UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA;
72
73typedef struct INVOKE_METHOD_SAVED_DATA_TAG
74{
75 const char* deviceId;
76 const char* moduleId;
77 const char* methodName;
78 const char* methodPayload;
79 unsigned int timeout;
80 IOTHUB_METHOD_INVOKE_CALLBACK methodInvokeCallback;
81} INVOKE_METHOD_SAVED_DATA;
82
83typedef struct HTTPWORKER_THREAD_INFO_TAG
84{
85 HTTPWORKER_THREAD_TYPE workerThreadType;
86 char* destinationFileName;
87 THREAD_HANDLE threadHandle;
88 LOCK_HANDLE lockGarbage;
89 int canBeGarbageCollected; /*flag indicating that the structure can be freed because the thread deadling with it finished*/
90 IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle;
91 void* context;
92 UPLOADTOBLOB_SAVED_DATA uploadBlobSavedData;
93 INVOKE_METHOD_SAVED_DATA invokeMethodSavedData;
94 UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA uploadBlobMultiblockSavedData;
95}HTTPWORKER_THREAD_INFO;
96
97#define USER_CALLBACK_TYPE_VALUES \
98 CALLBACK_TYPE_DEVICE_TWIN, \
99 CALLBACK_TYPE_EVENT_CONFIRM, \
100 CALLBACK_TYPE_REPORTED_STATE, \
101 CALLBACK_TYPE_CONNECTION_STATUS, \
102 CALLBACK_TYPE_DEVICE_METHOD, \
103 CALLBACK_TYPE_INBOUD_DEVICE_METHOD, \
104 CALLBACK_TYPE_MESSAGE, \
105 CALLBACK_TYPE_INPUTMESSAGE
106
107MU_DEFINE_ENUM_WITHOUT_INVALID(USER_CALLBACK_TYPE, USER_CALLBACK_TYPE_VALUES)
108MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(USER_CALLBACK_TYPE, USER_CALLBACK_TYPE_VALUES)
109
110typedef struct DEVICE_TWIN_CALLBACK_INFO_TAG
111{
112 DEVICE_TWIN_UPDATE_STATE update_state;
113 unsigned char* payLoad;
114 size_t size;
115 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK userCallback;
116 void* userContext;
117} DEVICE_TWIN_CALLBACK_INFO;
118
119typedef struct EVENT_CONFIRM_CALLBACK_INFO_TAG
120{
121 IOTHUB_CLIENT_CONFIRMATION_RESULT confirm_result;
122 IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback;
123} EVENT_CONFIRM_CALLBACK_INFO;
124
125typedef struct REPORTED_STATE_CALLBACK_INFO_TAG
126{
127 int status_code;
128 IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback;
129} REPORTED_STATE_CALLBACK_INFO;
130
131typedef struct CONNECTION_STATUS_CALLBACK_INFO_TAG
132{
133 IOTHUB_CLIENT_CONNECTION_STATUS connection_status;
134 IOTHUB_CLIENT_CONNECTION_STATUS_REASON status_reason;
135} CONNECTION_STATUS_CALLBACK_INFO;
136
137typedef struct METHOD_CALLBACK_INFO_TAG
138{
139 STRING_HANDLE method_name;
140 BUFFER_HANDLE payload;
141 METHOD_HANDLE method_id;
142} METHOD_CALLBACK_INFO;
143
144typedef struct INPUTMESSAGE_CALLBACK_INFO_TAG
145{
146 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC eventHandlerCallback;
147 MESSAGE_CALLBACK_INFO* message_cb_info;
148} INPUTMESSAGE_CALLBACK_INFO;
149
150typedef struct USER_CALLBACK_INFO_TAG
151{
152 USER_CALLBACK_TYPE type;
153 void* userContextCallback;
154 union IOTHUB_CALLBACK
155 {
156 DEVICE_TWIN_CALLBACK_INFO dev_twin_cb_info;
157 EVENT_CONFIRM_CALLBACK_INFO event_confirm_cb_info;
158 REPORTED_STATE_CALLBACK_INFO reported_state_cb_info;
159 CONNECTION_STATUS_CALLBACK_INFO connection_status_cb_info;
160 METHOD_CALLBACK_INFO method_cb_info;
161 MESSAGE_CALLBACK_INFO* message_cb_info;
162 INPUTMESSAGE_CALLBACK_INFO inputmessage_cb_info;
163 } iothub_callback;
164} USER_CALLBACK_INFO;
165
166typedef struct IOTHUB_QUEUE_CONTEXT_TAG
167{
168 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientHandle;
169 void* userContextCallback;
170 union IOTHUB_CALLBACK_FUNCTION
171 {
172 IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback;
173 IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback;
174 } callbackFunction;
175} IOTHUB_QUEUE_CONTEXT;
176
177typedef struct IOTHUB_QUEUE_CONSOLIDATED_CONTEXT_TAG
178{
179 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientHandle;
180
181 union USER_CALLBACK_TAG
182 {
183 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK getTwin;
184 } userCallback;
185
186 void* userContext;
187} IOTHUB_QUEUE_CONSOLIDATED_CONTEXT;
188
189typedef struct IOTHUB_INPUTMESSAGE_CALLBACK_CONTEXT_TAG
190{
191 IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle;
192 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC eventHandlerCallback;
193 void* userContextCallback;
194} IOTHUB_INPUTMESSAGE_CALLBACK_CONTEXT;
195
196/*used by unittests only*/
197const size_t IoTHubClientCore_ThreadTerminationOffset = offsetof(IOTHUB_CLIENT_CORE_INSTANCE, StopThread);
198
199typedef enum CREATE_HUB_INSTANCE_TYPE_TAG
200{
201 CREATE_HUB_INSTANCE_FROM_CONNECTION_STRING,
202 CREATE_HUB_INSTANCE_FROM_EDGE_ENVIRONMENT,
203 CREATE_HUB_INSTANCE_FROM_TRANSPORT,
204 CREATE_HUB_INSTANCE_FROM_CLIENT_CONFIG,
205 CREATE_HUB_INSTANCE_FROM_DEVICE_AUTH
206} CREATE_HUB_INSTANCE_TYPE;
207
208static void freeHttpWorkerThreadInfo(HTTPWORKER_THREAD_INFO* threadInfo)
209{
210 Lock_Deinit(threadInfo->lockGarbage);
211 if (threadInfo->workerThreadType == HTTPWORKER_THREAD_UPLOAD_TO_BLOB)
212 {
213 free(threadInfo->uploadBlobSavedData.source);
214 free(threadInfo->destinationFileName);
215 }
216 else if (threadInfo->workerThreadType == HTTPWORKER_THREAD_INVOKE_METHOD)
217 {
218 free((char*)threadInfo->invokeMethodSavedData.deviceId);
219 free((char*)threadInfo->invokeMethodSavedData.moduleId);
220 free((char*)threadInfo->invokeMethodSavedData.methodName);
221 free((char*)threadInfo->invokeMethodSavedData.methodPayload);
222 }
223
224 free(threadInfo);
225}
226
227/*this function is called from _Destroy and from ScheduleWork_Thread to join finished blobUpload threads and free that memory*/
228static void garbageCollectorImpl(IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance)
229{
230 /*see if any savedData structures can be disposed of*/
231 /*Codes_SRS_IOTHUBCLIENT_02_072: [ All threads marked as disposable (upon completion of a file upload) shall be joined and the data structures build for them shall be freed. ]*/
232 LIST_ITEM_HANDLE item = singlylinkedlist_get_head_item(iotHubClientInstance->httpWorkerThreadInfoList);
233 while (item != NULL)
234 {
235 HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)singlylinkedlist_item_get_value(item);
236 LIST_ITEM_HANDLE old_item = item;
237 item = singlylinkedlist_get_next_item(item);
238
239 if (Lock(threadInfo->lockGarbage) != LOCK_OK)
240 {
241 LogError("unable to Lock");
242 }
243 else
244 {
245 if (threadInfo->canBeGarbageCollected == 1)
246 {
247 int notUsed;
248 if (ThreadAPI_Join(threadInfo->threadHandle, &notUsed) != THREADAPI_OK)
249 {
250 LogError("unable to ThreadAPI_Join");
251 }
252 (void)singlylinkedlist_remove(iotHubClientInstance->httpWorkerThreadInfoList, old_item);
253
254 if (Unlock(threadInfo->lockGarbage) != LOCK_OK)
255 {
256 LogError("unable to unlock after locking");
257 }
258 freeHttpWorkerThreadInfo(threadInfo);
259 }
260 else
261 {
262 if (Unlock(threadInfo->lockGarbage) != LOCK_OK)
263 {
264 LogError("unable to unlock after locking");
265 }
266 }
267 }
268 }
269}
270
271
272static bool iothub_ll_message_callback(MESSAGE_CALLBACK_INFO* messageData, void* userContextCallback)
273{
274 bool result;
275 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
276 if (queue_context == NULL)
277 {
278 LogError("invalid parameter userContextCallback(NULL)");
279 result = false;
280 }
281 else
282 {
283 USER_CALLBACK_INFO queue_cb_info;
284 queue_cb_info.type = CALLBACK_TYPE_MESSAGE;
285 queue_cb_info.userContextCallback = queue_context->userContextCallback;
286 queue_cb_info.iothub_callback.message_cb_info = messageData;
287 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) == 0)
288 {
289 result = true;
290 }
291 else
292 {
293 LogError("message callback vector push failed.");
294 result = false;
295 }
296 }
297 return result;
298}
299
300static bool iothub_ll_inputmessage_callback(MESSAGE_CALLBACK_INFO* message_cb_info, void* userContextCallback)
301{
302 bool result;
303 IOTHUB_INPUTMESSAGE_CALLBACK_CONTEXT *inputMessageCallbackContext = (IOTHUB_INPUTMESSAGE_CALLBACK_CONTEXT *)userContextCallback;
304 if (inputMessageCallbackContext == NULL)
305 {
306 LogError("invalid parameter userContextCallback(NULL)");
307 result = false;
308 }
309 else
310 {
311 USER_CALLBACK_INFO queue_cb_info;
312 queue_cb_info.type = CALLBACK_TYPE_INPUTMESSAGE;
313 queue_cb_info.userContextCallback = inputMessageCallbackContext->userContextCallback;
314 queue_cb_info.iothub_callback.inputmessage_cb_info.eventHandlerCallback = inputMessageCallbackContext->eventHandlerCallback;
315 queue_cb_info.iothub_callback.inputmessage_cb_info.message_cb_info = message_cb_info;
316
317 if (VECTOR_push_back(inputMessageCallbackContext->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) == 0)
318 {
319 result = true;
320 }
321 else
322 {
323 LogError("message callback vector push failed.");
324 result = false;
325 }
326 }
327
328 return result;
329}
330
331static int make_method_calback_queue_context(USER_CALLBACK_INFO* queue_cb_info, const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, IOTHUB_QUEUE_CONTEXT* queue_context)
332{
333 int result;
334 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [ IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall copy the method_name and payload. ] */
335 queue_cb_info->userContextCallback = queue_context->userContextCallback;
336 queue_cb_info->iothub_callback.method_cb_info.method_id = method_id;
337 if ((queue_cb_info->iothub_callback.method_cb_info.method_name = STRING_construct(method_name)) == NULL)
338 {
339 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
340 LogError("STRING_construct failed");
341 result = MU_FAILURE;
342 }
343 else
344 {
345 if ((queue_cb_info->iothub_callback.method_cb_info.payload = BUFFER_create(payload, size)) == NULL)
346 {
347 STRING_delete(queue_cb_info->iothub_callback.method_cb_info.method_name);
348 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
349 LogError("BUFFER_create failed");
350 result = MU_FAILURE;
351 }
352 else
353 {
354 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, queue_cb_info, 1) == 0)
355 {
356 result = 0;
357 }
358 else
359 {
360 STRING_delete(queue_cb_info->iothub_callback.method_cb_info.method_name);
361 BUFFER_delete(queue_cb_info->iothub_callback.method_cb_info.payload);
362 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
363 LogError("VECTOR_push_back failed");
364 result = MU_FAILURE;
365 }
366 }
367 }
368 return result;
369}
370
371static int iothub_ll_device_method_callback(const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, void* userContextCallback)
372{
373 int result;
374 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [ if userContextCallback is NULL, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a nonNULL value. ] */
375 if (userContextCallback == NULL)
376 {
377 LogError("invalid parameter userContextCallback(NULL)");
378 result = MU_FAILURE;
379 }
380 else
381 {
382 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
383
384 USER_CALLBACK_INFO queue_cb_info;
385 queue_cb_info.type = CALLBACK_TYPE_DEVICE_METHOD;
386
387 result = make_method_calback_queue_context(&queue_cb_info, method_name, payload, size, method_id, queue_context);
388 if (result != 0)
389 {
390 LogError("construction of method calback queue context failed");
391 result = MU_FAILURE;
392 }
393 }
394 return result;
395}
396
397static int iothub_ll_inbound_device_method_callback(const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, void* userContextCallback)
398{
399 int result;
400 /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [ if userContextCallback is NULL, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a nonNULL value. ] */
401 if (userContextCallback == NULL)
402 {
403 LogError("invalid parameter userContextCallback(NULL)");
404 result = MU_FAILURE;
405 }
406 else
407 {
408 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
409
410 USER_CALLBACK_INFO queue_cb_info;
411 queue_cb_info.type = CALLBACK_TYPE_INBOUD_DEVICE_METHOD;
412
413 result = make_method_calback_queue_context(&queue_cb_info, method_name, payload, size, method_id, queue_context);
414 if (result != 0)
415 {
416 LogError("construction of method calback queue context failed");
417 result = MU_FAILURE;
418 }
419 }
420 return result;
421}
422
423static void iothub_ll_connection_status_callback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* userContextCallback)
424{
425 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
426 if (queue_context != NULL)
427 {
428 USER_CALLBACK_INFO queue_cb_info;
429 queue_cb_info.type = CALLBACK_TYPE_CONNECTION_STATUS;
430 queue_cb_info.userContextCallback = queue_context->userContextCallback;
431 queue_cb_info.iothub_callback.connection_status_cb_info.status_reason = reason;
432 queue_cb_info.iothub_callback.connection_status_cb_info.connection_status = result;
433 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) != 0)
434 {
435 LogError("connection status callback vector push failed.");
436 }
437 }
438}
439
440static void iothub_ll_event_confirm_callback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
441{
442 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
443 if (queue_context != NULL)
444 {
445 USER_CALLBACK_INFO queue_cb_info;
446 queue_cb_info.type = CALLBACK_TYPE_EVENT_CONFIRM;
447 queue_cb_info.userContextCallback = queue_context->userContextCallback;
448 queue_cb_info.iothub_callback.event_confirm_cb_info.confirm_result = result;
449 queue_cb_info.iothub_callback.event_confirm_cb_info.eventConfirmationCallback = queue_context->callbackFunction.eventConfirmationCallback;
450 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) != 0)
451 {
452 LogError("event confirm callback vector push failed.");
453 }
454 free(queue_context);
455 }
456}
457
458static void iothub_ll_reported_state_callback(int status_code, void* userContextCallback)
459{
460 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
461 if (queue_context != NULL)
462 {
463 USER_CALLBACK_INFO queue_cb_info;
464 queue_cb_info.type = CALLBACK_TYPE_REPORTED_STATE;
465 queue_cb_info.userContextCallback = queue_context->userContextCallback;
466 queue_cb_info.iothub_callback.reported_state_cb_info.status_code = status_code;
467 queue_cb_info.iothub_callback.reported_state_cb_info.reportedStateCallback = queue_context->callbackFunction.reportedStateCallback;
468 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) != 0)
469 {
470 LogError("reported state callback vector push failed.");
471 }
472 free(queue_context);
473 }
474}
475
476static void iothub_ll_device_twin_callback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
477{
478 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
479 if (queue_context != NULL)
480 {
481 int push_to_vector;
482
483 USER_CALLBACK_INFO queue_cb_info;
484 queue_cb_info.type = CALLBACK_TYPE_DEVICE_TWIN;
485 queue_cb_info.userContextCallback = queue_context->userContextCallback;
486 queue_cb_info.iothub_callback.dev_twin_cb_info.update_state = update_state;
487 queue_cb_info.iothub_callback.dev_twin_cb_info.userCallback = NULL;
488 queue_cb_info.iothub_callback.dev_twin_cb_info.userContext = NULL;
489
490 if (payLoad == NULL)
491 {
492 queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad = NULL;
493 queue_cb_info.iothub_callback.dev_twin_cb_info.size = 0;
494 push_to_vector = 0;
495 }
496 else
497 {
498 queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad = (unsigned char*)malloc(size);
499 if (queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad == NULL)
500 {
501 LogError("failure allocating payload in device twin callback.");
502 queue_cb_info.iothub_callback.dev_twin_cb_info.size = 0;
503 push_to_vector = MU_FAILURE;
504 }
505 else
506 {
507 (void)memcpy(queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad, payLoad, size);
508 queue_cb_info.iothub_callback.dev_twin_cb_info.size = size;
509 push_to_vector = 0;
510 }
511 }
512 if (push_to_vector == 0)
513 {
514 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) != 0)
515 {
516 if (queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad != NULL)
517 {
518 free(queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad);
519 }
520 LogError("device twin callback userContextCallback vector push failed.");
521 }
522 }
523 }
524 else
525 {
526 LogError("device twin callback userContextCallback NULL");
527 }
528}
529
530static void iothub_ll_get_device_twin_async_callback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
531{
532 IOTHUB_QUEUE_CONSOLIDATED_CONTEXT* queue_context = (IOTHUB_QUEUE_CONSOLIDATED_CONTEXT*)userContextCallback;
533
534 if (queue_context != NULL)
535 {
536 USER_CALLBACK_INFO queue_cb_info;
537 queue_cb_info.type = CALLBACK_TYPE_DEVICE_TWIN;
538 queue_cb_info.userContextCallback = queue_context->userContext;
539 queue_cb_info.iothub_callback.dev_twin_cb_info.update_state = update_state;
540 queue_cb_info.iothub_callback.dev_twin_cb_info.userCallback = queue_context->userCallback.getTwin;
541 queue_cb_info.iothub_callback.dev_twin_cb_info.userContext = queue_context->userContext;
542
543 if (payLoad == NULL)
544 {
545 queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad = NULL;
546 queue_cb_info.iothub_callback.dev_twin_cb_info.size = 0;
547 }
548 else
549 {
550 queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad = (unsigned char*)malloc(size);
551
552 if (queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad == NULL)
553 {
554 LogError("Failure allocating payload in get device twin callback.");
555 queue_cb_info.iothub_callback.dev_twin_cb_info.size = 0;
556 }
557 else
558 {
559 (void)memcpy(queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad, payLoad, size);
560 queue_cb_info.iothub_callback.dev_twin_cb_info.size = size;
561 }
562 }
563
564 if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) != 0)
565 {
566 LogError("device twin callback userContextCallback vector push failed.");
567
568 if (queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad != NULL)
569 {
570 free(queue_cb_info.iothub_callback.dev_twin_cb_info.payLoad);
571 }
572 }
573
574 free(queue_context);
575 }
576 else
577 {
578 LogError("Get device twin callback userContextCallback NULL");
579 }
580}
581
582static void dispatch_user_callbacks(IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance, VECTOR_HANDLE call_backs)
583{
584 size_t callbacks_length = VECTOR_size(call_backs);
585 size_t index;
586
587 IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK desired_state_callback = NULL;
588 IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connection_status_callback = NULL;
589 IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC device_method_callback = NULL;
590 IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK inbound_device_method_callback = NULL;
591 IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC message_callback = NULL;
592 IOTHUB_CLIENT_CORE_HANDLE message_user_context_handle = NULL;
593 IOTHUB_CLIENT_CORE_HANDLE method_user_context_handle = NULL;
594
595 // Make a local copy of these callbacks, as we don't run with a lock held and iotHubClientInstance may change mid-run.
596 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
597 {
598 LogError("failed locking for dispatch_user_callbacks");
599 }
600 else
601 {
602 desired_state_callback = iotHubClientInstance->desired_state_callback;
603 connection_status_callback = iotHubClientInstance->connection_status_callback;
604 device_method_callback = iotHubClientInstance->device_method_callback;
605 inbound_device_method_callback = iotHubClientInstance->inbound_device_method_callback;
606 message_callback = iotHubClientInstance->message_callback;
607 if (iotHubClientInstance->method_user_context)
608 {
609 method_user_context_handle = iotHubClientInstance->method_user_context->iotHubClientHandle;
610 }
611 if (iotHubClientInstance->message_user_context)
612 {
613 message_user_context_handle = iotHubClientInstance->message_user_context->iotHubClientHandle;
614 }
615
616 (void)Unlock(iotHubClientInstance->LockHandle);
617 }
618
619
620 for (index = 0; index < callbacks_length; index++)
621 {
622 USER_CALLBACK_INFO* queued_cb = (USER_CALLBACK_INFO*)VECTOR_element(call_backs, index);
623 if (queued_cb == NULL)
624 {
625 LogError("VECTOR_element at index %zd is NULL.", index);
626 }
627 else
628 {
629 switch (queued_cb->type)
630 {
631 case CALLBACK_TYPE_DEVICE_TWIN:
632 {
633 // Callback if for GetTwinAsync
634 if (queued_cb->iothub_callback.dev_twin_cb_info.userCallback)
635 {
636 queued_cb->iothub_callback.dev_twin_cb_info.userCallback(
637 queued_cb->iothub_callback.dev_twin_cb_info.update_state,
638 queued_cb->iothub_callback.dev_twin_cb_info.payLoad,
639 queued_cb->iothub_callback.dev_twin_cb_info.size,
640 queued_cb->iothub_callback.dev_twin_cb_info.userContext
641 );
642 }
643 // Callback if for Desired properties.
644 else if (desired_state_callback)
645 {
646 desired_state_callback(queued_cb->iothub_callback.dev_twin_cb_info.update_state, queued_cb->iothub_callback.dev_twin_cb_info.payLoad, queued_cb->iothub_callback.dev_twin_cb_info.size, queued_cb->userContextCallback);
647 }
648
649 if (queued_cb->iothub_callback.dev_twin_cb_info.payLoad)
650 {
651 free(queued_cb->iothub_callback.dev_twin_cb_info.payLoad);
652 }
653 break;
654 }
655 case CALLBACK_TYPE_EVENT_CONFIRM:
656 if (queued_cb->iothub_callback.event_confirm_cb_info.eventConfirmationCallback)
657 {
658 queued_cb->iothub_callback.event_confirm_cb_info.eventConfirmationCallback(queued_cb->iothub_callback.event_confirm_cb_info.confirm_result, queued_cb->userContextCallback);
659 }
660 break;
661 case CALLBACK_TYPE_REPORTED_STATE:
662 if (queued_cb->iothub_callback.reported_state_cb_info.reportedStateCallback)
663 {
664 queued_cb->iothub_callback.reported_state_cb_info.reportedStateCallback(queued_cb->iothub_callback.reported_state_cb_info.status_code, queued_cb->userContextCallback);
665 }
666 break;
667 case CALLBACK_TYPE_CONNECTION_STATUS:
668 if (connection_status_callback)
669 {
670 connection_status_callback(queued_cb->iothub_callback.connection_status_cb_info.connection_status, queued_cb->iothub_callback.connection_status_cb_info.status_reason, queued_cb->userContextCallback);
671 }
672 break;
673 case CALLBACK_TYPE_DEVICE_METHOD:
674 if (device_method_callback)
675 {
676 const char* method_name = STRING_c_str(queued_cb->iothub_callback.method_cb_info.method_name);
677 const unsigned char* payload = BUFFER_u_char(queued_cb->iothub_callback.method_cb_info.payload);
678 size_t payload_len = BUFFER_length(queued_cb->iothub_callback.method_cb_info.payload);
679
680 unsigned char* payload_resp = NULL;
681 size_t response_size = 0;
682 int status = device_method_callback(method_name, payload, payload_len, &payload_resp, &response_size, queued_cb->userContextCallback);
683
684 if (payload_resp && (response_size > 0))
685 {
686 IOTHUB_CLIENT_RESULT result = IoTHubClientCore_DeviceMethodResponse(method_user_context_handle, queued_cb->iothub_callback.method_cb_info.method_id, (const unsigned char*)payload_resp, response_size, status);
687 if (result != IOTHUB_CLIENT_OK)
688 {
689 LogError("IoTHubClientCore_LL_DeviceMethodResponse failed");
690 }
691 }
692
693 BUFFER_delete(queued_cb->iothub_callback.method_cb_info.payload);
694 STRING_delete(queued_cb->iothub_callback.method_cb_info.method_name);
695
696 if (payload_resp)
697 {
698 free(payload_resp);
699 }
700 }
701 break;
702 case CALLBACK_TYPE_INBOUD_DEVICE_METHOD:
703 if (inbound_device_method_callback)
704 {
705 const char* method_name = STRING_c_str(queued_cb->iothub_callback.method_cb_info.method_name);
706 const unsigned char* payload = BUFFER_u_char(queued_cb->iothub_callback.method_cb_info.payload);
707 size_t payload_len = BUFFER_length(queued_cb->iothub_callback.method_cb_info.payload);
708
709 inbound_device_method_callback(method_name, payload, payload_len, queued_cb->iothub_callback.method_cb_info.method_id, queued_cb->userContextCallback);
710
711 BUFFER_delete(queued_cb->iothub_callback.method_cb_info.payload);
712 STRING_delete(queued_cb->iothub_callback.method_cb_info.method_name);
713 }
714 break;
715 case CALLBACK_TYPE_MESSAGE:
716 if (message_callback && message_user_context_handle)
717 {
718 IOTHUBMESSAGE_DISPOSITION_RESULT disposition = message_callback(queued_cb->iothub_callback.message_cb_info->messageHandle, queued_cb->userContextCallback);
719
720 if (Lock(message_user_context_handle->LockHandle) == LOCK_OK)
721 {
722 IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SendMessageDisposition(message_user_context_handle->IoTHubClientLLHandle, queued_cb->iothub_callback.message_cb_info, disposition);
723 (void)Unlock(message_user_context_handle->LockHandle);
724 if (result != IOTHUB_CLIENT_OK)
725 {
726 LogError("IoTHubClientCore_LL_SendMessageDisposition failed");
727 }
728 }
729 else
730 {
731 LogError("Lock failed");
732 }
733 }
734 break;
735
736 case CALLBACK_TYPE_INPUTMESSAGE:
737 {
738 const INPUTMESSAGE_CALLBACK_INFO *inputmessage_cb_info = &queued_cb->iothub_callback.inputmessage_cb_info;
739 IOTHUBMESSAGE_DISPOSITION_RESULT disposition = inputmessage_cb_info->eventHandlerCallback(inputmessage_cb_info->message_cb_info->messageHandle, queued_cb->userContextCallback);
740
741 if (Lock(iotHubClientInstance->LockHandle) == LOCK_OK)
742 {
743 IOTHUB_CLIENT_RESULT result = IoTHubClientCore_LL_SendMessageDisposition(iotHubClientInstance->IoTHubClientLLHandle, inputmessage_cb_info->message_cb_info, disposition);
744 (void)Unlock(iotHubClientInstance->LockHandle);
745 if (result != IOTHUB_CLIENT_OK)
746 {
747 LogError("IoTHubClient_LL_SendMessageDisposition failed");
748 }
749 }
750 else
751 {
752 LogError("Lock failed");
753 }
754 }
755 break;
756
757 default:
758 LogError("Invalid callback type '%s'", MU_ENUM_TO_STRING(USER_CALLBACK_TYPE, queued_cb->type));
759 break;
760 }
761 }
762 }
763 VECTOR_destroy(call_backs);
764}
765
766static void ScheduleWork_Thread_ForMultiplexing(void* iotHubClientHandle)
767{
768 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
769
770 garbageCollectorImpl(iotHubClientInstance);
771 if (Lock(iotHubClientInstance->LockHandle) == LOCK_OK)
772 {
773 VECTOR_HANDLE call_backs = VECTOR_move(iotHubClientInstance->saved_user_callback_list);
774 (void)Unlock(iotHubClientInstance->LockHandle);
775
776 if (call_backs == NULL)
777 {
778 LogError("Failed moving user callbacks");
779 }
780 else
781 {
782 dispatch_user_callbacks(iotHubClientInstance, call_backs);
783 }
784 }
785 else
786 {
787 LogError("failed locking for ScheduleWork_Thread_ForMultiplexing");
788 }
789}
790
791static int ScheduleWork_Thread(void* threadArgument)
792{
793 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)threadArgument;
794 unsigned int sleeptime_in_ms = DO_WORK_FREQ_DEFAULT;
795
796 srand((unsigned int)get_time(NULL));
797
798 while (1)
799 {
800 if (Lock(iotHubClientInstance->LockHandle) == LOCK_OK)
801 {
802 /*Codes_SRS_IOTHUBCLIENT_01_038: [ The thread shall exit when IoTHubClient_Destroy is called. ]*/
803 if (iotHubClientInstance->StopThread)
804 {
805 (void)Unlock(iotHubClientInstance->LockHandle);
806 break; /*gets out of the thread*/
807 }
808 else
809 {
810 /* Codes_SRS_IOTHUBCLIENT_01_037: [The thread created by IoTHubClient_SendEvent or IoTHubClient_SetMessageCallback shall call IoTHubClientCore_LL_DoWork every 1 ms by default.] */
811 /* Codes_SRS_IOTHUBCLIENT_01_039: [All calls to IoTHubClientCore_LL_DoWork shall be protected by the lock created in IotHubClient_Create.] */
812 IoTHubClientCore_LL_DoWork(iotHubClientInstance->IoTHubClientLLHandle);
813
814 garbageCollectorImpl(iotHubClientInstance);
815 VECTOR_HANDLE call_backs = VECTOR_move(iotHubClientInstance->saved_user_callback_list);
816 sleeptime_in_ms = (unsigned int)iotHubClientInstance->do_work_freq_ms; // Update the sleepval within the locked thread.
817 (void)Unlock(iotHubClientInstance->LockHandle);
818 if (call_backs == NULL)
819 {
820 LogError("VECTOR_move failed");
821 }
822 else
823 {
824 dispatch_user_callbacks(iotHubClientInstance, call_backs);
825 }
826
827
828 }
829 }
830 else
831 {
832 /*Codes_SRS_IOTHUBCLIENT_01_040: [If acquiring the lock fails, IoTHubClientCore_LL_DoWork shall not be called.]*/
833 /*no code, shall retry*/
834 }
835 /* Codes_SRS_IOTHUBCLIENT_041_02: [The thread shall sleep for a specified time in ms as provided through IoTHubClientCore_SetOption, with a default of 1 ms ] */
836 (void)ThreadAPI_Sleep(sleeptime_in_ms);
837 }
838
839 ThreadAPI_Exit(0);
840 return 0;
841}
842
843static IOTHUB_CLIENT_RESULT StartWorkerThreadIfNeeded(IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance)
844{
845 IOTHUB_CLIENT_RESULT result;
846 if (iotHubClientInstance->TransportHandle == NULL)
847 {
848 if (iotHubClientInstance->ThreadHandle == NULL)
849 {
850 iotHubClientInstance->StopThread = 0;
851 if (ThreadAPI_Create(&iotHubClientInstance->ThreadHandle, ScheduleWork_Thread, iotHubClientInstance) != THREADAPI_OK)
852 {
853 LogError("ThreadAPI_Create failed");
854 iotHubClientInstance->ThreadHandle = NULL;
855 result = IOTHUB_CLIENT_ERROR;
856 }
857 else
858 {
859 result = IOTHUB_CLIENT_OK;
860 }
861 }
862 else
863 {
864 result = IOTHUB_CLIENT_OK;
865 }
866 }
867 else
868 {
869 /*Codes_SRS_IOTHUBCLIENT_17_012: [ If the transport connection is shared, the thread shall be started by calling IoTHubTransport_StartWorkerThread. ]*/
870 /*Codes_SRS_IOTHUBCLIENT_17_011: [ If the transport connection is shared, the thread shall be started by calling IoTHubTransport_StartWorkerThread*/
871 result = IoTHubTransport_StartWorkerThread(iotHubClientInstance->TransportHandle, iotHubClientInstance, ScheduleWork_Thread_ForMultiplexing);
872 }
873 return result;
874}
875
876static IOTHUB_CLIENT_CORE_INSTANCE* create_iothub_instance(CREATE_HUB_INSTANCE_TYPE create_hub_instance_type, const IOTHUB_CLIENT_CONFIG* config, TRANSPORT_HANDLE transportHandle, const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, const char* iothub_uri, const char* device_id)
877{
878 /* Codes_SRS_IOTHUBCLIENT_12_020: [** `IoTHubClient_CreateFromDeviceAuth` shall allocate a new `IoTHubClient` instance. **] */
879 IOTHUB_CLIENT_CORE_INSTANCE* result = (IOTHUB_CLIENT_CORE_INSTANCE*)malloc(sizeof(IOTHUB_CLIENT_CORE_INSTANCE));
880 (void)create_hub_instance_type;
881
882 /* Codes_SRS_IOTHUBCLIENT_12_021: [** If allocating memory for the new `IoTHubClient` instance fails, then `IoTHubClient_CreateFromDeviceAuth` shall return `NULL`. **] */
883 /* Codes_SRS_IOTHUBCLIENT_01_004: [If allocating memory for the new IoTHubClient instance fails, then IoTHubClient_Create shall return NULL.] */
884 if (result != NULL)
885 {
886 memset((void *)result, 0, sizeof(IOTHUB_CLIENT_CORE_INSTANCE));
887
888 /* Codes_SRS_IOTHUBCLIENT_41_02 [] */
889 result->do_work_freq_ms = DO_WORK_FREQ_DEFAULT;
890 /* Default currentMessageTimeout to NULL until it is set by SetOption */
891 result->currentMessageTimeout = 0;
892
893 /* Codes_SRS_IOTHUBCLIENT_01_029: [IoTHubClient_Create shall create a lock object to be used later for serializing IoTHubClient calls.] */
894 if ((result->saved_user_callback_list = VECTOR_create(sizeof(USER_CALLBACK_INFO))) == NULL)
895 {
896 LogError("Failed creating VECTOR");
897 free(result);
898 result = NULL;
899 }
900 else
901 {
902 /*Codes_SRS_IOTHUBCLIENT_02_060: [ IoTHubClient_Create shall create a SINGLYLINKEDLIST_HANDLE containing THREAD_HANDLE (created by future calls to IoTHubClient_UploadToBlobAsync). ]*/
903 if ((result->httpWorkerThreadInfoList = singlylinkedlist_create()) == NULL)
904 {
905 /*Codes_SRS_IOTHUBCLIENT_02_061: [ If creating the SINGLYLINKEDLIST_HANDLE fails then IoTHubClient_Create shall fail and return NULL. ]*/
906 LogError("unable to singlylinkedlist_create");
907 VECTOR_destroy(result->saved_user_callback_list);
908 free(result);
909 result = NULL;
910 }
911 else
912 {
913 result->TransportHandle = transportHandle;
914 result->created_with_transport_handle = 0;
915 if (config != NULL)
916 {
917 if (transportHandle != NULL)
918 {
919 /*Codes_SRS_IOTHUBCLIENT_17_005: [ IoTHubClient_CreateWithTransport shall call IoTHubTransport_GetLock to get the transport lock to be used later for serializing IoTHubClient calls. ]*/
920 result->LockHandle = IoTHubTransport_GetLock(transportHandle);
921 if (result->LockHandle == NULL)
922 {
923 LogError("unable to IoTHubTransport_GetLock");
924 result->IoTHubClientLLHandle = NULL;
925 }
926 else
927 {
928 IOTHUB_CLIENT_DEVICE_CONFIG deviceConfig;
929 deviceConfig.deviceId = config->deviceId;
930 deviceConfig.deviceKey = config->deviceKey;
931 deviceConfig.protocol = config->protocol;
932 deviceConfig.deviceSasToken = config->deviceSasToken;
933
934 /*Codes_SRS_IOTHUBCLIENT_17_003: [ IoTHubClient_CreateWithTransport shall call IoTHubTransport_GetLLTransport on transportHandle to get lower layer transport. ]*/
935 deviceConfig.transportHandle = IoTHubTransport_GetLLTransport(transportHandle);
936 if (deviceConfig.transportHandle == NULL)
937 {
938 LogError("unable to IoTHubTransport_GetLLTransport");
939 result->IoTHubClientLLHandle = NULL;
940 }
941 else
942 {
943 if (Lock(result->LockHandle) != LOCK_OK)
944 {
945 LogError("unable to Lock");
946 result->IoTHubClientLLHandle = NULL;
947 }
948 else
949 {
950 /*Codes_SRS_IOTHUBCLIENT_17_007: [ IoTHubClient_CreateWithTransport shall instantiate a new IoTHubClientCore_LL instance by calling IoTHubClientCore_LL_CreateWithTransport and passing the lower layer transport and config argument. ]*/
951 result->IoTHubClientLLHandle = IoTHubClientCore_LL_CreateWithTransport(&deviceConfig);
952 result->created_with_transport_handle = 1;
953 if (Unlock(result->LockHandle) != LOCK_OK)
954 {
955 LogError("unable to Unlock");
956 result->IoTHubClientLLHandle = NULL;
957 }
958 }
959 }
960 }
961 }
962 else
963 {
964 result->LockHandle = Lock_Init();
965 if (result->LockHandle == NULL)
966 {
967 /* Codes_SRS_IOTHUBCLIENT_01_030: [If creating the lock fails, then IoTHubClient_Create shall return NULL.] */
968 /* Codes_SRS_IOTHUBCLIENT_01_031: [If IoTHubClient_Create fails, all resources allocated by it shall be freed.] */
969 LogError("Failure creating Lock object");
970 result->IoTHubClientLLHandle = NULL;
971 }
972 else
973 {
974 /* Codes_SRS_IOTHUBCLIENT_01_002: [IoTHubClient_Create shall instantiate a new IoTHubClientCore_LL instance by calling IoTHubClientCore_LL_Create and passing the config argument.] */
975 result->IoTHubClientLLHandle = IoTHubClientCore_LL_Create(config);
976 }
977 }
978 }
979 else if (iothub_uri != NULL)
980 {
981#ifdef USE_PROV_MODULE
982 /* Codes_SRS_IOTHUBCLIENT_12_022: [** `IoTHubClient_CreateFromDeviceAuth` shall create a lock object to be used later for serializing IoTHubClient calls. **] */
983 result->LockHandle = Lock_Init();
984 if (result->LockHandle == NULL)
985 {
986 /* Codes_SRS_IOTHUBCLIENT_12_023: [** If creating the lock fails, then IoTHubClient_CreateFromDeviceAuth shall return NULL. **] */
987 LogError("Failure creating Lock object");
988 result->IoTHubClientLLHandle = NULL;
989 }
990 else
991 {
992 /* Codes_SRS_IOTHUBCLIENT_12_025: [** `IoTHubClient_CreateFromDeviceAuth` shall instantiate a new `IoTHubClientCore_LL` instance by calling `IoTHubClientCore_LL_CreateFromDeviceAuth` and passing iothub_uri, device_id and protocol argument. **] */
993 result->IoTHubClientLLHandle = IoTHubClientCore_LL_CreateFromDeviceAuth(iothub_uri, device_id, protocol);
994 }
995#else
996 (void)device_id;
997 LogError("Provisioning is not enabled for the build");
998 result->IoTHubClientLLHandle = NULL;
999#endif
1000 }
1001#ifdef USE_EDGE_MODULES
1002 else if (create_hub_instance_type == CREATE_HUB_INSTANCE_FROM_EDGE_ENVIRONMENT)
1003 {
1004 result->LockHandle = Lock_Init();
1005 if (result->LockHandle == NULL)
1006 {
1007 /* Codes_SRS_IOTHUBCLIENT_01_030: [If creating the lock fails, then IoTHubClient_Create shall return NULL.] */
1008 /* Codes_SRS_IOTHUBCLIENT_01_031: [If IoTHubClient_Create fails, all resources allocated by it shall be freed.] */
1009 LogError("Failure creating Lock object");
1010 result->IoTHubClientLLHandle = NULL;
1011 }
1012 else
1013 {
1014 result->IoTHubClientLLHandle = IoTHubClientCore_LL_CreateFromEnvironment(protocol);
1015 }
1016 }
1017#endif
1018 else
1019 {
1020 result->LockHandle = Lock_Init();
1021 if (result->LockHandle == NULL)
1022 {
1023 /* Codes_SRS_IOTHUBCLIENT_01_030: [If creating the lock fails, then IoTHubClient_Create shall return NULL.] */
1024 /* Codes_SRS_IOTHUBCLIENT_01_031: [If IoTHubClient_Create fails, all resources allocated by it shall be freed.] */
1025 LogError("Failure creating Lock object");
1026 result->IoTHubClientLLHandle = NULL;
1027 }
1028 else
1029 {
1030 result->IoTHubClientLLHandle = IoTHubClientCore_LL_CreateFromConnectionString(connectionString, protocol);
1031 }
1032 }
1033
1034 if (result->IoTHubClientLLHandle == NULL)
1035 {
1036 /* Codes_SRS_IOTHUBCLIENT_01_003: [If IoTHubClientCore_LL_Create fails, then IoTHubClient_Create shall return NULL.] */
1037 /* Codes_SRS_IOTHUBCLIENT_01_031: [If IoTHubClient_Create fails, all resources allocated by it shall be freed.] */
1038 /* Codes_SRS_IOTHUBCLIENT_17_006: [ If IoTHubTransport_GetLock fails, then IoTHubClient_CreateWithTransport shall return NULL. ]*/
1039 if ((transportHandle == NULL) && (result->LockHandle != NULL))
1040 {
1041 Lock_Deinit(result->LockHandle);
1042 }
1043 singlylinkedlist_destroy(result->httpWorkerThreadInfoList);
1044 LogError("Failure creating iothub handle");
1045 VECTOR_destroy(result->saved_user_callback_list);
1046 free(result);
1047 result = NULL;
1048 }
1049 else
1050 {
1051 result->ThreadHandle = NULL;
1052 result->desired_state_callback = NULL;
1053 result->devicetwin_user_context = NULL;
1054 result->connection_status_callback = NULL;
1055 result->connection_status_user_context = NULL;
1056 result->message_callback = NULL;
1057 result->message_user_context = NULL;
1058 result->method_user_context = NULL;
1059 }
1060 }
1061 }
1062 }
1063 return result;
1064}
1065
1066IOTHUB_CLIENT_CORE_HANDLE IoTHubClientCore_CreateFromConnectionString(const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
1067{
1068 IOTHUB_CLIENT_CORE_INSTANCE* result;
1069
1070 if (connectionString == NULL)
1071 {
1072 LogError("Input parameter is NULL: connectionString");
1073 result = NULL;
1074 }
1075 else if (protocol == NULL)
1076 {
1077 LogError("Input parameter is NULL: protocol");
1078 result = NULL;
1079 }
1080 else
1081 {
1082 result = create_iothub_instance(CREATE_HUB_INSTANCE_FROM_CONNECTION_STRING, NULL, NULL, connectionString, protocol, NULL, NULL);
1083 }
1084 return result;
1085}
1086
1087IOTHUB_CLIENT_CORE_HANDLE IoTHubClientCore_Create(const IOTHUB_CLIENT_CONFIG* config)
1088{
1089 IOTHUB_CLIENT_CORE_INSTANCE* result;
1090 if (config == NULL)
1091 {
1092 LogError("Input parameter is NULL: IOTHUB_CLIENT_CONFIG");
1093 result = NULL;
1094 }
1095 else
1096 {
1097 result = create_iothub_instance(CREATE_HUB_INSTANCE_FROM_CLIENT_CONFIG, config, NULL, NULL, NULL, NULL, NULL);
1098 }
1099 return result;
1100}
1101
1102IOTHUB_CLIENT_CORE_HANDLE IoTHubClientCore_CreateWithTransport(TRANSPORT_HANDLE transportHandle, const IOTHUB_CLIENT_CONFIG* config)
1103{
1104 IOTHUB_CLIENT_CORE_INSTANCE* result;
1105 /*Codes_SRS_IOTHUBCLIENT_17_013: [ IoTHubClient_CreateWithTransport shall return NULL if transportHandle is NULL. ]*/
1106 /*Codes_SRS_IOTHUBCLIENT_17_014: [ IoTHubClient_CreateWithTransport shall return NULL if config is NULL. ]*/
1107 if (transportHandle == NULL || config == NULL)
1108 {
1109 LogError("invalid parameter TRANSPORT_HANDLE transportHandle=%p, const IOTHUB_CLIENT_CONFIG* config=%p", transportHandle, config);
1110 result = NULL;
1111 }
1112 else
1113 {
1114 result = create_iothub_instance(CREATE_HUB_INSTANCE_FROM_TRANSPORT, config, transportHandle, NULL, NULL, NULL, NULL);
1115 }
1116 return result;
1117}
1118
1119IOTHUB_CLIENT_CORE_HANDLE IoTHubClientCore_CreateFromDeviceAuth(const char* iothub_uri, const char* device_id, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
1120{
1121 IOTHUB_CLIENT_CORE_INSTANCE* result;
1122
1123 /* Codes_SRS_IOTHUBCLIENT_12_019: [** `IoTHubClient_CreateFromDeviceAuth` shall verify the input parameters and if any of them `NULL` then return `NULL`. **] */
1124 if (iothub_uri == NULL)
1125 {
1126 LogError("Input parameter is NULL: iothub_uri");
1127 result = NULL;
1128 }
1129 else if (device_id == NULL)
1130 {
1131 LogError("Input parameter is NULL: device_id");
1132 result = NULL;
1133 }
1134 else if (protocol == NULL)
1135 {
1136 LogError("Input parameter is NULL: protocol");
1137 result = NULL;
1138 }
1139 else
1140 {
1141 /* Codes_SRS_IOTHUBCLIENT_12_020: [** `IoTHubClient_CreateFromDeviceAuth` shall allocate a new `IoTHubClient` instance. **] */
1142 /* Codes_SRS_IOTHUBCLIENT_12_021: [** If allocating memory for the new `IoTHubClient` instance fails, then `IoTHubClient_CreateFromDeviceAuth` shall return `NULL`. **] */
1143 /* Codes_SRS_IOTHUBCLIENT_12_022: [** `IoTHubClient_CreateFromDeviceAuth` shall create a lock object to be used later for serializing IoTHubClient calls. **] */
1144 /* Codes_SRS_IOTHUBCLIENT_12_023: [** If creating the lock fails, then IoTHubClient_CreateFromDeviceAuth shall return NULL. **] */
1145 /* Codes_SRS_IOTHUBCLIENT_12_024: [** If IoTHubClient_CreateFromDeviceAuth fails, all resources allocated by it shall be freed. **] */
1146 /* Codes_SRS_IOTHUBCLIENT_12_025: [** `IoTHubClient_CreateFromDeviceAuth` shall instantiate a new `IoTHubClientCore_LL` instance by calling `IoTHubClientCore_LL_CreateFromDeviceAuth` and passing iothub_uri, device_id and protocol argument. **] */
1147 result = create_iothub_instance(CREATE_HUB_INSTANCE_FROM_DEVICE_AUTH, NULL, NULL, NULL, protocol, iothub_uri, device_id);
1148 }
1149 return result;
1150}
1151
1152#ifdef USE_EDGE_MODULES
1153IOTHUB_CLIENT_CORE_HANDLE IoTHubClientCore_CreateFromEnvironment(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol)
1154{
1155 return create_iothub_instance(CREATE_HUB_INSTANCE_FROM_EDGE_ENVIRONMENT, NULL, NULL, NULL, protocol, NULL, NULL);
1156}
1157#endif
1158
1159
1160/* Codes_SRS_IOTHUBCLIENT_01_005: [IoTHubClient_Destroy shall free all resources associated with the iotHubClientHandle instance.] */
1161void IoTHubClientCore_Destroy(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle)
1162{
1163 /* Codes_SRS_IOTHUBCLIENT_01_008: [IoTHubClient_Destroy shall do nothing if parameter iotHubClientHandle is NULL.] */
1164 if (iotHubClientHandle != NULL)
1165 {
1166 bool joinClientThread;
1167 bool joinTransportThread;
1168 size_t vector_size;
1169
1170 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1171
1172 if (iotHubClientInstance->TransportHandle != NULL)
1173 {
1174 /*Codes_SRS_IOTHUBCLIENT_01_007: [ The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetNotificationMessageCallback shall be joined. ]*/
1175 joinTransportThread = IoTHubTransport_SignalEndWorkerThread(iotHubClientInstance->TransportHandle, iotHubClientHandle);
1176 }
1177 else
1178 {
1179 joinTransportThread = false;
1180 }
1181
1182 /*Codes_SRS_IOTHUBCLIENT_02_043: [ IoTHubClient_Destroy shall lock the serializing lock and signal the worker thread (if any) to end ]*/
1183 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1184 {
1185 LogError("unable to Lock - - will still proceed to try to end the thread without locking");
1186 }
1187
1188 if (iotHubClientInstance->ThreadHandle != NULL)
1189 {
1190 iotHubClientInstance->StopThread = 1;
1191 joinClientThread = true;
1192 }
1193 else
1194 {
1195 joinClientThread = false;
1196 }
1197
1198 /*Codes_SRS_IOTHUBCLIENT_02_045: [ IoTHubClient_Destroy shall unlock the serializing lock. ]*/
1199 if (Unlock(iotHubClientInstance->LockHandle) != LOCK_OK)
1200 {
1201 LogError("unable to Unlock");
1202 }
1203
1204 if (joinClientThread == true)
1205 {
1206 int res;
1207 /*Codes_SRS_IOTHUBCLIENT_01_007: [ The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetNotificationMessageCallback shall be joined. ]*/
1208 if (ThreadAPI_Join(iotHubClientInstance->ThreadHandle, &res) != THREADAPI_OK)
1209 {
1210 LogError("ThreadAPI_Join failed");
1211 }
1212 }
1213
1214 if (joinTransportThread == true)
1215 {
1216 /*Codes_SRS_IOTHUBCLIENT_01_007: [ The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetNotificationMessageCallback shall be joined. ]*/
1217 IoTHubTransport_JoinWorkerThread(iotHubClientInstance->TransportHandle, iotHubClientHandle);
1218 }
1219
1220 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1221 {
1222 LogError("unable to Lock - - will still proceed to try to end the thread without locking");
1223 }
1224
1225 /*Codes_SRS_IOTHUBCLIENT_02_069: [ IoTHubClient_Destroy shall free all data created by IoTHubClient_UploadToBlobAsync ]*/
1226 /*wait for all uploading threads to finish*/
1227 while (singlylinkedlist_get_head_item(iotHubClientInstance->httpWorkerThreadInfoList) != NULL)
1228 {
1229 garbageCollectorImpl(iotHubClientInstance);
1230 }
1231
1232 if (iotHubClientInstance->httpWorkerThreadInfoList != NULL)
1233 {
1234 singlylinkedlist_destroy(iotHubClientInstance->httpWorkerThreadInfoList);
1235 }
1236
1237 /* Codes_SRS_IOTHUBCLIENT_01_006: [That includes destroying the IoTHubClientCore_LL instance by calling IoTHubClientCore_LL_Destroy.] */
1238 IoTHubClientCore_LL_Destroy(iotHubClientInstance->IoTHubClientLLHandle);
1239
1240 if (Unlock(iotHubClientInstance->LockHandle) != LOCK_OK)
1241 {
1242 LogError("unable to Unlock");
1243 }
1244
1245
1246 vector_size = VECTOR_size(iotHubClientInstance->saved_user_callback_list);
1247 size_t index = 0;
1248 for (index = 0; index < vector_size; index++)
1249 {
1250 USER_CALLBACK_INFO* queue_cb_info = (USER_CALLBACK_INFO*)VECTOR_element(iotHubClientInstance->saved_user_callback_list, index);
1251 if (queue_cb_info != NULL)
1252 {
1253 if ((queue_cb_info->type == CALLBACK_TYPE_DEVICE_METHOD) || (queue_cb_info->type == CALLBACK_TYPE_INBOUD_DEVICE_METHOD))
1254 {
1255 STRING_delete(queue_cb_info->iothub_callback.method_cb_info.method_name);
1256 BUFFER_delete(queue_cb_info->iothub_callback.method_cb_info.payload);
1257 }
1258 else if (queue_cb_info->type == CALLBACK_TYPE_DEVICE_TWIN)
1259 {
1260 if (queue_cb_info->iothub_callback.dev_twin_cb_info.payLoad != NULL)
1261 {
1262 free(queue_cb_info->iothub_callback.dev_twin_cb_info.payLoad);
1263 }
1264 }
1265 else if (queue_cb_info->type == CALLBACK_TYPE_EVENT_CONFIRM)
1266 {
1267 if (queue_cb_info->iothub_callback.event_confirm_cb_info.eventConfirmationCallback)
1268 {
1269 queue_cb_info->iothub_callback.event_confirm_cb_info.eventConfirmationCallback(queue_cb_info->iothub_callback.event_confirm_cb_info.confirm_result, queue_cb_info->userContextCallback);
1270 }
1271 }
1272 else if (queue_cb_info->type == CALLBACK_TYPE_REPORTED_STATE)
1273 {
1274 if (queue_cb_info->iothub_callback.reported_state_cb_info.reportedStateCallback)
1275 {
1276 queue_cb_info->iothub_callback.reported_state_cb_info.reportedStateCallback(queue_cb_info->iothub_callback.reported_state_cb_info.status_code, queue_cb_info->userContextCallback);
1277 }
1278 }
1279 }
1280 }
1281 VECTOR_destroy(iotHubClientInstance->saved_user_callback_list);
1282
1283 if (iotHubClientInstance->TransportHandle == NULL)
1284 {
1285 /* Codes_SRS_IOTHUBCLIENT_01_032: [If the lock was allocated in IoTHubClient_Create, it shall be also freed..] */
1286 Lock_Deinit(iotHubClientInstance->LockHandle);
1287 }
1288 if (iotHubClientInstance->devicetwin_user_context != NULL)
1289 {
1290 free(iotHubClientInstance->devicetwin_user_context);
1291 }
1292 if (iotHubClientInstance->connection_status_user_context != NULL)
1293 {
1294 free(iotHubClientInstance->connection_status_user_context);
1295 }
1296 if (iotHubClientInstance->message_user_context != NULL)
1297 {
1298 free(iotHubClientInstance->message_user_context);
1299 }
1300 if (iotHubClientInstance->method_user_context != NULL)
1301 {
1302 free(iotHubClientInstance->method_user_context);
1303 }
1304 free(iotHubClientInstance);
1305 }
1306}
1307
1308IOTHUB_CLIENT_RESULT IoTHubClientCore_SendEventAsync(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback)
1309{
1310 IOTHUB_CLIENT_RESULT result;
1311
1312 if (iotHubClientHandle == NULL)
1313 {
1314 /* Codes_SRS_IOTHUBCLIENT_01_011: [If iotHubClientHandle is NULL, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_INVALID_ARG.] */
1315 result = IOTHUB_CLIENT_INVALID_ARG;
1316 LogError("NULL iothubClientHandle");
1317 }
1318 else
1319 {
1320 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1321
1322 /* Codes_SRS_IOTHUBCLIENT_01_009: [IoTHubClient_SendEventAsync shall start the worker thread if it was not previously started.] */
1323 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1324 {
1325 /* Codes_SRS_IOTHUBCLIENT_01_010: [If starting the thread fails, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_ERROR.] */
1326 result = IOTHUB_CLIENT_ERROR;
1327 LogError("Could not start worker thread");
1328 }
1329 else
1330 {
1331 /* Codes_SRS_IOTHUBCLIENT_01_025: [IoTHubClient_SendEventAsync shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1332 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1333 {
1334 /* Codes_SRS_IOTHUBCLIENT_01_026: [If acquiring the lock fails, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_ERROR.] */
1335 result = IOTHUB_CLIENT_ERROR;
1336 LogError("Could not acquire lock");
1337 }
1338 else
1339 {
1340 if (iotHubClientInstance->created_with_transport_handle != 0 || eventConfirmationCallback == NULL)
1341 {
1342 result = IoTHubClientCore_LL_SendEventAsync(iotHubClientInstance->IoTHubClientLLHandle, eventMessageHandle, eventConfirmationCallback, userContextCallback);
1343 }
1344 else
1345 {
1346 /* Codes_SRS_IOTHUBCLIENT_07_001: [ IoTHubClient_SendEventAsync shall allocate a IOTHUB_QUEUE_CONTEXT object to be sent to the IoTHubClientCore_LL_SendEventAsync function as a user context. ] */
1347 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
1348 if (queue_context == NULL)
1349 {
1350 result = IOTHUB_CLIENT_ERROR;
1351 LogError("Failed allocating QUEUE_CONTEXT");
1352 }
1353 else
1354 {
1355 queue_context->iotHubClientHandle = iotHubClientInstance;
1356 queue_context->userContextCallback = userContextCallback;
1357 queue_context->callbackFunction.eventConfirmationCallback = eventConfirmationCallback;
1358 /* Codes_SRS_IOTHUBCLIENT_01_012: [IoTHubClient_SendEventAsync shall call IoTHubClientCore_LL_SendEventAsync, while passing the IoTHubClientCore_LL handle created by IoTHubClient_Create and the parameters eventMessageHandle, eventConfirmationCallback and userContextCallback.] */
1359 /* Codes_SRS_IOTHUBCLIENT_01_013: [When IoTHubClientCore_LL_SendEventAsync is called, IoTHubClient_SendEventAsync shall return the result of IoTHubClientCore_LL_SendEventAsync.] */
1360 result = IoTHubClientCore_LL_SendEventAsync(iotHubClientInstance->IoTHubClientLLHandle, eventMessageHandle, iothub_ll_event_confirm_callback, queue_context);
1361 if (result != IOTHUB_CLIENT_OK)
1362 {
1363 LogError("IoTHubClientCore_LL_SendEventAsync failed");
1364 free(queue_context);
1365 }
1366 }
1367 }
1368
1369 /* Codes_SRS_IOTHUBCLIENT_01_025: [IoTHubClient_SendEventAsync shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1370 (void)Unlock(iotHubClientInstance->LockHandle);
1371 }
1372 }
1373 }
1374
1375 return result;
1376}
1377
1378IOTHUB_CLIENT_RESULT IoTHubClientCore_GetSendStatus(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_STATUS *iotHubClientStatus)
1379{
1380 IOTHUB_CLIENT_RESULT result;
1381
1382 if (iotHubClientHandle == NULL)
1383 {
1384 /* Codes_SRS_IOTHUBCLIENT_01_023: [If iotHubClientHandle is NULL, IoTHubClient_ GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG.] */
1385 result = IOTHUB_CLIENT_INVALID_ARG;
1386 LogError("NULL iothubClientHandle");
1387 }
1388 else
1389 {
1390 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1391
1392 /* Codes_SRS_IOTHUBCLIENT_01_033: [IoTHubClient_GetSendStatus shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1393 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1394 {
1395 /* Codes_SRS_IOTHUBCLIENT_01_034: [If acquiring the lock fails, IoTHubClient_GetSendStatus shall return IOTHUB_CLIENT_ERROR.] */
1396 result = IOTHUB_CLIENT_ERROR;
1397 LogError("Could not acquire lock");
1398 }
1399 else
1400 {
1401 /* Codes_SRS_IOTHUBCLIENT_01_022: [IoTHubClient_GetSendStatus shall call IoTHubClientCore_LL_GetSendStatus, while passing the IoTHubClientCore_LL handle created by IoTHubClient_Create and the parameter iotHubClientStatus.] */
1402 /* Codes_SRS_IOTHUBCLIENT_01_024: [Otherwise, IoTHubClient_GetSendStatus shall return the result of IoTHubClientCore_LL_GetSendStatus.] */
1403 result = IoTHubClientCore_LL_GetSendStatus(iotHubClientInstance->IoTHubClientLLHandle, iotHubClientStatus);
1404
1405 /* Codes_SRS_IOTHUBCLIENT_01_033: [IoTHubClient_GetSendStatus shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1406 (void)Unlock(iotHubClientInstance->LockHandle);
1407 }
1408 }
1409
1410 return result;
1411}
1412
1413IOTHUB_CLIENT_RESULT IoTHubClientCore_SetMessageCallback(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback, void* userContextCallback)
1414{
1415 IOTHUB_CLIENT_RESULT result;
1416
1417 if (iotHubClientHandle == NULL)
1418 {
1419 /* Codes_SRS_IOTHUBCLIENT_01_016: [If iotHubClientHandle is NULL, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_INVALID_ARG.] */
1420 result = IOTHUB_CLIENT_INVALID_ARG;
1421 LogError("NULL iothubClientHandle");
1422 }
1423 else
1424 {
1425 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1426
1427 /* Codes_SRS_IOTHUBCLIENT_01_014: [IoTHubClient_SetMessageCallback shall start the worker thread if it was not previously started.] */
1428 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1429 {
1430 /* Codes_SRS_IOTHUBCLIENT_01_015: [If starting the thread fails, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_ERROR.] */
1431 result = IOTHUB_CLIENT_ERROR;
1432 LogError("Could not start worker thread");
1433 }
1434 else
1435 {
1436 /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1437 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1438 {
1439 /* Codes_SRS_IOTHUBCLIENT_01_028: [If acquiring the lock fails, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_ERROR.] */
1440 result = IOTHUB_CLIENT_ERROR;
1441 LogError("Could not acquire lock");
1442 }
1443 else
1444 {
1445 if (iotHubClientInstance->created_with_transport_handle == 0)
1446 {
1447 iotHubClientInstance->message_callback = messageCallback;
1448 }
1449 if (iotHubClientInstance->message_user_context != NULL)
1450 {
1451 free(iotHubClientInstance->message_user_context);
1452 iotHubClientInstance->message_user_context = NULL;
1453 }
1454 if (messageCallback == NULL)
1455 {
1456 result = IoTHubClientCore_LL_SetMessageCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, NULL, iotHubClientInstance->message_user_context);
1457 }
1458 else if (iotHubClientInstance->created_with_transport_handle != 0)
1459 {
1460 result = IoTHubClientCore_LL_SetMessageCallback(iotHubClientInstance->IoTHubClientLLHandle, messageCallback, userContextCallback);
1461 }
1462 else
1463 {
1464 iotHubClientInstance->message_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
1465 if (iotHubClientInstance->message_user_context == NULL)
1466 {
1467 result = IOTHUB_CLIENT_ERROR;
1468 LogError("Failed allocating QUEUE_CONTEXT");
1469 }
1470 else
1471 {
1472 iotHubClientInstance->message_user_context->iotHubClientHandle = iotHubClientHandle;
1473 iotHubClientInstance->message_user_context->userContextCallback = userContextCallback;
1474
1475 /* Codes_SRS_IOTHUBCLIENT_01_017: [IoTHubClient_SetMessageCallback shall call IoTHubClientCore_LL_SetMessageCallback_Ex, while passing the IoTHubClientCore_LL handle created by IoTHubClient_Create and the local iothub_ll_message_callback wrapper of messageCallback and userContextCallback.] */
1476 /* Codes_SRS_IOTHUBCLIENT_01_018: [When IoTHubClientCore_LL_SetMessageCallback_Ex is called, IoTHubClient_SetMessageCallback shall return the result of IoTHubClientCore_LL_SetMessageCallback_Ex.] */
1477 result = IoTHubClientCore_LL_SetMessageCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_message_callback, iotHubClientInstance->message_user_context);
1478 if (result != IOTHUB_CLIENT_OK)
1479 {
1480 LogError("IoTHubClientCore_LL_SetMessageCallback failed");
1481 free(iotHubClientInstance->message_user_context);
1482 iotHubClientInstance->message_user_context = NULL;
1483 }
1484 }
1485 }
1486
1487 /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1488 (void)Unlock(iotHubClientInstance->LockHandle);
1489 }
1490 }
1491 }
1492
1493 return result;
1494}
1495
1496IOTHUB_CLIENT_RESULT IoTHubClientCore_SetConnectionStatusCallback(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connectionStatusCallback, void * userContextCallback)
1497{
1498 IOTHUB_CLIENT_RESULT result;
1499
1500 if (iotHubClientHandle == NULL)
1501 {
1502 /* Codes_SRS_IOTHUBCLIENT_25_076: [** If `iotHubClientHandle` is `NULL`, `IoTHubClient_SetRetryPolicy` shall return `IOTHUB_CLIENT_INVALID_ARG`. ] */
1503 result = IOTHUB_CLIENT_INVALID_ARG;
1504 LogError("NULL iothubClientHandle");
1505 }
1506 else
1507 {
1508 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1509
1510 /* Codes_SRS_IOTHUBCLIENT_25_081: [ `IoTHubClient_SetConnectionStatusCallback` shall start the worker thread if it was not previously started. ]*/
1511 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1512 {
1513 /* Codes_SRS_IOTHUBCLIENT_25_083: [ If starting the thread fails, `IoTHubClient_SetConnectionStatusCallback` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1514 result = IOTHUB_CLIENT_ERROR;
1515 LogError("Could not start worker thread");
1516 }
1517 else
1518 {
1519 /* Codes_SRS_IOTHUBCLIENT_25_087: [ `IoTHubClient_SetConnectionStatusCallback` shall be made thread-safe by using the lock created in `IoTHubClient_Create`. ] */
1520 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1521 {
1522 /* Codes_SRS_IOTHUBCLIENT_25_088: [ If acquiring the lock fails, `IoTHubClient_SetConnectionStatusCallback` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1523 result = IOTHUB_CLIENT_ERROR;
1524 LogError("Could not acquire lock");
1525 }
1526 else
1527 {
1528 if (iotHubClientInstance->created_with_transport_handle == 0)
1529 {
1530 iotHubClientInstance->connection_status_callback = connectionStatusCallback;
1531 }
1532
1533 if (iotHubClientInstance->created_with_transport_handle != 0 || connectionStatusCallback == NULL)
1534 {
1535 /* Codes_SRS_IOTHUBCLIENT_25_085: [ `IoTHubClient_SetConnectionStatusCallback` shall call `IoTHubClientCore_LL_SetConnectionStatusCallback`, while passing the `IoTHubClientCore_LL` handle created by `IoTHubClient_Create` and the parameters `connectionStatusCallback` and `userContextCallback`. ]*/
1536 result = IoTHubClientCore_LL_SetConnectionStatusCallback(iotHubClientInstance->IoTHubClientLLHandle, connectionStatusCallback, userContextCallback);
1537 }
1538 else
1539 {
1540 if (iotHubClientInstance->connection_status_user_context != NULL)
1541 {
1542 free(iotHubClientInstance->connection_status_user_context);
1543 }
1544 iotHubClientInstance->connection_status_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
1545 if (iotHubClientInstance->connection_status_user_context == NULL)
1546 {
1547 result = IOTHUB_CLIENT_ERROR;
1548 LogError("Failed allocating QUEUE_CONTEXT");
1549 }
1550 else
1551 {
1552 iotHubClientInstance->connection_status_user_context->iotHubClientHandle = iotHubClientInstance;
1553 iotHubClientInstance->connection_status_user_context->userContextCallback = userContextCallback;
1554
1555 /* Codes_SRS_IOTHUBCLIENT_25_085: [ `IoTHubClient_SetConnectionStatusCallback` shall call `IoTHubClientCore_LL_SetConnectionStatusCallback`, while passing the `IoTHubClientCore_LL` handle created by `IoTHubClient_Create` and the parameters `connectionStatusCallback` and `userContextCallback`. ]*/
1556 result = IoTHubClientCore_LL_SetConnectionStatusCallback(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_connection_status_callback, iotHubClientInstance->connection_status_user_context);
1557 if (result != IOTHUB_CLIENT_OK)
1558 {
1559 LogError("IoTHubClientCore_LL_SetConnectionStatusCallback failed");
1560 free(iotHubClientInstance->connection_status_user_context);
1561 iotHubClientInstance->connection_status_user_context = NULL;
1562 }
1563 }
1564 }
1565 (void)Unlock(iotHubClientInstance->LockHandle);
1566 }
1567 }
1568 }
1569 return result;
1570}
1571
1572IOTHUB_CLIENT_RESULT IoTHubClientCore_SetRetryPolicy(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY retryPolicy, size_t retryTimeoutLimitInSeconds)
1573{
1574 IOTHUB_CLIENT_RESULT result;
1575
1576 if (iotHubClientHandle == NULL)
1577 {
1578 /* Codes_SRS_IOTHUBCLIENT_25_076: [** If `iotHubClientHandle` is `NULL`, `IoTHubClient_SetRetryPolicy` shall return `IOTHUB_CLIENT_INVALID_ARG`. ] */
1579 result = IOTHUB_CLIENT_INVALID_ARG;
1580 LogError("NULL iothubClientHandle");
1581 }
1582 else
1583 {
1584 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1585
1586 /* Codes_SRS_IOTHUBCLIENT_25_073: [ `IoTHubClient_SetRetryPolicy` shall start the worker thread if it was not previously started. ] */
1587 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1588 {
1589 /* Codes_SRS_IOTHUBCLIENT_25_075: [ If starting the thread fails, `IoTHubClient_SetRetryPolicy` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1590 result = IOTHUB_CLIENT_ERROR;
1591 LogError("Could not start worker thread");
1592 }
1593 else
1594 {
1595 /* Codes_SRS_IOTHUBCLIENT_25_079: [ `IoTHubClient_SetRetryPolicy` shall be made thread-safe by using the lock created in `IoTHubClient_Create`.] */
1596 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1597 {
1598 /* Codes_SRS_IOTHUBCLIENT_25_080: [ If acquiring the lock fails, `IoTHubClient_SetRetryPolicy` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1599 result = IOTHUB_CLIENT_ERROR;
1600 LogError("Could not acquire lock");
1601 }
1602 else
1603 {
1604 /* Codes_SRS_IOTHUBCLIENT_25_077: [ `IoTHubClient_SetRetryPolicy` shall call `IoTHubClientCore_LL_SetRetryPolicy`, while passing the `IoTHubClientCore_LL` handle created by `IoTHubClient_Create` and the parameters `retryPolicy` and `retryTimeoutLimitinSeconds`.]*/
1605 result = IoTHubClientCore_LL_SetRetryPolicy(iotHubClientInstance->IoTHubClientLLHandle, retryPolicy, retryTimeoutLimitInSeconds);
1606 (void)Unlock(iotHubClientInstance->LockHandle);
1607 }
1608
1609 }
1610 }
1611
1612 return result;
1613}
1614
1615IOTHUB_CLIENT_RESULT IoTHubClientCore_GetRetryPolicy(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_RETRY_POLICY* retryPolicy, size_t* retryTimeoutLimitInSeconds)
1616{
1617 IOTHUB_CLIENT_RESULT result;
1618
1619 if (iotHubClientHandle == NULL)
1620 {
1621 /* Codes_SRS_IOTHUBCLIENT_25_092: [ If `iotHubClientHandle` is `NULL`, `IoTHubClient_GetRetryPolicy` shall return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
1622 result = IOTHUB_CLIENT_INVALID_ARG;
1623 LogError("NULL iothubClientHandle");
1624 }
1625 else
1626 {
1627 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1628
1629 /* Codes_SRS_IOTHUBCLIENT_25_089: [ `IoTHubClient_GetRetryPolicy` shall start the worker thread if it was not previously started.]*/
1630 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1631 {
1632 /* Codes_SRS_IOTHUBCLIENT_25_091: [ If starting the thread fails, `IoTHubClient_GetRetryPolicy` shall return `IOTHUB_CLIENT_ERROR`.]*/
1633 result = IOTHUB_CLIENT_ERROR;
1634 LogError("Could not start worker thread");
1635 }
1636 else
1637 {
1638 /* Codes_SRS_IOTHUBCLIENT_25_095: [ `IoTHubClient_GetRetryPolicy` shall be made thread-safe by using the lock created in `IoTHubClient_Create`. ]*/
1639 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1640 {
1641 /* Codes_SRS_IOTHUBCLIENT_25_096: [ If acquiring the lock fails, `IoTHubClient_GetRetryPolicy` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1642 result = IOTHUB_CLIENT_ERROR;
1643 LogError("Could not acquire lock");
1644 }
1645 else
1646 {
1647 /* Codes_SRS_IOTHUBCLIENT_25_093: [ `IoTHubClient_GetRetryPolicy` shall call `IoTHubClientCore_LL_GetRetryPolicy`, while passing the `IoTHubClientCore_LL` handle created by `IoTHubClient_Create` and the parameters `connectionStatusCallback` and `userContextCallback`.]*/
1648 result = IoTHubClientCore_LL_GetRetryPolicy(iotHubClientInstance->IoTHubClientLLHandle, retryPolicy, retryTimeoutLimitInSeconds);
1649 (void)Unlock(iotHubClientInstance->LockHandle);
1650 }
1651 }
1652 }
1653
1654 return result;
1655}
1656
1657IOTHUB_CLIENT_RESULT IoTHubClientCore_GetLastMessageReceiveTime(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, time_t* lastMessageReceiveTime)
1658{
1659 IOTHUB_CLIENT_RESULT result;
1660
1661 if (iotHubClientHandle == NULL)
1662 {
1663 /* Codes_SRS_IOTHUBCLIENT_01_020: [If iotHubClientHandle is NULL, IoTHubClient_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_INVALID_ARG.] */
1664 result = IOTHUB_CLIENT_INVALID_ARG;
1665 LogError("NULL iothubClientHandle");
1666 }
1667 else
1668 {
1669 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1670
1671 /* Codes_SRS_IOTHUBCLIENT_01_035: [IoTHubClient_GetLastMessageReceiveTime shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1672 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1673 {
1674 /* Codes_SRS_IOTHUBCLIENT_01_036: [If acquiring the lock fails, IoTHubClient_GetLastMessageReceiveTime shall return IOTHUB_CLIENT_ERROR.] */
1675 result = IOTHUB_CLIENT_ERROR;
1676 LogError("Could not acquire lock");
1677 }
1678 else
1679 {
1680 /* Codes_SRS_IOTHUBCLIENT_01_019: [IoTHubClient_GetLastMessageReceiveTime shall call IoTHubClientCore_LL_GetLastMessageReceiveTime, while passing the IoTHubClientCore_LL handle created by IoTHubClient_Create and the parameter lastMessageReceiveTime.] */
1681 /* Codes_SRS_IOTHUBCLIENT_01_021: [Otherwise, IoTHubClient_GetLastMessageReceiveTime shall return the result of IoTHubClientCore_LL_GetLastMessageReceiveTime.] */
1682 result = IoTHubClientCore_LL_GetLastMessageReceiveTime(iotHubClientInstance->IoTHubClientLLHandle, lastMessageReceiveTime);
1683
1684 /* Codes_SRS_IOTHUBCLIENT_01_035: [IoTHubClient_GetLastMessageReceiveTime shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
1685 (void)Unlock(iotHubClientInstance->LockHandle);
1686 }
1687 }
1688
1689 return result;
1690}
1691
1692IOTHUB_CLIENT_RESULT IoTHubClientCore_SetOption(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const char* optionName, const void* value)
1693{
1694 IOTHUB_CLIENT_RESULT result;
1695 /*Codes_SRS_IOTHUBCLIENT_02_034: [If parameter iotHubClientHandle is NULL then IoTHubClient_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.] */
1696 /*Codes_SRS_IOTHUBCLIENT_02_035: [ If parameter optionName is NULL then IoTHubClient_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
1697 /*Codes_SRS_IOTHUBCLIENT_02_036: [ If parameter value is NULL then IoTHubClient_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
1698 if (
1699 (iotHubClientHandle == NULL) ||
1700 (optionName == NULL) ||
1701 (value == NULL)
1702 )
1703 {
1704 result = IOTHUB_CLIENT_INVALID_ARG;
1705 LogError("invalid arg (NULL)");
1706 }
1707 else
1708 {
1709 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1710
1711 /* Codes_SRS_IOTHUBCLIENT_01_041: [ IoTHubClient_SetOption shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
1712 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1713 {
1714 /* Codes_SRS_IOTHUBCLIENT_01_042: [ If acquiring the lock fails, IoTHubClient_SetOption shall return IOTHUB_CLIENT_ERROR. ]*/
1715 result = IOTHUB_CLIENT_ERROR;
1716 LogError("Could not acquire lock");
1717 }
1718 else
1719 {
1720 /* Codes_SRS_IOTHUBCLIENT_41_001 [ If parameter `optionName` is `OPTION_DO_WORK_FREQUENCY_IN_MS` then `IoTHubClient_SetOption` shall set `do_work_freq_ms` parameter of `IoTHubClientInstance` ]*/
1721 if (strcmp(OPTION_DO_WORK_FREQUENCY_IN_MS, optionName) == 0)
1722 {
1723 /* Codes_SRS_IOTHUBCLIENT_41_003: [ The value for `OPTION_DO_WORK_FREQUENCY_IN_MS` shall be limited to 100 to follow SDK best practices by not reducing the DoWork frequency below 10 Hz ]*/
1724 if (0 < * (unsigned int *)value && * (unsigned int *)value <= 100)
1725 {
1726 /* Codes_SRS_IOTHUBCLIENT_41_004: [ If `currentMessageTimeout` is not greater than `do_work_freq_ms`, `IotHubClientCore_SetOption` shall return `IOTHUB_CLIENT_INVALID_ARG` ]*/
1727 /* Codes_SRS_IOTHUBCLIENT_41_007: [** If parameter `optionName` is `OPTION_DO_WORK_FREQUENCY_IN_MS` then `value` should be of type `tickcounter_ms_t *`. **]*/
1728 if ((!iotHubClientInstance->currentMessageTimeout) || ( * (tickcounter_ms_t *)value < iotHubClientInstance->currentMessageTimeout))
1729 {
1730 iotHubClientInstance->do_work_freq_ms = * (tickcounter_ms_t *)value;
1731 result = IOTHUB_CLIENT_OK;
1732 }
1733 else
1734 {
1735 result = IOTHUB_CLIENT_INVALID_ARG;
1736 LogError("Invalid value: OPTION_DO_WORK_FREQUENCY_IN_MS cannot exceed that of OPTION_MESSAGE_TIMEOUT.");
1737 }
1738 }
1739 else
1740 {
1741 result = IOTHUB_CLIENT_INVALID_ARG;
1742 LogError("Invalid value: OPTION_DO_WORK_FREQUENCY_IN_MS cannot exceed 100 ms. If you wish to reduce the frequency further, consider using the LL layer.");
1743 }
1744 }
1745 /* Codes_SRS_IOTHUBCLIENT_41_005: [ If parameter `optionName` is `OPTION_MESSAGE_TIMEOUT` then `IoTHubClientCore_SetOption` shall set `currentMessageTimeout` parameter of `IoTHubClientInstance` ]*/
1746 else if (strcmp(OPTION_MESSAGE_TIMEOUT, optionName) == 0)
1747 {
1748 iotHubClientInstance->currentMessageTimeout = * (tickcounter_ms_t *)value;
1749
1750 /* Codes_SRS_IOTHUBCLIENT_41_004: [ If `currentMessageTimeout` is not greater than `do_work_freq_ms`, `IotHubClientCore_SetOption` shall return `IOTHUB_CLIENT_INVALID_ARG` ]*/
1751 if (iotHubClientInstance->do_work_freq_ms < iotHubClientInstance->currentMessageTimeout)
1752 {
1753 /*Codes_SRS_IOTHUBCLIENT_41_006: [ If parameter `optionName` is `OPTION_MESSAGE_TIMEOUT` then `IoTHubClientCore_SetOption` shall call `IoTHubClientCore_LL_SetOption` passing the same parameters and return what IoTHubClientCore_LL_SetOption returns. ] */
1754 result = IoTHubClientCore_LL_SetOption(iotHubClientInstance->IoTHubClientLLHandle, optionName, value);
1755 if (result != IOTHUB_CLIENT_OK)
1756 {
1757 LogError("IoTHubClientCore_LL_SetOption failed");
1758 }
1759 }
1760 else
1761 {
1762 result = IOTHUB_CLIENT_INVALID_ARG;
1763 LogError("invalid value: OPTION_MESSAGE_TIMEOUT cannot exceed the value of OPTION_DO_WORK_FREQUENCY_IN_MS ");
1764 }
1765 }
1766 else
1767 {
1768 /*Codes_SRS_IOTHUBCLIENT_02_038: [If optionName doesn't match one of the options handled by this module then IoTHubClient_SetOption shall call IoTHubClientCore_LL_SetOption passing the same parameters and return what IoTHubClientCore_LL_SetOption returns.] */
1769 result = IoTHubClientCore_LL_SetOption(iotHubClientInstance->IoTHubClientLLHandle, optionName, value);
1770 if (result != IOTHUB_CLIENT_OK)
1771 {
1772 LogError("IoTHubClientCore_LL_SetOption failed");
1773 }
1774 }
1775 (void)Unlock(iotHubClientInstance->LockHandle);
1776 }
1777 }
1778 return result;
1779}
1780
1781IOTHUB_CLIENT_RESULT IoTHubClientCore_SetDeviceTwinCallback(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
1782{
1783 IOTHUB_CLIENT_RESULT result;
1784
1785 /*Codes_SRS_IOTHUBCLIENT_10_001: [** `IoTHubClient_SetDeviceTwinCallback` shall fail and return `IOTHUB_CLIENT_INVALID_ARG` if parameter `iotHubClientHandle` is `NULL`. ]*/
1786 if (iotHubClientHandle == NULL)
1787 {
1788 result = IOTHUB_CLIENT_INVALID_ARG;
1789 LogError("invalid arg (NULL)");
1790 }
1791 else
1792 {
1793 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1794
1795 /*Codes_SRS_IOTHUBCLIENT_10_003: [** If the transport connection is shared, the thread shall be started by calling `IoTHubTransport_StartWorkerThread`. ]*/
1796 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1797 {
1798 /*Codes_SRS_IOTHUBCLIENT_10_004: [** If starting the thread fails, `IoTHubClient_SetDeviceTwinCallback` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1799 result = IOTHUB_CLIENT_ERROR;
1800 LogError("Could not start worker thread");
1801 }
1802 else
1803 {
1804 /*Codes_SRS_IOTHUBCLIENT_10_020: [** `IoTHubClient_SetDeviceTwinCallback` shall be made thread - safe by using the lock created in IoTHubClient_Create. ]*/
1805 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1806 {
1807 /*Codes_SRS_IOTHUBCLIENT_10_002: [** If acquiring the lock fails, `IoTHubClient_SetDeviceTwinCallback` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1808 result = IOTHUB_CLIENT_ERROR;
1809 LogError("Could not acquire lock");
1810 }
1811 else
1812 {
1813 if (iotHubClientInstance->created_with_transport_handle == 0)
1814 {
1815 iotHubClientInstance->desired_state_callback = deviceTwinCallback;
1816 }
1817
1818 if (iotHubClientInstance->created_with_transport_handle != 0 || deviceTwinCallback == NULL)
1819 {
1820 /*Codes_SRS_IOTHUBCLIENT_10_005: [** `IoTHubClientCore_LL_SetDeviceTwinCallback` shall call `IoTHubClientCore_LL_SetDeviceTwinCallback`, while passing the `IoTHubClientCore_LL handle` created by `IoTHubClientCore_LL_Create` along with the parameters `reportedStateCallback` and `userContextCallback`. ]*/
1821 result = IoTHubClientCore_LL_SetDeviceTwinCallback(iotHubClientInstance->IoTHubClientLLHandle, deviceTwinCallback, userContextCallback);
1822 }
1823 else
1824 {
1825 if (iotHubClientInstance->devicetwin_user_context != NULL)
1826 {
1827 free(iotHubClientInstance->devicetwin_user_context);
1828 }
1829
1830 /*Codes_SRS_IOTHUBCLIENT_07_002: [ IoTHubClient_SetDeviceTwinCallback shall allocate a IOTHUB_QUEUE_CONTEXT object to be sent to the IoTHubClientCore_LL_SetDeviceTwinCallback function as a user context. ]*/
1831 iotHubClientInstance->devicetwin_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
1832 if (iotHubClientInstance->devicetwin_user_context == NULL)
1833 {
1834 result = IOTHUB_CLIENT_ERROR;
1835 LogError("Failed allocating QUEUE_CONTEXT");
1836 }
1837 else
1838 {
1839 /*Codes_SRS_IOTHUBCLIENT_10_005: [** `IoTHubClientCore_LL_SetDeviceTwinCallback` shall call `IoTHubClientCore_LL_SetDeviceTwinCallback`, while passing the `IoTHubClientCore_LL handle` created by `IoTHubClientCore_LL_Create` along with the parameters `iothub_ll_device_twin_callback` and IOTHUB_QUEUE_CONTEXT variable. ]*/
1840 iotHubClientInstance->devicetwin_user_context->iotHubClientHandle = iotHubClientInstance;
1841 iotHubClientInstance->devicetwin_user_context->userContextCallback = userContextCallback;
1842 result = IoTHubClientCore_LL_SetDeviceTwinCallback(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_device_twin_callback, iotHubClientInstance->devicetwin_user_context);
1843 if (result != IOTHUB_CLIENT_OK)
1844 {
1845 LogError("IoTHubClientCore_LL_SetDeviceTwinCallback failed");
1846 free(iotHubClientInstance->devicetwin_user_context);
1847 iotHubClientInstance->devicetwin_user_context = NULL;
1848 }
1849 }
1850 }
1851
1852 (void)Unlock(iotHubClientInstance->LockHandle);
1853 }
1854 }
1855 }
1856 return result;
1857}
1858
1859IOTHUB_CLIENT_RESULT IoTHubClientCore_SendReportedState(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const unsigned char* reportedState, size_t size, IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reportedStateCallback, void* userContextCallback)
1860{
1861 IOTHUB_CLIENT_RESULT result;
1862
1863 /*Codes_SRS_IOTHUBCLIENT_10_013: [** If `iotHubClientHandle` is `NULL`, `IoTHubClient_SendReportedState` shall return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
1864 if (iotHubClientHandle == NULL)
1865 {
1866 result = IOTHUB_CLIENT_INVALID_ARG;
1867 LogError("invalid arg (NULL)");
1868 }
1869 else
1870 {
1871 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1872
1873 /*Codes_SRS_IOTHUBCLIENT_10_015: [** If the transport connection is shared, the thread shall be started by calling `IoTHubTransport_StartWorkerThread`. ]*/
1874 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1875 {
1876 /*Codes_SRS_IOTHUBCLIENT_10_016: [** If starting the thread fails, `IoTHubClient_SendReportedState` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1877 result = IOTHUB_CLIENT_ERROR;
1878 LogError("Could not start worker thread");
1879 }
1880 else
1881 {
1882 /*Codes_SRS_IOTHUBCLIENT_10_021: [** `IoTHubClient_SendReportedState` shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
1883 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1884 {
1885 /*Codes_SRS_IOTHUBCLIENT_10_014: [** If acquiring the lock fails, `IoTHubClient_SendReportedState` shall return `IOTHUB_CLIENT_ERROR`. ]*/
1886 result = IOTHUB_CLIENT_ERROR;
1887 LogError("Could not acquire lock");
1888 }
1889 else
1890 {
1891 if (iotHubClientInstance->created_with_transport_handle != 0 || reportedStateCallback == NULL)
1892 {
1893 /*Codes_SRS_IOTHUBCLIENT_10_017: [** `IoTHubClient_SendReportedState` shall call `IoTHubClientCore_LL_SendReportedState`, while passing the `IoTHubClientCore_LL handle` created by `IoTHubClientCore_LL_Create` along with the parameters `reportedState`, `size`, `reportedStateCallback`, and `userContextCallback`. ]*/
1894 /*Codes_SRS_IOTHUBCLIENT_10_018: [** When `IoTHubClientCore_LL_SendReportedState` is called, `IoTHubClient_SendReportedState` shall return the result of `IoTHubClientCore_LL_SendReportedState`. **]*/
1895 result = IoTHubClientCore_LL_SendReportedState(iotHubClientInstance->IoTHubClientLLHandle, reportedState, size, reportedStateCallback, userContextCallback);
1896 }
1897 else
1898 {
1899 /* Codes_SRS_IOTHUBCLIENT_07_003: [ IoTHubClient_SendReportedState shall allocate a IOTHUB_QUEUE_CONTEXT object to be sent to the IoTHubClientCore_LL_SendReportedState function as a user context. ] */
1900 IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
1901 if (queue_context == NULL)
1902 {
1903 result = IOTHUB_CLIENT_ERROR;
1904 LogError("Failed allocating QUEUE_CONTEXT");
1905 }
1906 else
1907 {
1908 queue_context->iotHubClientHandle = iotHubClientInstance;
1909 queue_context->userContextCallback = userContextCallback;
1910 queue_context->callbackFunction.reportedStateCallback = reportedStateCallback;
1911 /*Codes_SRS_IOTHUBCLIENT_10_017: [** `IoTHubClient_SendReportedState` shall call `IoTHubClientCore_LL_SendReportedState`, while passing the `IoTHubClientCore_LL handle` created by `IoTHubClientCore_LL_Create` along with the parameters `reportedState`, `size`, `iothub_ll_reported_state_callback` and IOTHUB_QUEUE_CONTEXT variable. ]*/
1912 /*Codes_SRS_IOTHUBCLIENT_10_018: [** When `IoTHubClientCore_LL_SendReportedState` is called, `IoTHubClient_SendReportedState` shall return the result of `IoTHubClientCore_LL_SendReportedState`. **]*/
1913 result = IoTHubClientCore_LL_SendReportedState(iotHubClientInstance->IoTHubClientLLHandle, reportedState, size, iothub_ll_reported_state_callback, queue_context);
1914 if (result != IOTHUB_CLIENT_OK)
1915 {
1916 LogError("IoTHubClientCore_LL_SendReportedState failed");
1917 free(queue_context);
1918 }
1919 }
1920 }
1921
1922 (void)Unlock(iotHubClientInstance->LockHandle);
1923 }
1924 }
1925 }
1926 return result;
1927}
1928
1929IOTHUB_CLIENT_RESULT IoTHubClientCore_GetTwinAsync(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK deviceTwinCallback, void* userContextCallback)
1930{
1931 IOTHUB_CLIENT_RESULT result;
1932
1933 // Codes_SRS_IOTHUBCLIENT_09_009: [ If `iotHubClientHandle` or `deviceTwinCallback` are `NULL`, `IoTHubClientCore_GetTwinAsync` shall return `IOTHUB_CLIENT_INVALID_ARG`. ]
1934 if (iotHubClientHandle == NULL || deviceTwinCallback == NULL)
1935 {
1936 result = IOTHUB_CLIENT_INVALID_ARG;
1937 LogError("Invalid argument (iotHubClientHandle=%p, deviceTwinCallback=%p)", iotHubClientHandle, deviceTwinCallback);
1938 }
1939 else
1940 {
1941 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
1942
1943 // Codes_SRS_IOTHUBCLIENT_09_010: [ The thread that executes the client I/O shall be started if not running already. ]
1944 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
1945 {
1946 // Codes_SRS_IOTHUBCLIENT_09_011: [ If starting the thread fails, `IoTHubClientCore_GetTwinAsync` shall return `IOTHUB_CLIENT_ERROR`. ]
1947 result = IOTHUB_CLIENT_ERROR;
1948 LogError("Could not start worker thread");
1949 }
1950 else
1951 {
1952 IOTHUB_QUEUE_CONSOLIDATED_CONTEXT* queueContext;
1953
1954 if ((queueContext = (IOTHUB_QUEUE_CONSOLIDATED_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONSOLIDATED_CONTEXT))) == NULL)
1955 {
1956 LogError("Failed creating queue context");
1957 result = IOTHUB_CLIENT_ERROR;
1958 }
1959 else
1960 {
1961 queueContext->iotHubClientHandle = iotHubClientHandle;
1962 queueContext->userCallback.getTwin = deviceTwinCallback;
1963 queueContext->userContext = userContextCallback;
1964
1965 // Codes_SRS_IOTHUBCLIENT_09_012: [ `IoTHubClientCore_GetTwinAsync` shall be made thread-safe by using the lock created in IoTHubClient_Create. ]
1966 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
1967 {
1968 // Codes_SRS_IOTHUBCLIENT_09_013: [ If acquiring the lock fails, `IoTHubClientCore_GetTwinAsync` shall return `IOTHUB_CLIENT_ERROR`. ]
1969 result = IOTHUB_CLIENT_ERROR;
1970 LogError("Could not acquire lock");
1971 free(queueContext);
1972 }
1973 else
1974 {
1975 // Codes_SRS_IOTHUBCLIENT_09_014: [ `IoTHubClientCore_GetTwinAsync` shall call `IoTHubClientCore_LL_GetTwinAsync`, passing the `IoTHubClient_LL handle`, `deviceTwinCallback` and `userContextCallback` as arguments ]
1976 // Codes_SRS_IOTHUBCLIENT_09_015: [ When `IoTHubClientCore_LL_GetTwinAsync` is called, `IoTHubClientCore_GetTwinAsync` shall return the result of `IoTHubClientCore_LL_GetTwinAsync`. ]
1977 result = IoTHubClientCore_LL_GetTwinAsync(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_get_device_twin_async_callback, queueContext);
1978
1979 if (result != IOTHUB_CLIENT_OK)
1980 {
1981 LogError("IoTHubClientCore_LL_GetTwinAsync failed");
1982 free(queueContext);
1983 }
1984
1985 (void)Unlock(iotHubClientInstance->LockHandle);
1986 }
1987 }
1988 }
1989 }
1990 return result;
1991}
1992
1993IOTHUB_CLIENT_RESULT IoTHubClientCore_SetDeviceMethodCallback(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC deviceMethodCallback, void* userContextCallback)
1994{
1995 IOTHUB_CLIENT_RESULT result;
1996
1997 /*Codes_SRS_IOTHUBCLIENT_12_012: [ If iotHubClientHandle is NULL, IoTHubClient_SetDeviceMethodCallback shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
1998 if (iotHubClientHandle == NULL)
1999 {
2000 result = IOTHUB_CLIENT_INVALID_ARG;
2001 LogError("invalid arg (NULL)");
2002 }
2003 else
2004 {
2005 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
2006
2007 /*Codes_SRS_IOTHUBCLIENT_12_014: [ If the transport handle is null and the worker thread is not initialized, the thread shall be started by calling IoTHubTransport_StartWorkerThread. ]*/
2008 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
2009 {
2010 /*Codes_SRS_IOTHUBCLIENT_12_015: [ If starting the thread fails, IoTHubClient_SetDeviceMethodCallback shall return IOTHUB_CLIENT_ERROR. ]*/
2011 result = IOTHUB_CLIENT_ERROR;
2012 LogError("Could not start worker thread");
2013 }
2014 else
2015 {
2016 /*Codes_SRS_IOTHUBCLIENT_12_018: [ IoTHubClient_SetDeviceMethodCallback shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
2017 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
2018 {
2019 /*Codes_SRS_IOTHUBCLIENT_12_013: [ If acquiring the lock fails, IoTHubClient_SetDeviceMethodCallback shall return IOTHUB_CLIENT_ERROR. ]*/
2020 result = IOTHUB_CLIENT_ERROR;
2021 LogError("Could not acquire lock");
2022 }
2023 else
2024 {
2025 if (iotHubClientInstance->created_with_transport_handle == 0)
2026 {
2027 iotHubClientInstance->device_method_callback = deviceMethodCallback;
2028 }
2029
2030 if (iotHubClientInstance->method_user_context)
2031 {
2032 free(iotHubClientInstance->method_user_context);
2033 iotHubClientInstance->method_user_context = NULL;
2034 }
2035 if (deviceMethodCallback == NULL)
2036 {
2037 result = IoTHubClientCore_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, NULL, NULL);
2038 }
2039 else
2040 {
2041 iotHubClientInstance->method_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
2042 if (iotHubClientInstance->method_user_context == NULL)
2043 {
2044 result = IOTHUB_CLIENT_ERROR;
2045 LogError("Failed allocating QUEUE_CONTEXT");
2046 }
2047 else
2048 {
2049 iotHubClientInstance->method_user_context->iotHubClientHandle = iotHubClientHandle;
2050 iotHubClientInstance->method_user_context->userContextCallback = userContextCallback;
2051
2052 /*Codes_SRS_IOTHUBCLIENT_12_016: [ IoTHubClient_SetDeviceMethodCallback shall call IoTHubClientCore_LL_SetDeviceMethodCallback, while passing the IoTHubClientCore_LL_handle created by IoTHubClientCore_LL_Create along with the parameters deviceMethodCallback and userContextCallback. ]*/
2053 /*Codes_SRS_IOTHUBCLIENT_12_017: [ When IoTHubClientCore_LL_SetDeviceMethodCallback is called, IoTHubClient_SetDeviceMethodCallback shall return the result of IoTHubClientCore_LL_SetDeviceMethodCallback. ]*/
2054 result = IoTHubClientCore_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_device_method_callback, iotHubClientInstance->method_user_context);
2055 if (result != IOTHUB_CLIENT_OK)
2056 {
2057 LogError("IoTHubClientCore_LL_SetDeviceMethodCallback_Ex failed");
2058 free(iotHubClientInstance->method_user_context);
2059 iotHubClientInstance->method_user_context = NULL;
2060 }
2061 else
2062 {
2063 iotHubClientInstance->device_method_callback = deviceMethodCallback;
2064 }
2065 }
2066 }
2067
2068 (void)Unlock(iotHubClientInstance->LockHandle);
2069 }
2070
2071 }
2072 }
2073 return result;
2074}
2075
2076IOTHUB_CLIENT_RESULT IoTHubClientCore_SetDeviceMethodCallback_Ex(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK inboundDeviceMethodCallback, void* userContextCallback)
2077{
2078 IOTHUB_CLIENT_RESULT result;
2079
2080 /*Codes_SRS_IOTHUBCLIENT_07_001: [ If iotHubClientHandle is NULL, IoTHubClient_SetDeviceMethodCallback_Ex shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
2081 if (iotHubClientHandle == NULL)
2082 {
2083 result = IOTHUB_CLIENT_INVALID_ARG;
2084 LogError("invalid arg (NULL)");
2085 }
2086 else
2087 {
2088 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
2089
2090 /*Codes_SRS_IOTHUBCLIENT_07_003: [ If the transport handle is NULL and the worker thread is not initialized, the thread shall be started by calling IoTHubTransport_StartWorkerThread. ]*/
2091 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
2092 {
2093 /*Codes_SRS_IOTHUBCLIENT_07_004: [ If starting the thread fails, IoTHubClient_SetDeviceMethodCallback_Ex shall return IOTHUB_CLIENT_ERROR. ]*/
2094 result = IOTHUB_CLIENT_ERROR;
2095 LogError("Could not start worker thread");
2096 }
2097 else
2098 {
2099 /*Codes_SRS_IOTHUBCLIENT_07_007: [ IoTHubClient_SetDeviceMethodCallback_Ex shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
2100 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
2101 {
2102 /*Codes_SRS_IOTHUBCLIENT_07_002: [ If acquiring the lock fails, IoTHubClient_SetDeviceMethodCallback_Ex shall return IOTHUB_CLIENT_ERROR. ]*/
2103 result = IOTHUB_CLIENT_ERROR;
2104 LogError("Could not acquire lock");
2105 }
2106 else
2107 {
2108 if (iotHubClientInstance->created_with_transport_handle == 0)
2109 {
2110 iotHubClientInstance->inbound_device_method_callback = inboundDeviceMethodCallback;
2111 }
2112
2113 if (iotHubClientInstance->method_user_context)
2114 {
2115 free(iotHubClientInstance->method_user_context);
2116 iotHubClientInstance->method_user_context = NULL;
2117 }
2118 if (inboundDeviceMethodCallback == NULL)
2119 {
2120 /* Codes_SRS_IOTHUBCLIENT_07_008: [ If inboundDeviceMethodCallback is NULL, IoTHubClient_SetDeviceMethodCallback_Ex shall call IoTHubClientCore_LL_SetDeviceMethodCallback_Ex, passing NULL for the iothub_ll_inbound_device_method_callback. ] */
2121 result = IoTHubClientCore_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, NULL, NULL);
2122 }
2123 else
2124 {
2125 iotHubClientInstance->method_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
2126 if (iotHubClientInstance->method_user_context == NULL)
2127 {
2128 result = IOTHUB_CLIENT_ERROR;
2129 LogError("Failed allocating QUEUE_CONTEXT");
2130 }
2131 else
2132 {
2133 /*Codes_SRS_IOTHUBCLIENT_07_005: [ IoTHubClient_SetDeviceMethodCallback_Ex shall call IoTHubClientCore_LL_SetDeviceMethodCallback_Ex, while passing the IoTHubClientCore_LL_handle created by IoTHubClientCore_LL_Create along with the parameters iothub_ll_inbound_device_method_callback and IOTHUB_QUEUE_CONTEXT. ]*/
2134 iotHubClientInstance->method_user_context->iotHubClientHandle = iotHubClientHandle;
2135 iotHubClientInstance->method_user_context->userContextCallback = userContextCallback;
2136
2137 /* Codes_SRS_IOTHUBCLIENT_07_006: [ When IoTHubClientCore_LL_SetDeviceMethodCallback_Ex is called, IoTHubClient_SetDeviceMethodCallback_Ex shall return the result of IoTHubClientCore_LL_SetDeviceMethodCallback_Ex. ] */
2138 result = IoTHubClientCore_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_inbound_device_method_callback, iotHubClientInstance->method_user_context);
2139 if (result != IOTHUB_CLIENT_OK)
2140 {
2141 LogError("IoTHubClientCore_LL_SetDeviceMethodCallback_Ex failed");
2142 free(iotHubClientInstance->method_user_context);
2143 iotHubClientInstance->method_user_context = NULL;
2144 }
2145 else
2146 {
2147 iotHubClientInstance->inbound_device_method_callback = inboundDeviceMethodCallback;
2148 }
2149 }
2150 }
2151
2152 (void)Unlock(iotHubClientInstance->LockHandle);
2153 }
2154 }
2155 }
2156 return result;
2157}
2158
2159IOTHUB_CLIENT_RESULT IoTHubClientCore_DeviceMethodResponse(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, METHOD_HANDLE methodId, const unsigned char* response, size_t respSize, int statusCode)
2160{
2161 IOTHUB_CLIENT_RESULT result;
2162
2163 /*Codes_SRS_IOTHUBCLIENT_12_012: [ If iotHubClientHandle is NULL, IoTHubClient_SetDeviceMethodCallback shall return IOTHUB_CLIENT_INVALID_ARG. ]*/
2164 if (iotHubClientHandle == NULL)
2165 {
2166 result = IOTHUB_CLIENT_INVALID_ARG;
2167 LogError("invalid arg (NULL)");
2168 }
2169 else
2170 {
2171 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
2172
2173 /*Codes_SRS_IOTHUBCLIENT_12_018: [ IoTHubClient_SetDeviceMethodCallback shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
2174 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
2175 {
2176 /*Codes_SRS_IOTHUBCLIENT_12_013: [ If acquiring the lock fails, IoTHubClient_SetDeviceMethodCallback shall return IOTHUB_CLIENT_ERROR. ]*/
2177 result = IOTHUB_CLIENT_ERROR;
2178 LogError("Could not acquire lock");
2179 }
2180 else
2181 {
2182 result = IoTHubClientCore_LL_DeviceMethodResponse(iotHubClientInstance->IoTHubClientLLHandle, methodId, response, respSize, statusCode);
2183 if (result != IOTHUB_CLIENT_OK)
2184 {
2185 LogError("IoTHubClientCore_LL_DeviceMethodResponse failed");
2186 }
2187 (void)Unlock(iotHubClientInstance->LockHandle);
2188 }
2189 }
2190 return result;
2191}
2192
2193#if !defined(DONT_USE_UPLOADTOBLOB) || defined(USE_EDGE_MODULES)
2194static IOTHUB_CLIENT_RESULT startHttpWorkerThread(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, HTTPWORKER_THREAD_INFO* threadInfo, THREAD_START_FUNC httpWorkerThreadFunc)
2195{
2196 IOTHUB_CLIENT_RESULT result;
2197
2198 LIST_ITEM_HANDLE item;
2199
2200 // StartWorkerThreadIfNeeded creates the "main" worker thread used for transports. Though its not used
2201 // for these HTTP based worker threads (see ThreadAPI_Create call below) the main one is needed for garbage collection.
2202 if ((result = StartWorkerThreadIfNeeded(iotHubClientHandle)) != IOTHUB_CLIENT_OK)
2203 {
2204 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2205 LogError("Could not start worker thread");
2206 }
2207 else if (Lock(threadInfo->iotHubClientHandle->LockHandle) != LOCK_OK)
2208 {
2209 LogError("Lock failed");
2210 result = IOTHUB_CLIENT_ERROR;
2211 }
2212 else
2213 {
2214 if ((item = singlylinkedlist_add(threadInfo->iotHubClientHandle->httpWorkerThreadInfoList, threadInfo)) == NULL)
2215 {
2216 LogError("Adding item to list failed");
2217 result = IOTHUB_CLIENT_ERROR;
2218 }
2219 else if (ThreadAPI_Create(&threadInfo->threadHandle, httpWorkerThreadFunc, threadInfo) != THREADAPI_OK)
2220 {
2221 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2222 LogError("unable to ThreadAPI_Create");
2223 // Remove the item from linked list here, while we're still under lock. Final garbage collector also does it under lock.
2224 (void)singlylinkedlist_remove(threadInfo->iotHubClientHandle->httpWorkerThreadInfoList, item);
2225 result = IOTHUB_CLIENT_ERROR;
2226 }
2227 else
2228 {
2229 result = IOTHUB_CLIENT_OK;
2230 }
2231 (void)Unlock(threadInfo->iotHubClientHandle->LockHandle);
2232 }
2233
2234 return result;
2235}
2236
2237static int markThreadReadyToBeGarbageCollected(HTTPWORKER_THREAD_INFO* threadInfo)
2238{
2239 /*Codes_SRS_IOTHUBCLIENT_02_071: [ The thread shall mark itself as disposable. ]*/
2240 if (Lock(threadInfo->lockGarbage) != LOCK_OK)
2241 {
2242 LogError("unable to Lock - trying anyway");
2243 threadInfo->canBeGarbageCollected = 1;
2244 }
2245 else
2246 {
2247 threadInfo->canBeGarbageCollected = 1;
2248
2249 if (Unlock(threadInfo->lockGarbage) != LOCK_OK)
2250 {
2251 LogError("unable to Unlock after locking");
2252 }
2253 }
2254
2255 ThreadAPI_Exit(0);
2256 return 0;
2257}
2258
2259#endif // !defined(DONT_USE_UPLOADTOBLOB) || defined(USE_EDGE_MODULES)
2260
2261#if !defined(DONT_USE_UPLOADTOBLOB)
2262static HTTPWORKER_THREAD_INFO* allocateUploadToBlob(const char* destinationFileName, IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, void* context)
2263{
2264 HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)malloc(sizeof(HTTPWORKER_THREAD_INFO));
2265 if (threadInfo == NULL)
2266 {
2267 LogError("unable to allocate thread object");
2268 }
2269 else
2270 {
2271 memset(threadInfo, 0, sizeof(HTTPWORKER_THREAD_INFO));
2272 threadInfo->workerThreadType = HTTPWORKER_THREAD_UPLOAD_TO_BLOB;
2273 threadInfo->iotHubClientHandle = iotHubClientHandle;
2274 threadInfo->context = context;
2275
2276 if (mallocAndStrcpy_s(&threadInfo->destinationFileName, destinationFileName) != 0)
2277 {
2278 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2279 LogError("unable to mallocAndStrcpy_s");
2280 freeHttpWorkerThreadInfo(threadInfo);
2281 threadInfo = NULL;
2282 }
2283 else if ((threadInfo->lockGarbage = Lock_Init()) == NULL)
2284 {
2285 LogError("unable to allocate a lock");
2286 freeHttpWorkerThreadInfo(threadInfo);
2287 threadInfo = NULL;
2288 }
2289 }
2290
2291 return threadInfo;
2292}
2293
2294
2295static IOTHUB_CLIENT_RESULT initializeUploadToBlobData(HTTPWORKER_THREAD_INFO* threadInfo, const unsigned char* source, size_t size, IOTHUB_CLIENT_FILE_UPLOAD_CALLBACK iotHubClientFileUploadCallback)
2296{
2297 IOTHUB_CLIENT_RESULT result;
2298
2299 threadInfo->uploadBlobSavedData.size = size;
2300 threadInfo->uploadBlobSavedData.iotHubClientFileUploadCallback = iotHubClientFileUploadCallback;
2301
2302 if (size != 0)
2303 {
2304 if ((threadInfo->uploadBlobSavedData.source = (unsigned char*)malloc(size)) == NULL)
2305 {
2306 LogError("Cannot allocate source field");
2307 result = IOTHUB_CLIENT_ERROR;
2308 }
2309 else
2310 {
2311 memcpy(threadInfo->uploadBlobSavedData.source, source, size);
2312 result = IOTHUB_CLIENT_OK;
2313 }
2314 }
2315 else
2316 {
2317 result = IOTHUB_CLIENT_OK;
2318 }
2319
2320 return result;
2321}
2322
2323
2324static int uploadingThread(void *data)
2325{
2326 IOTHUB_CLIENT_FILE_UPLOAD_RESULT upload_result;
2327 HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)data;
2328
2329 srand((unsigned int)get_time(NULL));
2330
2331 /*it so happens that IoTHubClientCore_LL_UploadToBlob is thread-safe because there's no saved state in the handle and there are no globals, so no need to protect it*/
2332 /*not having it protected means multiple simultaneous uploads can happen*/
2333 /*Codes_SRS_IOTHUBCLIENT_02_054: [ The thread shall call IoTHubClientCore_LL_UploadToBlob passing the information packed in the structure. ]*/
2334 if (IoTHubClientCore_LL_UploadToBlob(threadInfo->iotHubClientHandle->IoTHubClientLLHandle, threadInfo->destinationFileName, threadInfo->uploadBlobSavedData.source, threadInfo->uploadBlobSavedData.size) == IOTHUB_CLIENT_OK)
2335 {
2336 upload_result = FILE_UPLOAD_OK;
2337 }
2338 else
2339 {
2340 LogError("unable to IoTHubClientCore_LL_UploadToBlob");
2341 upload_result = FILE_UPLOAD_ERROR;
2342 }
2343
2344 if (threadInfo->uploadBlobSavedData.iotHubClientFileUploadCallback != NULL)
2345 {
2346 /*Codes_SRS_IOTHUBCLIENT_02_055: [ If IoTHubClientCore_LL_UploadToBlob fails then the thread shall call iotHubClientFileUploadCallbackInternal passing as result FILE_UPLOAD_ERROR and as context the structure from SRS IOTHUBCLIENT 02 051. ]*/
2347 threadInfo->uploadBlobSavedData.iotHubClientFileUploadCallback(upload_result, threadInfo->context);
2348 }
2349
2350 return markThreadReadyToBeGarbageCollected(threadInfo);
2351}
2352
2353IOTHUB_CLIENT_RESULT IoTHubClientCore_UploadToBlobAsync(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const char* destinationFileName, const unsigned char* source, size_t size, IOTHUB_CLIENT_FILE_UPLOAD_CALLBACK iotHubClientFileUploadCallback, void* context)
2354{
2355 IOTHUB_CLIENT_RESULT result;
2356 /*Codes_SRS_IOTHUBCLIENT_02_047: [ If iotHubClientHandle is NULL then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
2357 /*Codes_SRS_IOTHUBCLIENT_02_048: [ If destinationFileName is NULL then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
2358 /*Codes_SRS_IOTHUBCLIENT_02_049: [ If source is NULL and size is greated than 0 then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_INVALID_ARG. ]*/
2359 if (
2360 (iotHubClientHandle == NULL) ||
2361 (destinationFileName == NULL) ||
2362 ((source == NULL) && (size > 0))
2363 )
2364 {
2365 LogError("invalid parameters IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle = %p , const char* destinationFileName = %s, const unsigned char* source= %p, size_t size = %lu, IOTHUB_CLIENT_FILE_UPLOAD_CALLBACK iotHubClientFileUploadCallback = %p, void* context = %p",
2366 iotHubClientHandle,
2367 destinationFileName,
2368 source,
2369 (unsigned long)size,
2370 iotHubClientFileUploadCallback,
2371 context
2372 );
2373 result = IOTHUB_CLIENT_INVALID_ARG;
2374 }
2375 else
2376 {
2377 /*Codes_SRS_IOTHUBCLIENT_02_051: [IoTHubClient_UploadToBlobAsync shall copy the souce, size, iotHubClientFileUploadCallback, context into a structure.]*/
2378 HTTPWORKER_THREAD_INFO *threadInfo = allocateUploadToBlob(destinationFileName, iotHubClientHandle, context);
2379 if (threadInfo == NULL)
2380 {
2381 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2382 LogError("unable to create upload thread info");
2383 result = IOTHUB_CLIENT_ERROR;
2384 }
2385 else if ((result = initializeUploadToBlobData(threadInfo, source, size, iotHubClientFileUploadCallback)) != IOTHUB_CLIENT_OK)
2386 {
2387 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2388 LogError("unable to initialize upload blob info");
2389 result = IOTHUB_CLIENT_ERROR;
2390 }
2391 /*Codes_SRS_IOTHUBCLIENT_02_052: [ IoTHubClient_UploadToBlobAsync shall spawn a thread passing the structure build in SRS IOTHUBCLIENT 02 051 as thread data.]*/
2392 else if ((result = startHttpWorkerThread(iotHubClientHandle, threadInfo, uploadingThread)) != IOTHUB_CLIENT_OK)
2393 {
2394 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2395 LogError("unable to start upload thread");
2396 freeHttpWorkerThreadInfo(threadInfo);
2397 }
2398 else
2399 {
2400 result = IOTHUB_CLIENT_OK;
2401 }
2402 }
2403
2404 return result;
2405}
2406
2407static int uploadMultipleBlock_thread(void* data)
2408{
2409 HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)data;
2410 IOTHUB_CLIENT_CORE_LL_HANDLE llHandle = threadInfo->iotHubClientHandle->IoTHubClientLLHandle;
2411
2412 /*Codes_SRS_IOTHUBCLIENT_99_078: [ The thread shall call `IoTHubClientCore_LL_UploadMultipleBlocksToBlob` or `IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx` passing the information packed in the structure. ]*/
2413 IOTHUB_CLIENT_RESULT result;
2414
2415 srand((unsigned int)get_time(NULL));
2416
2417 if (threadInfo->uploadBlobMultiblockSavedData.getDataCallback != NULL)
2418 {
2419 result = IoTHubClientCore_LL_UploadMultipleBlocksToBlob(llHandle, threadInfo->destinationFileName, threadInfo->uploadBlobMultiblockSavedData.getDataCallback, threadInfo->context);
2420 }
2421 else
2422 {
2423 result = IoTHubClientCore_LL_UploadMultipleBlocksToBlobEx(llHandle, threadInfo->destinationFileName, threadInfo->uploadBlobMultiblockSavedData.getDataCallbackEx, threadInfo->context);
2424 }
2425 (void)markThreadReadyToBeGarbageCollected(threadInfo);
2426
2427 return result;
2428}
2429
2430IOTHUB_CLIENT_RESULT IoTHubClientCore_UploadMultipleBlocksToBlobAsync(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const char* destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX getDataCallbackEx, void* context)
2431{
2432 IOTHUB_CLIENT_RESULT result;
2433
2434 /*Codes_SRS_IOTHUBCLIENT_99_072: [ If `iotHubClientHandle` is `NULL` then `IoTHubClient_UploadMultipleBlocksToBlobAsync(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2435 /*Codes_SRS_IOTHUBCLIENT_99_073: [ If `destinationFileName` is `NULL` then `IoTHubClient_UploadMultipleBlocksToBlobAsync(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2436 /*Codes_SRS_IOTHUBCLIENT_99_074: [ If `getDataCallback` is `NULL` then `IoTHubClient_UploadMultipleBlocksToBlobAsync(Ex)` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
2437 if (
2438 (iotHubClientHandle == NULL) ||
2439 (destinationFileName == NULL) ||
2440 ((getDataCallback == NULL) && (getDataCallbackEx == NULL))
2441 )
2442 {
2443 LogError("invalid parameters iotHubClientHandle = %p , destinationFileName = %p, getDataCallback = %p, getDataCallbackEx = %p",
2444 iotHubClientHandle,
2445 destinationFileName,
2446 getDataCallback,
2447 getDataCallbackEx
2448 );
2449 result = IOTHUB_CLIENT_INVALID_ARG;
2450 }
2451 else
2452 {
2453 /*Codes_SRS_IOTHUBCLIENT_99_075: [ `IoTHubClient_UploadMultipleBlocksToBlobAsync(Ex)` shall copy the `destinationFileName`, `getDataCallback`, `context` and `iotHubClientHandle` into a structure. ]*/
2454 HTTPWORKER_THREAD_INFO *threadInfo = allocateUploadToBlob(destinationFileName, iotHubClientHandle, context);
2455 if (threadInfo == NULL)
2456 {
2457 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2458 LogError("unable to create upload thread info");
2459 result = IOTHUB_CLIENT_ERROR;
2460 }
2461 else
2462 {
2463 /*Codes_SRS_IOTHUBCLIENT_99_075: [ `IoTHubClient_UploadMultipleBlocksToBlobAsync(Ex)` shall copy the `destinationFileName`, `getDataCallback`, `context` and `iotHubClientHandle` into a structure. ]*/
2464 threadInfo->uploadBlobMultiblockSavedData.getDataCallback = getDataCallback;
2465 threadInfo->uploadBlobMultiblockSavedData.getDataCallbackEx = getDataCallbackEx;
2466
2467 if ((result = startHttpWorkerThread(iotHubClientHandle, threadInfo, uploadMultipleBlock_thread)) != IOTHUB_CLIENT_OK)
2468 {
2469 /*Codes_SRS_IOTHUBCLIENT_02_053: [ If copying to the structure or spawning the thread fails, then IoTHubClient_UploadToBlobAsync shall fail and return IOTHUB_CLIENT_ERROR. ]*/
2470 LogError("unable to start upload thread");
2471 freeHttpWorkerThreadInfo(threadInfo);
2472 }
2473 else
2474 {
2475 /*Codes_SRS_IOTHUBCLIENT_99_077: [ If copying to the structure and spawning the thread succeeds, then `IoTHubClient_UploadMultipleBlocksToBlobAsync(Ex)` shall return `IOTHUB_CLIENT_OK`. ]*/
2476 result = IOTHUB_CLIENT_OK;
2477 }
2478 }
2479 }
2480 return result;
2481}
2482
2483#endif /*DONT_USE_UPLOADTOBLOB*/
2484
2485IOTHUB_CLIENT_RESULT IoTHubClientCore_SendEventToOutputAsync(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, IOTHUB_MESSAGE_HANDLE eventMessageHandle, const char* outputName, IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK eventConfirmationCallback, void* userContextCallback)
2486{
2487 IOTHUB_CLIENT_RESULT result;
2488
2489 if ((iotHubClientHandle == NULL) || (outputName == NULL) || (eventMessageHandle == NULL))
2490 {
2491 // Codes_SRS_IOTHUBCLIENT_31_100: [ If `iotHubClientHandle`, `outputName`, or `eventConfirmationCallback` is `NULL`, `IoTHubClient_SendEventToOutputAsync` shall return `IOTHUB_CLIENT_INVALID_ARG`. ]
2492 LogError("Invalid argument (iotHubClientHandle=%p, outputName=%p, eventMessageHandle=%p)", iotHubClientHandle, outputName, eventMessageHandle);
2493 result = IOTHUB_CLIENT_INVALID_ARG;
2494 }
2495 else
2496 {
2497 // Codes_SRS_IOTHUBCLIENT_31_101: [ `IoTHubClient_SendEventToOutputAsync` shall set the outputName of the message to send. ]
2498 if (IoTHubMessage_SetOutputName(eventMessageHandle, outputName) != IOTHUB_MESSAGE_OK)
2499 {
2500 LogError("IoTHubMessage_SetOutputName failed");
2501 result = IOTHUB_CLIENT_ERROR;
2502 }
2503 // Codes_SRS_IOTHUBCLIENT_31_102: [ `IoTHubClient_SendEventToOutputAsync` shall invoke `IoTHubClient_SendEventAsync` to send the message. ]
2504 else if ((result = IoTHubClientCore_SendEventAsync(iotHubClientHandle, eventMessageHandle, eventConfirmationCallback, userContextCallback)) != IOTHUB_CLIENT_OK)
2505 {
2506 LogError("Call into IoTHubClient_SendEventAsync failed, result=%d", result);
2507 }
2508 }
2509
2510 return result;
2511}
2512
2513
2514IOTHUB_CLIENT_RESULT IoTHubClientCore_SetInputMessageCallback(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const char* inputName, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC eventHandlerCallback, void* userContextCallback)
2515{
2516 IOTHUB_CLIENT_RESULT result;
2517
2518 if (iotHubClientHandle == NULL)
2519 {
2520 result = IOTHUB_CLIENT_INVALID_ARG;
2521 LogError("NULL iothubClientHandle");
2522 }
2523 else
2524 {
2525 IOTHUB_CLIENT_CORE_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_CORE_INSTANCE*)iotHubClientHandle;
2526
2527 // Codes_SRS_IOTHUBCLIENT_31_098: [ `IoTHubClient_SetMessageCallback` shall start the worker thread if it was not previously started. ]
2528 if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
2529 {
2530 result = IOTHUB_CLIENT_ERROR;
2531 LogError("Could not start worker thread");
2532 }
2533 else
2534 {
2535 if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
2536 {
2537 result = IOTHUB_CLIENT_ERROR;
2538 LogError("Could not acquire lock");
2539 }
2540 else
2541 {
2542 // Codes_SRS_IOTHUBCLIENT_31_099: [ `IoTHubClient_SetMessageCallback` shall call `IoTHubClient_LL_SetInputMessageCallback`, passing its input arguments ]
2543 IOTHUB_INPUTMESSAGE_CALLBACK_CONTEXT inputMessageCallbackContext;
2544 inputMessageCallbackContext.iotHubClientHandle = iotHubClientHandle;
2545 inputMessageCallbackContext.eventHandlerCallback = eventHandlerCallback;
2546 inputMessageCallbackContext.userContextCallback = userContextCallback;
2547
2548 result = IoTHubClientCore_LL_SetInputMessageCallbackEx(iotHubClientInstance->IoTHubClientLLHandle, inputName, iothub_ll_inputmessage_callback, (void*)&inputMessageCallbackContext, sizeof(inputMessageCallbackContext));
2549 (void)Unlock(iotHubClientInstance->LockHandle);
2550 }
2551 }
2552 }
2553
2554 return result;
2555}
2556
2557#ifdef USE_EDGE_MODULES
2558
2559HTTPWORKER_THREAD_INFO * allocateMethodInvoke(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const char* deviceId, const char* moduleId, const char* methodName, const char* methodPayload, unsigned int timeout, IOTHUB_METHOD_INVOKE_CALLBACK methodInvokeCallback, void* context)
2560{
2561 HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)malloc(sizeof(HTTPWORKER_THREAD_INFO));
2562 if (threadInfo == NULL)
2563 {
2564 LogError("unable to allocate thread object");
2565 }
2566 else
2567 {
2568 memset(threadInfo, 0, sizeof(HTTPWORKER_THREAD_INFO));
2569 threadInfo->workerThreadType = HTTPWORKER_THREAD_INVOKE_METHOD;
2570 threadInfo->iotHubClientHandle = iotHubClientHandle;
2571 threadInfo->context = context;
2572
2573 threadInfo->invokeMethodSavedData.timeout = timeout;
2574 threadInfo->invokeMethodSavedData.methodInvokeCallback = methodInvokeCallback;
2575
2576 if ((mallocAndStrcpy_s((char**)&threadInfo->invokeMethodSavedData.deviceId, deviceId) != 0) ||
2577 ((moduleId != NULL) && mallocAndStrcpy_s((char**)&threadInfo->invokeMethodSavedData.moduleId, moduleId) != 0) ||
2578 (mallocAndStrcpy_s((char**)&threadInfo->invokeMethodSavedData.methodName, methodName) != 0) ||
2579 (mallocAndStrcpy_s((char**)&threadInfo->invokeMethodSavedData.methodPayload, methodPayload) != 0))
2580 {
2581 LogError("Allocating resources failed");
2582 freeHttpWorkerThreadInfo(threadInfo);
2583 threadInfo = NULL;
2584 }
2585 else if ((threadInfo->lockGarbage = Lock_Init()) == NULL)
2586 {
2587 LogError("unable to allocate a lock");
2588 freeHttpWorkerThreadInfo(threadInfo);
2589 threadInfo = NULL;
2590 }
2591 }
2592
2593 return threadInfo;
2594}
2595
2596static int uploadMethodInvoke_thread(void* data)
2597{
2598 IOTHUB_CLIENT_RESULT result;
2599
2600 HTTPWORKER_THREAD_INFO* threadInfo = (HTTPWORKER_THREAD_INFO*)data;
2601
2602 srand((unsigned int)get_time(NULL));
2603
2604 int responseStatus;
2605 unsigned char* responsePayload = NULL;
2606 size_t responsePayloadSize;
2607
2608 result = IoTHubClientCore_LL_GenericMethodInvoke(threadInfo->iotHubClientHandle->IoTHubClientLLHandle,
2609 threadInfo->invokeMethodSavedData.deviceId,
2610 threadInfo->invokeMethodSavedData.moduleId,
2611 threadInfo->invokeMethodSavedData.methodName,
2612 threadInfo->invokeMethodSavedData.methodPayload,
2613 threadInfo->invokeMethodSavedData.timeout,
2614 &responseStatus,
2615 &responsePayload,
2616 &responsePayloadSize);
2617
2618 if (threadInfo->invokeMethodSavedData.methodInvokeCallback != NULL)
2619 {
2620 threadInfo->invokeMethodSavedData.methodInvokeCallback(result, responseStatus, responsePayload, responsePayloadSize, threadInfo->context);
2621 }
2622
2623 if (responsePayload != NULL)
2624 {
2625 free(responsePayload);
2626 }
2627
2628 (void)markThreadReadyToBeGarbageCollected(threadInfo);
2629 return result;
2630}
2631
2632
2633IOTHUB_CLIENT_RESULT IoTHubClientCore_GenericMethodInvoke(IOTHUB_CLIENT_CORE_HANDLE iotHubClientHandle, const char* deviceId, const char* moduleId, const char* methodName, const char* methodPayload, unsigned int timeout, IOTHUB_METHOD_INVOKE_CALLBACK methodInvokeCallback, void* context)
2634{
2635 IOTHUB_CLIENT_RESULT result;
2636 HTTPWORKER_THREAD_INFO *threadInfo;
2637
2638 if ((iotHubClientHandle == NULL) || (deviceId == NULL) || (methodName == NULL) || (methodPayload == NULL))
2639 {
2640 LogError("Invalid argument (iotHubClientHandle=%p, deviceId=%p, methodName=%p, methodPayload=%p)", iotHubClientHandle, deviceId, methodName, methodPayload);
2641 result = IOTHUB_CLIENT_INVALID_ARG;
2642 }
2643 else if ((threadInfo = allocateMethodInvoke(iotHubClientHandle, deviceId, moduleId, methodName, methodPayload, timeout, methodInvokeCallback, context)) == NULL)
2644 {
2645 LogError("failed allocating method invoke thread info");
2646 result = IOTHUB_CLIENT_ERROR;
2647 }
2648 else if ((result = startHttpWorkerThread(iotHubClientHandle, threadInfo, uploadMethodInvoke_thread)) != IOTHUB_CLIENT_OK)
2649 {
2650 LogError("unable to start method invoke thread");
2651 freeHttpWorkerThreadInfo(threadInfo);
2652 }
2653 else
2654 {
2655 result = IOTHUB_CLIENT_OK;
2656 }
2657 return result;
2658}
2659#endif /* USE_EDGE_MODULES */
2660
Note: See TracBrowser for help on using the repository browser.