1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 
10 #include "linkkit/infra/infra_defs.h"
11 #include "linkkit/infra/infra_types.h"
12 #include "linkkit/infra/infra_httpc.h"
13 #include "linkkit/infra/infra_sha1.h"
14 #include "linkkit/infra/infra_timer.h"
15 #include "linkkit/infra/infra_list.h"
16 #include "linkkit/infra/infra_log.h"
17 
18 #include "http2_internal.h"
19 #include "linkkit/http2_api.h"
20 #include "http2_config.h"
21 
22 #define URL_MAX_LEN (100)
23 
24 typedef enum {
25     NUM_STRING_ENUM = 0,
26     PATH_CREATE_STR_ENUM = 1,
27     PATH_UPLOAD_STR_ENUM = 2,
28     CID_STRING_ENUM = 3,
29     ORI_SIGN_STR_ENUM = 4,
30     FS_STRING_ENUM = 5,
31     REAL_SIGN_STR_ENUM = 6,
32 } HEADER_TYPE_ENUM;
33 
34 typedef struct _device_info_struct_ {
35     char product_key[IOTX_PRODUCT_KEY_LEN + 1];
36     char device_name[IOTX_DEVICE_NAME_LEN + 1];
37     char device_secret[IOTX_DEVICE_SECRET_LEN + 1];
38     char url[URL_MAX_LEN + 1];
39     int port;
40 } device_info;
41 
42 typedef struct {
43     unsigned int stream_id; /* http2 protocol stream id */
44     char *channel_id; /* string return by server to identify a specific stream
45                          channel, different from stream identifier which is a
46                          field in http2 frame */
47     stream_type_t stream_type; /* check @stream_type_t */
48     void *semaphore;           /* semaphore for http2 response sync */
49     char status_code[5];       /* http2 response status code */
50     uint8_t rcv_hd_cnt;        /* the number of concerned heads received*/
51     void *user_data;           /* data passed to the stream callback function */
52     http2_list_t list;         /* list_head */
53 } http2_stream_node_t;
54 
55 static device_info g_device_info;
56 
57 static stream_handle_t *g_stream_handle = NULL;
58 static httpclient_t g_client;
59 
_set_device_info(device_conn_info_t * device_info)60 static int _set_device_info(device_conn_info_t *device_info)
61 {
62     memset(g_device_info.product_key, 0, IOTX_PRODUCT_KEY_LEN + 1);
63     memset(g_device_info.device_name, 0, IOTX_DEVICE_NAME_LEN + 1);
64     memset(g_device_info.device_secret, 0, IOTX_DEVICE_SECRET_LEN + 1);
65     memset(g_device_info.url, 0, URL_MAX_LEN + 1);
66 
67     strncpy(g_device_info.product_key, device_info->product_key,
68             IOTX_PRODUCT_KEY_LEN);
69     strncpy(g_device_info.device_name, device_info->device_name,
70             IOTX_DEVICE_NAME_LEN);
71     strncpy(g_device_info.device_secret, device_info->device_secret,
72             IOTX_DEVICE_SECRET_LEN);
73     if (device_info->url != NULL) {
74         strncpy(g_device_info.url, device_info->url, URL_MAX_LEN);
75     }
76     g_device_info.port = device_info->port;
77 
78     return 0;
79 }
80 
http2_nv_copy(http2_header * nva,int start,http2_header * nva_copy,int num)81 static int http2_nv_copy(http2_header *nva, int start, http2_header *nva_copy,
82                          int num)
83 {
84     int i, j;
85     for (i = start, j = 0; j < num; i++, j++) {
86         nva[i].name = nva_copy[j].name;
87         nva[i].value = nva_copy[j].value;
88         nva[i].namelen = nva_copy[j].namelen;
89         nva[i].valuelen = nva_copy[j].valuelen;
90     }
91     return i;
92 }
93 
iotx_http2_get_url(char * buf,char * productkey)94 static int iotx_http2_get_url(char *buf, char *productkey)
95 {
96     if (strlen(g_device_info.url) != 0) {
97         strncpy(buf, g_device_info.url, URL_MAX_LEN);
98         return g_device_info.port;
99     }
100 #if defined(ON_DAILY)
101     sprintf(buf, "%s", "10.101.12.205");
102     return 9999;
103 #elif defined(ON_PRE)
104     sprintf(buf, "%s", "100.67.141.158");
105     return 8443;
106 #else
107     sprintf(buf, "%s", productkey);
108     strcat(buf, ".iot-as-http2.cn-shanghai.aliyuncs.com");
109     return 443;
110 #endif
111 }
112 
file_upload_gen_string(char * str,int type,char * para1,int para2)113 static void file_upload_gen_string(char *str, int type, char *para1, int para2)
114 {
115     switch (type) {
116     case NUM_STRING_ENUM:
117         {
118             sprintf(str, "%d", para2);
119             break;
120         }
121     case PATH_CREATE_STR_ENUM:
122     case PATH_UPLOAD_STR_ENUM:
123     case ORI_SIGN_STR_ENUM:
124     case CID_STRING_ENUM:
125         {
126             if (type == PATH_CREATE_STR_ENUM) {
127                 sprintf(str, "/message/pub_with_resp/sys/%s/%s/thing/%s/create",
128                         g_device_info.product_key, g_device_info.device_name,
129                         para1);
130             } else if (type == PATH_UPLOAD_STR_ENUM) {
131                 sprintf(str, "/message/pub_with_resp/sys/%s/%s/thing/%s/upload",
132                         g_device_info.product_key, g_device_info.device_name,
133                         para1);
134             } else if (type == ORI_SIGN_STR_ENUM) {
135                 sprintf(str, "clientId%sdeviceName%sproductKey%s", para1,
136                         g_device_info.device_name, g_device_info.product_key);
137             } else {
138                 sprintf(str, "%s.%s", g_device_info.product_key,
139                         g_device_info.device_name);
140             }
141             break;
142         }
143     case REAL_SIGN_STR_ENUM:
144         {
145             utils_hmac_sha1(para1, strlen(para1), str,
146                             g_device_info.device_secret,
147                             strlen(g_device_info.device_secret));
148             break;
149         }
150     default:
151         {
152             h2_err("ASSERT\n");
153             break;
154         }
155     }
156 }
157 
http2_stream_node_search(stream_handle_t * handle,unsigned int stream_id,http2_stream_node_t ** p_node)158 static int http2_stream_node_search(stream_handle_t *handle,
159                                     unsigned int stream_id,
160                                     http2_stream_node_t **p_node)
161 {
162     http2_stream_node_t *search_node = NULL;
163     *p_node = NULL;
164 
165     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
166     POINTER_SANITY_CHECK(p_node, NULL_VALUE_ERROR);
167 
168     list_for_each_entry(search_node, &handle->stream_list, list,
169                         http2_stream_node_t)
170     {
171         if (search_node->stream_id == stream_id) {
172             *p_node = search_node;
173             return SUCCESS_RETURN;
174         }
175     }
176 
177     h2_debug("stream node not exist, stream_id = %d", stream_id);
178     return FAIL_RETURN;
179 }
180 
on_stream_header(int32_t stream_id,int cat,const uint8_t * name,uint32_t namelen,const uint8_t * value,uint32_t valuelen,uint8_t flags)181 static void on_stream_header(int32_t stream_id, int cat, const uint8_t *name,
182                              uint32_t namelen, const uint8_t *value,
183                              uint32_t valuelen, uint8_t flags)
184 {
185     http2_stream_node_t *node = NULL;
186     char *channel_id = NULL;
187     char *user_data = NULL;
188 
189     if (g_stream_handle == NULL) {
190         return;
191     }
192     http2_stream_node_search(g_stream_handle, stream_id, &node);
193     if (node != NULL) {
194         channel_id = node->channel_id;
195         user_data = node->user_data;
196 
197         switch (cat) {
198         case 0x01:
199             if (strncmp((char *)name, "x-data-stream-id", (int)namelen) == 0) {
200                 node->channel_id = HTTP2_STREAM_MALLOC(valuelen + 1);
201                 if (node->channel_id == NULL) {
202                     return;
203                 }
204                 memset(node->channel_id, 0, (int)valuelen + 1);
205                 memcpy(node->channel_id, (char *)value, (int)valuelen);
206                 if (++node->rcv_hd_cnt == 2) {
207                     HAL_SemaphorePost(node->semaphore);
208                 }
209             }
210 #ifdef FS_ENABLED
211             else if (strncmp((char *)name, "x-file-upload-id", (int)namelen) ==
212                      0) {
213                 fs_rsp_header_val_t *rsp_data =
214                     (fs_rsp_header_val_t *)user_data;
215                 memcpy(rsp_data->fs_upload_id, value, valuelen);
216             } else if (strncmp((char *)name, "x-next-append-position",
217                                (int)namelen) == 0) {
218                 fs_rsp_header_val_t *rsp_data =
219                     (fs_rsp_header_val_t *)user_data;
220                 rsp_data->fs_offset = atoi((char *)value);
221             } else if (strncmp((char *)name, "x-response-status",
222                                (int)namelen) == 0) {
223                 strncpy(node->status_code, (char *)value,
224                         sizeof(node->status_code) - 1);
225                 if (++node->rcv_hd_cnt == 2) {
226                     HAL_SemaphorePost(node->semaphore);
227                 }
228             }
229 #else
230             else if (strncmp((char *)name, ":status", (int)namelen) == 0) {
231                 strncpy(node->status_code, (char *)value,
232                         sizeof(node->status_code) - 1);
233                 if (++node->rcv_hd_cnt == 2) {
234                     HAL_SemaphorePost(node->semaphore);
235                 }
236             }
237 #endif
238         }
239     }
240 
241     if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_header_cb) {
242         g_stream_handle->cbs->on_stream_header_cb(stream_id, channel_id, cat,
243                                                   name, namelen, value,
244                                                   valuelen, flags, user_data);
245     }
246 }
247 
on_stream_chunk_recv(int32_t stream_id,const uint8_t * data,uint32_t len,uint8_t flags)248 static void on_stream_chunk_recv(int32_t stream_id, const uint8_t *data,
249                                  uint32_t len, uint8_t flags)
250 {
251     http2_stream_node_t *node;
252     char *channel_id = NULL;
253     char *user_data = NULL;
254 
255     if (g_stream_handle == NULL) {
256         return;
257     }
258     http2_stream_node_search(g_stream_handle, stream_id, &node);
259     if (node != NULL) {
260         channel_id = node->channel_id;
261         user_data = node->user_data;
262     }
263 
264     if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_chunk_recv_cb) {
265         g_stream_handle->cbs->on_stream_chunk_recv_cb(
266             stream_id, channel_id, data, len, flags, user_data);
267     }
268 }
269 
on_stream_close(int32_t stream_id,uint32_t error_code)270 static void on_stream_close(int32_t stream_id, uint32_t error_code)
271 {
272     http2_stream_node_t *node;
273     char *channel_id = NULL;
274     char *user_data = NULL;
275 
276     if (g_stream_handle == NULL) {
277         return;
278     }
279     http2_stream_node_search(g_stream_handle, stream_id, &node);
280     if (node != NULL) {
281         channel_id = node->channel_id;
282         user_data = node->user_data;
283     }
284     if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_close_cb) {
285         g_stream_handle->cbs->on_stream_close_cb(stream_id, channel_id,
286                                                  error_code, user_data);
287     }
288 }
289 
on_stream_frame_send(int32_t stream_id,int type,uint8_t flags)290 static void on_stream_frame_send(int32_t stream_id, int type, uint8_t flags)
291 {
292     http2_stream_node_t *node;
293     char *channel_id = NULL;
294     char *user_data = NULL;
295 
296     if (g_stream_handle == NULL) {
297         return;
298     }
299     http2_stream_node_search(g_stream_handle, stream_id, &node);
300     if (node != NULL) {
301         channel_id = node->channel_id;
302         user_data = node->user_data;
303     }
304     if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_frame_send_cb) {
305         g_stream_handle->cbs->on_stream_frame_send_cb(stream_id, channel_id,
306                                                       type, flags, user_data);
307     }
308 }
309 
on_stream_frame_recv(int32_t stream_id,int type,uint8_t flags)310 static void on_stream_frame_recv(int32_t stream_id, int type, uint8_t flags)
311 {
312     http2_stream_node_t *node;
313     char *channel_id = NULL;
314     char *user_data = NULL;
315     if (g_stream_handle == NULL) {
316         return;
317     }
318     http2_stream_node_search(g_stream_handle, stream_id, &node);
319     if (node != NULL) {
320         channel_id = node->channel_id;
321         user_data = node->user_data;
322     }
323 
324     if (g_stream_handle->cbs && g_stream_handle->cbs->on_stream_frame_recv_cb) {
325         g_stream_handle->cbs->on_stream_frame_recv_cb(stream_id, channel_id,
326                                                       type, flags, user_data);
327     }
328 }
329 
330 static http2_user_cb_t my_cb = {
331     .on_user_header_cb = on_stream_header,
332     .on_user_chunk_recv_cb = on_stream_chunk_recv,
333     .on_user_stream_close_cb = on_stream_close,
334     .on_user_frame_send_cb = on_stream_frame_send,
335     .on_user_frame_recv_cb = on_stream_frame_recv,
336 };
337 
reconnect(stream_handle_t * handle)338 static int reconnect(stream_handle_t *handle)
339 {
340     char buf[100] = { 0 };
341     http2_connection_t *conn = NULL;
342     int port = 0;
343 
344     iotx_http2_client_disconnect(handle->http2_connect);
345     handle->http2_connect = NULL;
346     port = iotx_http2_get_url(buf, g_device_info.product_key);
347     conn =
348         iotx_http2_client_connect_with_cb((void *)&g_client, buf, port, &my_cb);
349     if (conn == NULL) {
350         return -1;
351     }
352     handle->http2_connect = conn;
353     return 0;
354 }
355 
http2_io(void * user_data)356 static void *http2_io(void *user_data)
357 {
358     stream_handle_t *handle = (stream_handle_t *)user_data;
359     int rv = 0;
360     iotx_time_t timer, timer_rsp;
361     static uint8_t timer_valid = 0;
362     POINTER_SANITY_CHECK(handle, NULL);
363     iotx_time_init(&timer);
364     iotx_time_init(&timer_rsp);
365     while (handle->init_state) {
366         if (handle->connect_state) {
367             HAL_MutexLock(handle->mutex);
368             rv = iotx_http2_exec_io(handle->http2_connect);
369             HAL_MutexUnlock(handle->mutex);
370         }
371         if (utils_time_is_expired(&timer)) {
372             HAL_MutexLock(handle->mutex);
373             rv = iotx_http2_client_send_ping(handle->http2_connect);
374             HAL_MutexUnlock(handle->mutex);
375             utils_time_countdown_ms(&timer, IOT_HTTP2_KEEP_ALIVE_TIME);
376             if (rv >= 0) {
377                 utils_time_countdown_ms(&timer_rsp, 3000);
378                 timer_valid = 1;
379             }
380         }
381 
382         if (timer_valid && utils_time_is_expired(&timer_rsp)) {
383             timer_valid = 0;
384             rv = iotx_http2_client_recv_ping();
385         }
386 
387         if (rv < 0) {
388             if (handle->retry_cnt == IOT_HTTP2_KEEP_ALIVE_CNT - 1) {
389                 h2_info("rv =%d, try reconnect\n", rv);
390                 if (handle->connect_state != 0) {
391                     handle->connect_state = 0;
392                     if (handle->cbs && handle->cbs->on_disconnect_cb) {
393                         handle->cbs->on_disconnect_cb();
394                     }
395                 }
396                 rv = reconnect(handle);
397                 continue;
398             } else {
399                 handle->retry_cnt++;
400             }
401         } else {
402             if (handle->connect_state == 0) {
403                 handle->connect_state = 1;
404                 handle->retry_cnt = 0;
405                 if (handle->cbs && handle->cbs->on_reconnect_cb) {
406                     handle->cbs->on_reconnect_cb();
407                 }
408             }
409         }
410         HAL_SleepMs(100);
411     }
412     HAL_SemaphorePost(handle->semaphore);
413 
414     return NULL;
415 }
416 
http2_stream_node_insert(stream_handle_t * handle,unsigned int id,void * user_data,http2_stream_node_t ** p_node)417 static int http2_stream_node_insert(stream_handle_t *handle, unsigned int id,
418                                     void *user_data,
419                                     http2_stream_node_t **p_node)
420 {
421     http2_stream_node_t *node = NULL;
422     void *semaphore = NULL;
423 
424     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
425 
426     ARGUMENT_SANITY_CHECK(id != 0, FAIL_RETURN);
427 
428     if (p_node != NULL) {
429         *p_node = NULL;
430     }
431 
432     node =
433         (http2_stream_node_t *)HTTP2_STREAM_MALLOC(sizeof(http2_stream_node_t));
434     if (node == NULL) {
435         return FAIL_RETURN;
436     }
437 
438     memset(node, 0, sizeof(http2_stream_node_t));
439     node->stream_id = id;
440     node->user_data = user_data;
441     semaphore = HAL_SemaphoreCreate();
442     if (semaphore == NULL) {
443         HTTP2_STREAM_FREE(node);
444         return FAIL_RETURN;
445     }
446     node->semaphore = semaphore;
447 
448     INIT_LIST_HEAD((list_head_t *)&node->list);
449     list_add((list_head_t *)&node->list, (list_head_t *)&handle->stream_list);
450 
451     if (p_node != NULL) {
452         *p_node = node;
453     }
454 
455     return SUCCESS_RETURN;
456 }
457 
http2_stream_node_remove(stream_handle_t * handle,unsigned int id)458 static int http2_stream_node_remove(stream_handle_t *handle, unsigned int id)
459 {
460     http2_stream_node_t *search_node;
461 
462     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
463     ARGUMENT_SANITY_CHECK(id != 0, FAIL_RETURN);
464 
465     list_for_each_entry(search_node, &handle->stream_list, list,
466                         http2_stream_node_t)
467     {
468         if (id == search_node->stream_id) {
469             h2_info("stream_node found, delete\n");
470 
471             list_del((list_head_t *)&search_node->list);
472             HTTP2_STREAM_FREE(search_node->channel_id);
473             HAL_SemaphoreDestroy(search_node->semaphore);
474             HTTP2_STREAM_FREE(search_node);
475             return SUCCESS_RETURN;
476         }
477     }
478     return FAIL_RETURN;
479 }
480 
get_version_int()481 static int get_version_int()
482 {
483     const char *p_version = IOTX_SDK_VERSION;
484     int v_int = 0;
485 
486     while (*p_version != 0) {
487         if (*p_version <= '9' && *p_version >= '0') {
488             v_int = v_int * 10 + *p_version - '0';
489         }
490         p_version++;
491     }
492     return v_int;
493 }
494 
IOT_HTTP2_Connect(device_conn_info_t * conn_info,http2_stream_cb_t * user_cb)495 void *IOT_HTTP2_Connect(device_conn_info_t *conn_info,
496                         http2_stream_cb_t *user_cb)
497 {
498     stream_handle_t *stream_handle = NULL;
499     http2_connection_t *conn = NULL;
500     hal_os_thread_param_t thread_parms = { 0 };
501     char buf[URL_MAX_LEN + 1] = { 0 };
502     int port = 0;
503     int ret = 0;
504 
505     POINTER_SANITY_CHECK(conn_info, NULL);
506     POINTER_SANITY_CHECK(conn_info->product_key, NULL);
507     POINTER_SANITY_CHECK(conn_info->device_name, NULL);
508     POINTER_SANITY_CHECK(conn_info->device_secret, NULL);
509 
510     memset(&g_client, 0, sizeof(httpclient_t));
511 
512     stream_handle = HTTP2_STREAM_MALLOC(sizeof(stream_handle_t));
513     if (stream_handle == NULL) {
514         return NULL;
515     }
516 
517     memset(stream_handle, 0, sizeof(stream_handle_t));
518     stream_handle->mutex = HAL_MutexCreate();
519     if (stream_handle->mutex == NULL) {
520         HTTP2_STREAM_FREE(stream_handle);
521         h2_err("mutex create error\n");
522         return NULL;
523     }
524     stream_handle->semaphore = HAL_SemaphoreCreate();
525     if (stream_handle->semaphore == NULL) {
526         h2_err("semaphore create error\n");
527         HAL_MutexDestroy(stream_handle->mutex);
528         HTTP2_STREAM_FREE(stream_handle);
529         return NULL;
530     }
531 
532     INIT_LIST_HEAD((list_head_t *)&(stream_handle->stream_list));
533 
534     _set_device_info(conn_info);
535     g_stream_handle = stream_handle;
536     g_stream_handle->cbs = user_cb;
537 
538     port = iotx_http2_get_url(buf, conn_info->product_key);
539     conn =
540         iotx_http2_client_connect_with_cb((void *)&g_client, buf, port, &my_cb);
541     if (conn == NULL) {
542         HAL_MutexDestroy(stream_handle->mutex);
543         HAL_SemaphoreDestroy(stream_handle->semaphore);
544         HTTP2_STREAM_FREE(stream_handle);
545         return NULL;
546     }
547     stream_handle->http2_connect = conn;
548     stream_handle->init_state = 1;
549 
550     thread_parms.stack_size = 6144;
551     thread_parms.name = "http2_io";
552     ret = HAL_ThreadCreate(&stream_handle->rw_thread, http2_io, stream_handle,
553                            &thread_parms, NULL);
554     if (ret != 0) {
555         h2_err("thread create error\n");
556         IOT_HTTP2_Disconnect(stream_handle);
557         return NULL;
558     }
559 
560     return stream_handle;
561 }
562 
IOT_HTTP2_Stream_Open(void * hd,stream_data_info_t * info,header_ext_info_t * header)563 int IOT_HTTP2_Stream_Open(void *hd, stream_data_info_t *info,
564                           header_ext_info_t *header)
565 {
566     char client_id[64 + 1] = { 0 };
567     char sign_str[256 + 1] = { 0 };
568     char sign[41 + 1] = { 0 };
569     char path[128] = { 0 };
570     char version[33] = { 0 };
571     int header_count = 0;
572     int header_num;
573     int rv = 0;
574     http2_data h2_data;
575     http2_stream_node_t *node = NULL;
576     stream_handle_t *handle = (stream_handle_t *)hd;
577     http2_header *nva = NULL;
578 
579     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
580     POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR);
581     POINTER_SANITY_CHECK(info->identify, NULL_VALUE_ERROR);
582 
583     memset(&h2_data, 0, sizeof(http2_data));
584 
585     HAL_Snprintf(path, sizeof(path), "/stream/open/%s", info->identify);
586 
587     file_upload_gen_string(client_id, CID_STRING_ENUM, NULL, 0);
588     file_upload_gen_string(sign_str, ORI_SIGN_STR_ENUM, client_id, 0);
589     file_upload_gen_string(sign, REAL_SIGN_STR_ENUM, sign_str, 0);
590 
591     HAL_Snprintf(version, sizeof(version), "%d", get_version_int());
592 
593     {
594         const http2_header static_header[] = {
595             MAKE_HEADER(":method", "POST"),
596             MAKE_HEADER_CS(":path", path),
597             MAKE_HEADER(":scheme", "https"),
598             MAKE_HEADER("x-auth-name", "devicename"),
599             MAKE_HEADER_CS("x-auth-param-client-id", client_id),
600             MAKE_HEADER("x-auth-param-signmethod", "hmacsha1"),
601             MAKE_HEADER_CS("x-auth-param-product-key",
602                            g_device_info.product_key),
603             MAKE_HEADER_CS("x-auth-param-device-name",
604                            g_device_info.device_name),
605             MAKE_HEADER_CS("x-auth-param-sign", sign),
606             MAKE_HEADER_CS("x-sdk-version", version),
607             MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION),
608             MAKE_HEADER("x-sdk-platform", "c"),
609             MAKE_HEADER("content-length", "0"),
610         };
611 
612         header_num = sizeof(static_header) / sizeof(static_header[0]);
613         if (header != NULL) {
614             header_num += header->num;
615         }
616         nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) *
617                                                   header_num);
618         if (nva == NULL) {
619             h2_err("nva malloc failed\n");
620             return FAIL_RETURN;
621         }
622 
623         /* add external header if it's not NULL */
624         header_count =
625             http2_nv_copy(nva, 0, (http2_header *)static_header,
626                           sizeof(static_header) / sizeof(static_header[0]));
627         if (header != NULL) {
628             header_count = http2_nv_copy(
629                 nva, header_count, (http2_header *)header->nva, header->num);
630         }
631 
632         h2_data.header = (http2_header *)nva;
633         h2_data.header_count = header_count;
634         h2_data.data = NULL;
635         h2_data.len = 0;
636         h2_data.flag = 1;
637         h2_data.stream_id = 0;
638 
639         HAL_MutexLock(handle->mutex);
640         rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
641         http2_stream_node_insert(handle, h2_data.stream_id, info->user_data,
642                                  &node);
643         HTTP2_STREAM_FREE(nva);
644     }
645 
646     if (rv < 0) {
647         h2_err("client send error\n");
648         HAL_MutexUnlock(handle->mutex);
649         return FAIL_RETURN;
650     }
651 
652     if (node == NULL) {
653         h2_err("node insert failed!");
654         HAL_MutexUnlock(handle->mutex);
655         return FAIL_RETURN;
656     }
657 
658     node->stream_type = STREAM_TYPE_AUXILIARY;
659     HAL_MutexUnlock(handle->mutex);
660 
661     rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS);
662     if (rv < 0 || memcmp(node->status_code, "200", 3)) {
663         h2_err("semaphore wait overtime or status code error\n");
664         HAL_MutexLock(handle->mutex);
665         http2_stream_node_remove(handle, node->stream_id);
666         HAL_MutexUnlock(handle->mutex);
667         return FAIL_RETURN;
668     }
669     info->channel_id = HTTP2_STREAM_MALLOC(strlen(node->channel_id) + 1);
670     if (info->channel_id == NULL) {
671         h2_err("channel_id malloc failed\n");
672         HAL_MutexLock(handle->mutex);
673         http2_stream_node_remove(handle, node->stream_id);
674         HAL_MutexUnlock(handle->mutex);
675         return FAIL_RETURN;
676     }
677     memset(info->channel_id, 0, strlen(node->channel_id) + 1);
678     strcpy(info->channel_id, node->channel_id);
679 
680     return SUCCESS_RETURN;
681 }
682 
IOT_HTTP2_Stream_Send_Message(void * hd,const char * identify,char * channel_id,char * data,uint32_t data_len,header_ext_info_t * header)683 int IOT_HTTP2_Stream_Send_Message(void *hd, const char *identify,
684                                   char *channel_id, char *data,
685                                   uint32_t data_len, header_ext_info_t *header)
686 {
687     int rv = 0;
688     http2_data h2_data;
689     char path[128] = { 0 };
690     char data_len_str[33] = { 0 };
691     int windows_size;
692     int count = 0;
693     stream_handle_t *handle = (stream_handle_t *)hd;
694     http2_header *nva = NULL;
695     int header_count, header_num;
696     char version[33] = { 0 };
697     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
698     POINTER_SANITY_CHECK(identify, NULL_VALUE_ERROR);
699     POINTER_SANITY_CHECK(channel_id, NULL_VALUE_ERROR);
700 
701     windows_size = iotx_http2_get_available_window_size(handle->http2_connect);
702     while (windows_size < data_len) {
703         h2_warning("windows_size < info->packet_len ,wait ...\n");
704         HAL_SleepMs(100);
705         if (++count > 50) {
706             return FAIL_RETURN;
707         }
708         windows_size =
709             iotx_http2_get_available_window_size(handle->http2_connect);
710     }
711 
712     HAL_Snprintf(data_len_str, sizeof(data_len_str), "%d", data_len);
713     HAL_Snprintf(path, sizeof(path), "/stream/send/%s", identify);
714     HAL_Snprintf(version, sizeof(version), "%d", get_version_int());
715 
716     {
717         const http2_header static_header[] = {
718             MAKE_HEADER(":method", "POST"),
719             MAKE_HEADER_CS(":path", path),
720             MAKE_HEADER(":scheme", "https"),
721             MAKE_HEADER_CS("content-length", data_len_str),
722             MAKE_HEADER_CS("x-data-stream-id", channel_id),
723             MAKE_HEADER_CS("x-sdk-version", version),
724             MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION),
725             MAKE_HEADER("x-sdk-platform", "c"),
726         };
727 
728         header_num = sizeof(static_header) / sizeof(static_header[0]);
729         if (header != NULL) {
730             header_num += header->num;
731         }
732         nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) *
733                                                   header_num);
734         if (nva == NULL) {
735             h2_err("nva malloc failed\n");
736             return FAIL_RETURN;
737         }
738 
739         /* add external header if it's not NULL */
740         header_count =
741             http2_nv_copy(nva, 0, (http2_header *)static_header,
742                           sizeof(static_header) / sizeof(static_header[0]));
743         if (header != NULL) {
744             header_count = http2_nv_copy(
745                 nva, header_count, (http2_header *)header->nva, header->num);
746         }
747         memset(&h2_data, 0, sizeof(h2_data));
748         h2_data.header = (http2_header *)nva;
749         h2_data.header_count = header_count;
750         h2_data.data = data;
751         h2_data.len = data_len;
752         h2_data.flag = 1;
753 
754         HAL_MutexLock(handle->mutex);
755         rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
756         HAL_MutexUnlock(handle->mutex);
757         HTTP2_STREAM_FREE(nva);
758     }
759 
760     if (rv < 0) {
761         h2_err("send failed!");
762         return rv;
763     }
764 
765     return h2_data.stream_id;
766 }
767 
IOT_HTTP2_Stream_Send(void * hd,stream_data_info_t * info,header_ext_info_t * header)768 int IOT_HTTP2_Stream_Send(void *hd, stream_data_info_t *info,
769                           header_ext_info_t *header)
770 {
771     int rv = 0;
772     http2_data h2_data;
773     char path[128] = { 0 };
774     char data_len_str[33] = { 0 };
775     int windows_size;
776     int count = 0;
777     http2_stream_node_t *node = NULL;
778     stream_handle_t *handle = (stream_handle_t *)hd;
779     http2_header *nva = NULL;
780 
781     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
782     POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR);
783     POINTER_SANITY_CHECK(info->stream, NULL_VALUE_ERROR);
784     POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR);
785     ARGUMENT_SANITY_CHECK(info->stream_len != 0, FAIL_RETURN);
786     ARGUMENT_SANITY_CHECK(info->packet_len != 0, FAIL_RETURN);
787 
788     windows_size = iotx_http2_get_available_window_size(handle->http2_connect);
789     while (windows_size < info->packet_len) {
790         h2_warning("windows_size < info->packet_len ,wait ...\n");
791         HAL_SleepMs(100);
792         if (++count > 50) {
793             return FAIL_RETURN;
794         }
795         windows_size =
796             iotx_http2_get_available_window_size(handle->http2_connect);
797     }
798 
799     HAL_Snprintf(data_len_str, sizeof(data_len_str), "%d", info->stream_len);
800     HAL_Snprintf(path, sizeof(path), "/stream/send/%s", info->identify);
801     if (info->send_len == 0) { /* first send,need header */
802         int header_count, header_num;
803         char version[33] = { 0 };
804         HAL_Snprintf(version, sizeof(version), "%d", get_version_int());
805         {
806             const http2_header static_header[] = {
807                 MAKE_HEADER(":method", "POST"),
808                 MAKE_HEADER_CS(":path", path),
809                 MAKE_HEADER(":scheme", "https"),
810                 MAKE_HEADER_CS("content-length", data_len_str),
811                 MAKE_HEADER_CS("x-data-stream-id", info->channel_id),
812                 MAKE_HEADER_CS("x-sdk-version", version),
813                 MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION),
814                 MAKE_HEADER("x-sdk-platform", "c"),
815             };
816 
817             header_num = sizeof(static_header) / sizeof(static_header[0]);
818             if (header != NULL) {
819                 header_num += header->num;
820             }
821             nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) *
822                                                       header_num);
823             if (nva == NULL) {
824                 h2_err("nva malloc failed\n");
825                 return FAIL_RETURN;
826             }
827 
828             /* add external header if it's not NULL */
829             header_count =
830                 http2_nv_copy(nva, 0, (http2_header *)static_header,
831                               sizeof(static_header) / sizeof(static_header[0]));
832             if (header != NULL) {
833                 header_count =
834                     http2_nv_copy(nva, header_count,
835                                   (http2_header *)header->nva, header->num);
836             }
837             memset(&h2_data, 0, sizeof(h2_data));
838             h2_data.header = (http2_header *)nva;
839             h2_data.header_count = header_count;
840             h2_data.data = info->stream;
841             h2_data.len = info->packet_len; /* TODO */
842 
843             if (info->packet_len + info->send_len ==
844                 info->stream_len) { /* last frame */
845                 h2_data.flag = 1;
846             } else {
847                 h2_data.flag = 0;
848             }
849 
850             HAL_MutexLock(handle->mutex);
851             rv =
852                 iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
853             http2_stream_node_insert(handle, h2_data.stream_id, info->user_data,
854                                      &node);
855             HTTP2_STREAM_FREE(nva);
856         }
857 
858         if (rv < 0) {
859             h2_err("send failed!");
860             HAL_MutexUnlock(handle->mutex);
861             return FAIL_RETURN;
862         }
863 
864         if (node == NULL) {
865             h2_err("node insert failed!");
866             HAL_MutexUnlock(handle->mutex);
867             return FAIL_RETURN;
868         }
869 
870         node->stream_type = STREAM_TYPE_UPLOAD;
871         HAL_MutexUnlock(handle->mutex);
872 
873         info->h2_stream_id = h2_data.stream_id;
874         info->send_len += info->packet_len;
875     } else {
876         h2_data.header = NULL;
877         h2_data.header_count = 0;
878         h2_data.data = info->stream;
879         h2_data.len = info->packet_len;
880 
881         h2_data.stream_id = info->h2_stream_id;
882         if (info->packet_len + info->send_len ==
883             info->stream_len) { /* last frame */
884             h2_data.flag = 1;
885         } else {
886             h2_data.flag = 0;
887         }
888 
889         HAL_MutexLock(handle->mutex);
890         rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
891         HAL_MutexUnlock(handle->mutex);
892         if (rv < 0) {
893             return FAIL_RETURN;
894         }
895         info->send_len += info->packet_len;
896     }
897 
898     if (h2_data.flag == 1) {
899         http2_stream_node_t *node = NULL;
900         HAL_MutexLock(handle->mutex);
901         http2_stream_node_search(handle, h2_data.stream_id, &node);
902         HAL_MutexUnlock(handle->mutex);
903         if (node == NULL) {
904             h2_err("node search failed!");
905             return FAIL_RETURN;
906         }
907         rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS);
908         if (rv < 0 || memcmp(node->status_code, "200", 3)) {
909             h2_err(
910                 "semaphore wait overtime or status code "
911                 "error,h2_data.stream_id %d\n",
912                 h2_data.stream_id);
913             HAL_MutexLock(handle->mutex);
914             http2_stream_node_remove(handle, node->stream_id);
915             HAL_MutexUnlock(handle->mutex);
916             return FAIL_RETURN;
917         }
918     }
919 
920     return rv;
921 }
922 
IOT_HTTP2_Stream_Query(void * hd,stream_data_info_t * info,header_ext_info_t * header)923 int IOT_HTTP2_Stream_Query(void *hd, stream_data_info_t *info,
924                            header_ext_info_t *header)
925 {
926     int rv = 0;
927     http2_data h2_data;
928     http2_stream_node_t *node = NULL;
929     char path[128] = { 0 };
930     int header_count, header_num;
931     stream_handle_t *handle = (stream_handle_t *)hd;
932     http2_header *nva = NULL;
933     char version[33] = { 0 };
934 
935     POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR);
936     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
937     POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR);
938     HAL_Snprintf(version, sizeof(version), "%d", get_version_int());
939     HAL_Snprintf(path, sizeof(path), "/stream/send/%s", info->identify);
940     {
941         const http2_header static_header[] = {
942             MAKE_HEADER(":method", "GET"),
943             MAKE_HEADER_CS(":path", path),
944             MAKE_HEADER(":scheme", "https"),
945             MAKE_HEADER_CS("x-data-stream-id", info->channel_id),
946             MAKE_HEADER("x-test-downstream", "1"),
947             MAKE_HEADER_CS("x-sdk-version", version),
948             MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION),
949             MAKE_HEADER("x-sdk-platform", "c"),
950         };
951 
952         header_num = sizeof(static_header) / sizeof(static_header[0]);
953         if (header != NULL) {
954             header_num += header->num;
955         }
956         nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) *
957                                                   header_num);
958         if (nva == NULL) {
959             h2_err("nva malloc failed\n");
960             return FAIL_RETURN;
961         }
962 
963         /* add external header if it's not NULL */
964         header_count =
965             http2_nv_copy(nva, 0, (http2_header *)static_header,
966                           sizeof(static_header) / sizeof(static_header[0]));
967         if (header != NULL) {
968             header_count = http2_nv_copy(
969                 nva, header_count, (http2_header *)header->nva, header->num);
970         }
971         h2_data.header = (http2_header *)nva;
972         h2_data.header_count = header_count;
973         h2_data.data = NULL;
974         h2_data.len = 0;
975         h2_data.flag = 1;
976         h2_data.stream_id = 0;
977 
978         HAL_MutexLock(handle->mutex);
979         rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
980         http2_stream_node_insert(handle, h2_data.stream_id, info->user_data,
981                                  &node);
982         HTTP2_STREAM_FREE(nva);
983     }
984 
985     if (rv < 0) {
986         h2_err("client send error\n");
987         HAL_MutexUnlock(handle->mutex);
988         return rv;
989     }
990 
991     if (node == NULL) {
992         h2_err("node insert failed!");
993         HAL_MutexUnlock(handle->mutex);
994         return FAIL_RETURN;
995     }
996 
997     node->stream_type = STREAM_TYPE_DOWNLOAD;
998     HAL_MutexUnlock(handle->mutex);
999 
1000     rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS);
1001     if (rv < 0 || memcmp(node->status_code, "200", 3)) {
1002         h2_err("semaphore wait overtime or status code error\n");
1003         HAL_MutexLock(handle->mutex);
1004         http2_stream_node_remove(handle, node->stream_id);
1005         HAL_MutexUnlock(handle->mutex);
1006         return FAIL_RETURN;
1007     }
1008 
1009     return rv;
1010 }
1011 
1012 #ifdef FS_ENABLED
IOT_HTTP2_FS_Close(void * hd,stream_data_info_t * info,header_ext_info_t * header)1013 int IOT_HTTP2_FS_Close(void *hd, stream_data_info_t *info,
1014                        header_ext_info_t *header)
1015 {
1016     int rv = 0;
1017     http2_data h2_data;
1018     char path[128] = { 0 };
1019     stream_handle_t *handle = (stream_handle_t *)hd;
1020     char version[33] = { 0 };
1021     char *stream_id = info->channel_id;
1022     int len = strlen(stream_id);
1023     http2_stream_node_t *node, *next;
1024     http2_header *nva = NULL;
1025     int header_count, header_num;
1026 
1027     POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR);
1028     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
1029     POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR);
1030     HAL_Snprintf(version, sizeof(version), "%d", get_version_int());
1031     HAL_Snprintf(path, sizeof(path), "/stream/close/%s", info->identify);
1032     {
1033         const http2_header static_header[] = {
1034             MAKE_HEADER(":method", "POST"),
1035             MAKE_HEADER_CS(":path", path),
1036             MAKE_HEADER(":scheme", "https"),
1037             MAKE_HEADER_CS("x-data-stream-id", info->channel_id),
1038             MAKE_HEADER_CS("x-sdk-version", version),
1039             MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION),
1040             MAKE_HEADER("x-sdk-platform", "c"),
1041         };
1042 
1043         header_num = sizeof(static_header) / sizeof(static_header[0]);
1044         if (header != NULL) {
1045             header_num += header->num;
1046         }
1047         nva = (http2_header *)HTTP2_STREAM_MALLOC(sizeof(http2_header) *
1048                                                   header_num);
1049         if (nva == NULL) {
1050             h2_err("nva malloc failed\n");
1051             HTTP2_STREAM_FREE(info->channel_id);
1052             return FAIL_RETURN;
1053         }
1054 
1055         /* add external header if it's not NULL */
1056         header_count =
1057             http2_nv_copy(nva, 0, (http2_header *)static_header,
1058                           sizeof(static_header) / sizeof(static_header[0]));
1059         if (header != NULL) {
1060             header_count = http2_nv_copy(
1061                 nva, header_count, (http2_header *)header->nva, header->num);
1062         }
1063 
1064         header_count = sizeof(static_header) / sizeof(static_header[0]);
1065         h2_data.header = (http2_header *)static_header;
1066         h2_data.header_count = header_count;
1067         h2_data.data = NULL;
1068         h2_data.len = 0;
1069         h2_data.flag = 1;
1070         h2_data.stream_id = 0;
1071 
1072         HAL_MutexLock(handle->mutex);
1073         if (info->send_len < info->stream_len) {
1074             iotx_http2_reset_stream(handle->http2_connect, info->h2_stream_id);
1075         }
1076         rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
1077         http2_stream_node_insert(handle, h2_data.stream_id, info->user_data,
1078                                  &node);
1079         HTTP2_STREAM_FREE(nva);
1080     }
1081 
1082     if (rv < 0) {
1083         h2_err("client send error\n");
1084         HAL_MutexUnlock(handle->mutex);
1085         HTTP2_STREAM_FREE(info->channel_id);
1086         return rv;
1087     }
1088 
1089     if (node == NULL) {
1090         h2_err("node insert failed!");
1091         HAL_MutexUnlock(handle->mutex);
1092         HTTP2_STREAM_FREE(info->channel_id);
1093         return FAIL_RETURN;
1094     }
1095 
1096     node->stream_type = STREAM_TYPE_AUXILIARY;
1097     HAL_MutexUnlock(handle->mutex);
1098 
1099     rv = HAL_SemaphoreWait(node->semaphore, IOT_HTTP2_RES_OVERTIME_MS);
1100     if (rv < 0 || memcmp(node->status_code, "200", 3)) {
1101         h2_err("semaphore wait overtime or status code error\n");
1102     }
1103 
1104     /* just delete stream node */
1105     HAL_MutexLock(handle->mutex);
1106     list_for_each_entry_safe(node, next, &handle->stream_list, list,
1107                              http2_stream_node_t)
1108     {
1109         if (info->h2_stream_id == node->stream_id) {
1110             h2_info("stream_node found:stream_id= %d, Delete It",
1111                     node->stream_id);
1112             list_del((list_head_t *)&node->list);
1113             HTTP2_STREAM_FREE(node->channel_id);
1114             HAL_SemaphoreDestroy(node->semaphore);
1115             HTTP2_STREAM_FREE(node);
1116             continue;
1117         }
1118         if ((node->channel_id != NULL) && (stream_id != NULL) &&
1119             (len == strlen(node->channel_id) &&
1120              !strncmp(node->channel_id, stream_id, len))) {
1121             list_del((list_head_t *)&node->list);
1122             HTTP2_STREAM_FREE(node->channel_id);
1123             HAL_SemaphoreDestroy(node->semaphore);
1124             HTTP2_STREAM_FREE(node);
1125         }
1126     }
1127     HTTP2_STREAM_FREE(info->channel_id);
1128     info->channel_id = NULL;
1129     HAL_MutexUnlock(handle->mutex);
1130 
1131     return rv;
1132 }
1133 #endif /* #ifdef FS_ENABLED */
1134 
IOT_HTTP2_Stream_Close(void * hd,stream_data_info_t * info)1135 int IOT_HTTP2_Stream_Close(void *hd, stream_data_info_t *info)
1136 {
1137     int rv = 0;
1138     http2_data h2_data;
1139     char path[128] = { 0 };
1140     stream_handle_t *handle = (stream_handle_t *)hd;
1141     char version[33] = { 0 };
1142     char *stream_id = info->channel_id;
1143     int len = strlen(stream_id);
1144     http2_stream_node_t *node, *next;
1145 
1146     POINTER_SANITY_CHECK(info, NULL_VALUE_ERROR);
1147     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
1148     POINTER_SANITY_CHECK(info->channel_id, NULL_VALUE_ERROR);
1149     HAL_Snprintf(version, sizeof(version), "%d", get_version_int());
1150     HAL_Snprintf(path, sizeof(path), "/stream/close/%s", info->identify);
1151     {
1152         const http2_header static_header[] = {
1153             MAKE_HEADER(":method", "POST"),
1154             MAKE_HEADER_CS(":path", path),
1155             MAKE_HEADER(":scheme", "https"),
1156             MAKE_HEADER_CS("x-data-stream-id", info->channel_id),
1157             MAKE_HEADER_CS("x-sdk-version", version),
1158             MAKE_HEADER_CS("x-sdk-version-name", IOTX_SDK_VERSION),
1159             MAKE_HEADER("x-sdk-platform", "c"),
1160         };
1161 
1162         int header_count = sizeof(static_header) / sizeof(static_header[0]);
1163         h2_data.header = (http2_header *)static_header;
1164         h2_data.header_count = header_count;
1165         h2_data.data = NULL;
1166         h2_data.len = 0;
1167         h2_data.flag = 1;
1168         h2_data.stream_id = 0;
1169 
1170         HAL_MutexLock(handle->mutex);
1171         if (info->send_len < info->stream_len) {
1172             iotx_http2_reset_stream(handle->http2_connect, info->h2_stream_id);
1173         }
1174         rv = iotx_http2_client_send((void *)handle->http2_connect, &h2_data);
1175         HAL_MutexUnlock(handle->mutex);
1176     }
1177 
1178     if (rv < 0) {
1179         h2_warning("client send error\n");
1180     }
1181 
1182     /* just delete stream node */
1183     HAL_MutexLock(handle->mutex);
1184     list_for_each_entry_safe(node, next, &handle->stream_list, list,
1185                              http2_stream_node_t)
1186     {
1187         if (info->h2_stream_id == node->stream_id) {
1188             h2_info("stream_node found:stream_id= %d, Delete It",
1189                     node->stream_id);
1190             list_del((list_head_t *)&node->list);
1191             HTTP2_STREAM_FREE(node->channel_id);
1192             HAL_SemaphoreDestroy(node->semaphore);
1193             HTTP2_STREAM_FREE(node);
1194             continue;
1195         }
1196         if ((node->channel_id != NULL) && (stream_id != NULL) &&
1197             (len == strlen(node->channel_id) &&
1198              !strncmp(node->channel_id, stream_id, len))) {
1199             list_del((list_head_t *)&node->list);
1200             HTTP2_STREAM_FREE(node->channel_id);
1201             HAL_SemaphoreDestroy(node->semaphore);
1202             HTTP2_STREAM_FREE(node);
1203         }
1204     }
1205     HTTP2_STREAM_FREE(info->channel_id);
1206     info->channel_id = NULL;
1207     HAL_MutexUnlock(handle->mutex);
1208     return rv;
1209 }
1210 
IOT_HTTP2_Disconnect(void * hd)1211 int IOT_HTTP2_Disconnect(void *hd)
1212 {
1213     int ret;
1214     stream_handle_t *handle = (stream_handle_t *)hd;
1215     http2_stream_node_t *node, *next;
1216 
1217     POINTER_SANITY_CHECK(handle, NULL_VALUE_ERROR);
1218     handle->init_state = 0;
1219 
1220     ret = HAL_SemaphoreWait(handle->semaphore, PLATFORM_WAIT_INFINITE);
1221     if (ret < 0) {
1222         h2_err("semaphore wait err\n");
1223         return FAIL_RETURN;
1224     }
1225 
1226     HAL_MutexLock(handle->mutex);
1227     list_for_each_entry_safe(node, next, &handle->stream_list, list,
1228                              http2_stream_node_t)
1229     {
1230         list_del((list_head_t *)&node->list);
1231         HTTP2_STREAM_FREE(node->channel_id);
1232         HAL_SemaphoreDestroy(node->semaphore);
1233         HTTP2_STREAM_FREE(node);
1234     }
1235     HAL_MutexUnlock(handle->mutex);
1236     g_stream_handle = NULL;
1237 
1238     HAL_MutexDestroy(handle->mutex);
1239     HAL_SemaphoreDestroy(handle->semaphore);
1240 
1241     ret = iotx_http2_client_disconnect(handle->http2_connect);
1242     HTTP2_STREAM_FREE(handle);
1243     return ret;
1244 }
1245