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

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

WolfSSLとAzure IoT SDKを更新

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