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