source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/provisioning_client/src/prov_transport_http_client.c@ 457

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

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 50.1 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 "azure_c_shared_utility/gballoc.h"
8#include "azure_c_shared_utility/platform.h"
9#include "azure_c_shared_utility/xlogging.h"
10#include "azure_c_shared_utility/crt_abstractions.h"
11#include "azure_c_shared_utility/tlsio.h"
12#include "azure_c_shared_utility/shared_util_options.h"
13#include "azure_c_shared_utility/http_proxy_io.h"
14#include "azure_c_shared_utility/urlencode.h"
15#include "azure_c_shared_utility/azure_base64.h"
16
17#include "azure_prov_client/prov_transport_http_client.h"
18#include "azure_prov_client/internal/prov_transport_private.h"
19#include "azure_prov_client/prov_client_const.h"
20
21#include "azure_uhttp_c/uhttp.h"
22#include "parson.h"
23
24#define HTTP_PORT_NUM 443
25#define HTTP_STATUS_CODE_OK 200
26#define HTTP_STATUS_CODE_OK_MAX 226
27#define HTTP_STATUS_CODE_UNAUTHORIZED 401
28
29static const char* const PROV_REGISTRATION_URI_FMT = "/%s/registrations/%s/register?api-version=%s";
30static const char* const PROV_OP_STATUS_URI_FMT = "/%s/registrations/%s/operations/%s?api-version=%s";
31static const char* const HEADER_KEY_AUTHORIZATION = "Authorization";
32static const char* const HEADER_USER_AGENT = "UserAgent";
33static const char* const HEADER_ACCEPT = "Accept";
34static const char* const HEADER_CONTENT_TYPE = "Content-Type";
35static const char* const HEADER_CONNECTION = "Connection";
36static const char* const USER_AGENT_VALUE = "prov_device_client/1.0";
37static const char* const ACCEPT_VALUE = "application/json";
38static const char* const CONTENT_TYPE_VALUE = "application/json; charset=utf-8";
39static const char* const KEEP_ALIVE_VALUE = "keep-alive";
40static const char* const KEY_NAME_VALUE = "registration";
41
42MU_DEFINE_ENUM_STRINGS_WITHOUT_INVALID(HTTP_CALLBACK_REASON, HTTP_CALLBACK_REASON_VALUES);
43
44typedef enum PROV_TRANSPORT_STATE_TAG
45{
46 TRANSPORT_CLIENT_STATE_IDLE,
47
48 TRANSPORT_CLIENT_STATE_REG_SEND,
49 TRANSPORT_CLIENT_STATE_REG_SENT,
50 TRANSPORT_CLIENT_STATE_REG_RECV,
51
52 TRANSPORT_CLIENT_STATE_STATUS_SENT,
53 TRANSPORT_CLIENT_STATE_STATUS_RECV,
54
55 TRANSPORT_CLIENT_STATE_TRANSIENT,
56
57 TRANSPORT_CLIENT_STATE_ERROR
58} PROV_TRANSPORT_STATE;
59
60typedef struct PROV_TRANSPORT_HTTP_INFO_TAG
61{
62 PROV_DEVICE_TRANSPORT_REGISTER_CALLBACK register_data_cb;
63 void* user_ctx;
64 PROV_DEVICE_TRANSPORT_STATUS_CALLBACK status_cb;
65 void* status_ctx;
66 PROV_TRANSPORT_CHALLENGE_CALLBACK challenge_cb;
67 void* challenge_ctx;
68 PROV_TRANSPORT_CREATE_JSON_PAYLOAD json_create_cb;
69 PROV_TRANSPORT_JSON_PARSE json_parse_cb;
70 void* json_ctx;
71
72 char* hostname;
73 char* proxy_host;
74 int proxy_port;
75 char* username;
76 char* password;
77
78 char* x509_cert;
79 char* private_key;
80
81 char* certificate;
82
83 BUFFER_HANDLE ek;
84 BUFFER_HANDLE srk;
85 char* registration_id;
86 char* scope_id;
87 char* sas_token;
88
89 BUFFER_HANDLE nonce;
90
91 char* operation_id;
92
93 char* api_version;
94
95 char* payload_data;
96 unsigned int http_status_code;
97
98 bool http_connected;
99 bool log_trace;
100 PROV_TRANSPORT_STATE transport_state;
101 TRANSPORT_HSM_TYPE hsm_type;
102
103 HTTP_CLIENT_HANDLE http_client;
104 uint32_t retry_after_value;
105
106 PROV_TRANSPORT_ERROR_CALLBACK error_cb;
107 void* error_ctx;
108} PROV_TRANSPORT_HTTP_INFO;
109
110static void on_http_error(void* callback_ctx, HTTP_CALLBACK_REASON error_result)
111{
112 (void)error_result;
113 if (callback_ctx != NULL)
114 {
115 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)callback_ctx;
116 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
117 LogError("http error encountered: %s", MU_ENUM_TO_STRING(HTTP_CALLBACK_REASON, error_result));
118 }
119 else
120 {
121 LogError("callback_ctx NULL. http error encountered: %s", MU_ENUM_TO_STRING(HTTP_CALLBACK_REASON, error_result));
122 }
123}
124
125static void on_http_reply_recv(void* callback_ctx, HTTP_CALLBACK_REASON request_result, const unsigned char* content, size_t content_len, unsigned int status_code, HTTP_HEADERS_HANDLE responseHeadersHandle)
126{
127 (void)responseHeadersHandle;
128 if (callback_ctx != NULL)
129 {
130 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)callback_ctx;
131 http_info->http_status_code = status_code;
132 if (request_result != HTTP_CALLBACK_REASON_OK)
133 {
134 LogError("Failure http reply %s", MU_ENUM_TO_STRING(HTTP_CALLBACK_REASON, request_result));
135 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
136 }
137 else if ((status_code >= HTTP_STATUS_CODE_OK && status_code <= HTTP_STATUS_CODE_OK_MAX) || status_code == HTTP_STATUS_CODE_UNAUTHORIZED)
138 {
139 if (content != NULL && content_len > 0)
140 {
141 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_038: [ prov_transport_http_dowork shall free the payload_data ] */
142 if (http_info->payload_data != NULL)
143 {
144 free(http_info->payload_data);
145 }
146 http_info->payload_data = malloc(content_len + 1);
147 if (http_info->payload_data == NULL)
148 {
149 LogError("Failure sending http request");
150 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
151 }
152 else
153 {
154 memset(http_info->payload_data, 0, content_len + 1);
155 memcpy(http_info->payload_data, content, content_len);
156 if (http_info->transport_state == TRANSPORT_CLIENT_STATE_REG_SENT)
157 {
158 http_info->transport_state = TRANSPORT_CLIENT_STATE_REG_RECV;
159 }
160 else
161 {
162 http_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_RECV;
163 }
164 }
165 }
166 else
167 {
168 if (http_info->transport_state == TRANSPORT_CLIENT_STATE_REG_SENT)
169 {
170 http_info->transport_state = TRANSPORT_CLIENT_STATE_REG_RECV;
171 }
172 else
173 {
174 http_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_RECV;
175 }
176 }
177 }
178 else if (status_code >= PROV_STATUS_CODE_TRANSIENT_ERROR)
179 {
180 // On transient error reset the transport to send state
181 http_info->transport_state = TRANSPORT_CLIENT_STATE_TRANSIENT;
182 }
183 else
184 {
185 LogError("Failure status code sent from the server: %u", status_code);
186 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
187 }
188 // The call to parse_retry_after_value can not fail
189 http_info->retry_after_value = parse_retry_after_value(HTTPHeaders_FindHeaderValue(responseHeadersHandle, RETRY_AFTER_KEY_VALUE));
190 }
191 else
192 {
193 LogError("Null callback_ctx specified");
194 }
195}
196
197static void on_http_connected(void* callback_ctx, HTTP_CALLBACK_REASON open_result)
198{
199 if (callback_ctx != NULL)
200 {
201 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)callback_ctx;
202 if (open_result == HTTP_CALLBACK_REASON_OK)
203 {
204 if (http_info->status_cb != NULL)
205 {
206 http_info->status_cb(PROV_DEVICE_TRANSPORT_STATUS_CONNECTED, http_info->retry_after_value, http_info->status_ctx);
207 }
208 http_info->http_connected = true;
209 }
210 else
211 {
212 LogError("Http connection failed to connect");
213 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
214 http_info->http_connected = false;
215 }
216 }
217 else
218 {
219 LogError("Null callback_ctx specified");
220 }
221}
222
223static HTTP_HEADERS_HANDLE construct_http_headers(const char* sas_token)
224{
225 HTTP_HEADERS_HANDLE result;
226 if ((result = HTTPHeaders_Alloc()) == NULL)
227 {
228 LogError("failure sending request");
229 }
230 else
231 {
232 if ((HTTPHeaders_AddHeaderNameValuePair(result, HEADER_USER_AGENT, USER_AGENT_VALUE) != HTTP_HEADERS_OK) ||
233 (HTTPHeaders_AddHeaderNameValuePair(result, HEADER_ACCEPT, ACCEPT_VALUE) != HTTP_HEADERS_OK) ||
234 (HTTPHeaders_AddHeaderNameValuePair(result, HEADER_CONNECTION, KEEP_ALIVE_VALUE) != HTTP_HEADERS_OK) ||
235 (HTTPHeaders_AddHeaderNameValuePair(result, HEADER_CONTENT_TYPE, CONTENT_TYPE_VALUE) != HTTP_HEADERS_OK))
236 {
237 LogError("failure adding header value");
238 HTTPHeaders_Free(result);
239 result = NULL;
240 }
241 else
242 {
243 if (sas_token != NULL)
244 {
245 if (HTTPHeaders_AddHeaderNameValuePair(result, HEADER_KEY_AUTHORIZATION, sas_token) != HTTP_HEADERS_OK)
246 {
247 LogError("failure adding sas_token header value");
248 HTTPHeaders_Free(result);
249 result = NULL;
250 }
251 }
252 }
253 }
254 return result;
255}
256
257static char* construct_json_data(PROV_TRANSPORT_HTTP_INFO* http_info)
258{
259 char* result;
260 bool data_success = true;
261 STRING_HANDLE encoded_srk = NULL;
262 STRING_HANDLE encoded_ek = NULL;
263 const char* ek_value = NULL;
264 const char* srk_value = NULL;
265
266 // For TPM we need to add tpm encoded values
267 if (http_info->hsm_type == TRANSPORT_HSM_TYPE_TPM)
268 {
269 if ((encoded_ek = Azure_Base64_Encode(http_info->ek)) == NULL)
270 {
271 LogError("Failure encoding ek");
272 data_success = false;
273 }
274 else if ((encoded_srk = Azure_Base64_Encode(http_info->srk)) == NULL)
275 {
276 LogError("Failure encoding srk");
277 data_success = false;
278 }
279 else
280 {
281 ek_value = STRING_c_str(encoded_ek);
282 srk_value = STRING_c_str(encoded_srk);
283 }
284 }
285
286 if (data_success)
287 {
288 result = http_info->json_create_cb(ek_value, srk_value, http_info->json_ctx);
289 }
290 else
291 {
292 result = NULL;
293 }
294
295 if (encoded_srk != NULL)
296 {
297 STRING_delete(encoded_srk);
298 }
299 if (encoded_ek != NULL)
300 {
301 STRING_delete(encoded_ek);
302 }
303 return result;
304}
305
306static char* construct_url_path(PROV_TRANSPORT_HTTP_INFO* http_info)
307{
308 char* result;
309 size_t path_len;
310 STRING_HANDLE encoded_scope;
311
312 STRING_HANDLE encoded_reg_id = URL_EncodeString(http_info->registration_id);
313 if (encoded_reg_id == NULL)
314 {
315 LogError("Failure encoding reg id");
316 result = NULL;
317 }
318 else if ((encoded_scope = URL_EncodeString(http_info->scope_id)) == NULL)
319 {
320 LogError("Failure encoding string value");
321 STRING_delete(encoded_reg_id);
322 result = NULL;
323 }
324 else
325 {
326 if (http_info->operation_id == NULL)
327 {
328 path_len = strlen(PROV_REGISTRATION_URI_FMT) + STRING_length(encoded_scope) + STRING_length(encoded_reg_id) + strlen(http_info->api_version);
329 if ((result = malloc(path_len + 1)) == NULL)
330 {
331 LogError("Failure allocating url path");
332 }
333 else
334 {
335 if (sprintf(result, PROV_REGISTRATION_URI_FMT, STRING_c_str(encoded_scope), STRING_c_str(encoded_reg_id), http_info->api_version) == 0)
336 {
337 LogError("Failure constructing url path");
338 free(result);
339 result = NULL;
340 }
341 }
342 }
343 else
344 {
345 STRING_HANDLE encoded_op_id = URL_EncodeString(http_info->operation_id);
346 if (encoded_op_id == NULL)
347 {
348 LogError("Failure encoding operation id");
349 result = NULL;
350 }
351 else
352 {
353 path_len = strlen(PROV_OP_STATUS_URI_FMT) + STRING_length(encoded_scope) + STRING_length(encoded_reg_id) + STRING_length(encoded_op_id) + strlen(http_info->api_version);
354 if ((result = malloc(path_len + 1)) == NULL)
355 {
356 LogError("failure allocating retrieval path");
357 }
358 else
359 {
360 if (sprintf(result, PROV_OP_STATUS_URI_FMT, STRING_c_str(encoded_scope), STRING_c_str(encoded_reg_id), STRING_c_str(encoded_op_id), http_info->api_version) == 0)
361 {
362 LogError("failure allocating retrieval path");
363 free(result);
364 result = NULL;
365 }
366 }
367 STRING_delete(encoded_op_id);
368 }
369 }
370 STRING_delete(encoded_scope);
371 STRING_delete(encoded_reg_id);
372 }
373 return result;
374}
375
376static int send_registration_info(PROV_TRANSPORT_HTTP_INFO* http_info)
377{
378 int result;
379 char* uri_path;
380 char* json_data;
381 HTTP_HEADERS_HANDLE http_headers;
382
383 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_018: [ prov_transport_http_register_device shall construct the http headers for anonymous communication to the service. ] */
384 if ((http_headers = construct_http_headers(http_info->sas_token)) == NULL)
385 {
386 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_021: [ If any error is encountered prov_transport_http_register_device shall return a non-zero value. ] */
387 LogError("failure constructing http headers");
388 result = MU_FAILURE;
389 }
390 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_019: [ prov_transport_http_register_device shall construct the path to the service in the following format: /<scope_id>/registrations/<url_encoded_registration_id>/register-me?api-version=<api_version> ] */
391 else if ((uri_path = construct_url_path(http_info)) == NULL)
392 {
393 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_021: [ If any error is encountered prov_transport_http_register_device shall return a non-zero value. ] */
394 LogError("Failure constructing uri path");
395 HTTPHeaders_Free(http_headers);
396 result = MU_FAILURE;
397 }
398 else if ((json_data = construct_json_data(http_info)) == NULL)
399 {
400 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_021: [ If any error is encountered prov_transport_http_register_device shall return a non-zero value. ] */
401 LogError("Failure constructing json payload");
402 HTTPHeaders_Free(http_headers);
403 free(uri_path);
404 result = MU_FAILURE;
405 }
406 else
407 {
408 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_020: [ prov_transport_http_register_device shall send the request using the http client. ] */
409 if (uhttp_client_execute_request(http_info->http_client, HTTP_CLIENT_REQUEST_PUT, uri_path, http_headers, (const unsigned char*)json_data, strlen(json_data), on_http_reply_recv, http_info) != HTTP_CLIENT_OK)
410 {
411 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_021: [ If any error is encountered prov_transport_http_register_device shall return a non-zero value. ] */
412 LogError("Failure sending http request");
413 result = MU_FAILURE;
414 }
415 else
416 {
417 result = 0;
418 }
419 free(uri_path);
420 free(json_data);
421 HTTPHeaders_Free(http_headers);
422 }
423 return result;
424}
425
426static int send_challenge_response(PROV_TRANSPORT_HTTP_INFO* http_info)
427{
428 int result;
429 HTTP_HEADERS_HANDLE http_headers;
430 char* uri_path;
431 char* json_data;
432
433 if ((http_headers = construct_http_headers(http_info->sas_token)) == NULL)
434 {
435 LogError("failure constructing http headers");
436 result = MU_FAILURE;
437 }
438 else if ((uri_path = construct_url_path(http_info)) == NULL)
439 {
440 LogError("Failure constructing uri path");
441 HTTPHeaders_Free(http_headers);
442 result = MU_FAILURE;
443 }
444 else if ((json_data = construct_json_data(http_info)) == NULL)
445 {
446 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_021: [ If any error is encountered prov_transport_http_register_device shall return a non-zero value. ] */
447 LogError("Failure constructing uri path");
448 HTTPHeaders_Free(http_headers);
449 free(uri_path);
450 result = MU_FAILURE;
451 }
452 else
453 {
454 if (uhttp_client_execute_request(http_info->http_client, HTTP_CLIENT_REQUEST_PUT, uri_path, http_headers, (const unsigned char*)json_data, strlen(json_data), on_http_reply_recv, http_info) != HTTP_CLIENT_OK)
455 {
456 LogError("Failure sending http request");
457 result = MU_FAILURE;
458 }
459 else
460 {
461 result = 0;
462 }
463 free(json_data);
464 free(uri_path);
465 HTTPHeaders_Free(http_headers);
466 }
467 return result;
468}
469
470static void free_json_parse_info(PROV_JSON_INFO* parse_info)
471{
472 switch (parse_info->prov_status)
473 {
474 case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED:
475 BUFFER_delete(parse_info->authorization_key);
476 free(parse_info->key_name);
477 break;
478 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED:
479 BUFFER_delete(parse_info->authorization_key);
480 free(parse_info->iothub_uri);
481 free(parse_info->device_id);
482 break;
483 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING:
484 free(parse_info->operation_id);
485 break;
486 default:
487 break;
488 }
489 free(parse_info);
490}
491
492static void free_allocated_data(PROV_TRANSPORT_HTTP_INFO* http_info)
493{
494 free(http_info->hostname);
495 free(http_info->registration_id);
496 free(http_info->api_version);
497 free(http_info->scope_id);
498 free(http_info->certificate);
499 free(http_info->proxy_host);
500 free(http_info->x509_cert);
501 free(http_info->private_key);
502 free(http_info->username);
503 free(http_info->password);
504 free(http_info->payload_data);
505 free(http_info->sas_token);
506 free(http_info->operation_id);
507 BUFFER_delete(http_info->ek);
508 BUFFER_delete(http_info->srk);
509 BUFFER_delete(http_info->nonce);
510 if (http_info->http_client != NULL)
511 {
512 uhttp_client_destroy(http_info->http_client);
513 }
514 free(http_info);
515}
516
517static int create_transport_io_object(PROV_TRANSPORT_HTTP_INFO* http_info)
518{
519 int result;
520 if (http_info->http_client == NULL)
521 {
522 TLSIO_CONFIG tls_io_config;
523 HTTP_PROXY_IO_CONFIG http_proxy;
524 memset(&tls_io_config, 0, sizeof(TLSIO_CONFIG));
525 tls_io_config.hostname = http_info->hostname;
526 tls_io_config.port = HTTP_PORT_NUM;
527
528 // Setup proxy
529 if (http_info->proxy_host != NULL)
530 {
531 memset(&http_proxy, 0, sizeof(HTTP_PROXY_IO_CONFIG));
532 http_proxy.hostname = http_info->hostname;
533 http_proxy.port = HTTP_PORT_NUM;
534 http_proxy.proxy_hostname = http_info->proxy_host;
535 http_proxy.proxy_port = http_info->proxy_port;
536 http_proxy.username = http_info->username;
537 http_proxy.password = http_info->password;
538
539 tls_io_config.underlying_io_interface = http_proxy_io_get_interface_description();
540 tls_io_config.underlying_io_parameters = &http_proxy;
541 }
542 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_009: [ prov_transport_http_open shall create the http client adding any proxy and certificate information that is presented. ] */
543 const IO_INTERFACE_DESCRIPTION* interface_desc;
544
545 if ((interface_desc = platform_get_default_tlsio()) == NULL)
546 {
547 LogError("failgetting tls interface description");
548 result = MU_FAILURE;
549 }
550 else if ((http_info->http_client = uhttp_client_create(interface_desc, &tls_io_config, on_http_error, http_info)) == NULL)
551 {
552 LogError("failed to create http client");
553 result = MU_FAILURE;
554 }
555 else
556 {
557 result = 0;
558 }
559 }
560 else
561 {
562 result = 0;
563 }
564 return result;
565}
566
567static int create_connection(PROV_TRANSPORT_HTTP_INFO* http_info)
568{
569 int result;
570 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_009: [ prov_transport_http_open shall create the http client adding any proxy and certificate information that is presented. ] */
571 if (create_transport_io_object(http_info) != 0)
572 {
573 LogError("Failure setting transport object");
574 result = MU_FAILURE;
575 }
576 else
577 {
578 (void)uhttp_client_set_trace(http_info->http_client, http_info->log_trace, true);
579
580 if (http_info->certificate != NULL && uhttp_client_set_trusted_cert(http_info->http_client, http_info->certificate) != HTTP_CLIENT_OK)
581 {
582 LogError("fail to set the trusted certificate in the http client");
583 uhttp_client_destroy(http_info->http_client);
584 http_info->http_client = NULL;
585 result = MU_FAILURE;
586 }
587 else
588 {
589 if (http_info->hsm_type == TRANSPORT_HSM_TYPE_X509)
590 {
591 if (http_info->x509_cert == NULL || http_info->private_key == NULL)
592 {
593 LogError("x509 certificate information was not properly set");
594 result = MU_FAILURE;
595 }
596 else if (uhttp_client_set_X509_cert(http_info->http_client, true, http_info->x509_cert, http_info->private_key) != HTTP_CLIENT_OK)
597 {
598 LogError("failed to set x509 certificate information");
599 result = MU_FAILURE;
600 }
601 else
602 {
603 result = 0;
604 }
605 }
606 else
607 {
608 result = 0;
609 }
610 }
611 }
612 if (result == 0 && !http_info->http_connected)
613 {
614 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_010: [ prov_transport_http_open shall opening the http communications with the service. ] */
615 if (uhttp_client_open(http_info->http_client, http_info->hostname, HTTP_PORT_NUM, on_http_connected, http_info) != HTTP_CLIENT_OK)
616 {
617 LogError("failed to open http client");
618 if (http_info->error_cb != NULL)
619 {
620 http_info->error_cb(PROV_DEVICE_ERROR_KEY_FAIL, http_info->error_ctx);
621 }
622 uhttp_client_destroy(http_info->http_client);
623 http_info->http_client = NULL;
624 result = MU_FAILURE;
625 }
626 else
627 {
628 result = 0;
629 }
630 }
631 return result;
632}
633
634PROV_DEVICE_TRANSPORT_HANDLE prov_transport_http_create(const char* uri, TRANSPORT_HSM_TYPE type, const char* scope_id, const char* api_version, PROV_TRANSPORT_ERROR_CALLBACK error_cb, void* error_ctx)
635{
636 PROV_TRANSPORT_HTTP_INFO* result;
637 if (uri == NULL || scope_id == NULL || api_version == NULL)
638 {
639 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_001: [ If uri, scope_id, registration_id or api_version are NULL prov_transport_http_create shall return NULL. ] */
640 LogError("Invalid parameter specified uri: %p, scope_id: %p, api_version: %p", uri, scope_id, api_version);
641 result = NULL;
642 }
643 else
644 {
645 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_002: [ prov_transport_http_create shall allocate the memory for the PROV_DEVICE_TRANSPORT_HANDLE variables. ] */
646 result = malloc(sizeof(PROV_TRANSPORT_HTTP_INFO));
647 if (result == NULL)
648 {
649 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_003: [ If any error is encountered prov_transport_http_create shall return NULL. ] */
650 LogError("Unable to allocate PROV_TRANSPORT_HTTP_INFO");
651 }
652 else
653 {
654 memset(result, 0, sizeof(PROV_TRANSPORT_HTTP_INFO));
655 if (mallocAndStrcpy_s(&result->hostname, uri) != 0)
656 {
657 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_003: [ If any error is encountered prov_transport_http_create shall return NULL. ] */
658 LogError("Failure allocating hostname");
659 free(result);
660 result = NULL;
661 }
662 else if (mallocAndStrcpy_s(&result->api_version, api_version) != 0)
663 {
664 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_003: [ If any error is encountered prov_transport_http_create shall return NULL. ] */
665 LogError("Failure allocating api_version");
666 free_allocated_data(result);
667 result = NULL;
668 }
669 else if (mallocAndStrcpy_s(&result->scope_id, scope_id) != 0)
670 {
671 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_003: [ If any error is encountered prov_transport_http_create shall return NULL. ] */
672 LogError("Failure allocating scope Id");
673 free_allocated_data(result);
674 result = NULL;
675 }
676 else
677 {
678 result->retry_after_value = PROV_GET_THROTTLE_TIME;
679 result->hsm_type = type;
680 result->error_cb = error_cb;
681 result->error_ctx = error_ctx;
682 }
683 }
684 }
685 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_004: [ On success prov_transport_http_create shall return a PROV_DEVICE_TRANSPORT_HANDLE. ] */
686 return result;
687}
688
689void prov_transport_http_destroy(PROV_DEVICE_TRANSPORT_HANDLE handle)
690{
691 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_007: [ If the argument handle is NULL, prov_transport_http_destroy shall do nothing ] */
692 if (handle != NULL)
693 {
694 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_005: [ prov_transport_http_destroy shall free all resources associated with the PROV_DEVICE_TRANSPORT_HANDLE handle ] */
695 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
696 free_allocated_data(http_info);
697 }
698}
699
700int prov_transport_http_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)
701{
702 int result;
703 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
704 if (http_info == NULL || data_callback == NULL || status_cb == NULL || registration_id == NULL)
705 {
706 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_008: [ If the argument handle, data_callback, or status_cb are NULL, prov_transport_http_open shall return a non-zero value. ] */
707 LogError("Invalid parameter specified handle: %p, data_callback: %p, status_cb: %p, registration_id: %p", handle, data_callback, status_cb, registration_id);
708 result = MU_FAILURE;
709 }
710 else if ((http_info->hsm_type == TRANSPORT_HSM_TYPE_TPM || http_info->hsm_type == TRANSPORT_HSM_TYPE_SYMM_KEY) && reg_challenge_cb == NULL)
711 {
712 LogError("registration challenge callback must be set");
713 result = MU_FAILURE;
714 }
715 else if (http_info->hsm_type == TRANSPORT_HSM_TYPE_TPM && (ek == NULL || srk == NULL))
716 {
717 LogError("Invalid parameter specified ek: %p, srk: %p", ek, srk);
718 result = MU_FAILURE;
719 }
720 else if (ek != NULL && (http_info->ek = BUFFER_clone(ek)) == NULL)
721 {
722 LogError("Unable to allocate endorsement key");
723 result = MU_FAILURE;
724 }
725 else if (srk != NULL && (http_info->srk = BUFFER_clone(srk)) == NULL)
726 {
727 LogError("Unable to allocate storage root key");
728 BUFFER_delete(http_info->ek);
729 http_info->ek = NULL;
730 result = MU_FAILURE;
731 }
732 else if (mallocAndStrcpy_s(&http_info->registration_id, registration_id) != 0)
733 {
734 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_003: [ If any error is encountered prov_transport_http_create shall return NULL. ] */
735 LogError("failure constructing registration Id");
736 BUFFER_delete(http_info->ek);
737 http_info->ek = NULL;
738 BUFFER_delete(http_info->srk);
739 http_info->srk = NULL;
740 result = MU_FAILURE;
741 }
742 else if ((http_info->hsm_type == TRANSPORT_HSM_TYPE_SYMM_KEY) && (http_info->sas_token = reg_challenge_cb(NULL, 0, KEY_NAME_VALUE, challenge_ctx)) == NULL)
743 {
744 LogError("failure constructing challenge value");
745 BUFFER_delete(http_info->ek);
746 http_info->ek = NULL;
747 BUFFER_delete(http_info->srk);
748 http_info->srk = NULL;
749 result = MU_FAILURE;
750 }
751 else
752 {
753 http_info->register_data_cb = data_callback;
754 http_info->user_ctx = user_ctx;
755 http_info->status_cb = status_cb;
756 http_info->status_ctx = status_ctx;
757 http_info->challenge_cb = reg_challenge_cb;
758 http_info->challenge_ctx = challenge_ctx;
759
760 if (create_connection(http_info) != 0)
761 {
762 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_013: [ If an error is encountered prov_transport_http_open shall return a non-zero value. ] */
763 LogError("Failure creating http connection");
764 if (http_info->ek != NULL)
765 {
766 BUFFER_delete(http_info->ek);
767 http_info->ek = NULL;
768 }
769 if (http_info->srk != NULL)
770 {
771 BUFFER_delete(http_info->srk);
772 http_info->srk = NULL;
773 }
774 http_info->register_data_cb = NULL;
775 http_info->user_ctx = NULL;
776 http_info->status_cb = NULL;
777 http_info->status_ctx = NULL;
778 free(http_info->registration_id);
779 http_info->registration_id = NULL;
780 result = MU_FAILURE;
781 }
782 else
783 {
784 result = 0;
785 }
786 }
787 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_012: [ If successful prov_transport_http_open shall return 0. ] */
788 return result;
789}
790
791int prov_transport_http_close(PROV_DEVICE_TRANSPORT_HANDLE handle)
792{
793 int result;
794 if (handle == NULL)
795 {
796 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_014: [ If the argument handle is NULL, prov_transport_http_close shall return a non-zero value. ] */
797 LogError("Invalid parameter specified handle: %p", handle);
798 result = MU_FAILURE;
799 }
800 else
801 {
802 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_015: [ prov_transport_http_close shall attempt to close the http communication with the service. ] */
803 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
804 if (http_info->http_client != NULL)
805 {
806 BUFFER_delete(http_info->ek);
807 http_info->ek = NULL;
808 BUFFER_delete(http_info->srk);
809 http_info->srk = NULL;
810 free(http_info->registration_id);
811 http_info->registration_id = NULL;
812
813 uhttp_client_close(http_info->http_client, NULL, NULL);
814 uhttp_client_dowork(http_info->http_client);
815
816 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_006: [ prov_transport_http_close shall call the uhttp_client_destroy function function associated with the http_client ] */
817 uhttp_client_destroy(http_info->http_client);
818 http_info->http_client = NULL;
819 }
820 http_info->http_connected = false;
821 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_016: [ On success prov_transport_http_close shall return 0. ] */
822 result = 0;
823 }
824 return result;
825}
826
827int prov_transport_http_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)
828{
829 int result;
830 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
831 if (http_info == NULL || json_parse_cb == NULL || json_create_cb == NULL)
832 {
833 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_017: [ If the argument handle or json_data is NULL, prov_transport_http_register_device shall return a non-zero value. ] */
834 LogError("Invalid parameter specified handle: %p, json_parse_cb: %p", handle, json_parse_cb);
835 result = MU_FAILURE;
836 }
837 else if (http_info->transport_state == TRANSPORT_CLIENT_STATE_ERROR)
838 {
839 LogError("Provisioning is in an error state, close the connection and try again.");
840 result = MU_FAILURE;
841 }
842 else
843 {
844 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_022: [ On success prov_transport_http_register_device shall return 0. ] */
845 http_info->transport_state = TRANSPORT_CLIENT_STATE_REG_SEND;
846 http_info->json_parse_cb = json_parse_cb;
847 http_info->json_create_cb = json_create_cb;
848 http_info->json_ctx = json_ctx;
849
850 result = 0;
851 }
852 return result;
853}
854
855int prov_transport_http_get_operation_status(PROV_DEVICE_TRANSPORT_HANDLE handle)
856{
857 int result;
858 if (handle == NULL)
859 {
860 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_029: [ If the argument handle, or operation_id is NULL, prov_transport_http_get_operation_status shall return a non-zero value. ] */
861 LogError("Invalid parameter specified handle: %p", handle);
862 result = MU_FAILURE;
863 }
864 else
865 {
866 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
867 HTTP_HEADERS_HANDLE http_headers;
868 char* uri_path;
869
870 if (http_info->operation_id == NULL)
871 {
872 LogError("operation_id was not previously set in the challenge method");
873 result = MU_FAILURE;
874 }
875 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_030: [ prov_transport_http_get_operation_status shall construct the http headers with SAS_TOKEN as Authorization header. ] */
876 else if ((http_headers = construct_http_headers(http_info->sas_token)) == NULL)
877 {
878 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_033: [ If any error is encountered prov_transport_http_get_operation_status shall return a non-zero value. ] */
879 LogError("failure constructing http headers");
880 result = MU_FAILURE;
881 }
882 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_031: [ prov_transport_http_get_operation_status shall construct the path to the service in the following format: /<scope_id>/registrations/<url_encoded_registration_id>/operations<url_encoded_operation_id>?api-version=<api_version> ] */
883 else if ((uri_path = construct_url_path(http_info)) == NULL)
884 {
885 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_033: [ If any error is encountered prov_transport_http_get_operation_status shall return a non-zero value. ] */
886 LogError("Failure constructing uri path");
887 result = MU_FAILURE;
888 }
889 else
890 {
891 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_032: [ prov_transport_http_get_operation_status shall send the request using the http client. ] */
892 if (uhttp_client_execute_request(http_info->http_client, HTTP_CLIENT_REQUEST_GET, uri_path, http_headers, NULL, 0, on_http_reply_recv, http_info) != HTTP_CLIENT_OK)
893 {
894 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_033: [ If any error is encountered prov_transport_http_get_operation_status shall return a non-zero value. ] */
895 LogError("Failure sending data to server");
896 result = MU_FAILURE;
897 }
898 else
899 {
900 http_info->transport_state = TRANSPORT_CLIENT_STATE_STATUS_SENT;
901 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_034: [ On success prov_transport_http_get_operation_status shall return 0. ] */
902 result = 0;
903 }
904 HTTPHeaders_Free(http_headers);
905 free(uri_path);
906 }
907 }
908 return result;
909}
910
911void prov_transport_http_dowork(PROV_DEVICE_TRANSPORT_HANDLE handle)
912{
913 if (handle != NULL)
914 {
915 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
916 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_036: [ prov_transport_http_dowork shall call the underlying http client do work method. ] */
917 uhttp_client_dowork(http_info->http_client);
918
919 if (http_info->http_connected || http_info->transport_state == TRANSPORT_CLIENT_STATE_ERROR)
920 {
921 switch (http_info->transport_state)
922 {
923 case TRANSPORT_CLIENT_STATE_REG_SEND:
924 if (send_registration_info(http_info) != 0)
925 {
926 LogError("NULL sas_token provided in challenge callback.");
927 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
928 }
929 else
930 {
931 http_info->transport_state = TRANSPORT_CLIENT_STATE_REG_SENT;
932 }
933 break;
934 case TRANSPORT_CLIENT_STATE_STATUS_RECV:
935 case TRANSPORT_CLIENT_STATE_REG_RECV:
936 {
937 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_037: [ If the prov_transport_http_dowork state is Message received prov_transport_http_dowork shall call the calling process registration_data callback ] */
938 PROV_JSON_INFO* parse_info = http_info->json_parse_cb(http_info->payload_data, http_info->json_ctx);
939 if (parse_info == NULL)
940 {
941 LogError("Unable to process registration reply.");
942 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
943 }
944 else
945 {
946 switch (parse_info->prov_status)
947 {
948 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNED:
949 http_info->register_data_cb(PROV_DEVICE_TRANSPORT_RESULT_OK, parse_info->authorization_key, parse_info->iothub_uri, parse_info->device_id, http_info->user_ctx);
950 http_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
951 break;
952
953 case PROV_DEVICE_TRANSPORT_STATUS_UNASSIGNED:
954 {
955 const unsigned char* nonce = BUFFER_u_char(parse_info->authorization_key);
956 size_t nonce_len = BUFFER_length(parse_info->authorization_key);
957
958 http_info->sas_token = http_info->challenge_cb(nonce, nonce_len, parse_info->key_name, http_info->user_ctx);
959 if (http_info->sas_token == NULL)
960 {
961 LogError("NULL sas_token provided in challenge callback.");
962 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
963 }
964 else
965 {
966 send_challenge_response(http_info);
967 http_info->transport_state = TRANSPORT_CLIENT_STATE_REG_SENT;
968 }
969 break;
970 }
971
972 case PROV_DEVICE_TRANSPORT_STATUS_ASSIGNING:
973 if (parse_info->operation_id == NULL)
974 {
975 LogError("Failure operation Id invalid");
976 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
977 }
978 else if (http_info->operation_id == NULL && mallocAndStrcpy_s(&http_info->operation_id, parse_info->operation_id) != 0)
979 {
980 LogError("Failure copying operation Id");
981 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
982 }
983 else
984 {
985 if (http_info->status_cb != NULL)
986 {
987 http_info->status_cb(parse_info->prov_status, http_info->retry_after_value, http_info->status_ctx);
988 }
989 http_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
990 }
991 break;
992
993 default:
994 case PROV_DEVICE_TRANSPORT_STATUS_ERROR:
995 LogError("Unable to process status reply");
996 http_info->transport_state = TRANSPORT_CLIENT_STATE_ERROR;
997 break;
998 }
999 free_json_parse_info(parse_info);
1000 }
1001 break;
1002 }
1003
1004 case TRANSPORT_CLIENT_STATE_TRANSIENT:
1005 if (http_info->status_cb != NULL)
1006 {
1007 http_info->status_cb(PROV_DEVICE_TRANSPORT_STATUS_TRANSIENT, http_info->retry_after_value, http_info->status_ctx);
1008 }
1009 http_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
1010 break;
1011
1012 case TRANSPORT_CLIENT_STATE_ERROR:
1013 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_039: [ If the state is Error, prov_transport_http_dowork shall call the registration_data callback with PROV_DEVICE_TRANSPORT_RESULT_ERROR and NULL payload_data. ] */
1014 http_info->register_data_cb(PROV_DEVICE_TRANSPORT_RESULT_ERROR, NULL, NULL, NULL, http_info->user_ctx);
1015 http_info->transport_state = TRANSPORT_CLIENT_STATE_IDLE;
1016 break;
1017
1018 case TRANSPORT_CLIENT_STATE_REG_SENT:
1019 case TRANSPORT_CLIENT_STATE_STATUS_SENT:
1020 case TRANSPORT_CLIENT_STATE_IDLE:
1021 default:
1022 break;
1023 }
1024 }
1025 }
1026}
1027
1028int prov_transport_http_set_trace(PROV_DEVICE_TRANSPORT_HANDLE handle, bool trace_on)
1029{
1030 int result;
1031 if (handle == NULL)
1032 {
1033 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_040: [ If the argument handle, is NULL, prov_transport_http_set_trace shall return a non-zero value. ] */
1034 LogError("Invalid parameter specified handle: %p", handle);
1035 result = MU_FAILURE;
1036 }
1037 else
1038 {
1039 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
1040 if (http_info->hsm_type == TRANSPORT_HSM_TYPE_X509)
1041 {
1042 http_info->log_trace = trace_on;
1043 if (http_info->http_client != NULL)
1044 {
1045 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_041: [ If the http client is not NULL, prov_transport_http_set_trace shall set the http client log trace function with the specified trace_on flag. ] */
1046 (void)uhttp_client_set_trace(http_info->http_client, http_info->log_trace, http_info->log_trace);
1047 }
1048 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_042: [ On success prov_transport_http_set_trace shall return zero. ] */
1049 result = 0;
1050 }
1051 else
1052 {
1053 LogError("Unable to enable logging when not using x509 certificates");
1054 result = MU_FAILURE;
1055 }
1056 }
1057 return result;
1058}
1059
1060static int prov_transport_http_x509_cert(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* certificate, const char* private_key)
1061{
1062 int result;
1063 if (handle == NULL || certificate == NULL || private_key == NULL)
1064 {
1065 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_043: [ If the argument handle, private_key or certificate is NULL, prov_transport_http_x509_cert shall return a non-zero value. ] */
1066 LogError("Invalid parameter specified handle: %p, certificate: %p, private_key: %p", handle, certificate, private_key);
1067 result = MU_FAILURE;
1068 }
1069 else
1070 {
1071 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
1072 if (http_info->x509_cert != NULL)
1073 {
1074 free(http_info->x509_cert);
1075 }
1076 if (http_info->private_key != NULL)
1077 {
1078 free(http_info->private_key);
1079 }
1080
1081 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_045: [ prov_transport_http_x509_cert shall store the certificate and private_key for use when the http client connects. ] */
1082 if (mallocAndStrcpy_s(&http_info->x509_cert, certificate) != 0)
1083 {
1084 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_044: [ If any error is encountered prov_transport_http_x509_cert shall return a non-zero value. ] */
1085 result = MU_FAILURE;
1086 LogError("failure allocating certificate");
1087 }
1088 else if (mallocAndStrcpy_s(&http_info->private_key, private_key) != 0)
1089 {
1090 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_044: [ If any error is encountered prov_transport_http_x509_cert shall return a non-zero value. ] */
1091 free(http_info->x509_cert);
1092 http_info->x509_cert = NULL;
1093 result = MU_FAILURE;
1094 LogError("failure allocating certificate");
1095 }
1096 else
1097 {
1098 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_046: [ On success prov_transport_http_set_trace shall return zero. ] */
1099 result = 0;
1100 }
1101 }
1102 return result;
1103}
1104
1105static int prov_transport_http_set_trusted_cert(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* certificate)
1106{
1107 int result;
1108 if (handle == NULL || certificate == NULL)
1109 {
1110 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_047: [ If the argument handle, certificate is NULL, prov_transport_http_set_trusted_cert shall return a non-zero value. ] */
1111 LogError("Invalid parameter specified handle: %p, certificate: %p", handle, certificate);
1112 result = MU_FAILURE;
1113 }
1114 else
1115 {
1116 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
1117 if (http_info->certificate != NULL)
1118 {
1119 free(http_info->certificate);
1120 }
1121
1122 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_049: [ prov_transport_http_set_trusted_cert shall store the certificate for use when the http client connects. ] */
1123 if (mallocAndStrcpy_s(&http_info->certificate, certificate) != 0)
1124 {
1125 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_048: [ If any error is encountered prov_transport_http_set_trusted_cert shall return a non-zero value. ] */
1126 result = MU_FAILURE;
1127 LogError("failure allocating certificate");
1128 }
1129 else
1130 {
1131 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_050: [ On success prov_transport_http_set_trusted_cert shall return zero. ] */
1132 result = 0;
1133 }
1134 }
1135 return result;
1136}
1137
1138static int prov_transport_http_set_proxy(PROV_DEVICE_TRANSPORT_HANDLE handle, const HTTP_PROXY_OPTIONS* proxy_options)
1139{
1140 int result;
1141 if (handle == NULL || proxy_options == NULL)
1142 {
1143 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_051: [ If the argument handle or proxy_options is NULL, prov_transport_http_set_proxy shall return a non-zero value. ] */
1144 LogError("Invalid parameter specified handle: %p, proxy_options: %p", handle, proxy_options);
1145 result = MU_FAILURE;
1146 }
1147 else
1148 {
1149 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
1150 if (proxy_options->host_address == NULL)
1151 {
1152 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_055: [ If proxy_options host_name is NULL prov_transport_http_set_proxy shall return a non-zero value. ] */
1153 LogError("NULL host_address in proxy options");
1154 result = MU_FAILURE;
1155 }
1156 else if (((proxy_options->username == NULL) || (proxy_options->password == NULL)) &&
1157 (proxy_options->username != proxy_options->password))
1158 {
1159 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_053: [ If proxy_options username is NULL and proxy_options::password is not NULL prov_transport_http_set_proxy shall return a non-zero value. ] */
1160 LogError("Only one of username and password for proxy settings was NULL");
1161 result = MU_FAILURE;
1162 }
1163 else
1164 {
1165 if (http_info->proxy_host != NULL)
1166 {
1167 free(http_info->proxy_host);
1168 }
1169 if (http_info->username != NULL)
1170 {
1171 free(http_info->username);
1172 http_info->username = NULL;
1173 }
1174 if (http_info->password != NULL)
1175 {
1176 free(http_info->password);
1177 http_info->password = NULL;
1178 }
1179
1180 http_info->proxy_port = proxy_options->port;
1181 if (mallocAndStrcpy_s(&http_info->proxy_host, proxy_options->host_address) != 0)
1182 {
1183 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_052: [ If any error is encountered prov_transport_http_set_proxy shall return a non-zero value. ] */
1184 LogError("Failure setting proxy_host name");
1185 result = MU_FAILURE;
1186 }
1187 else if (proxy_options->username != NULL && mallocAndStrcpy_s(&http_info->username, proxy_options->username) != 0)
1188 {
1189 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_052: [ If any error is encountered prov_transport_http_set_proxy shall return a non-zero value. ] */
1190 free(http_info->proxy_host);
1191 http_info->proxy_host = NULL;
1192 LogError("Failure setting proxy username");
1193 result = MU_FAILURE;
1194 }
1195 else if (proxy_options->password != NULL && mallocAndStrcpy_s(&http_info->password, proxy_options->password) != 0)
1196 {
1197 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_052: [ If any error is encountered prov_transport_http_set_proxy shall return a non-zero value. ] */
1198 LogError("Failure setting proxy password");
1199 free(http_info->proxy_host);
1200 http_info->proxy_host = NULL;
1201 free(http_info->username);
1202 http_info->username = NULL;
1203 result = MU_FAILURE;
1204 }
1205 else
1206 {
1207 /* Codes_PROV_TRANSPORT_HTTP_CLIENT_07_054: [ On success prov_transport_http_set_proxy shall return zero. ] */
1208 result = 0;
1209 }
1210 }
1211 }
1212 return result;
1213}
1214
1215static int prov_transport_http_set_option(PROV_DEVICE_TRANSPORT_HANDLE handle, const char* option, const void* value)
1216{
1217 int result;
1218 // needs to invoke correct behavior
1219 if (handle == NULL || option == NULL)
1220 {
1221 LogError("Invalid parameter specified handle: %p, option: %p", handle, option);
1222 result = MU_FAILURE;
1223 }
1224 else
1225 {
1226 PROV_TRANSPORT_HTTP_INFO* http_info = (PROV_TRANSPORT_HTTP_INFO*)handle;
1227 if (http_info->http_client == NULL && create_transport_io_object(http_info) != 0)
1228 {
1229 LogError("Failure creating transport io object");
1230 result = MU_FAILURE;
1231 }
1232 else
1233 {
1234 result = uhttp_client_set_option(http_info->http_client, option, value);
1235 }
1236 }
1237 return result;
1238}
1239
1240static PROV_DEVICE_TRANSPORT_PROVIDER prov_http_func =
1241{
1242 prov_transport_http_create,
1243 prov_transport_http_destroy,
1244 prov_transport_http_open,
1245 prov_transport_http_close,
1246 prov_transport_http_register_device,
1247 prov_transport_http_get_operation_status,
1248 prov_transport_http_dowork,
1249 prov_transport_http_set_trace,
1250 prov_transport_http_x509_cert,
1251 prov_transport_http_set_trusted_cert,
1252 prov_transport_http_set_proxy,
1253 prov_transport_http_set_option
1254};
1255
1256const PROV_DEVICE_TRANSPORT_PROVIDER* Prov_Device_HTTP_Protocol(void)
1257{
1258 return &prov_http_func;
1259}
Note: See TracBrowser for help on using the repository browser.