source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/provisioning_client/src/prov_transport_mqtt_common.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: 53.4 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdint.h>
6#include <stdbool.h>
7#include <ctype.h>
8#include <limits.h>
9#include <inttypes.h>
10
11#include "azure_c_shared_utility/gballoc.h"
12#include "azure_c_shared_utility/platform.h"
13#include "azure_c_shared_utility/xlogging.h"
14#include "azure_c_shared_utility/crt_abstractions.h"
15#include "azure_c_shared_utility/tlsio.h"
16#include "azure_c_shared_utility/shared_util_options.h"
17#include "azure_c_shared_utility/http_proxy_io.h"
18#include "azure_c_shared_utility/urlencode.h"
19#include "azure_c_shared_utility/http_proxy_io.h"
20
21#include "azure_prov_client/internal/prov_transport_mqtt_common.h"
22#include "azure_umqtt_c/mqtt_client.h"
23
24#include "azure_prov_client/prov_client_const.h"
25
26#define SUBSCRIBE_TOPIC_COUNT 1
27
28static const char* const MQTT_SUBSCRIBE_TOPIC = "$dps/registrations/res/#";
29static const char* const MQTT_USERNAME_FMT = "%s/registrations/%s/api-version=%s&ClientVersion=%s";
30static const char* const MQTT_REGISTER_MESSAGE_FMT = "$dps/registrations/PUT/iotdps-register/?$rid=%d";
31static const char* const MQTT_STATUS_MESSAGE_FMT = "$dps/registrations/GET/iotdps-get-operationstatus/?$rid=%d&operationId=%s";
32static const char* const MQTT_TOPIC_STATUS_PREFIX = "$dps/registrations/res/";
33static const char* const KEY_NAME_VALUE = "registration";
34
35typedef enum MQTT_TRANSPORT_STATE_TAG
36{
37 MQTT_STATE_IDLE,
38 MQTT_STATE_DISCONNECTED,
39 MQTT_STATE_CONNECTING,
40 MQTT_STATE_CONNECTED,
41
42 MQTT_STATE_SUBSCRIBING,
43 MQTT_STATE_SUBSCRIBED,
44
45 MQTT_STATE_ERROR
46} MQTT_TRANSPORT_STATE;
47
48typedef enum PROV_TRANSPORT_STATE_TAG
49{
50 TRANSPORT_CLIENT_STATE_IDLE,
51
52 TRANSPORT_CLIENT_STATE_REG_SEND,
53 TRANSPORT_CLIENT_STATE_REG_SENT,
54 TRANSPORT_CLIENT_STATE_REG_RECV,
55
56 TRANSPORT_CLIENT_STATE_STATUS_SEND,
57 TRANSPORT_CLIENT_STATE_STATUS_SENT,
58 TRANSPORT_CLIENT_STATE_STATUS_RECV,
59
60 TRANSPORT_CLIENT_STATE_TRANSIENT,
61 TRANSPORT_CLIENT_STATE_ERROR
62} PROV_TRANSPORT_STATE;
63
64typedef struct PROV_TRANSPORT_MQTT_INFO_TAG
65{
66 PROV_DEVICE_TRANSPORT_REGISTER_CALLBACK register_data_cb;
67 void* user_ctx;
68 PROV_DEVICE_TRANSPORT_STATUS_CALLBACK status_cb;
69 void* status_ctx;
70 PROV_TRANSPORT_CHALLENGE_CALLBACK challenge_cb;
71 void* challenge_ctx;
72 PROV_TRANSPORT_JSON_PARSE json_parse_cb;
73 PROV_TRANSPORT_CREATE_JSON_PAYLOAD json_create_cb;
74 void* json_ctx;
75
76 MQTT_CLIENT_HANDLE mqtt_client;
77
78 char* hostname;
79
80 HTTP_PROXY_OPTIONS proxy_option;
81
82 char* x509_cert;
83 char* private_key;
84
85 char* certificate;
86
87 BUFFER_HANDLE ek;
88 BUFFER_HANDLE srk;
89 char* registration_id;
90 char* scope_id;
91 char* sas_token;
92
93 char* operation_id;
94
95 char* api_version;
96 char* payload_data;
97
98 bool log_trace;
99
100 uint16_t packet_id;
101
102 TRANSPORT_HSM_TYPE hsm_type;
103
104 PROV_MQTT_TRANSPORT_IO transport_io_cb;
105
106 PROV_TRANSPORT_STATE transport_state;
107 MQTT_TRANSPORT_STATE mqtt_state;
108
109 XIO_HANDLE transport_io;
110 uint32_t retry_after_value;
111
112 PROV_TRANSPORT_ERROR_CALLBACK error_cb;
113 void* error_ctx;
114} PROV_TRANSPORT_MQTT_INFO;
115
116static uint16_t get_next_packet_id(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
117{
118 if (mqtt_info->packet_id + 1 >= USHRT_MAX)
119 {
120 mqtt_info->packet_id = 1;
121 }
122 else
123 {
124 mqtt_info->packet_id++;
125 }
126 return mqtt_info->packet_id;
127}
128
129static void mqtt_error_callback(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_ERROR error, void* user_ctx)
130{
131 (void)handle;
132 if (user_ctx != NULL)
133 {
134 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)user_ctx;
135 switch (error)
136 {
137 case MQTT_CLIENT_CONNECTION_ERROR:
138 case MQTT_CLIENT_COMMUNICATION_ERROR:
139 LogError("MQTT communication error");
140 break;
141 case MQTT_CLIENT_NO_PING_RESPONSE:
142 LogError("Mqtt Ping Response was not encountered. Reconnecting device...");
143 break;
144
145 case MQTT_CLIENT_PARSE_ERROR:
146 case MQTT_CLIENT_MEMORY_ERROR:
147 case MQTT_CLIENT_UNKNOWN_ERROR:
148 default:
149 {
150 LogError("INTERNAL ERROR: unexpected error value received %d", error);
151 break;
152 }
153 }
154 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
155 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
156 }
157 else
158 {
159 LogError("mqtt_error_callback was invoked with a NULL context");
160 }
161}
162
163#ifndef NO_LOGGING
164static const char* retrieve_mqtt_return_codes(CONNECT_RETURN_CODE rtn_code)
165{
166 switch (rtn_code)
167 {
168 case CONNECTION_ACCEPTED:
169 return "Accepted";
170 case CONN_REFUSED_UNACCEPTABLE_VERSION:
171 return "Unacceptable Version";
172 case CONN_REFUSED_ID_REJECTED:
173 return "Id Rejected";
174 case CONN_REFUSED_SERVER_UNAVAIL:
175 return "Server Unavailable";
176 case CONN_REFUSED_BAD_USERNAME_PASSWORD:
177 return "Bad Username/Password";
178 case CONN_REFUSED_NOT_AUTHORIZED:
179 return "Not Authorized";
180 case CONN_REFUSED_UNKNOWN:
181 default:
182 return "Unknown";
183 }
184}
185#endif // NO_LOGGING
186
187static void mqtt_operation_complete_callback(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_RESULT event_result, const void* msg_info, void* user_ctx)
188{
189 (void)handle;
190 (void)msg_info;
191 if (user_ctx != NULL)
192 {
193 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)user_ctx;
194 switch (event_result)
195 {
196 case MQTT_CLIENT_ON_CONNACK:
197 {
198 const CONNECT_ACK* connack = (const CONNECT_ACK*)msg_info;
199 if (connack != NULL)
200 {
201 if (connack->returnCode == CONNECTION_ACCEPTED)
202 {
203 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_052: [ Once the mqtt CONNACK is recieved prov_transport_common_mqtt_dowork shall set mqtt_state to MQTT_STATE_CONNECTED ] */
204 mqtt_info->mqtt_state = MQTT_STATE_CONNECTED;
205 }
206 else
207 {
208 LogError("Connection Not Accepted: 0x%x: %s", connack->returnCode, retrieve_mqtt_return_codes(connack->returnCode));
209 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
210 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
211 if (mqtt_info->error_cb != NULL)
212 {
213 mqtt_info->error_cb(PROV_DEVICE_ERROR_KEY_UNAUTHORIZED, mqtt_info->error_ctx);
214 }
215 }
216 }
217 else
218 {
219 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
220 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
221 LogError("CONNECT_ACK packet is NULL");
222 }
223 break;
224 }
225 case MQTT_CLIENT_ON_SUBSCRIBE_ACK:
226 {
227 const SUBSCRIBE_ACK* suback = (const SUBSCRIBE_ACK*)msg_info;
228 if (suback != NULL)
229 {
230 size_t index = 0;
231 for (index = 0; index < suback->qosCount; index++)
232 {
233 if (suback->qosReturn[index] == DELIVER_FAILURE)
234 {
235 LogError("Subscribe delivery failure of subscribe %lu", (unsigned long)index);
236 break;
237 }
238 }
239
240 if (index == suback->qosCount)
241 {
242 mqtt_info->mqtt_state = MQTT_STATE_SUBSCRIBED;
243 }
244 else
245 {
246 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
247 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
248 }
249 }
250 else
251 {
252 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
253 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
254 LogError("SUBSCRIBE_ACK packet is NULL");
255 }
256 break;
257 }
258 case MQTT_CLIENT_ON_PUBLISH_ACK:
259 case MQTT_CLIENT_ON_PUBLISH_COMP:
260 case MQTT_CLIENT_ON_PUBLISH_RECV:
261 case MQTT_CLIENT_ON_PUBLISH_REL:
262 case MQTT_CLIENT_ON_DISCONNECT:
263 case MQTT_CLIENT_ON_UNSUBSCRIBE_ACK:
264 break;
265 default:
266 LogError("Unknown MQTT_CLIENT_EVENT_RESULT item %d", (int)event_result);
267 break;
268 }
269 }
270 else
271 {
272 LogError("mqtt_operation_complete_callback was invoked with a NULL context");
273 }
274}
275
276static int get_retry_after_property(const char* topic_name, PROV_TRANSPORT_MQTT_INFO* mqtt_info)
277{
278 int result = MU_FAILURE;
279
280 const char* iterator = topic_name;
281
282 size_t topic_len = strlen(iterator);
283 size_t retry_len = strlen(RETRY_AFTER_KEY_VALUE);
284 while (iterator != NULL && *iterator != '\0')
285 {
286 if (topic_len > retry_len)
287 {
288 if (memcmp(iterator, RETRY_AFTER_KEY_VALUE, retry_len) == 0)
289 {
290 // send the retry-after value to parse
291 mqtt_info->retry_after_value = parse_retry_after_value(iterator + retry_len + 1);
292 result = 0;
293 break;
294 }
295 }
296 else
297 {
298 // Topic string is not there
299 result = MU_FAILURE;
300 break;
301 }
302 iterator++;
303 topic_len--;
304 }
305 return result;
306}
307
308static void mqtt_notification_callback(MQTT_MESSAGE_HANDLE handle, void* user_ctx)
309{
310 if (user_ctx != NULL)
311 {
312 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)user_ctx;
313
314 bool is_transient_error = false;
315 const char* topic_resp = mqttmessage_getTopicName(handle);
316 if (topic_resp != NULL)
317 {
318 // Extract the registration status
319 size_t status_pos = strlen(MQTT_TOPIC_STATUS_PREFIX);
320 if (memcmp(MQTT_TOPIC_STATUS_PREFIX, topic_resp, status_pos) == 0)
321 {
322 // If the status code is >= 429 then this is a transient error
323 long status_code = atol(topic_resp + status_pos);
324 if (status_code >= PROV_STATUS_CODE_TRANSIENT_ERROR)
325 {
326 // On transient error reset the transport to send state
327 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_TRANSIENT;
328 is_transient_error = true;
329 }
330 }
331
332 // Get the retry after field on failures this value will
333 // be set to the default value
334 (void)get_retry_after_property(topic_resp, mqtt_info);
335 }
336 else
337 {
338 LogError("failure topic name is NULL");
339 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
340 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
341 }
342
343 if (!is_transient_error)
344 {
345 const APP_PAYLOAD* payload = mqttmessage_getApplicationMsg(handle);
346 if (payload != NULL)
347 {
348 if (mqtt_info->payload_data != NULL)
349 {
350 free(mqtt_info->payload_data);
351 mqtt_info->payload_data = NULL;
352 }
353
354 if ((mqtt_info->payload_data = malloc(payload->length + 1)) == NULL)
355 {
356 LogError("failure allocating payload data");
357 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
358 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
359 }
360 else
361 {
362 memset(mqtt_info->payload_data, 0, payload->length + 1);
363 memcpy(mqtt_info->payload_data, payload->message, payload->length);
364 if (mqtt_info->transport_state == TRANSPORT_CLIENT_STATE_REG_SENT)
365 {
366 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_REG_RECV;
367 }
368 else
369 {
370 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_RECV;
371 }
372 }
373 }
374 else
375 {
376 LogError("failure NULL message encountered from umqtt");
377 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
378 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
379 }
380 }
381 }
382 else
383 {
384 LogError("mqtt_notification_callback was invoked with a NULL context");
385 }
386}
387
388static int send_mqtt_message(PROV_TRANSPORT_MQTT_INFO* mqtt_info, const char* msg_topic)
389{
390 int result;
391 MQTT_MESSAGE_HANDLE msg_handle = NULL;
392 char* prov_payload;
393
394 if ((prov_payload = mqtt_info->json_create_cb(NULL, NULL, mqtt_info->json_ctx)) == NULL)
395 {
396 LogError("Failed creating json mqtt payload");
397 result = MU_FAILURE;
398 }
399 else if ((msg_handle = mqttmessage_create_in_place(get_next_packet_id(mqtt_info), msg_topic, DELIVER_AT_MOST_ONCE, (const uint8_t*)prov_payload, strlen(prov_payload))) == NULL)
400 {
401 LogError("Failed creating mqtt message");
402 result = MU_FAILURE;
403 free(prov_payload);
404 }
405 else
406 {
407 if (mqtt_client_publish(mqtt_info->mqtt_client, msg_handle) != 0)
408 {
409 LogError("Failed publishing client message");
410 result = MU_FAILURE;
411 }
412 else
413 {
414 result = 0;
415 }
416 mqttmessage_destroy(msg_handle);
417 free(prov_payload);
418 }
419 return result;
420}
421
422static int send_register_message(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
423{
424 int result;
425 char* msg_topic;
426
427 size_t length = strlen(MQTT_REGISTER_MESSAGE_FMT) + 8;
428 if ((msg_topic = malloc(length + 1)) == NULL)
429 {
430 LogError("Failed allocating mqtt registration message");
431 result = MU_FAILURE;
432 }
433 else if (sprintf(msg_topic, MQTT_REGISTER_MESSAGE_FMT, mqtt_info->packet_id) <= 0)
434 {
435 LogError("Failed setting registration message");
436 free(msg_topic);
437 result = MU_FAILURE;
438 }
439 else
440 {
441 result = send_mqtt_message(mqtt_info, msg_topic);
442 free(msg_topic);
443 }
444 return result;
445}
446
447static int send_operation_status_message(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
448{
449 int result;
450 char* msg_topic;
451
452 size_t length = strlen(MQTT_STATUS_MESSAGE_FMT) + strlen(mqtt_info->operation_id) + 8;
453 if ((msg_topic = malloc(length + 1)) == NULL)
454 {
455 LogError("Failed allocating mqtt status message");
456 result = MU_FAILURE;
457 }
458 else if (sprintf(msg_topic, MQTT_STATUS_MESSAGE_FMT, mqtt_info->packet_id, mqtt_info->operation_id) <= 0)
459 {
460 LogError("Failed creating mqtt status message");
461 free(msg_topic);
462 result = MU_FAILURE;
463 }
464 else
465 {
466 result = send_mqtt_message(mqtt_info, msg_topic);
467 free(msg_topic);
468 }
469 return result;
470}
471
472static int subscribe_to_topic(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
473{
474 int result;
475 SUBSCRIBE_PAYLOAD subscribe[SUBSCRIBE_TOPIC_COUNT];
476 subscribe[0].subscribeTopic = MQTT_SUBSCRIBE_TOPIC;
477 subscribe[0].qosReturn = DELIVER_AT_LEAST_ONCE;
478
479 if (mqtt_client_subscribe(mqtt_info->mqtt_client, get_next_packet_id(mqtt_info), subscribe, SUBSCRIBE_TOPIC_COUNT) != 0)
480 {
481 LogError("Failed subscribing to topic.");
482 result = MU_FAILURE;
483 }
484 else
485 {
486 result = 0;
487 }
488 return result;
489}
490
491static char* construct_username(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
492{
493 char* result;
494 size_t length;
495
496 length = strlen(MQTT_USERNAME_FMT) + strlen(mqtt_info->registration_id) + strlen(mqtt_info->scope_id) + strlen(mqtt_info->api_version) + strlen(PROV_DEVICE_CLIENT_VERSION);
497 if ((result = malloc(length + 1)) == NULL)
498 {
499 LogError("Failure allocating username");
500 result = NULL;
501 }
502 else if (sprintf(result, MQTT_USERNAME_FMT, mqtt_info->scope_id, mqtt_info->registration_id, mqtt_info->api_version, PROV_DEVICE_CLIENT_VERSION) <= 0)
503 {
504 LogError("Failure creating mqtt username");
505 free(result);
506 result = NULL;
507 }
508 return result;
509}
510
511static int create_transport_io_object(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
512{
513 int result;
514 if (mqtt_info->transport_io == NULL)
515 {
516 HTTP_PROXY_OPTIONS* transport_proxy;
517 if (mqtt_info->proxy_option.host_address != NULL)
518 {
519 transport_proxy = &mqtt_info->proxy_option;
520 }
521 else
522 {
523 transport_proxy = NULL;
524 }
525
526 if ((mqtt_info->transport_io = mqtt_info->transport_io_cb(mqtt_info->hostname, transport_proxy)) == NULL)
527 {
528 LogError("Failure calling transport_io callback");
529 result = MU_FAILURE;
530 }
531 else
532 {
533 result = 0;
534 }
535 }
536 else
537 {
538 result = 0;
539 }
540 return result;
541}
542
543static int construct_transport(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
544{
545 int result;
546
547 if (create_transport_io_object(mqtt_info) != 0)
548 {
549 LogError("Failed constructing transport io");
550 result = MU_FAILURE;
551 }
552 else
553 {
554 if (mqtt_info->certificate != NULL && xio_setoption(mqtt_info->transport_io, OPTION_TRUSTED_CERT, mqtt_info->certificate) != 0)
555 {
556 LogError("Failure setting trusted certs");
557 result = MU_FAILURE;
558 xio_destroy(mqtt_info->transport_io);
559 mqtt_info->transport_io = NULL;
560 }
561 else if (mqtt_info->hsm_type == TRANSPORT_HSM_TYPE_X509)
562 {
563 if (mqtt_info->x509_cert != NULL && mqtt_info->private_key != NULL)
564 {
565 if (xio_setoption(mqtt_info->transport_io, OPTION_X509_ECC_CERT, mqtt_info->x509_cert) != 0)
566 {
567 LogError("Failure setting x509 cert on xio");
568 xio_destroy(mqtt_info->transport_io);
569 mqtt_info->transport_io = NULL;
570 result = MU_FAILURE;
571 }
572 else if (xio_setoption(mqtt_info->transport_io, OPTION_X509_ECC_KEY, mqtt_info->private_key) != 0)
573 {
574 LogError("Failure setting x509 key on xio");
575 if (mqtt_info->error_cb != NULL)
576 {
577 mqtt_info->error_cb(PROV_DEVICE_ERROR_KEY_FAIL, mqtt_info->error_ctx);
578 }
579 xio_destroy(mqtt_info->transport_io);
580 mqtt_info->transport_io = NULL;
581 result = MU_FAILURE;
582 }
583 else
584 {
585 result = 0;
586 }
587 }
588 else
589 {
590 LogError("x509 certificate is NULL");
591 xio_destroy(mqtt_info->transport_io);
592 mqtt_info->transport_io = NULL;
593 result = MU_FAILURE;
594 }
595 }
596 else
597 {
598 result = 0;
599 }
600 }
601 return result;
602}
603
604static int create_connection(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
605{
606 int result;
607 MQTT_CLIENT_OPTIONS options;
608 memset(&options, 0, sizeof(MQTT_CLIENT_OPTIONS));
609
610 char* username_info;
611
612 if ((username_info = construct_username(mqtt_info)) == NULL)
613 {
614 LogError("Failure creating username info");
615 result = MU_FAILURE;
616 }
617 else if (construct_transport(mqtt_info) != 0)
618 {
619 LogError("Failure constructing transport");
620 free(username_info);
621 result = MU_FAILURE;
622 }
623 else if ((mqtt_info->hsm_type == TRANSPORT_HSM_TYPE_SYMM_KEY) && (options.password = mqtt_info->challenge_cb(NULL, 0, KEY_NAME_VALUE, mqtt_info->challenge_ctx)) == NULL)
624 {
625 LogError("Failure retrieving sas token from key");
626 xio_destroy(mqtt_info->transport_io);
627 mqtt_info->transport_io = NULL;
628 free(username_info);
629 result = MU_FAILURE;
630 }
631 else
632 {
633 (void)mqtt_client_set_trace(mqtt_info->mqtt_client, mqtt_info->log_trace, false);
634
635 options.username = username_info;
636 options.clientId = mqtt_info->registration_id;
637 options.useCleanSession = 1;
638 options.log_trace = mqtt_info->log_trace;
639 options.qualityOfServiceValue = DELIVER_AT_LEAST_ONCE;
640 if (mqtt_client_connect(mqtt_info->mqtt_client, mqtt_info->transport_io, &options) != 0)
641 {
642 xio_destroy(mqtt_info->transport_io);
643 mqtt_info->transport_io = NULL;
644 LogError("Failure connecting to mqtt server");
645 result = MU_FAILURE;
646 }
647 else
648 {
649 result = 0;
650 }
651 if (options.password != NULL)
652 {
653 free(options.password);
654 }
655 free(username_info);
656 }
657 return result;
658}
659
660static void free_json_parse_info(PROV_JSON_INFO* parse_info)
661{
662 switch (parse_info->prov_status)
663 {
664 case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED:
665 BUFFER_delete(parse_info->authorization_key);
666 free(parse_info->key_name);
667 break;
668 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED:
669 BUFFER_delete(parse_info->authorization_key);
670 free(parse_info->iothub_uri);
671 free(parse_info->device_id);
672 break;
673 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING:
674 free(parse_info->operation_id);
675 break;
676 default:
677 break;
678 }
679 free(parse_info);
680}
681
682void cleanup_mqtt_data(PROV_TRANSPORT_MQTT_INFO* mqtt_info)
683{
684 free(mqtt_info->hostname);
685 free(mqtt_info->registration_id);
686 free(mqtt_info->operation_id);
687 free(mqtt_info->api_version);
688 free(mqtt_info->scope_id);
689 free(mqtt_info->certificate);
690 free((char*)mqtt_info->proxy_option.host_address);
691 free((char*)mqtt_info->proxy_option.username);
692 free((char*)mqtt_info->proxy_option.password);
693 free(mqtt_info->x509_cert);
694 free(mqtt_info->private_key);
695 free(mqtt_info->sas_token);
696 free(mqtt_info->payload_data);
697 if (mqtt_info->transport_io != NULL)
698 {
699 xio_destroy(mqtt_info->transport_io);
700 }
701 free(mqtt_info);
702}
703
704PROV_DEVICE_TRANSPORT_HANDLE prov_transport_common_mqtt_create(const char* uri, TRANSPORT_HSM_TYPE type, const char* scope_id, const char* api_version, PROV_MQTT_TRANSPORT_IO transport_io, PROV_TRANSPORT_ERROR_CALLBACK error_cb, void* error_ctx)
705{
706 PROV_TRANSPORT_MQTT_INFO* result;
707 if (uri == NULL || scope_id == NULL || api_version == NULL || transport_io == NULL)
708 {
709 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_001: [ If uri, scope_id, registration_id, api_version, or transport_io is NULL, prov_transport_common_mqtt_create shall return NULL. ] */
710 LogError("Invalid parameter specified uri: %p, scope_id: %p, api_version: %p, transport_io: %p", uri, scope_id, api_version, transport_io);
711 result = NULL;
712 }
713 else if (type == TRANSPORT_HSM_TYPE_TPM)
714 {
715 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_062: [ If TRANSPORT_HSM_TYPE is TRANSPORT_HSM_TYPE_TPM prov_transport_common_mqtt_create shall return NULL (currently TPM is not supported). ] */
716 LogError("HSM type of TPM is not supported");
717 result = NULL;
718 }
719 else
720 {
721 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_003: [ prov_transport_common_mqtt_create shall allocate a PROV_TRANSPORT_MQTT_INFO and initialize the containing fields. ] */
722 result = malloc(sizeof(PROV_TRANSPORT_MQTT_INFO));
723 if (result == NULL)
724 {
725 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_002: [ If any error is encountered, prov_transport_common_mqtt_create shall return NULL. ] */
726 LogError("Unable to allocate PROV_TRANSPORT_MQTT_INFO");
727 }
728 else
729 {
730 memset(result, 0, sizeof(PROV_TRANSPORT_MQTT_INFO));
731 if (mallocAndStrcpy_s(&result->hostname, uri) != 0)
732 {
733 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_002: [ If any error is encountered, prov_transport_common_mqtt_create shall return NULL. ] */
734 LogError("Failure allocating hostname");
735 free(result);
736 result = NULL;
737 }
738 else if (mallocAndStrcpy_s(&result->api_version, api_version) != 0)
739 {
740 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_002: [ If any error is encountered, prov_transport_common_mqtt_create shall return NULL. ] */
741 LogError("Failure allocating api_version");
742 cleanup_mqtt_data(result);
743 result = NULL;
744 }
745 else if (mallocAndStrcpy_s(&result->scope_id, scope_id) != 0)
746 {
747 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_002: [ If any error is encountered, prov_transport_common_mqtt_create shall return NULL. ] */
748 LogError("Failure allocating scope_id");
749 cleanup_mqtt_data(result);
750 result = NULL;
751 }
752 else if ((result->mqtt_client = mqtt_client_init(mqtt_notification_callback, mqtt_operation_complete_callback, result, mqtt_error_callback, result)) == NULL)
753 {
754 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_002: [ If any error is encountered, prov_transport_common_mqtt_create shall return NULL. ] */
755 LogError("Failed initializing mqtt client.");
756 cleanup_mqtt_data(result);
757 result = NULL;
758 }
759 else
760 {
761 result->transport_io_cb = transport_io;
762 result->hsm_type = type;
763 result->error_cb = error_cb;
764 result->error_ctx = error_ctx;
765 result->retry_after_value = PROV_GET_THROTTLE_TIME;
766 }
767 }
768 }
769 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_004: [ On success prov_transport_common_mqtt_create shall return a new instance of PROV_DEVICE_TRANSPORT_HANDLE. ] */
770 return result;
771}
772
773void prov_transport_common_mqtt_destroy(PROV_DEVICE_TRANSPORT_HANDLE handle)
774{
775 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_005: [ If handle is NULL, prov_transport_common_mqtt_destroy shall do nothing. ] */
776 if (handle != NULL)
777 {
778 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_006: [ prov_transport_common_mqtt_destroy shall free all resources used in this module. ] */
779 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
780 mqtt_client_deinit(mqtt_info->mqtt_client);
781 mqtt_info->mqtt_client = NULL;
782 cleanup_mqtt_data(mqtt_info);
783 }
784}
785
786int prov_transport_common_mqtt_open(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* registration_id, BUFFER_HANDLE ek, BUFFER_HANDLE srk, PROV_DEVICE_TRANSPORT_REGISTER_CALLBACK data_callback, void* user_ctx, PROV_DEVICE_TRANSPORT_STATUS_CALLBACK status_cb, void* status_ctx, PROV_TRANSPORT_CHALLENGE_CALLBACK reg_challenge_cb, void* challenge_ctx)
787{
788 int result;
789 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
790 if (mqtt_info == NULL || data_callback == NULL || status_cb == NULL || registration_id == NULL)
791 {
792 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_007: [ If handle, data_callback, or status_cb is NULL, prov_transport_common_mqtt_open shall return a non-zero value. ] */
793 LogError("Invalid parameter specified handle: %p, data_callback: %p, status_cb: %p, registration_id: %p", handle, data_callback, status_cb, registration_id);
794 result = MU_FAILURE;
795 }
796 else if ((mqtt_info->hsm_type == TRANSPORT_HSM_TYPE_TPM || mqtt_info->hsm_type == TRANSPORT_HSM_TYPE_SYMM_KEY) && reg_challenge_cb == NULL)
797 {
798 LogError("registration challenge callback must be set");
799 result = MU_FAILURE;
800 }
801 // Should never be here since TPM is not supported, so I'm going to check to ensure compliance
802 else if (ek != NULL || srk != NULL)
803 {
804 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_008: [ If hsm_type is TRANSPORT_HSM_TYPE_TPM and ek or srk is NULL, prov_transport_common_mqtt_open shall return a non-zero value. ] */
805 LogError("Invalid parameter specified ek: %p, srk: %p", ek, srk);
806 result = MU_FAILURE;
807 }
808 else if (mallocAndStrcpy_s(&mqtt_info->registration_id, registration_id) != 0)
809 {
810 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_003: [ If any error is encountered prov_transport_http_create shall return NULL. ] */
811 LogError("failure constructing registration Id");
812 result = MU_FAILURE;
813 }
814 else
815 {
816 mqtt_info->register_data_cb = data_callback;
817 mqtt_info->user_ctx = user_ctx;
818 mqtt_info->status_cb = status_cb;
819 mqtt_info->status_ctx = status_ctx;
820 mqtt_info->mqtt_state = MQTT_STATE_DISCONNECTED;
821 // Must add a false connect here due to the protocol quirk
822 //mqtt_info->status_cb(PROV_DEVICE_TRANSPORT_STATUS_CONNECTED, mqtt_info->status_ctx);
823 mqtt_info->challenge_cb = reg_challenge_cb;
824 mqtt_info->challenge_ctx = challenge_ctx;
825
826 result = 0;
827 }
828 return result;
829}
830
831int prov_transport_common_mqtt_close(PROV_DEVICE_TRANSPORT_HANDLE handle)
832{
833 int result;
834 if (handle == NULL)
835 {
836 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_011: [ If handle is NULL, prov_transport_common_mqtt_close shall return a non-zero value. ] */
837 LogError("Invalid parameter specified handle: %p", handle);
838 result = MU_FAILURE;
839 }
840 else
841 {
842 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
843 BUFFER_delete(mqtt_info->ek);
844 mqtt_info->ek = NULL;
845 BUFFER_delete(mqtt_info->srk);
846 mqtt_info->srk = NULL;
847 free(mqtt_info->registration_id);
848 mqtt_info->registration_id = NULL;
849
850 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_012: [ prov_transport_common_mqtt_close shall close all connection associated with mqtt communication. ] */
851 if (mqtt_client_disconnect(mqtt_info->mqtt_client, NULL, NULL) == 0)
852 {
853 mqtt_client_dowork(mqtt_info->mqtt_client);
854 }
855 xio_destroy(mqtt_info->transport_io);
856 mqtt_info->transport_io = NULL;
857
858 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_013: [ On success prov_transport_common_mqtt_close shall return a zero value. ] */
859 mqtt_info->mqtt_state = MQTT_STATE_IDLE;
860 result = 0;
861 }
862 return result;
863}
864
865int prov_transport_common_mqtt_register_device(PROV_DEVICE_TRANSPORT_HANDLE handle, PROV_TRANSPORT_JSON_PARSE json_parse_cb, PROV_TRANSPORT_CREATE_JSON_PAYLOAD json_create_cb, void* json_ctx)
866{
867 int result;
868 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
869 if (mqtt_info == NULL || json_parse_cb == NULL || json_create_cb == NULL)
870 {
871 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_014: [ If handle is NULL, prov_transport_common_mqtt_register_device shall return a non-zero value. ] */
872 LogError("Invalid parameter specified handle: %p, json_parse_cb: %p", handle, json_parse_cb);
873 result = MU_FAILURE;
874 }
875 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_061: [ If the transport_state is TRANSPORT_CLIENT_STATE_REG_SEND or the the operation_id is NULL, prov_transport_common_mqtt_register_device shall return a non-zero value. ] */
876 else if (mqtt_info->transport_state == TRANSPORT_CLIENT_STATE_REG_SEND || mqtt_info->operation_id != NULL)
877 {
878 LogError("Failure: device is currently in the registration process");
879 result = MU_FAILURE;
880 }
881 else if (mqtt_info->transport_state == TRANSPORT_CLIENT_STATE_ERROR)
882 {
883 LogError("Provisioning is in an error state, close the connection and try again.");
884 result = MU_FAILURE;
885 }
886 else
887 {
888 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_REG_SEND;
889 mqtt_info->json_parse_cb = json_parse_cb;
890 mqtt_info->json_create_cb = json_create_cb;
891 mqtt_info->json_ctx = json_ctx;
892
893 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_017: [ On success prov_transport_common_mqtt_register_device shall return a zero value. ] */
894 result = 0;
895 }
896 return result;
897}
898
899int prov_transport_common_mqtt_get_operation_status(PROV_DEVICE_TRANSPORT_HANDLE handle)
900{
901 int result;
902 if (handle == NULL)
903 {
904 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_018: [ If handle is NULL, prov_transport_common_mqtt_get_operation_status shall return a non-zero value. ] */
905 LogError("Invalid parameter specified handle: %p", handle);
906 result = MU_FAILURE;
907 }
908 else
909 {
910 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
911 if (mqtt_info->operation_id == NULL)
912 {
913 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_019: [ If the operation_id is NULL, prov_transport_common_mqtt_get_operation_status shall return a non-zero value. ] */
914 LogError("operation_id was not previously set in the challenge method");
915 result = MU_FAILURE;
916 }
917 else if (mqtt_info->transport_state == TRANSPORT_CLIENT_STATE_ERROR)
918 {
919 LogError("Provisioning is in an error state, close the connection and try again.");
920 result = MU_FAILURE;
921 }
922 else
923 {
924 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_021: [ prov_transport_common_mqtt_get_operation_status shall set the transport_state to TRANSPORT_CLIENT_STATE_STATUS_SEND. ] */
925 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_SEND;
926 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_022: [ On success prov_transport_common_mqtt_get_operation_status shall return a zero value. ] */
927 result = 0;
928 }
929 }
930 return result;
931}
932
933void prov_transport_common_mqtt_dowork(PROV_DEVICE_TRANSPORT_HANDLE handle)
934{
935 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_046: [ If handle is NULL, prov_transport_common_mqtt_dowork shall do nothing. ] */
936 if (handle != NULL)
937 {
938 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
939 if (mqtt_info->mqtt_state == MQTT_STATE_DISCONNECTED)
940 {
941 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_047: [ If the mqtt_state is MQTT_STATE_DISCONNECTED prov_transport_common_mqtt_dowork shall attempt to connect the mqtt connections. ] */
942 if (create_connection(mqtt_info) != 0)
943 {
944 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
945 LogError("unable to create mqtt connection");
946 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
947 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
948 }
949 else
950 {
951 mqtt_info->mqtt_state = MQTT_STATE_CONNECTING;
952 }
953 }
954 else if (mqtt_info->mqtt_state == MQTT_STATE_CONNECTED)
955 {
956 mqtt_client_dowork(mqtt_info->mqtt_client);
957 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_050: [ When the mqtt_state is MQTT_STATE_CONNECTED, prov_transport_common_mqtt_dowork shall subscribe to the topic $dps/registrations/res/# ] */
958 if (subscribe_to_topic(mqtt_info) != 0)
959 {
960 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
961 LogError("Failure subscribing to topic");
962 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
963 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
964 }
965 else
966 {
967 mqtt_info->status_cb(PROV_DEVICE_TRANSPORT_STATUS_CONNECTED, mqtt_info->retry_after_value, mqtt_info->status_ctx);
968 mqtt_info->mqtt_state = MQTT_STATE_SUBSCRIBING;
969 }
970 }
971 else if (mqtt_info->mqtt_state != MQTT_STATE_IDLE)
972 {
973 mqtt_client_dowork(mqtt_info->mqtt_client);
974 if (mqtt_info->mqtt_state == MQTT_STATE_SUBSCRIBED || mqtt_info->mqtt_state == MQTT_STATE_ERROR)
975 {
976 switch (mqtt_info->transport_state)
977 {
978 case TRANSPORT_CLIENT_STATE_REG_SEND:
979 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_053: [ When then transport_state is set to TRANSPORT_CLIENT_STATE_REG_SEND, prov_transport_common_mqtt_dowork shall send a REGISTER_ME message ] */
980 if (send_register_message(mqtt_info) != 0)
981 {
982 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
983 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
984 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
985 }
986 else
987 {
988 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_054: [ Upon successful sending of a TRANSPORT_CLIENT_STATE_REG_SEND message, prov_transport_common_mqtt_dowork shall set the transport_state to TRANSPORT_CLIENT_STATE_REG_SENT ] */
989 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_REG_SENT;
990 }
991 break;
992 case TRANSPORT_CLIENT_STATE_STATUS_SEND:
993 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_055: [ When then transport_state is set to TRANSPORT_CLIENT_STATE_STATUS_SEND, prov_transport_common_mqtt_dowork shall send a AMQP_OPERATION_STATUS message ] */
994 if (send_operation_status_message(mqtt_info) != 0)
995 {
996 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
997 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
998 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
999 }
1000 else
1001 {
1002 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_056: [ Upon successful sending of a AMQP_OPERATION_STATUS message, prov_transport_common_mqtt_dowork shall set the transport_state to TRANSPORT_CLIENT_STATE_STATUS_SENT ] */
1003 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_SENT;
1004 }
1005 break;
1006
1007 case TRANSPORT_CLIENT_STATE_REG_RECV:
1008 case TRANSPORT_CLIENT_STATE_STATUS_RECV:
1009 {
1010 PROV_JSON_INFO* parse_info = mqtt_info->json_parse_cb(mqtt_info->payload_data, mqtt_info->json_ctx);
1011 if (parse_info == NULL)
1012 {
1013 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
1014 LogError("Unable to process registration reply.");
1015 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
1016 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
1017 }
1018 else
1019 {
1020 switch (parse_info->prov_status)
1021 {
1022 case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED:
1023 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING:
1024 if (parse_info->operation_id == NULL)
1025 {
1026 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
1027 LogError("Failure operation Id invalid");
1028 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
1029 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
1030 }
1031 else if (mqtt_info->operation_id == NULL && mallocAndStrcpy_s(&mqtt_info->operation_id, parse_info->operation_id) != 0)
1032 {
1033 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
1034 LogError("Failure copying operation Id");
1035 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
1036 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
1037 }
1038 else
1039 {
1040 if (mqtt_info->status_cb != NULL)
1041 {
1042 mqtt_info->status_cb(parse_info->prov_status, mqtt_info->retry_after_value, mqtt_info->status_ctx);
1043 }
1044 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
1045 }
1046 break;
1047 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED:
1048 mqtt_info->register_data_cb(PROV_DEVICE_TRANSPORT_RESULT_OK, parse_info->authorization_key, parse_info->iothub_uri, parse_info->device_id, mqtt_info->user_ctx);
1049 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
1050 break;
1051 case PROV_DEVICE_TRANSPORT_STATUS_TRANSIENT:
1052 break;
1053 case PROV_DEVICE_TRANSPORT_STATUS_ERROR:
1054 default:
1055 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_049: [ If any error is encountered prov_transport_common_mqtt_dowork shall set the mqtt_state to MQTT_STATE_ERROR and the transport_state to TRANSPORT_CLIENT_STATE_ERROR. ] */
1056 LogError("Unable to process message reply.");
1057 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
1058 mqtt_info->mqtt_state = MQTT_STATE_ERROR;
1059 break;
1060
1061 }
1062 free_json_parse_info(parse_info);
1063 }
1064 break;
1065 }
1066 case TRANSPORT_CLIENT_STATE_TRANSIENT:
1067 if (mqtt_info->status_cb != NULL)
1068 {
1069 mqtt_info->status_cb(PROV_DEVICE_TRANSPORT_STATUS_TRANSIENT, mqtt_info->retry_after_value, mqtt_info->status_ctx);
1070 }
1071 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
1072 break;
1073
1074 case TRANSPORT_CLIENT_STATE_ERROR:
1075 /* Codes_PROV_TRANSPORT_MQTT_COMMON_07_057: [ If transport_state is set to TRANSPORT_CLIENT_STATE_ERROR, prov_transport_common_mqtt_dowork shall call the register_data_cb function with PROV_DEVICE_TRANSPORT_RESULT_ERROR setting the transport_state to TRANSPORT_CLIENT_STATE_IDLE ] */
1076 mqtt_info->register_data_cb(PROV_DEVICE_TRANSPORT_RESULT_ERROR, NULL, NULL, NULL, mqtt_info->user_ctx);
1077 mqtt_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
1078 mqtt_info->mqtt_state = MQTT_STATE_IDLE;
1079 break;
1080 case TRANSPORT_CLIENT_STATE_REG_SENT:
1081 case TRANSPORT_CLIENT_STATE_STATUS_SENT:
1082 break;
1083
1084 case TRANSPORT_CLIENT_STATE_IDLE:
1085 default:
1086 break;
1087 }
1088 }
1089 }
1090 }
1091}
1092
1093int prov_transport_common_mqtt_set_trace(PROV_DEVICE_TRANSPORT_HANDLE handle, bool trace_on)
1094{
1095 int result;
1096 if (handle == NULL)
1097 {
1098 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_023: [ If handle is NULL, prov_transport_common_mqtt_set_trace shall return a non-zero value. ] */
1099 LogError("Invalid parameter specified handle: %p", handle);
1100 result = MU_FAILURE;
1101 }
1102 else
1103 {
1104 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
1105 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_024: [ prov_transport_common_mqtt_set_trace shall set the log_trace variable to trace_on. ]*/
1106 mqtt_info->log_trace = trace_on;
1107 if (mqtt_info->mqtt_client != NULL)
1108 {
1109 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_059: [ If the umqtt connection is not NULL, prov_transport_common_mqtt_set_trace shall set the trace option on that connection. ] */
1110 mqtt_client_set_trace(mqtt_info->mqtt_client, mqtt_info->log_trace, false);
1111 }
1112 result = 0;
1113 }
1114 return result;
1115}
1116
1117int prov_transport_common_mqtt_x509_cert(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* certificate, const char* private_key)
1118{
1119 int result;
1120 if (handle == NULL || certificate == NULL)
1121 {
1122 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_026: [ If handle or certificate is NULL, prov_transport_common_mqtt_x509_cert shall return a non-zero value. ] */
1123 LogError("Invalid parameter specified handle: %p, certificate: %p", handle, certificate);
1124 result = MU_FAILURE;
1125 }
1126 else
1127 {
1128 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
1129
1130 if (mqtt_info->x509_cert != NULL)
1131 {
1132 free(mqtt_info->x509_cert);
1133 mqtt_info->x509_cert = NULL;
1134 }
1135 if (mqtt_info->private_key != NULL)
1136 {
1137 free(mqtt_info->private_key);
1138 mqtt_info->private_key = NULL;
1139 }
1140
1141 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_027: [ prov_transport_common_mqtt_x509_cert shall copy the certificate and private_key values. ] */
1142 if (mallocAndStrcpy_s(&mqtt_info->x509_cert, certificate) != 0)
1143 {
1144 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_028: [ On any failure prov_transport_common_mqtt_x509_cert, shall return a non-zero value. ] */
1145 result = MU_FAILURE;
1146 LogError("failure allocating certificate");
1147 }
1148 else if (mallocAndStrcpy_s(&mqtt_info->private_key, private_key) != 0)
1149 {
1150 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_028: [ On any failure prov_transport_common_mqtt_x509_cert, shall return a non-zero value. ] */
1151 LogError("failure allocating certificate");
1152 free(mqtt_info->x509_cert);
1153 mqtt_info->x509_cert = NULL;
1154 result = MU_FAILURE;
1155 }
1156 else
1157 {
1158 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_029: [ On success prov_transport_common_mqtt_x509_cert shall return a zero value. ] */
1159 result = 0;
1160 }
1161 }
1162 return result;
1163}
1164
1165int prov_transport_common_mqtt_set_trusted_cert(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* certificate)
1166{
1167 int result;
1168 if (handle == NULL || certificate == NULL)
1169 {
1170 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_030: [ If handle or certificate is NULL, prov_transport_common_mqtt_set_trusted_cert shall return a non-zero value. ] */
1171 LogError("Invalid parameter specified handle: %p, certificate: %p", handle, certificate);
1172 result = MU_FAILURE;
1173 }
1174 else
1175 {
1176 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
1177
1178 if (mqtt_info->certificate != NULL)
1179 {
1180 free(mqtt_info->certificate);
1181 mqtt_info->certificate = NULL;
1182 }
1183
1184 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_031: [ prov_transport_common_mqtt_set_trusted_cert shall copy the certificate value. ] */
1185 if (mallocAndStrcpy_s(&mqtt_info->certificate, certificate) != 0)
1186 {
1187 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_032: [ On any failure prov_transport_common_mqtt_set_trusted_cert, shall return a non-zero value. ] */
1188 result = MU_FAILURE;
1189 LogError("failure allocating certificate");
1190 }
1191 else
1192 {
1193 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_033: [ On success prov_transport_common_mqtt_set_trusted_cert shall return a zero value. ] */
1194 result = 0;
1195 }
1196 }
1197 return result;
1198}
1199
1200int prov_transport_common_mqtt_set_proxy(PROV_DEVICE_TRANSPORT_HANDLE handle, const HTTP_PROXY_OPTIONS* proxy_options)
1201{
1202 int result;
1203 if (handle == NULL || proxy_options == NULL)
1204 {
1205 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_034: [ If handle or proxy_options is NULL, prov_transport_common_mqtt_set_proxy shall return a non-zero value. ]*/
1206 LogError("Invalid parameter specified handle: %p, proxy_options: %p", handle, proxy_options);
1207 result = MU_FAILURE;
1208 }
1209 else
1210 {
1211 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
1212 if (proxy_options->host_address == NULL)
1213 {
1214 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_035: [ If HTTP_PROXY_OPTIONS host_address is NULL, prov_transport_common_mqtt_set_proxy shall return a non-zero value. ] */
1215 LogError("NULL host_address in proxy options");
1216 result = MU_FAILURE;
1217 }
1218 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_036: [ If HTTP_PROXY_OPTIONS password is not NULL and username is NULL, prov_transport_common_mqtt_set_proxy shall return a non-zero value. ] */
1219 else if (((proxy_options->username == NULL) || (proxy_options->password == NULL)) &&
1220 (proxy_options->username != proxy_options->password))
1221 {
1222 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_039: [ On any failure prov_transport_common_mqtt_set_proxy, shall return a non-zero value. ] */
1223 LogError("Only one of username and password for proxy settings was NULL");
1224 result = MU_FAILURE;
1225 }
1226 else
1227 {
1228 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_037: [ If any of the host_addess, username, or password variables are non-NULL, prov_transport_common_mqtt_set_proxy shall free the memory. ] */
1229 if (mqtt_info->proxy_option.host_address != NULL)
1230 {
1231 free((char*)mqtt_info->proxy_option.host_address);
1232 mqtt_info->proxy_option.host_address = NULL;
1233 }
1234 if (mqtt_info->proxy_option.username != NULL)
1235 {
1236 free((char*)mqtt_info->proxy_option.username);
1237 mqtt_info->proxy_option.username = NULL;
1238 }
1239 if (mqtt_info->proxy_option.password != NULL)
1240 {
1241 free((char*)mqtt_info->proxy_option.password);
1242 mqtt_info->proxy_option.password = NULL;
1243 }
1244
1245 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_038: [ prov_transport_common_mqtt_set_proxy shall copy the host_addess, username, or password variables ] */
1246 mqtt_info->proxy_option.port = proxy_options->port;
1247 if (mallocAndStrcpy_s((char**)&mqtt_info->proxy_option.host_address, proxy_options->host_address) != 0)
1248 {
1249 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_039: [ On any failure prov_transport_common_mqtt_set_proxy, shall return a non-zero value. ] */
1250 LogError("Failure setting proxy_host name");
1251 result = MU_FAILURE;
1252 }
1253 else if (proxy_options->username != NULL && mallocAndStrcpy_s((char**)&mqtt_info->proxy_option.username, proxy_options->username) != 0)
1254 {
1255 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_039: [ On any failure prov_transport_common_mqtt_set_proxy, shall return a non-zero value. ] */
1256 LogError("Failure setting proxy username");
1257 free((char*)mqtt_info->proxy_option.host_address);
1258 mqtt_info->proxy_option.host_address = NULL;
1259 result = MU_FAILURE;
1260 }
1261 else if (proxy_options->password != NULL && mallocAndStrcpy_s((char**)&mqtt_info->proxy_option.password, proxy_options->password) != 0)
1262 {
1263 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_039: [ On any failure prov_transport_common_mqtt_set_proxy, shall return a non-zero value. ] */
1264 LogError("Failure setting proxy password");
1265 free((char*)mqtt_info->proxy_option.host_address);
1266 mqtt_info->proxy_option.host_address = NULL;
1267 free((char*)mqtt_info->proxy_option.username);
1268 mqtt_info->proxy_option.username = NULL;
1269 result = MU_FAILURE;
1270 }
1271 else
1272 {
1273 /* Tests_PROV_TRANSPORT_MQTT_COMMON_07_040: [ On success prov_transport_common_mqtt_set_proxy shall return a zero value. ] */
1274 result = 0;
1275 }
1276 }
1277 }
1278 return result;
1279}
1280
1281int prov_transport_common_mqtt_set_option(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* option, const void* value)
1282{
1283 int result;
1284 if (handle == NULL || option == NULL)
1285 {
1286 LogError("Invalid parameter specified handle: %p, option: %p", handle, option);
1287 result = MU_FAILURE;
1288 }
1289 else
1290 {
1291 PROV_TRANSPORT_MQTT_INFO* mqtt_info = (PROV_TRANSPORT_MQTT_INFO*)handle;
1292 if (mqtt_info->transport_io == NULL && create_transport_io_object(mqtt_info) != 0)
1293 {
1294 LogError("Failure creating transport io object");
1295 result = MU_FAILURE;
1296 }
1297 else
1298 {
1299 result = xio_setoption(mqtt_info->transport_io, option, value);
1300 }
1301 }
1302 return result;
1303}
Note: See TracBrowser for help on using the repository browser.