1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <stdarg.h>
8 #include <string.h>
9
10 #include "linkkit/infra/infra_httpc.h"
11 #include "linkkit/infra/infra_json_parser.h"
12 #include "linkkit/infra/infra_timer.h"
13 #include "linkkit/infra/infra_sha1.h"
14 #include "linkkit/infra/infra_report.h"
15 #include "http_debug.h"
16 #include "linkkit/http_api.h"
17 #include "linkkit/wrappers/wrappers.h"
18
19
20 #ifdef INFRA_MEM_STATS
21 #include "linkkit/infra/infra_mem_stats.h"
22 #define HTTP_API_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "http.api")
23 #define HTTP_API_FREE(ptr) LITE_free(ptr)
24 #else
25 #define HTTP_API_MALLOC(size) HAL_Malloc(size)
26 #define HTTP_API_FREE(ptr) \
27 { \
28 HAL_Free((void *)ptr); \
29 ptr = NULL; \
30 }
31 #endif
32
33 #define HTTP_LITE_JSON_VALUE_OF(key, src) \
34 LITE_json_value_of(key, src, 0x1234, "http.api")
35
36 #ifndef CONFIG_MID_HTTP_TIMEOUT
37 #define CONFIG_MID_HTTP_TIMEOUT (5 * 1000)
38 #endif
39
40 #ifndef CONFIG_HTTP_AUTH_TIMEOUT
41 #define CONFIG_HTTP_AUTH_TIMEOUT (5 * 1000)
42 #endif
43
44 /*
45 #define IOTX_HTTP_TIMESTAMP_OPTIONAL_ENABLE
46 */
47 #define IOTX_HTTP_SIGN_LENGTH (41)
48 #define IOTX_HTTP_SIGN_SOURCE_LEN (256)
49 #define IOTX_HTTP_AUTH_TOKEN_LEN (192 + 1)
50 #define IOTX_HTTP_URL_LEN_MAX (135)
51
52 #ifdef IOTX_HTTP_TIMESTAMP_OPTIONAL_ENABLE
53 #define IOTX_HTTP_SIGN_SRC_STR "clientId%sdeviceName%sproductKey%stimestamp%s"
54 #define IOTX_HTTP_AUTH_DEVICENAME_STR \
55 "{" \
56 "\"version\":\"%s\", \"clientId\":\"%s\"," \
57 "\"signmethod\":\"%s\",\"sign\":\"%s\"," \
58 "\"productKey\":\"%s\",\"deviceName\":\"%s\"," \
59 "\"timestamp\":\"%s\"" \
60 "}"
61 #else
62 #define IOTX_HTTP_SIGN_SRC_STR "clientId%sdeviceName%sproductKey%s"
63 #define IOTX_HTTP_AUTH_DEVICENAME_STR \
64 "{" \
65 "\"version\":\"%s\", \"clientId\":\"%s\"," \
66 "\"signmethod\":\"%s\",\"sign\":\"%s\"," \
67 "\"productKey\":\"%s\",\"deviceName\":\"%s\"" \
68 "}"
69 #endif
70
71 #define IOTX_HTTP_AUTH_STR "auth"
72 #define IOTX_HTTP_ONLINE_SERVER_URL \
73 "https://iot-as-http.cn-shanghai.aliyuncs.com"
74 #define IOTX_HTTP_ONLINE_SERVER_PORT 443
75
76 #define IOTX_SHA_METHOD "hmacsha1"
77
78 #define IOTX_HTTP_HEADER_KEEPALIVE_STR "Connection: Keep-Alive\r\n"
79 #define IOTX_HTTP_HEADER_PASSWORD_STR "password:"
80 #define IOTX_HTTP_HEADER_CONTENT_TYPE_STR \
81 "Content-Type: application/octet-stream\r\n"
82 #define IOTX_HTTP_HEADER_END_STR "\r\n"
83
84 #define IOTX_HTTP_UPSTREAM_HEADER_STR \
85 IOTX_HTTP_HEADER_KEEPALIVE_STR \
86 IOTX_HTTP_HEADER_PASSWORD_STR \
87 "%s" IOTX_HTTP_HEADER_END_STR IOTX_HTTP_HEADER_CONTENT_TYPE_STR
88
89 #define HTTP_AUTH_RESP_MAX_LEN (256)
90
91 typedef struct {
92 char *payload;
93 int alread_download;
94 int payload_len;
95 } http_recv_message_t;
96
97 static iotx_http_t *iotx_http_context_bak = NULL;
98
99 /*
100 Http server url: https://iot-as-http.cn-shanghai.aliyuncs.com
101 Only https protocal is supported at present.
102 The /auth interface is used to get access token before any data transform
103 which need to be requested just one time. The device must call /auth to get
104 the token before transfer any data. Every data transfer need to be with access
105 token. You need to request for a new token if the current token have been
106 expired. Token can be cached in local devices, which has 48 hours term of
107 validity. POST /auth HTTP/1.1 Host: iot-as-http.cn-shanghai.aliyuncs.com
108 Content-Type: application/json
109 body:
110 {"version":"default","clientId":"xxxxx","signmethod":"hmacsha1","sign":"xxxxxxxxxx","productKey":"xxxxxx","deviceName":"xxxxxxx","timestamp":"xxxxxxx"}
111 */
112
iotx_calc_sign(const char * p_device_secret,const char * p_msg,char * sign)113 static int iotx_calc_sign(const char *p_device_secret, const char *p_msg,
114 char *sign)
115 {
116 http_info("| method: %s", IOTX_SHA_METHOD);
117 utils_hmac_sha1(p_msg, strlen(p_msg), sign, p_device_secret,
118 strlen(p_device_secret));
119 return SUCCESS_RETURN;
120 }
121
calc_snprintf_string_length(char * fmt,...)122 static int calc_snprintf_string_length(char *fmt, ...)
123 {
124 va_list args;
125 int rc = 0;
126 char *p = NULL;
127 char *sval = NULL;
128
129 if (NULL == fmt) {
130 return -1;
131 }
132
133 va_start(args, fmt);
134
135 for (p = fmt; *p; p++) {
136 if (*p != '%') {
137 rc++;
138 continue;
139 }
140 switch (*++p) {
141 case 's':
142 for (sval = va_arg(args, char *); *sval; sval++) {
143 rc++;
144 }
145 break;
146 default:
147 rc++;
148 break;
149 }
150 }
151
152 va_end(args);
153
154 return rc;
155 }
156
construct_full_http_authenticate_url(char * buf)157 static int construct_full_http_authenticate_url(char *buf)
158 {
159 LITE_snprintf(buf, IOTX_HTTP_URL_LEN_MAX, "%s/%s",
160 IOTX_HTTP_ONLINE_SERVER_URL, IOTX_HTTP_AUTH_STR);
161 http_info("get_http_authenticate_url is %s", buf);
162 return 0;
163 }
164
construct_full_http_upstream_url(char * buf,const char * topic_path)165 static int construct_full_http_upstream_url(char *buf, const char *topic_path)
166 {
167 LITE_snprintf(buf, IOTX_HTTP_URL_LEN_MAX, "%s%s",
168 IOTX_HTTP_ONLINE_SERVER_URL, topic_path);
169 http_info("construct_full_http_upstream_url is %s", buf);
170 return 0;
171 }
172
http_report_func(void * handle,const char * topic_name,int req_ack,void * data,int len)173 static int http_report_func(void *handle, const char *topic_name, int req_ack,
174 void *data, int len)
175 {
176 iotx_http_message_param_t msg_param;
177 char request_buf[1024];
178 char topic_path[100];
179
180 if (handle == NULL || topic_name == NULL || data == NULL) {
181 http_err("params err");
182 return -1;
183 }
184
185 HAL_Snprintf(topic_path, sizeof(topic_path), "/topic%s", topic_name);
186
187 memset(&msg_param, 0, sizeof(iotx_http_message_param_t));
188 msg_param.request_payload = (char *)data;
189 msg_param.response_payload = request_buf;
190 msg_param.timeout_ms = CONFIG_MID_HTTP_TIMEOUT;
191 msg_param.request_payload_len = len;
192 msg_param.response_payload_len = 1024;
193 msg_param.topic_path = topic_path;
194
195 return IOT_HTTP_SendMessage(handle, &msg_param);
196 }
197
verify_iotx_http_context(void * handle)198 static void *verify_iotx_http_context(void *handle)
199 {
200 iotx_http_t *iotx_http_context = (iotx_http_t *)handle;
201
202 if (NULL == iotx_http_context || NULL == iotx_http_context_bak ||
203 iotx_http_context_bak != iotx_http_context) {
204 http_err("iotx_http_context not valid pointer!");
205
206 iotx_http_context = NULL;
207 }
208
209 return iotx_http_context;
210 }
211
_http_recv_callback(char * ptr,int length,int total_length,void * userdata)212 static int _http_recv_callback(char *ptr, int length, int total_length,
213 void *userdata)
214 {
215 http_recv_message_t *response = (http_recv_message_t *)userdata;
216 if (response->alread_download + length > response->payload_len) {
217 return FAIL_RETURN;
218 }
219
220 memcpy(response->payload + response->alread_download, ptr, length);
221 response->alread_download += length;
222
223 return length;
224 }
225
IOT_HTTP_Init(iotx_http_param_t * pInitParams)226 void *IOT_HTTP_Init(iotx_http_param_t *pInitParams)
227 {
228 iotx_device_info_t *p_devinfo;
229 iotx_http_t *iotx_http_context;
230
231 /* currently http is singleton, init twice not allowed. */
232 if (NULL != iotx_http_context_bak) {
233 http_err("Init twice not allowed, please deinit first");
234 return NULL;
235 }
236
237 if (NULL == pInitParams || NULL == pInitParams->device_info) {
238 http_err("Invalid argument: pInitParams or device_info = NULL");
239 return NULL;
240 }
241
242 p_devinfo = pInitParams->device_info;
243
244 /*
245 HAL_SetProductKey(p_devinfo->product_key);
246 HAL_SetDeviceName(p_devinfo->device_name);
247 HAL_SetDeviceSecret(p_devinfo->device_secret);
248 */
249
250 iotx_http_context = (iotx_http_t *)HTTP_API_MALLOC(sizeof(iotx_http_t));
251
252 if (NULL == iotx_http_context) {
253 http_err("Allocate memory for iotx_http_context failed");
254 return NULL;
255 }
256
257 memset(iotx_http_context, 0x00, sizeof(iotx_http_t));
258
259 iotx_http_context->keep_alive = pInitParams->keep_alive;
260 iotx_http_context->timeout_ms = pInitParams->timeout_ms;
261 iotx_http_context->p_auth_token = HTTP_API_MALLOC(IOTX_HTTP_AUTH_TOKEN_LEN);
262 if (NULL == iotx_http_context->p_auth_token) {
263 http_err("Allocate memory for auth token failed");
264 goto err;
265 }
266 memset(iotx_http_context->p_auth_token, 0x00, IOTX_HTTP_AUTH_TOKEN_LEN);
267 iotx_http_context->is_authed = 0;
268 iotx_http_context->auth_token_len = IOTX_HTTP_AUTH_TOKEN_LEN;
269
270 /*Get deivce information*/
271 iotx_http_context->p_devinfo =
272 (iotx_device_info_t *)HTTP_API_MALLOC(sizeof(iotx_device_info_t));
273 if (NULL == iotx_http_context->p_devinfo) {
274 http_err("Allocate memory for iotx_http_context->p_devinfo failed");
275 goto err;
276 }
277 memset(iotx_http_context->p_devinfo, 0x00, sizeof(iotx_device_info_t));
278
279 /*It should be implement by the user*/
280 memset(iotx_http_context->p_devinfo, 0x00, sizeof(iotx_device_info_t));
281 strncpy(iotx_http_context->p_devinfo->device_id, p_devinfo->device_id,
282 strlen(p_devinfo->device_id));
283 strncpy(iotx_http_context->p_devinfo->product_key, p_devinfo->product_key,
284 strlen(p_devinfo->product_key));
285 strncpy(iotx_http_context->p_devinfo->device_secret,
286 p_devinfo->device_secret, strlen(p_devinfo->device_secret));
287 strncpy(iotx_http_context->p_devinfo->device_name, p_devinfo->device_name,
288 strlen(p_devinfo->device_name));
289
290 iotx_http_context_bak = iotx_http_context;
291
292 return iotx_http_context;
293 err:
294 /* Error, release the memory */
295 if (NULL != iotx_http_context) {
296 if (NULL != iotx_http_context->p_devinfo) {
297 HTTP_API_FREE(iotx_http_context->p_devinfo);
298 }
299 if (NULL != iotx_http_context->p_auth_token) {
300 HTTP_API_FREE(iotx_http_context->p_auth_token);
301 }
302
303 iotx_http_context->auth_token_len = 0;
304 HTTP_API_FREE(iotx_http_context);
305 }
306 return NULL;
307 }
308
IOT_HTTP_DeInit(void ** handle)309 void IOT_HTTP_DeInit(void **handle)
310 {
311 iotx_http_t *iotx_http_context;
312 if (NULL == handle) {
313 http_err("handle is NULL pointer");
314 return;
315 }
316 iotx_http_context = verify_iotx_http_context(*handle);
317 if (iotx_http_context == NULL) {
318 return;
319 }
320
321 if (NULL != iotx_http_context->p_devinfo) {
322 HTTP_API_FREE(iotx_http_context->p_devinfo);
323 }
324 if (NULL != iotx_http_context->p_auth_token) {
325 HTTP_API_FREE(iotx_http_context->p_auth_token);
326 }
327
328 iotx_http_context->auth_token_len = 0;
329 HTTP_API_FREE(iotx_http_context);
330 iotx_http_context_bak = NULL;
331 }
332
IOT_HTTP_DeviceNameAuth(void * handle)333 int IOT_HTTP_DeviceNameAuth(void *handle)
334 {
335 int ret = -1;
336 int ret_code = 0;
337 char *pvalue = NULL;
338 char *response_message = NULL;
339 char sign[IOTX_HTTP_SIGN_LENGTH] = { 0 };
340 char http_url[IOTX_HTTP_URL_LEN_MAX] = { 0 };
341 char timestamp[14] = { 0 };
342 void *http_handle = NULL;
343 char *req_payload = NULL;
344 char *rsp_payload = NULL;
345 int len = 0;
346 char p_msg_unsign[IOTX_HTTP_SIGN_SOURCE_LEN] = { 0 };
347 iotx_time_t timer;
348 iotx_http_t *iotx_http_context;
349 const char *pub_key = NULL;
350 char *http_header =
351 "Connection: Keep-Alive\r\n"
352 "Content-Type: application/json\r\n";
353 int http_port = IOTX_HTTP_ONLINE_SERVER_PORT;
354 iotx_http_method_t http_method = IOTX_HTTP_POST;
355 int http_timeout_ms = CONFIG_HTTP_AUTH_TIMEOUT;
356 int http_recv_maxlen = 0;
357 http_recv_message_t recv_message;
358
359 /* */
360 /* body: */
361 /* { */
362 /* "version": "default",//默认default */
363 /* "clientId": "xxxxxx",//必填 */
364 /* "signmethod": "hmacsha1",//只支持hmacmd5和hmacsha1,默认hmacmd5 */
365 /* "sign": "xxxxxxxxxxxxx",//必填,signmethod(deviceSecret,content), content
366 * = 将所有提交给服务器的参数(version,sign,signmethod除外),
367 * 按照字母顺序排序, 然后将参数值依次拼接,无拼接符号 */
368 /* "productKey": "xxxxxx",//必填 */
369 /* "deviceName": "xxxxxx",//必填 */
370 /* "timestamp": "xxxxxx"//选填 13byte */
371 /* } */
372
373 iotx_http_context = verify_iotx_http_context(handle);
374 if (iotx_http_context == NULL) {
375 goto do_exit;
376 }
377 iotx_http_context->is_authed = 0;
378
379 /* FIXME:some compile error when calling this function. Get TimeStamp */
380 /*
381 if(!utils_get_epoch_time_from_ntp(timestamp, sizeof(timestamp)))
382 {
383 http_info("http time response: \r\n\r\n%s", timestamp);
384 goto do_exit;
385 }
386 */
387
388 /* Calculate Sign */
389 LITE_snprintf(p_msg_unsign, IOTX_HTTP_SIGN_SOURCE_LEN,
390 IOTX_HTTP_SIGN_SRC_STR,
391 iotx_http_context->p_devinfo->device_id,
392 iotx_http_context->p_devinfo->device_name,
393 iotx_http_context->p_devinfo->product_key
394 #ifdef IOTX_HTTP_TIMESTAMP_OPTIONAL_ENABLE
395 ,
396 timestamp
397 #endif
398 );
399
400 iotx_calc_sign(iotx_http_context->p_devinfo->device_secret, p_msg_unsign,
401 sign);
402
403 /* to save stack memory*/
404 len = calc_snprintf_string_length(
405 IOTX_HTTP_AUTH_DEVICENAME_STR, "default",
406 iotx_http_context->p_devinfo->device_id, IOTX_SHA_METHOD, sign,
407 iotx_http_context->p_devinfo->product_key,
408 iotx_http_context->p_devinfo->device_name, timestamp);
409
410 if (len < 0) {
411 goto do_exit;
412 }
413
414 req_payload = (char *)HTTP_API_MALLOC(len + 1);
415 memset(req_payload, 0, len + 1);
416
417 http_debug("allocate req_payload: len = %d", len);
418
419 len = HAL_Snprintf(req_payload, len + 1, IOTX_HTTP_AUTH_DEVICENAME_STR,
420 "default", iotx_http_context->p_devinfo->device_id,
421 IOTX_SHA_METHOD, sign,
422 iotx_http_context->p_devinfo->product_key,
423 iotx_http_context->p_devinfo->device_name, timestamp);
424 http_debug("len = %d, req_payload: \r\n%s", len, req_payload);
425
426 /* Malloc Http Response Payload */
427 rsp_payload = (char *)HTTP_API_MALLOC(HTTP_AUTH_RESP_MAX_LEN);
428 if (NULL == rsp_payload) {
429 http_err("Allocate HTTP rsp_payload buf failed!");
430 goto do_exit;
431 }
432 memset(rsp_payload, 0, HTTP_AUTH_RESP_MAX_LEN);
433
434 /* Construct Auth Url */
435 construct_full_http_authenticate_url(http_url);
436
437 http_recv_maxlen = HTTP_AUTH_RESP_MAX_LEN;
438
439 /* Set httpclient and httpclient_data */
440 memset(&recv_message, 0, sizeof(http_recv_message_t));
441 recv_message.payload = rsp_payload;
442 recv_message.payload_len = HTTP_AUTH_RESP_MAX_LEN;
443
444 /*
445 Test Code
446 iotx_http_context->p_auth_token =
447 "eyJ0eXBlIjoiSldUIiwiYWxnIjoiaG1hY3NoYTEifQ.eyJleHBpcmUiOjE1MDQ3ODE4MzQ5MDAsInRva2VuIjoiM2EyZTRmYzMyNjk5NDE0Y2E3MDFjNzIzNzI1YjIyNDgifQ.e87AFhkvNKiqF5xdgm1P47f9DwY";
448 iotx_http_context->is_authed = 1;
449 ret = 0;
450 goto do_exit;
451 Test Code
452 */
453
454 {
455 extern const char *iotx_ca_crt;
456 pub_key = iotx_ca_crt;
457 }
458
459 http_handle = wrapper_http_init();
460 if (http_handle == NULL) {
461 http_err("Allocate Http Resource Failed");
462 goto do_exit;
463 }
464
465 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_URL, (void *)http_url);
466 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_PORT, (void *)&http_port);
467 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_METHOD, (void *)&http_method);
468 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_HEADER, (void *)http_header);
469 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_CERT, (void *)pub_key);
470 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_TIMEOUT,
471 (void *)&http_timeout_ms);
472 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVCALLBACK,
473 (void *)_http_recv_callback);
474 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVMAXLEN,
475 (void *)&http_recv_maxlen);
476 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVCONTEXT,
477 (void *)&recv_message);
478
479 /* Send Request and Get Response */
480 if (0 > wrapper_http_perform(http_handle, req_payload, len)) {
481 http_err("wrapper_http_perform error");
482
483 goto do_exit;
484 }
485
486 if (0 == iotx_http_context->keep_alive) {
487 http_info("http not keepalive");
488 }
489 /*
490 body:
491 {
492 "code": 0,//业务状态码
493 "message": "success",//业务信息
494 "info": {
495 "token":
496 "eyJ0eXBlIjoiSldUIiwiYWxnIjoiaG1hY3NoYTEifQ.eyJleHBpcmUiOjE1MDI1MzE1MDc0NzcsInRva2VuIjoiODA0ZmFjYTBiZTE3NGUxNjliZjY0ODVlNWNiNDg3MTkifQ.OjMwu29F0CY2YR_6oOyiOLXz0c8"
497 }
498 }
499 */
500 http_info("http response: \r\n\r\n%s\r\n", rsp_payload);
501
502 pvalue = HTTP_LITE_JSON_VALUE_OF("code", rsp_payload);
503 if (!pvalue) {
504 goto do_exit;
505 }
506 ret_code = atoi(pvalue);
507 http_info("ret_code = %d", ret_code);
508 HTTP_API_FREE(pvalue);
509 pvalue = NULL;
510
511 pvalue = HTTP_LITE_JSON_VALUE_OF("message", rsp_payload);
512 if (NULL == pvalue) {
513 goto do_exit;
514 }
515 response_message = pvalue;
516 http_info("response_message: %s", response_message);
517 (void)response_message;
518 HTTP_API_FREE(pvalue);
519 pvalue = NULL;
520
521 switch (ret_code) {
522 case IOTX_HTTP_SUCCESS:
523 break;
524 case IOTX_HTTP_COMMON_ERROR:
525 case IOTX_HTTP_PARAM_ERROR:
526 case IOTX_HTTP_AUTH_CHECK_ERROR:
527 case IOTX_HTTP_UPDATE_SESSION_ERROR:
528 case IOTX_HTTP_REQUEST_TOO_MANY_ERROR:
529 default:
530 ret = FAIL_RETURN;
531 goto do_exit;
532 }
533
534 pvalue = HTTP_LITE_JSON_VALUE_OF("info.token", rsp_payload);
535 if (NULL == pvalue) {
536 http_err("can't get token from json, Abort!");
537 goto do_exit;
538 }
539
540 if (strlen(pvalue) > IOTX_HTTP_AUTH_TOKEN_LEN - 1) {
541 http_err("token is out of size");
542 goto do_exit;
543 }
544
545 strcpy(iotx_http_context->p_auth_token, pvalue);
546 iotx_http_context->is_authed = 1;
547 HTTP_API_FREE(pvalue);
548 pvalue = NULL;
549
550 iotx_set_report_func(http_report_func);
551 /* report module id */
552 ret = iotx_report_mid(iotx_http_context);
553 if (SUCCESS_RETURN != ret) {
554 http_err("Send ModuleId message to server(Http) failed, ret = %d", ret);
555 goto do_exit;
556 }
557 /* report device information */
558 ret = iotx_report_devinfo(iotx_http_context);
559 if (SUCCESS_RETURN != ret) {
560 http_err("Send devinfo message to server(Http) failed, ret = %d", ret);
561 goto do_exit;
562 }
563 /* report firmware */
564 ret = iotx_report_firmware_version(iotx_http_context);
565 if (SUCCESS_RETURN != ret) {
566 http_err("Send firmware message to server(Http) failed, ret = %d", ret);
567 goto do_exit;
568 }
569
570 ret = 0;
571
572 do_exit:
573 if (http_handle) {
574 wrapper_http_deinit(&http_handle);
575 http_handle = NULL;
576 }
577
578 if (pvalue) {
579 HTTP_API_FREE(pvalue);
580 pvalue = NULL;
581 }
582 if (req_payload) {
583 HTTP_API_FREE(req_payload);
584 req_payload = NULL;
585 }
586 if (rsp_payload) {
587 HTTP_API_FREE(rsp_payload);
588 rsp_payload = NULL;
589 }
590
591 return ret;
592 }
593
IOT_HTTP_SendMessage(void * handle,iotx_http_message_param_t * msg_param)594 int IOT_HTTP_SendMessage(void *handle, iotx_http_message_param_t *msg_param)
595 {
596 int ret = -1;
597 int response_code = 0;
598 char *pvalue = NULL;
599 char http_url[IOTX_HTTP_URL_LEN_MAX] = { 0 };
600 char *messageId = NULL;
601 char *user_data = NULL;
602 void *http_handle = NULL;
603 int len = 0;
604 uint32_t payload_len = 0;
605 iotx_time_t timer;
606 iotx_http_t *iotx_http_context;
607 const char *pub_key = NULL;
608 char *http_header =
609 "Connection: Keep-Alive\r\n"
610 "Content-Type: application/octet-stream\r\n";
611 int http_port = IOTX_HTTP_ONLINE_SERVER_PORT;
612 iotx_http_method_t http_method = IOTX_HTTP_POST;
613 int http_timeout_ms = 0;
614 int http_recv_maxlen = 0;
615 http_recv_message_t recv_message;
616
617 /*
618 POST /topic/${topic} HTTP/1.1
619 Host: iot-as-http.cn-shanghai.aliyuncs.com
620 password:${token}
621 Content-Type: application/octet-stream
622 body: ${your_data}
623 */
624 iotx_http_context = verify_iotx_http_context(handle);
625 if (iotx_http_context == NULL) {
626 goto do_exit;
627 }
628
629 if (NULL == msg_param) {
630 http_err("iotx_http_context or msg_param NULL pointer!");
631 goto do_exit;
632 }
633
634 if (0 == iotx_http_context->is_authed) {
635 http_err("Device is not authed");
636 goto do_exit;
637 }
638
639 if (NULL == msg_param->request_payload) {
640 http_err("IOT_HTTP_SendMessage request_payload NULL!");
641 goto do_exit;
642 }
643
644 if (NULL == msg_param->response_payload) {
645 http_err("IOT_HTTP_SendMessage response_payload NULL!");
646 goto do_exit;
647 }
648
649 if (NULL == msg_param->topic_path) {
650 http_err("IOT_HTTP_SendMessage topic_path NULL!");
651 goto do_exit;
652 }
653
654 http_timeout_ms = msg_param->timeout_ms;
655 payload_len = strlen(msg_param->request_payload) + 1;
656
657 msg_param->request_payload_len =
658 msg_param->request_payload_len > payload_len
659 ? payload_len
660 : msg_param->request_payload_len;
661
662 /* Construct Auth Url */
663 construct_full_http_upstream_url(http_url, msg_param->topic_path);
664
665 len = strlen(IOTX_HTTP_HEADER_PASSWORD_STR) +
666 strlen(iotx_http_context->p_auth_token) +
667 strlen(IOTX_HTTP_HEADER_KEEPALIVE_STR) +
668 strlen(IOTX_HTTP_HEADER_END_STR) +
669 strlen(IOTX_HTTP_HEADER_CONTENT_TYPE_STR);
670 http_header = HTTP_API_MALLOC(len + 1);
671 if (NULL == http_header) {
672 http_err("Allocate memory for httpc->header failed");
673 goto do_exit;
674 }
675 LITE_snprintf(http_header, len + 1, IOTX_HTTP_UPSTREAM_HEADER_STR,
676 iotx_http_context->p_auth_token);
677
678 http_info("httpc->header = %s", http_header);
679
680 http_info("request_payload: \r\n\r\n%s\r\n", msg_param->request_payload);
681
682 {
683 extern const char *iotx_ca_crt;
684 pub_key = iotx_ca_crt;
685 }
686
687 http_handle = wrapper_http_init();
688 if (http_handle == NULL) {
689 http_err("Allocate Http Resource Failed");
690 goto do_exit_pre;
691 }
692
693 http_recv_maxlen = msg_param->response_payload_len;
694
695 memset(&recv_message, 0, sizeof(http_recv_message_t));
696 recv_message.payload = msg_param->response_payload;
697 recv_message.payload_len = msg_param->response_payload_len;
698
699 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_URL, (void *)http_url);
700 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_PORT, (void *)&http_port);
701 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_METHOD, (void *)&http_method);
702 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_HEADER, (void *)http_header);
703 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_CERT, (void *)pub_key);
704 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_TIMEOUT,
705 (void *)&http_timeout_ms);
706 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVCALLBACK,
707 (void *)_http_recv_callback);
708 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVMAXLEN,
709 (void *)&http_recv_maxlen);
710 wrapper_http_setopt(http_handle, IOTX_HTTPOPT_RECVCONTEXT,
711 (void *)&recv_message);
712
713 /* Send Request and Get Response */
714 ret = wrapper_http_perform(http_handle, msg_param->request_payload,
715 msg_param->request_payload_len);
716 if (ret < 0) {
717 http_err("wrapper_http_perform error");
718
719 goto do_exit_pre;
720 }
721
722 /*
723 body:
724 {
725 "code": 0,
726 "message": "success",
727 "info": {
728 "messageId": 892687627916247040,
729 "data": byte[]//may be NULL
730 }
731 }
732 */
733 http_info("http response: \r\n\r\n%s\r\n", msg_param->response_payload);
734
735 pvalue = HTTP_LITE_JSON_VALUE_OF("code", msg_param->response_payload);
736 if (!pvalue) {
737 goto do_exit_pre;
738 }
739
740 response_code = atoi(pvalue);
741 HTTP_API_FREE(pvalue);
742 pvalue = NULL;
743 http_info("response code: %d", response_code);
744
745 pvalue = HTTP_LITE_JSON_VALUE_OF("message", msg_param->response_payload);
746 if (NULL == pvalue) {
747 goto do_exit_pre;
748 }
749 http_info("response_message: %s", pvalue);
750 HTTP_API_FREE(pvalue);
751 pvalue = NULL;
752
753 switch (response_code) {
754 case IOTX_HTTP_SUCCESS:
755 break;
756 case IOTX_HTTP_TOKEN_EXPIRED_ERROR:
757 iotx_http_context->is_authed = IOT_FALSE;
758 IOT_HTTP_DeviceNameAuth((iotx_http_t *)iotx_http_context);
759 case IOTX_HTTP_COMMON_ERROR:
760 case IOTX_HTTP_PARAM_ERROR:
761 case IOTX_HTTP_AUTH_CHECK_ERROR:
762 case IOTX_HTTP_TOKEN_NULL_ERROR:
763 case IOTX_HTTP_TOKEN_CHECK_ERROR:
764 case IOTX_HTTP_UPDATE_SESSION_ERROR:
765 case IOTX_HTTP_PUBLISH_MESSAGE_ERROR:
766 case IOTX_HTTP_REQUEST_TOO_MANY_ERROR:
767 default:
768 goto do_exit_pre;
769 }
770
771 /* info.messageId */
772 pvalue =
773 HTTP_LITE_JSON_VALUE_OF("info.messageId", msg_param->response_payload);
774 if (NULL == pvalue) {
775 http_err("messageId: NULL");
776 goto do_exit_pre;
777 }
778 messageId = pvalue;
779 http_info("messageId: %s", messageId);
780 (void)messageId;
781 HTTP_API_FREE(pvalue);
782 pvalue = NULL;
783
784 /* info.data */
785 pvalue = HTTP_LITE_JSON_VALUE_OF("info.data", msg_param->response_payload);
786 user_data = pvalue;
787
788 /* Maybe NULL */
789 if (user_data) {
790 http_info("user_data: %s", user_data);
791 } else {
792 http_info("user_data: %p", user_data);
793 }
794 if (NULL != pvalue) {
795 HTTP_API_FREE(pvalue);
796 }
797 pvalue = NULL;
798
799 ret = 0;
800
801 do_exit_pre:
802
803 if (http_handle) {
804 wrapper_http_deinit(&http_handle);
805 http_handle = NULL;
806 }
807
808 if (pvalue) {
809 HTTP_API_FREE(pvalue);
810 }
811
812 if (http_header) {
813 HTTP_API_FREE(http_header);
814 }
815
816 do_exit:
817
818 return ret;
819 }
820
IOT_HTTP_Disconnect(void * handle)821 void IOT_HTTP_Disconnect(void *handle)
822 {
823
824 verify_iotx_http_context(handle);
825 }
826
827