support aliyun sdk on TencentOS tiny

sample: examples\aliyun_iotkit_csdk_mqtt
project: board\TencentOS_tiny_EVB_MX_Plus\KEIL\aliyun_iotkit_csdk_mqtt
This commit is contained in:
dcxajichu
2019-10-31 16:36:28 +08:00
parent 30ea36a7ab
commit 8c24d921b0
692 changed files with 199829 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "http2_upload_api.h"
#include "http2_wrapper.h"
#define HTTP2_ONLINE_SERVER_URL "a1IgnOND7vI.iot-as-http2.cn-shanghai.aliyuncs.com"
#define HTTP2_ONLINE_SERVER_PORT 443
#define HTTP2_PRODUCT_KEY "a1IgnOND7vI"
#define HTTP2_DEVICE_NAME "H2_FS01"
#define HTTP2_DEVICE_SECRET "r9XSyeZOu6swgV8etCcCGmgQhBSpGBau"
#define EXAMPLE_TRACE(fmt, ...) \
do { \
HAL_Printf("%s|%03d :: ", __func__, __LINE__); \
HAL_Printf(fmt, ##__VA_ARGS__); \
HAL_Printf("%s", "\r\n"); \
} while (0)
#define UPLOAD_RETRY_TIME 50
static int upload_result = 1;
static char g_upload_id[50] = {0};
static uint8_t is_connected = 0;
void upload_file_result(const char *file_path, int result, void *user_data)
{
upload_result = result;
EXAMPLE_TRACE("=========== file_path = %s, result = %d ===========", file_path, upload_result);
}
void upload_id_received_handle(const char *file_path, const char *upload_id, void *user_data)
{
EXAMPLE_TRACE("=========== file_path = %s, upload_id = %s ===========", file_path, upload_id);
if (upload_id != NULL) {
memset(g_upload_id, 0, sizeof(g_upload_id));
strncpy(g_upload_id, upload_id, sizeof(g_upload_id) - 1);
}
}
static void _on_http2_reconnect(void)
{
EXAMPLE_TRACE("http2 reconnected");
is_connected = 1;
}
static void _on_http2_disconnect(void)
{
EXAMPLE_TRACE("http2 disconnected");
is_connected = 0;
}
static int http2_stream_test(char **argv,int argc)
{
http2_upload_conn_info_t conn_info;
http2_status_cb_t status_cb;
http2_upload_result_cb_t result_cb;
void *handle;
uint32_t retry_time = 0;
int ret;
memset(&conn_info, 0, sizeof( http2_upload_conn_info_t));
conn_info.product_key = HTTP2_PRODUCT_KEY;
conn_info.device_name = HTTP2_DEVICE_NAME;
conn_info.device_secret = HTTP2_DEVICE_SECRET;
conn_info.url = HTTP2_ONLINE_SERVER_URL;
conn_info.port = HTTP2_ONLINE_SERVER_PORT;
memset(&status_cb, 0, sizeof(http2_status_cb_t));
status_cb.on_reconnect_cb = _on_http2_reconnect;
status_cb.on_disconnect_cb = _on_http2_disconnect;
memset(&result_cb, 0, sizeof(http2_upload_result_cb_t));
result_cb.upload_completed_cb = upload_file_result;
result_cb.upload_id_received_cb = upload_id_received_handle;
handle = IOT_HTTP2_UploadFile_Connect(&conn_info, &status_cb);
if(handle == NULL) {
return -1;
}
is_connected = 1;
http2_upload_params_t fs_params;
memset(&fs_params, 0, sizeof(fs_params));
fs_params.file_path = argv[1];
fs_params.opt_bit_map = UPLOAD_FILE_OPT_BIT_OVERWRITE;
ret = IOT_HTTP2_UploadFile_Request(handle, &fs_params, &result_cb, NULL);
if(ret < 0) {
return -1;
}
/* wait until upload end */
while (upload_result == 1) {
HAL_SleepMs(200);
}
/* check the result */
if (upload_result == UPLOAD_SUCCESS) {
EXAMPLE_TRACE("upload succeed");
ret = IOT_HTTP2_UploadFile_Disconnect(handle);
EXAMPLE_TRACE("close connect %d\n", ret);
return 0;
}
else {
/* check if upload_id receivced */
if (g_upload_id[0] == '\0') {
EXAMPLE_TRACE("upload id is NULL, resume is impossible!");
return -1;
}
}
/* into resume routine */
do {
/* TODO: assume that http2 disconnected */
if (upload_result < 0 && is_connected == 1) {
HAL_SleepMs(30000);
}
/* wait until connected */
while (is_connected == 0) {
HAL_SleepMs(200);
}
/* reset upload result */
upload_result = 1;
/* use resume option to upload file */
fs_params.file_path = argv[1];
fs_params.upload_len = 0;
fs_params.upload_id = g_upload_id;
fs_params.opt_bit_map = UPLOAD_FILE_OPT_BIT_RESUME; /* resume option used */
ret = IOT_HTTP2_UploadFile_Request(handle, &fs_params, &result_cb, NULL);
if (ret < 0) {
EXAMPLE_TRACE("upload file request error");
return -1;
}
while (upload_result == 1) {
HAL_SleepMs(200);
}
} while (upload_result != UPLOAD_SUCCESS && (++retry_time < UPLOAD_RETRY_TIME));
EXAMPLE_TRACE("upload succeed %d\n", ret);
ret = IOT_HTTP2_UploadFile_Disconnect(handle);
EXAMPLE_TRACE("close connect %d\n", ret);
return 0;
}
int main(int argc, char **argv)
{
int ret;
if (argc < 2) {
HAL_Printf("no file name input!\n");
return 0;
}
ret = http2_stream_test(argv, argc);
return ret;
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "http2_api.h"
#include "http2_wrapper.h"
#ifndef ON_DAILY
#define ON_DAILY
#endif
#if defined(ON_DAILY)
#define HTTP2_ONLINE_SERVER_URL "10.101.12.205"
#define HTTP2_ONLINE_SERVER_PORT 9999
#define HTTP2_PRODUCT_KEY "a1L5EUOh21s"
#define HTTP2_DEVICE_NAME "zhangmei_test01"
#define HTTP2_DEVICE_SECRET "KQCftfEDCx35LChyEwZoYY6FCYidTOp0"
#elif defined(ON_PRE)
#define HTTP2_ONLINE_SERVER_URL "100.67.141.158"
#define HTTP2_ONLINE_SERVER_PORT 8443
#define HTTP2_PRODUCT_KEY "b1XVhqfan1X"
#define HTTP2_DEVICE_NAME "YvhjziEQmKusCFUgRpeo"
#define HTTP2_DEVICE_SECRET "QjkhCrAX0SbNWgKpIamuiDdLkk23Q1r7"
#else
#define HTTP2_ONLINE_SERVER_URL NULL
#define HTTP2_ONLINE_SERVER_PORT 443
#define HTTP2_PRODUCT_KEY "DM5b8zbTWJs"
#define HTTP2_DEVICE_NAME "mydevice1"
#define HTTP2_DEVICE_SECRET "q4tiwQuICYfr6JQ8aUFjWxocuXJ5ruEx"
#endif
#define EXAMPLE_TRACE(fmt, ...) \
do { \
HAL_Printf("%s|%03d :: ", __func__, __LINE__); \
HAL_Printf(fmt, ##__VA_ARGS__); \
HAL_Printf("%s", "\r\n"); \
} while (0)
void* pid1;
static const char UPLOAD_STRING[] =
"It was almost December, and Jonas was beginning to be frightened. No. Wrong word, Jonas thought."
"Frightened meant that deep, sickening feeling of something terrible about to happen. Frightened was"
" the way he had felt a year ago when an unidentified aircraft had overflown the community twice."
" He had seen it both times. Squinting toward the sky, he had seen the sleek jet, almost a blur at"
" its high speed, go past, and a second later heard the blast of sound that followed. Then one more time,"
" a moment later, from the opposite direction, the same plane. At first, he had been only fascinated. "
"He had never seen aircraft so close, for it was against the rules for Pilots to fly over the community."
" Occasionally, when supplies were delivered by cargo planes to the landing field across the river,"
" the children rode their bicycles to the riverbank and watched, intrigued, the unloading and then the "
"takeoff directed to the west, always away from the community. But the aircraft a year ago had been different."
" It was not a squat, fat-bellied cargo plane but a needle-nosed single-pilot jet. Jonas, looking around"
" anxiously, had seen others — adults as well as children — stop what they were doing and wait, confused,"
" for an explanation of the frightening event. Then all of the citizens had been ordered to go into the nearest"
" building and stay there. IMMEDIATELY, the rasping voice through the speakers had said. LEAVE YOUR BICYCLES "
"WHERE THEY ARE. Instantly, obediently, Jonas had dropped his bike on its side on the path behind his family's "
"dwelling. He had run indoors and stayed there, alone. His parents were both at work, and his little sister,"
" Lily, was at the Childcare Center where she spent her after-school hours. Looking through the front window,"
" he had seen no people: none of the busy afternoon crew of Street Cleaners, Landscape Workers, and Food "
"Delivery people who usually populated the community at that time of day. He saw only the abandoned bikes here "
"and there on their sides; an upturned wheel on one was still revolving slowly. He had been frightened then. "
"The sense of his own community silent, waiting, had made his stomach churn. He had trembled. But it had been "
"nothing. Within minutes the speakers had crackled again, and the voice, reassuring now and less urgent, "
"had explained that a Pilot-in-Training had misread his navigational instructions and made a wrong turn. "
"Desperately the Pilot had been trying to make his way back before his error was noticed. NEEDLESS TO SAY, "
"HE WILL BE RELEASED, the voice had said, followed by silence. There was an ironic tone to that final message, "
"as if the Speaker found it amusing; and Jonas had smiled a little, though he knew what a grim statement it had"
" been. For a contributing citizen to be released from the community was a final decision, a terrible punishment,"
" an overwhelming statement of failure. Even the children were scolded if they used the term lightly at play, "
"jeering at a teammate who missed a catch or stumbled in a race. Jonas had done it once, had shouted at his "
"best friend, &quot;That's it, Asher! You're released!&quot; when Asher's clumsy error had lost a match for "
"his team. He had been taken aside for a brief and serious talk by the coach, had hung his head with guilt and "
"embarrassment, and apologized to Asher after the game. Now, thinking about the feeling of fear as he pedaled "
"home along the river path, he remembered that moment of palpable, stomach-sinking terror when the aircraft had"
" streaked above. It was not what he was feeling now with December approaching. He searched for the right word"
" to describe his own feeling. Jonas was careful about language. Not like his friend, Asher, who talked too "
"fast and mixed things up, scrambling words and phrases until they were barely recognizable and often very funny. "
"Jonas grinned, remembering the morning that Asher had dashed into the classroom, late as usual, arriving "
"breathlessly in the middle of the chanting of the morning anthem. When the class took their seats at the "
"conclusion of the patriotic hymn, Asher remained standing to make his public apology as was required. "
"&quot;I apologize for inconveniencing my learning community.&quot; Asher ran through the standard apology"
" phrase rapidly, still catching his breath. The Instructor and class waited patiently for his explanation."
" The students had all been grinning, because they had listened to Asher's explanations so many times before. "
"&quot;I left home at the correct time but when I was riding along near the hatchery, the crew was separating "
"some salmon. I guess I just got distraught, watching them. &quot;I apologize to my classmates,&quot; Asher"
" concluded. He smoothed his rumpled tunic and sat down. &quot;We accept your apology, Asher.&quot; The class"
" recited the standard response in unison. Many of the students were biting their lips to keep from laughing."
" &quot;I accept your apology, Asher,&quot; the Instructor said. He was smiling. &quot;And I thank you, because "
"once again you have provided an opportunity for a lesson in language. &quot;Distraught' is too strong an adjective"
" to describe salmon-viewing.&quot; He turned and wrote &quot;distraught&quot; on the instructional board. "
"Beside it he wrote &quot;distracted.&quot; Jonas, nearing his home now, smiled at the recollection. Thinking, "
"still, as he wheeled his bike into its narrow port beside the door, he realized that frightened was the wrong "
"word to describe his feelings, now that December was almost here. It was too strong an adjective. He had waited a"
" long time for this special December. Now that it was almost upon him, he wasn't frightened, but he was ... eager,"
" he decided. He was eager for it to come. And he was excited, certainly. All of the Elevens were excited about the"
" event that would be coming so soon. But there was a little shudder of nervousness when he thought about it, about"
" what might happen. Apprehensive, Jonas decided. That's what I am. &quot;Who wants to be the first tonight, for "
"feelings?&quot; Jonas's father asked, at the conclusion of their evening meal. It was one of the rituals,"
" the evening telling of feelings. Sometimes Jonas and his sister, Lily, argued over turns, over who would get to go first."
" Their parents, of course, were part of the ritual; they, too, told their feelings each evening. But like all parents — "
"all adults — they didn't fight and wheedle for their turn. Nor did Jonas, tonight. His feelings were too complicated this evening.";
static void on_header(uint32_t stream_id, char *channel_id,int cat,const uint8_t *name,uint32_t namelen,
const uint8_t *value,uint32_t valuelen, uint8_t flags ,void *user_data)
{
EXAMPLE_TRACE("~~~~~stream_id = %d, channel_id=%s, name = %s, value = %s, flag = %d user_data =%p\n", stream_id,channel_id,name,value,flags ,user_data);
}
static void on_chunk_recv(uint32_t stream_id, char *channel_id,const uint8_t *data, uint32_t len,uint8_t flags,void *user_data)
{
EXAMPLE_TRACE("~~~~~stream_id = %d, channel_id=%s, data = %.*s, len = %d flag = %d\n", stream_id, channel_id, len, data, len, flags);
}
static void on_stream_close(uint32_t stream_id, char *channel_id,uint32_t error_code,void *user_data)
{
EXAMPLE_TRACE("~~~~~stream_id = %d channel_id=%s, error_code = %d\n", stream_id,channel_id,error_code);
}
static void on_stream_frame_send(uint32_t stream_id, char *channel_id, int type, uint8_t flags,void *user_data){
EXAMPLE_TRACE("~~~~~stream_id = %d user_data =%p, type = %d\n", stream_id,user_data,type);
}
static http2_stream_cb_t my_cb = {
.on_stream_header_cb = on_header,
.on_stream_chunk_recv_cb = on_chunk_recv,
.on_stream_close_cb = on_stream_close,
.on_stream_frame_send_cb = on_stream_frame_send,
};
static int test_user_data;
static int http2_stream_test()
{
int ret;
device_conn_info_t conn_info;
void *handle;
memset(&conn_info, 0, sizeof( device_conn_info_t));
conn_info.product_key = HTTP2_PRODUCT_KEY;
conn_info.device_name = HTTP2_DEVICE_NAME;
conn_info.device_secret = HTTP2_DEVICE_SECRET;
conn_info.url = HTTP2_ONLINE_SERVER_URL;
conn_info.port = HTTP2_ONLINE_SERVER_PORT;
handle = IOT_HTTP2_Connect(&conn_info,&my_cb);
if(handle == NULL) {
return -1;
}
http2_header header[] = {
MAKE_HEADER("test_name", "test_http2_header"),
MAKE_HEADER("x-for-test", "hello world"),
};
header_ext_info_t my_header_info = {
header,
2
};
stream_data_info_t info_upload, info_download;
memset(&info_upload,0,sizeof(stream_data_info_t));
//info_upload.identify = "com/aliyun/iotx/vision/picture/device/upstream";
info_upload.identify = "iotx/vision/voice/intercom/live";
memset(&info_download, 0, sizeof(stream_data_info_t));
info_download.identify = "iotx/vision/voice/intercom/live";
info_download.user_data = (void *)&test_user_data;
EXAMPLE_TRACE("----------usr_data =%p\n",(void *)&test_user_data);
ret = IOT_HTTP2_Stream_Open(handle, &info_download, &my_header_info);
if (ret < 0) {
EXAMPLE_TRACE("=========iotx_http2_downstream_open failed %d!!!!!\n", ret);
IOT_HTTP2_Disconnect(handle);
return -1;
}
ret = IOT_HTTP2_Stream_Query(handle, &info_download, &my_header_info);
if (ret < 0) {
EXAMPLE_TRACE("=========iotx_http2_downstream_query failed %d!!!!!\n", ret);
IOT_HTTP2_Stream_Close(handle, &info_download);
IOT_HTTP2_Disconnect(handle);
return -1;
}
info_upload.user_data = (void *)&test_user_data;
ret = IOT_HTTP2_Stream_Open(handle, &info_upload, &my_header_info);
if(ret < 0) {
EXAMPLE_TRACE("=========iotx_http2_upstream_open failed %d!!!!!\n", ret);
IOT_HTTP2_Stream_Close(handle, &info_download);
IOT_HTTP2_Disconnect(handle);
return -1;
}
//send request 1
info_upload.stream = (char *)UPLOAD_STRING;
info_upload.stream_len= sizeof(UPLOAD_STRING);
info_upload.send_len = 0;
info_upload.packet_len=2048;
while(info_upload.send_len<info_upload.stream_len) {
info_upload.stream = (char *)UPLOAD_STRING + info_upload.send_len;
if(info_upload.stream_len-info_upload.send_len<info_upload.packet_len) {
info_upload.packet_len = info_upload.stream_len-info_upload.send_len;
}
ret = IOT_HTTP2_Stream_Send(handle, &info_upload, &my_header_info);
if(ret <0 ) {
EXAMPLE_TRACE("send err, ret = %d\n",ret);
break;
}
EXAMPLE_TRACE("iotx_http2_stream_send info_upload.send_len =%d ret = %d\n", info_upload.send_len,ret);
}
//send request 2
info_upload.stream = (char *)UPLOAD_STRING;
info_upload.stream_len= sizeof(UPLOAD_STRING);
info_upload.send_len = 0;
info_upload.packet_len=1024;
while(info_upload.send_len<info_upload.stream_len) {
info_upload.stream = (char *)UPLOAD_STRING + info_upload.send_len;
if(info_upload.stream_len-info_upload.send_len<info_upload.packet_len) {
info_upload.packet_len = info_upload.stream_len-info_upload.send_len;
}
ret = IOT_HTTP2_Stream_Send(handle, &info_upload, &my_header_info);
if(ret <0 ) {
EXAMPLE_TRACE("send err, ret = %d\n",ret);
break;
}
EXAMPLE_TRACE("iotx_http2_stream_send info_upload.send_len =%d ret = %d\n", info_upload.send_len,ret);
}
EXAMPLE_TRACE("=========Wait 20 seconds to receive downstream data\n");
HAL_SleepMs(20000);
IOT_HTTP2_Stream_Close(handle, &info_upload);
IOT_HTTP2_Stream_Close(handle, &info_download);
HAL_SleepMs(2000);
ret = IOT_HTTP2_Disconnect(handle);
EXAMPLE_TRACE("close connect %d\n",ret);
return 0;
}
int main(int argc, char **argv)
{
int ret;
ret = http2_stream_test();
return ret;
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "http2_upload_api.h"
#include "http2_wrapper.h"
#define HTTP2_ONLINE_SERVER_URL "a1IgnOND7vI.iot-as-http2.cn-shanghai.aliyuncs.com"
#define HTTP2_ONLINE_SERVER_PORT 443
#define HTTP2_PRODUCT_KEY "a1IgnOND7vI"
#define HTTP2_DEVICE_NAME "H2_FS01"
#define HTTP2_DEVICE_SECRET "r9XSyeZOu6swgV8etCcCGmgQhBSpGBau"
#define EXAMPLE_TRACE(fmt, ...) \
do { \
HAL_Printf("%s|%03d :: ", __func__, __LINE__); \
HAL_Printf(fmt, ##__VA_ARGS__); \
HAL_Printf("%s", "\r\n"); \
} while (0)
static int upload_end = 0;
static char g_upload_id[50] = {0};
void upload_file_result(const char *file_path, int result, void *user_data)
{
upload_end++;
EXAMPLE_TRACE("=========== file_path = %s, result = %d, finish num = %d ===========", file_path, result, upload_end);
}
void upload_id_received_handle(const char *file_path, const char *upload_id, void *user_data)
{
EXAMPLE_TRACE("=========== file_path = %s, upload_id = %s ===========", file_path, upload_id);
if (upload_id != NULL) {
memset(g_upload_id, 0, sizeof(g_upload_id));
strncpy(g_upload_id, upload_id, sizeof(g_upload_id) - 1);
}
}
static int http2_stream_test(char **argv,int argc)
{
int ret;
http2_upload_conn_info_t conn_info;
http2_upload_result_cb_t result_cb;
void *handle;
int goal_num = 0;
int i;
memset(&conn_info, 0, sizeof(http2_upload_conn_info_t));
conn_info.product_key = HTTP2_PRODUCT_KEY;
conn_info.device_name = HTTP2_DEVICE_NAME;
conn_info.device_secret = HTTP2_DEVICE_SECRET;
conn_info.url = HTTP2_ONLINE_SERVER_URL;
conn_info.port = HTTP2_ONLINE_SERVER_PORT;
memset(&result_cb, 0, sizeof(http2_upload_result_cb_t));
result_cb.upload_completed_cb = upload_file_result;
result_cb.upload_id_received_cb = upload_id_received_handle;
handle = IOT_HTTP2_UploadFile_Connect(&conn_info, NULL);
if(handle == NULL) {
return -1;
}
for (i=1; i<argc; i++) {
http2_upload_params_t fs_params;
memset(&fs_params, 0, sizeof(fs_params));
fs_params.file_path = argv[i];
fs_params.upload_len = 1024 * 1024 * 100;
fs_params.opt_bit_map = UPLOAD_FILE_OPT_BIT_OVERWRITE;
ret = IOT_HTTP2_UploadFile_Request(handle, &fs_params, &result_cb, NULL);
if(ret == 0) {
goal_num++;
}
}
while(upload_end != goal_num) {
HAL_SleepMs(200);
}
ret = IOT_HTTP2_UploadFile_Disconnect(handle);
EXAMPLE_TRACE("close connect %d\n",ret);
return 0;
}
int main(int argc, char **argv)
{
int ret;
if (argc < 2) {
HAL_Printf("no file name input!\n");
return 0;
}
ret = http2_stream_test(argv, argc);
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#ifndef IOT_EXPORT_HTTP2_STREAM_H
#define IOT_EXPORT_HTTP2_STREAM_H
#include "infra_types.h"
#include "infra_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define IOT_HTTP2_RES_OVERTIME_MS (10000)
#define IOT_HTTP2_KEEP_ALIVE_CNT (1)
#define IOT_HTTP2_KEEP_ALIVE_TIME (30*1000) /* in seconds */
#define MAKE_HEADER(NAME, VALUE) \
{ \
(char *) NAME, (char *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1 \
}
#define MAKE_HEADER_CS(NAME, VALUE) \
{ \
(char *) NAME, (char *)VALUE, strlen(NAME) , strlen(VALUE) \
}
typedef struct {
char *product_key;
char *device_name;
char *device_secret;
char *url;
int port;
} device_conn_info_t;
typedef struct http2_header_struct {
char *name; /* header name */
char *value; /* the value of name */
int namelen; /* the length of header name */
int valuelen; /* the length of value */
} http2_header;
typedef struct {
http2_header *nva;
int num;
} header_ext_info_t;
typedef enum {
STREAM_TYPE_DOWNLOAD,
STREAM_TYPE_UPLOAD,
STREAM_TYPE_AUXILIARY,
STREAM_TYPE_NUM
} stream_type_t;
typedef void (*on_stream_header_callback)(uint32_t stream_id, char *channel_id, int cat, const uint8_t *name,
uint32_t namelen, const uint8_t *value, uint32_t valuelen, uint8_t flags, void *user_data);
typedef void (*on_stream_chunk_recv_callback)(uint32_t stream_id, char *channel_id,
const uint8_t *data, uint32_t len, uint8_t flags, void *user_data);
typedef void (*on_stream_close_callback)(uint32_t stream_id, char *channel_id, uint32_t error_code, void *user_data);
typedef void (*on_stream_frame_send_callback)(uint32_t stream_id, char *channel_id, int type, uint8_t flags, void *user_data);
typedef void (*on_stream_frame_recv_callback)(uint32_t stream_id, char *channel_id, int type, uint8_t flags,void *user_data);
typedef void (*on_reconnect_callback)();
typedef void (*on_disconnect_callback)();
typedef struct {
on_stream_header_callback on_stream_header_cb;
on_stream_chunk_recv_callback on_stream_chunk_recv_cb;
on_stream_close_callback on_stream_close_cb;
on_stream_frame_send_callback on_stream_frame_send_cb;
on_stream_frame_recv_callback on_stream_frame_recv_cb;
on_reconnect_callback on_reconnect_cb;
on_disconnect_callback on_disconnect_cb;
} http2_stream_cb_t;
typedef struct {
char *stream; /* point to stream data buffer */
uint32_t stream_len; /* file content length */
uint32_t send_len; /* data had sent length */
uint32_t packet_len; /* one packet length */
const char *identify; /* path string to identify a stream service */
int h2_stream_id; /* stream identifier which is a field in HTTP2 frame */
char *channel_id; /* string return by server to identify a specific stream channel,
different from stream identifier which is a field in HTTP2 frame */
void *user_data; /* user data brought in at stream open */
} stream_data_info_t;
void *IOT_HTTP2_Connect(device_conn_info_t *conn_info, http2_stream_cb_t *user_cb);
int IOT_HTTP2_Stream_Open(void *handle, stream_data_info_t *info, header_ext_info_t *header);
int IOT_HTTP2_Stream_Send(void *handle, stream_data_info_t *info, header_ext_info_t *header);
int IOT_HTTP2_Stream_Query(void *handle, stream_data_info_t *info, header_ext_info_t *header);
int IOT_HTTP2_Stream_Close(void *handle, stream_data_info_t *info);
int IOT_HTTP2_Stream_Send_Message(void *handle, const char *identify,char *channel_id, char *data,
uint32_t data_len, header_ext_info_t *header);
int IOT_HTTP2_Disconnect(void *handle);
#ifdef __cplusplus
}
#endif
#endif /* IOT_EXPORT_FILE_UPLOADER_H */

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#ifndef _HTTP2_CONFIG_H
#define _HTTP2_CONFIG_H
/* maximum packet len in one http2 frame */
#ifndef FS_UPLOAD_PACKET_LEN
#define FS_UPLOAD_PACKET_LEN 10240 /* must < 16384 */
#endif
/* maximum content len of the http2 request */
#ifndef FS_UPLOAD_PART_LEN
#define FS_UPLOAD_PART_LEN (1024 * 1024 * 4) /* 100KB ~ 100MB */
#endif
#endif /* #ifdef _HTTP2_CONFIG_H */

View File

@@ -0,0 +1,192 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#ifndef IOT_EXPORT_HTTP2_H
#define IOT_EXPORT_HTTP2_H
#ifdef __cplusplus
extern "C" {
#endif
#include "http2_api.h"
#include "http2_wrapper.h"
#ifdef INFRA_LOG
#include "infra_log.h"
#define h2_emerg(...) log_emerg("h2", __VA_ARGS__)
#define h2_crit(...) log_crit("h2", __VA_ARGS__)
#define h2_err(...) log_err("h2", __VA_ARGS__)
#define h2_warning(...) log_warning("h2", __VA_ARGS__)
#define h2_info(...) log_info("h2", __VA_ARGS__)
#define h2_debug(...) log_debug("h2", __VA_ARGS__)
#else
#define h2_emerg(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0)
#define h2_crit(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0)
#define h2_err(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0)
#define h2_warning(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0)
#define h2_info(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0)
#define h2_debug(...) do{HAL_Printf(__VA_ARGS__);HAL_Printf("\r\n");}while(0)
#endif
#ifdef INFRA_MEM_STATS
#include "infra_mem_stats.h"
#define HTTP2_STREAM_MALLOC(size) LITE_malloc(size, MEM_MAGIC, "http2.stream")
#define HTTP2_STREAM_FREE(ptr) LITE_free(ptr)
#else
#define HTTP2_STREAM_MALLOC(size) HAL_Malloc(size)
#define HTTP2_STREAM_FREE(ptr) do{if(ptr != NULL) {HAL_Free(ptr);ptr = NULL;}}while(0)
#endif /* #ifdef INFRA_MEM_STATS */
#define POINTER_SANITY_CHECK(ptr, err) \
do { \
if (NULL == (ptr)) { \
return (err); \
} \
} while(0)
#define ARGUMENT_SANITY_CHECK(expr, err) \
do { \
if (!(expr)) { \
return (err); \
} \
} while(0)
typedef enum {
HTTP2_FLAG_NONE = 0,
HTTP2_FLAG_END_STREAM = 0x01,
} http2_flag;
typedef struct http2_list_s {
struct http2_list_s *prev;
struct http2_list_s *next;
} http2_list_t;
typedef void (*on_user_header_callback)(int32_t stream_id, int cat, const uint8_t *name, uint32_t namelen,
const uint8_t *value, uint32_t valuelen, uint8_t flags);
typedef void (*on_user_chunk_recv_callback)(int32_t stream_id,
const uint8_t *data, uint32_t len, uint8_t flags);
typedef void (*on_user_stream_close_callback)(int32_t stream_id, uint32_t error_code);
typedef void (*on_user_frame_send_callback)(int32_t stream_id, int type, uint8_t flags);
typedef void (*on_user_frame_recv_callback)(int32_t stream_id, int type, uint8_t flags);
typedef struct {
on_user_header_callback on_user_header_cb;
on_user_chunk_recv_callback on_user_chunk_recv_cb;
on_user_stream_close_callback on_user_stream_close_cb;
on_user_frame_send_callback on_user_frame_send_cb;
on_user_frame_recv_callback on_user_frame_recv_cb;
} http2_user_cb_t;
typedef struct http2_connection {
void *network; /* iot network ptr */
void *session; /* http2 session */
int flag; /* check the stream is end or not */
int status;
http2_user_cb_t *cbs;
} http2_connection_t;
typedef struct http2_data_struct {
http2_header *header; /* header data. */
int header_count; /* the count of header data. */
char *data; /* send data. */
int len; /* send data length. */
int stream_id; /* send data over specify stream */
int flag; /* send data flag. */
} http2_data;
typedef struct {
http2_connection_t *http2_connect;
void *mutex;
void *semaphore;
void *rw_thread;
http2_list_t stream_list;
int init_state;
http2_stream_cb_t *cbs;
uint8_t connect_state;
uint8_t retry_cnt;
} stream_handle_t;
#ifdef FS_ENABLED
typedef struct {
char fs_upload_id[50];
int fs_offset;
} fs_rsp_header_val_t;
int IOT_HTTP2_FS_Close(void *hd, stream_data_info_t *info, header_ext_info_t *header);
#endif /* #ifdef FS_ENABLED */
/**
* @brief the http2 client connect.
* @param[in] pclient: http client. <struct httpclient_t>
* @return http2 client connection handler.
*/
extern http2_connection_t *iotx_http2_client_connect(void *pclient, char *url, int port);
http2_connection_t *iotx_http2_client_connect_with_cb(void *pclient, char *url, int port, http2_user_cb_t *cb);
/**
* @brief the http2 client send data.
* @param[in] handler: http2 client connection handler.
* @param[in] data: send data.
* @return The result. 0 is ok.
*/
extern int iotx_http2_client_send(http2_connection_t *conn, http2_data *h2_data);
/**
* @brief the http2 client receive data.
* @param[in] handler: http2 client connection handler.
* @param[in] data: receive data buffer.
* @param[in] data_len: buffer length.
* @param[in] len: receive data length.
* @param[in] timeout: receive data timeout.
* @return The result. 0 is ok.
*/
extern int iotx_http2_client_recv(http2_connection_t *conn, char *data, int data_len, int *len, int timeout);
/**
* @brief the http2 client connect.
* @param[in] handler: http2 client connection handler.
* @return The result. 0 is ok.
*/
extern int iotx_http2_client_disconnect(http2_connection_t *conn);
/**
* @brief the http2 client send ping to keep alive.
* @param[in] handler: http2 client connection handler.
* @return The result. 0 is ok.
*/
extern int iotx_http2_client_send_ping(http2_connection_t *conn);
/**
* @brief the http2 client get available windows size.
* @param[in] handler: http2 client connection handler.
* @return The window size.
*/
extern int iotx_http2_get_available_window_size(http2_connection_t *conn);
/**
* @brief the http2 client receive windows size packet to update window.
* @param[in] handler: http2 client connection handler.
* @return The result. 0 is ok.
*/
extern int iotx_http2_update_window_size(http2_connection_t *conn);
/**
* @brief the http2 client performs the network I/O.
* @param[in] handler: http2 client connection handler.
* @return The result. 0 is ok.
*/
extern int iotx_http2_exec_io(http2_connection_t *connection);
extern int iotx_http2_client_recv_ping(void);
int iotx_http2_reset_stream(http2_connection_t *connection, int32_t stream_id);
#ifdef __cplusplus
}
#endif
#endif /* IOT_EXPORT_HTTP2_H */

View File

@@ -0,0 +1,595 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include "infra_config.h"
#ifdef FS_ENABLED
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "infra_defs.h"
#include "infra_types.h"
#include "infra_httpc.h"
#include "infra_sha1.h"
#include "infra_timer.h"
#include "infra_list.h"
#include "infra_log.h"
#include "http2_internal.h"
#include "http2_api.h"
#include "http2_upload_api.h"
#include "http2_config.h"
#include "http2_wrapper.h"
#include "wrappers_defs.h"
#define PACKET_LEN 16384
#define HTTP2_FS_SERVICE_ID "c/iot/sys/thing/file/upload"
typedef enum {
FS_STATUS_WAITING,
FS_STATUS_UPLOADING,
FS_STATUS_BREAK,
FS_STATUS_END,
FS_STATUS_NUM
} file_stream_status_t;
typedef enum {
FS_TYPE_NORMAL,
FS_TYPE_CONTINUE,
FS_TYPE_OVERRIDE,
} file_stream_type_t;
typedef struct {
int idx;
const char *file_path;
char upload_id[40];
uint32_t spec_len;
uint32_t file_offset;
uint32_t part_len;
file_stream_type_t type;
http2_upload_id_received_cb_t opened_cb;
http2_upload_completed_cb_t end_cb;
void *user_data;
uint8_t if_stop;
http2_list_t list;
} http2_file_stream_t;
typedef struct {
stream_handle_t *http2_handle;
const char *service_id;
http2_list_t file_list;
void *list_mutex;
void *file_thread;
int upload_idx;
} http2_file_stream_ctx_t;
typedef struct {
char *send_buffer;
const char *upload_id;
uint32_t file_offset;
uint32_t part_len;
} fs_send_ext_info_t;
static http2_file_stream_ctx_t g_http2_fs_ctx = { 0 };
static http2_stream_cb_t callback_func = { 0 };
/* utils, get file sizef */
static int http2_stream_get_file_size(const char *file_name)
{
void *fp = NULL;
int size = 0;
if ((fp = HAL_Fopen(file_name, "r")) == NULL) {
h2_err("The file %s can not be opened.\n", file_name);
return -1;
}
HAL_Fseek(fp, 0L, HAL_SEEK_END);
size = HAL_Ftell(fp);
HAL_Fclose(fp);
return size;
}
/* utils, get file name */
static const char *_http2_fs_get_filename(const char *file_path)
{
const char *p_name = NULL;
if (file_path == NULL) {
return NULL;
}
p_name = file_path + strlen(file_path);
while (--p_name != file_path) {
if (*p_name == '/') {
p_name++;
break;
}
}
return p_name;
}
/* utils, read file data */
static int http2_stream_get_file_data(const char *file_name, char *data, int len, int offset)
{
void *fp = NULL;
int ret = 0;
if ((fp = HAL_Fopen(file_name, "r")) == NULL) {
h2_err("The file %s can not be opened.\n", file_name);
return -1;
}
ret = HAL_Fseek(fp, offset, HAL_SEEK_SET);
if (ret != 0) {
HAL_Fclose(fp);
h2_err("The file %s can not move offset.\n", file_name);
return -1;
}
ret = HAL_Fread(data, len, 1, fp);
HAL_Fclose(fp);
return len;
}
/* open http2 file upload channel */
static int _http2_fs_open_channel(http2_file_stream_t *fs_node, stream_data_info_t *info)
{
stream_handle_t *h2_handle = g_http2_fs_ctx.http2_handle;
header_ext_info_t ext_header;
fs_rsp_header_val_t *open_rsp = (fs_rsp_header_val_t *)info->user_data;
const char *filename = NULL;
int ret = UPLOAD_ERROR_COMMON;
/* header for normal upload */
http2_header header_filename[] = {
MAKE_HEADER_CS("x-file-name", ""),
};
/* header for override operation */
http2_header header_overwrite[] = {
MAKE_HEADER_CS("x-file-name", ""),
MAKE_HEADER_CS("x-file-overwrite", "1"),
};
/* header for continue operation */
http2_header header_uploadid[] = {
MAKE_HEADER("x-file-upload-id", ""),
};
filename = _http2_fs_get_filename(fs_node->file_path);
h2_info("filename = %s", filename);
header_filename[0].value = (char *)filename;
header_filename[0].valuelen = strlen(filename);
header_overwrite[0].value = (char *)filename;
header_overwrite[0].valuelen = strlen(filename);
/* setup http2 ext_header */
switch (fs_node->type) {
case FS_TYPE_NORMAL: {
ext_header.num = 1;
ext_header.nva = header_filename;
} break;
case FS_TYPE_OVERRIDE: {
ext_header.num = 2;
ext_header.nva = header_overwrite;
} break;
case FS_TYPE_CONTINUE: {
/* upload id must be exist */
header_uploadid[0].value = fs_node->upload_id;
header_uploadid[0].valuelen = strlen(fs_node->upload_id);
ext_header.num = 1;
ext_header.nva = header_uploadid;
} break;
default: break;
}
ret = IOT_HTTP2_Stream_Open(h2_handle, info, &ext_header);
if (ret < 0 || open_rsp->fs_offset == -1 || open_rsp->fs_upload_id[0] == '\0') {
h2_err("IOT_HTTP2_Stream_Open failed %d\n", ret);
return UPLOAD_STREAM_OPEN_FAILED;
}
h2_info("fs channel open succeed");
return SUCCESS_RETURN;
}
/* file part data send sync api */
static int _http2_fs_part_send_sync(http2_file_stream_t *fs_node, stream_data_info_t *info, fs_send_ext_info_t *ext_info)
{
stream_handle_t *h2_handle = g_http2_fs_ctx.http2_handle;
header_ext_info_t ext_header;
int res;
http2_header header_uploadid[] = {
MAKE_HEADER_CS("x-file-upload-id", ext_info->upload_id),
};
/* setup ext header */
ext_header.num = 1;
ext_header.nva = header_uploadid;
/* setup Stream_Send params */
info->stream = ext_info->send_buffer;
info->stream_len = ext_info->part_len;
info->send_len = 0;
info->packet_len = FS_UPLOAD_PACKET_LEN;
while (info->send_len < info->stream_len) {
if (!h2_handle->init_state) {
res = UPLOAD_ERROR_COMMON;
break;
}
res = http2_stream_get_file_data(fs_node->file_path, ext_info->send_buffer, FS_UPLOAD_PACKET_LEN, (info->send_len + ext_info->file_offset)); /* offset used */
if (res <= 0) {
res = UPLOAD_FILE_READ_FAILED;
break;
}
info->packet_len = res;
/* adjust the packet len */
if (info->stream_len - info->send_len < info->packet_len) {
info->packet_len = info->stream_len - info->send_len;
}
res = IOT_HTTP2_Stream_Send(h2_handle, info, &ext_header);
if (res < 0) {
res = UPLOAD_STREAM_SEND_FAILED;
break;
}
h2_debug("send len = %d\n", info->send_len);
if (fs_node->if_stop) {
res = UPLOAD_STOP_BY_IOCTL;
break;
}
res = SUCCESS_RETURN;
}
return res;
}
void *_http2_fs_node_handle(http2_file_stream_t *fs_node)
{
stream_handle_t *h2_handle = g_http2_fs_ctx.http2_handle;
int filesize = 0;
int upload_len = 0;
fs_rsp_header_val_t rsp_data;
fs_send_ext_info_t send_ext_info;
stream_data_info_t channel_info;
uint32_t part_len = 0;
int res = FAIL_RETURN;
/* params check */
if (h2_handle == NULL) {
/* TODO: handle */
return NULL;
}
/* get fileszie */
filesize = http2_stream_get_file_size(fs_node->file_path);
if (filesize <= 0) {
if (fs_node->end_cb) {
fs_node->end_cb(fs_node->file_path, UPLOAD_FILE_NOT_EXIST, fs_node->user_data);
}
return NULL;
}
h2_info("filesize = %d", filesize);
/* open http2 file upload channel */
memset(&rsp_data, 0, sizeof(fs_rsp_header_val_t));
memset(&channel_info, 0, sizeof(stream_data_info_t));
channel_info.identify = g_http2_fs_ctx.service_id;
channel_info.user_data = (void *)&rsp_data;
res = _http2_fs_open_channel(fs_node, &channel_info);
if (res < SUCCESS_RETURN) {
if (fs_node->end_cb) {
fs_node->end_cb(fs_node->file_path, res, fs_node->user_data);
}
return NULL;
}
h2_info("upload_id = %s", rsp_data.fs_upload_id);
h2_info("upload_offset = %d", rsp_data.fs_offset);
if (fs_node->opened_cb) {
fs_node->opened_cb(fs_node->file_path, rsp_data.fs_upload_id, fs_node->user_data);
}
if (fs_node->spec_len && (fs_node->spec_len + rsp_data.fs_offset < filesize)) {
upload_len = fs_node->spec_len + rsp_data.fs_offset;
}
else {
upload_len = filesize;
}
/* setup send part len */
if ((fs_node->part_len < (1024 * 100)) || (fs_node->part_len > (1024 * 1024 * 100))) {
part_len = FS_UPLOAD_PART_LEN;
}
else {
part_len = fs_node->part_len;
}
/* send http2 file upload data */
send_ext_info.upload_id = rsp_data.fs_upload_id;
send_ext_info.file_offset = rsp_data.fs_offset;
send_ext_info.send_buffer = HTTP2_STREAM_MALLOC(FS_UPLOAD_PACKET_LEN);
if (send_ext_info.send_buffer == NULL) {
if (fs_node->end_cb) {
fs_node->end_cb(fs_node->file_path, UPLOAD_MALLOC_FAILED, fs_node->user_data);
}
return NULL;
}
do {
/* setup the part len */
send_ext_info.part_len = ((upload_len - send_ext_info.file_offset) < part_len)?
(upload_len - send_ext_info.file_offset): part_len;
res = _http2_fs_part_send_sync(fs_node, &channel_info, &send_ext_info);
if (res < SUCCESS_RETURN) {
h2_err("fs send return %d", res);
break;
}
send_ext_info.file_offset += send_ext_info.part_len;
h2_info("file offset = %d now", send_ext_info.file_offset);
} while (send_ext_info.file_offset < upload_len);
if (res < 0) {
if (fs_node->end_cb) {
fs_node->end_cb(fs_node->file_path, res, fs_node->user_data);
}
HTTP2_STREAM_FREE(channel_info.channel_id);
HTTP2_STREAM_FREE(send_ext_info.send_buffer);
return NULL;
}
/* close http2 file upload channel */
IOT_HTTP2_FS_Close(h2_handle, &channel_info, NULL);
if (fs_node->end_cb) {
fs_node->end_cb(fs_node->file_path, UPLOAD_SUCCESS, fs_node->user_data);
}
HTTP2_STREAM_FREE(send_ext_info.send_buffer);
return NULL;
}
static void *http_upload_file_func(void *fs_data)
{
http2_file_stream_ctx_t *fs_ctx = (http2_file_stream_ctx_t *)fs_data;
http2_file_stream_t *node = NULL;
if (fs_ctx == NULL) {
return NULL;
}
while (fs_ctx->http2_handle->init_state) {
HAL_MutexLock(fs_ctx->list_mutex);
if (!list_empty((list_head_t *)&g_http2_fs_ctx.file_list)) {
node = list_first_entry(&fs_ctx->file_list, http2_file_stream_t, list);
HAL_MutexUnlock(fs_ctx->list_mutex);
/* execute upload routine */
_http2_fs_node_handle((void *)node);
/* delete the completed node */
HAL_MutexLock(fs_ctx->list_mutex);
list_del((list_head_t *)&node->list);
HTTP2_STREAM_FREE(node);
HAL_MutexUnlock(fs_ctx->list_mutex);
}
else {
HAL_MutexUnlock(fs_ctx->list_mutex);
h2_debug("file list is empty, file upload thread exit\n");
g_http2_fs_ctx.file_thread = NULL;
break;
}
}
return NULL;
}
static void _http2_fs_list_insert(http2_file_stream_ctx_t *fs_ctx, http2_file_stream_t *node)
{
INIT_LIST_HEAD((list_head_t *)&node->list);
HAL_MutexLock(fs_ctx->list_mutex);
list_add_tail((list_head_t *)&node->list, (list_head_t *)&fs_ctx->file_list);
HAL_MutexUnlock(fs_ctx->list_mutex);
}
typedef enum {
HTTP2_IOCTL_STOP_UPLOAD,
HTTP2_IOCTL_COMMAND_NUM,
} http2_file_upload_ioctl_command_t;
static int _http2_fs_list_search_by_idx(int idx, http2_file_stream_t **search_node)
{
http2_file_stream_t *node = NULL;
HAL_MutexLock(g_http2_fs_ctx.list_mutex);
list_for_each_entry(node, &g_http2_fs_ctx.file_list, list, http2_file_stream_t) {
if (idx == node->idx) {
*search_node = node;
HAL_MutexUnlock(g_http2_fs_ctx.list_mutex);
return SUCCESS_RETURN;
}
}
HAL_MutexUnlock(g_http2_fs_ctx.list_mutex);
*search_node = NULL;
return FAIL_RETURN;
}
int IOT_HTTP2_Ioctl(int upload_idx, int command, void *data)
{
http2_file_stream_t *node = NULL;
if (g_http2_fs_ctx.http2_handle == NULL) {
return UPLOAD_ERROR_COMMON;
}
_http2_fs_list_search_by_idx(upload_idx, &node);
if (node == NULL) {
return UPLOAD_ERROR_COMMON;
}
switch (command) {
case HTTP2_IOCTL_STOP_UPLOAD: {
if (g_http2_fs_ctx.http2_handle) {
HAL_MutexLock(g_http2_fs_ctx.list_mutex);
node->if_stop = 1;
HAL_MutexUnlock(g_http2_fs_ctx.list_mutex);
return SUCCESS_RETURN;
}
else {
return UPLOAD_ERROR_COMMON;
}
} break;
default: {
return UPLOAD_ERROR_COMMON;
}
}
return SUCCESS_RETURN;
}
void *IOT_HTTP2_UploadFile_Connect(http2_upload_conn_info_t *conn_info, http2_status_cb_t *cb)
{
void *handle;
memset(&callback_func, 0, sizeof(http2_stream_cb_t));
if (cb != NULL) {
callback_func.on_reconnect_cb = cb->on_reconnect_cb;
callback_func.on_disconnect_cb = cb->on_disconnect_cb;
}
handle = IOT_HTTP2_Connect((device_conn_info_t *)conn_info, &callback_func);
if (handle == NULL) {
return handle;
}
/* TODO */
g_http2_fs_ctx.list_mutex = HAL_MutexCreate();
if (g_http2_fs_ctx.list_mutex == NULL) {
h2_err("fs mutex create error\n");
IOT_HTTP2_UploadFile_Disconnect(handle);
return NULL;
}
INIT_LIST_HEAD((list_head_t *)&(g_http2_fs_ctx.file_list));
g_http2_fs_ctx.http2_handle = handle;
g_http2_fs_ctx.service_id = HTTP2_FS_SERVICE_ID;
return handle;
}
int IOT_HTTP2_UploadFile_Request(void *http2_handle, http2_upload_params_t *params, http2_upload_result_cb_t *cb, void *user_data)
{
int ret;
http2_file_stream_t *file_node = NULL;
if (http2_handle == NULL || params == NULL || cb == NULL) {
return NULL_VALUE_ERROR;
}
if (params->file_path == NULL) {
return UPLOAD_FILE_PATH_IS_NULL;
}
if ( (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_RESUME) && params->upload_id == NULL) {
return UPLOAD_ID_IS_NULL;
}
if ( (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN) && params->upload_len == 0) {
return UPLOAD_LEN_IS_ZERO;
}
file_node = (http2_file_stream_t *)HTTP2_STREAM_MALLOC(sizeof(http2_file_stream_t));
if (file_node == NULL) {
return UPLOAD_MALLOC_FAILED;
}
memset(file_node, 0, sizeof(http2_file_stream_t));
file_node->file_path = params->file_path;
file_node->part_len = params->part_len;
file_node->opened_cb = cb->upload_id_received_cb;
file_node->end_cb = cb->upload_completed_cb;
file_node->user_data = user_data;
file_node->type = FS_TYPE_NORMAL;
file_node->idx = g_http2_fs_ctx.upload_idx++;
if (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN) {
file_node->spec_len = params->upload_len;
}
if (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_OVERWRITE) {
file_node->type = FS_TYPE_OVERRIDE;
}
else if (params->opt_bit_map & UPLOAD_FILE_OPT_BIT_RESUME) {
file_node->type = FS_TYPE_CONTINUE;
memcpy(file_node->upload_id, params->upload_id, sizeof(file_node->upload_id));
}
/* inset http2_fs node */
_http2_fs_list_insert(&g_http2_fs_ctx, file_node);
if (g_http2_fs_ctx.file_thread == NULL) {
hal_os_thread_param_t thread_parms = {0};
thread_parms.stack_size = 6144;
thread_parms.name = "file_upload";
ret = HAL_ThreadCreate(&g_http2_fs_ctx.file_thread, http_upload_file_func, (void *)&g_http2_fs_ctx, &thread_parms, NULL);
if (ret != 0) {
h2_err("file upload thread create error\n");
return -1;
}
HAL_ThreadDetach(g_http2_fs_ctx.file_thread);
}
return SUCCESS_RETURN;
}
int IOT_HTTP2_UploadFile_Disconnect(void *handle)
{
int res = FAIL_RETURN;
res = IOT_HTTP2_Disconnect(handle);
if (g_http2_fs_ctx.list_mutex == NULL) {
memset(&g_http2_fs_ctx, 0, sizeof(g_http2_fs_ctx));
}
else {
http2_file_stream_t *node, *next;
HAL_MutexLock(g_http2_fs_ctx.list_mutex);
list_for_each_entry_safe(node, next, &g_http2_fs_ctx.file_list, list, http2_file_stream_t) {
list_del((list_head_t *)&node->list);
HTTP2_STREAM_FREE(node);
break;
}
HAL_MutexUnlock(g_http2_fs_ctx.list_mutex);
HAL_MutexDestroy(g_http2_fs_ctx.list_mutex);
memset(&g_http2_fs_ctx, 0, sizeof(g_http2_fs_ctx));
}
return res;
}
#endif /* #ifdef FS_ENABLED */

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#ifndef _HTTP2_UPLOAD_API_H_
#define _HTTP2_UPLOAD_API_H_
#include "infra_types.h"
#include "infra_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/* bit define of file override option */
#define UPLOAD_FILE_OPT_BIT_OVERWRITE (0x00000001)
#define UPLOAD_FILE_OPT_BIT_RESUME (0x00000002)
#define UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN (0x00000004)
/* http2 connect information */
typedef struct {
char *product_key;
char *device_name;
char *device_secret;
char *url;
int port;
} http2_upload_conn_info_t;
/* file upload option define */
typedef struct {
const char *file_path; /* file path, filename must be ASCII string and strlen < 2014 */
uint32_t part_len; /* maximum content len of one http2 request, must be in range of 100KB ~ 100MB */
const char *upload_id; /* a specific id used to indicate one upload session, only required when UPLOAD_FILE_OPT_BIT_RESUME option set */
uint32_t upload_len; /* used to indicate the upload length, only required when UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN option set */
uint32_t opt_bit_map; /* option bit map, support UPLOAD_FILE_OPT_BIT_OVERWRITE, UPLOAD_FILE_OPT_BIT_RESUME and UPLOAD_FILE_OPT_BIT_SPECIFIC_LEN */
} http2_upload_params_t;
/* error code for file upload */
typedef enum {
UPLOAD_STOP_BY_IOCTL = -14,
UPLOAD_HTTP2_HANDLE_NULL = -13,
UPLOAD_LEN_IS_ZERO = -12,
UPLOAD_FILE_PATH_IS_NULL = -11,
UPLOAD_ID_IS_NULL = -10,
UPLOAD_FILE_NOT_EXIST = -9,
UPLOAD_FILE_READ_FAILED = -8,
UPLOAD_STREAM_OPEN_FAILED = -7,
UPLOAD_STREAM_SEND_FAILED = -6,
UPLOAD_MALLOC_FAILED = -5,
UPLOAD_NULL_POINT = -2,
UPLOAD_ERROR_COMMON = -1,
UPLOAD_SUCCESS = 0,
} http2_file_upload_result_t;
/* gerneral callback function, this callback will be invoke when http2 disconnected */
typedef void (*http2_disconnect_cb_t)(void);
/* gerneral callback function, this callback will be invoke when http2 reconnected */
typedef void (*http2_reconnect_cb_t)(void);
/* callback function type define, this callback will be invoke when upload completed */
typedef void (*http2_upload_completed_cb_t)(const char *file_path, int result, void *user_data);
/* callback funciton type define, this callback will be invoke when upload_id received */
typedef void (*http2_upload_id_received_cb_t)(const char *file_path, const char *upload_id, void *user_data);
/* http2 connect status callback define */
typedef struct {
http2_disconnect_cb_t on_disconnect_cb;
http2_reconnect_cb_t on_reconnect_cb;
} http2_status_cb_t;
/* http2 upload result callback define */
typedef struct {
http2_upload_id_received_cb_t upload_id_received_cb;
http2_upload_completed_cb_t upload_completed_cb;
} http2_upload_result_cb_t;
/* http2 uploadfile connect api, http2 handle returned */
void *IOT_HTTP2_UploadFile_Connect(http2_upload_conn_info_t *conn_info, http2_status_cb_t *cb);
/* http2 uploadfile start api */
int IOT_HTTP2_UploadFile_Request(void *http2_handle, http2_upload_params_t *params, http2_upload_result_cb_t *cb, void *user_data);
/* http2 uploadfile disconnect api */
int IOT_HTTP2_UploadFile_Disconnect(void *handle);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _HTTP2_UPLOAD_API_H_ */

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#ifndef __HTTP2_WRAPPER_H__
#define __HTTP2_WRAPPER_H__
#include "infra_types.h"
#include "infra_defs.h"
#include "wrappers_defs.h"
extern void HAL_Printf(const char *fmt, ...);
extern void HAL_SleepMs(uint32_t ms);
extern void *HAL_Malloc(uint32_t size);
extern void *HAL_Realloc(void *ptr, uint32_t size);
extern void HAL_Free(void *ptr);
extern void *HAL_MutexCreate(void);
extern void HAL_MutexDestroy(void *mutex);
extern void HAL_MutexLock(void *mutex);
extern void HAL_MutexUnlock(void *mutex);
extern void *HAL_SemaphoreCreate(void);
extern void HAL_SemaphoreDestroy(void *sem);
extern void HAL_SemaphorePost(void *sem);
extern int HAL_SemaphoreWait(void *sem, uint32_t timeout_ms);
extern int HAL_ThreadCreate(
void **thread_handle,
void *(*work_routine)(void *),
void *arg,
hal_os_thread_param_t *hal_os_thread_param,
int *stack_used);
extern void HAL_ThreadDetach(void *thread_handle);
extern void HAL_ThreadDelete(void *thread_handle);
#ifdef FS_ENABLED
typedef enum {
HAL_SEEK_SET,
HAL_SEEK_CUR,
HAL_SEEK_END
} hal_fs_seek_type_t;
extern void *HAL_Fopen(const char *path, const char *mode);
extern uint32_t HAL_Fread(void *buff, uint32_t size, uint32_t count, void *stream);
extern uint32_t HAL_Fwrite(const void *ptr, uint32_t size, uint32_t count, void *stream);
extern int HAL_Fseek(void *stream, long offset, int framewhere);
extern int HAL_Fclose(void *stream);
extern long HAL_Ftell(void *stream);
#endif /* #ifdef FS_ENABLED */
#endif /* #ifndef __HTTP2_WRAPPER_H__ */

View File

@@ -0,0 +1,16 @@
LIBA_TARGET := libiot_http2.a
HDR_REFS += src/infra
DEPENDS += wrappers external_libs/nghttp2
LDFLAGS += -liot_sdk -liot_hal -liot_tls -liot_nghttp2
LIB_SRCS_EXCLUDE := examples/http2_example_stream.c examples/http2_example_uploadfile.c examples/http2_example_break_resume.c
SRCS_http2-example-stream += examples/http2_example_stream.c
SRCS_http2-example-uploadfile += examples/http2_example_uploadfile.c
SRCS_http2-example-break-resume += examples/http2_example_break_resume.c
$(call Append_Conditional, TARGET, http2-example-stream, HTTP2_COMM_ENABLED)
$(call Append_Conditional, TARGET, http2-example-uploadfile http2-example-break-resume, HTTP2_COMM_ENABLED FS_ENABLED)

View File

@@ -0,0 +1,841 @@
/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nghttp2.h"
#include "nghttp2_session.h"
#include "infra_httpc.h"
#include "http2_internal.h"
#include "http2_wrapper.h"
#define MAX_HTTP2_HOST_LEN (128)
#define NGHTTP2_DBG h2_info
typedef enum {
PING_IDLE,
PING_SENDING,
PING_SENT,
PING_RECVED,
} http2_ping_state_t;
enum { IO_NONE, WANT_READ, WANT_WRITE };
typedef struct _http2_request_struct_ {
/* Stream ID for this request. */
int32_t stream_id;
} http2_request;
extern const char *iotx_ca_get(void);
extern int httpclient_connect(httpclient_t *client);
static int http2_nv_copy_nghttp2_nv(nghttp2_nv *nva, int start, http2_header *nva_copy, int end);
/*static int http2_parse_host(char *url, char *host, size_t maxHostLen);*/
static http2_ping_state_t ping_state = PING_IDLE;
int g_recv_timeout = 10;
int set_http2_recv_timeout(int timeout)
{
g_recv_timeout = timeout;
return 1;
}
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
size_t length, int flags, void *user_data)
{
http2_connection_t *connection;
httpclient_t *client;
int rv;
connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
NGHTTP2_DBG("send_callback data len %d, session->remote_window_size=%d!\r\n", (int)length,
session->remote_window_size);
if (session->remote_window_size < length * 2) {
HAL_SleepMs(50);
NGHTTP2_DBG("wait a munite ....");
}
/*if(length < 50)
LITE_hexdump("data:", data, length);*/
client = (httpclient_t *)connection->network;
rv = client->net.write(&client->net, (char *)data, length, 5000);
NGHTTP2_DBG("send_callback data ends len = %d!\r\n", rv);
if (rv < 0 || rv < length) {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
}
return rv;
}
/**
* @brief The implementation of nghttp2_recv_callback type. Here we read |data| from the network
* and write them in |buf|. The capacity of |buf| is |length| bytes. Returns the number of
* bytes stored in |buf|. See the documentation of nghttp2_recv_callback for the details.
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_send_callback()`.
* @param[in] session: nghttp2 session.
* @param[in] buf: receive data buffer.
* @param[in] length: data length.
* @param[in] flags: no using.
* @param[in] user_data: user data.
* @return Received data length.
*/
static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf,
size_t length, int flags, void *user_data)
{
http2_connection_t *connection;
int rv;
httpclient_t *client;
connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
client = (httpclient_t *)connection->network;
rv = client->net.read(&client->net, (char *)buf, length, g_recv_timeout);
/* NGHTTP2_DBG("recv_callback len= %d\r\n", rv); */
if (rv < 0) {
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
} else if (rv == 0) {
rv = 0;
}
return rv;
}
/**
* @brief Callback function invoked after the frame |frame| is sent.
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_send_callback()`.
* @param[in] session: nghttp2 session.
* @param[in] frame: nghttp2 frame.
* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
* and `nghttp2_session_mem_send()` functions immediately return :enum:
* `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_frame_send_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
size_t i;
http2_connection_t *connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
switch (frame->hd.type) {
case NGHTTP2_HEADERS: {
const nghttp2_nv *nva = frame->headers.nva;
NGHTTP2_DBG("[INFO] C ---------> S (HEADERS) stream_id [%d]\n", frame->hd.stream_id);
for (i = 0; i < frame->headers.nvlen; ++i) {
NGHTTP2_DBG("> %s: %s\n", nva[i].name, nva[i].value);
}
(void)nva;
} break;
case NGHTTP2_RST_STREAM: {
NGHTTP2_DBG("[INFO] C ---------> S (RST_STREAM)\n");
} break;
case NGHTTP2_GOAWAY: {
NGHTTP2_DBG("[INFO] C ---------> S (GOAWAY) code = %d\n",frame->goaway.error_code);
} break;
case NGHTTP2_PING: {
NGHTTP2_DBG("[INFO] C ---------> S (PING)\n");
ping_state = PING_SENDING;
} break;
default: break;
}
if (connection->cbs && connection->cbs->on_user_frame_send_cb) {
connection->cbs->on_user_frame_send_cb(frame->hd.stream_id, frame->hd.type, frame->hd.flags);
}
return 0;
}
/**
* @brief Callback function invoked by `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` when a frame is received.
* If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``member of their data structure are always
* ``NULL`` and 0 respectively. The header name/value pairs are emitted via:type:`nghttp2_on_header_callback`
* To set this callback to :type:`nghttp2_session_callbacks`, use`nghttp2_session_callbacks_set_on_frame_send_callback()`.
* For HEADERS, PUSH_PROMISE and DATA frames, this callback may be called after stream is closed (see:type:
* `nghttp2_on_stream_close_callback`). The application should check that stream is still alive using its own stream
* management or :func:`nghttp2_session_get_stream_user_data()`.
* Only HEADERS and DATA frame can signal the end of incoming data. If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM``
* is nonzero, the|frame| is the last frame from the remote peer in this stream.
* This callback won't be called for CONTINUATION frames.
* HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame.
* @param[in] session: nghttp2 session.
* @param[in] frame: nghttp2 frame.
* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
* and `nghttp2_session_mem_send()` functions immediately return :enum:
* `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_frame_recv_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
http2_connection_t *connection = (http2_connection_t *)user_data;
http2_request *req;
NGHTTP2_DBG("on_frame_recv_callback, type = %d\n", frame->hd.type);
NGHTTP2_DBG("on_frame_recv_callback, stream_id = %d\n", frame->hd.stream_id);
if (connection == NULL) {
return 0;
}
req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (req == NULL) {
NGHTTP2_DBG("stream user data is not exist\n");
}
switch (frame->hd.type) {
case NGHTTP2_HEADERS: {
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
}
} break;
case NGHTTP2_RST_STREAM: {
connection->status = 0;
NGHTTP2_DBG("[INFO] C <--------- S (RST_STREAM)\n");
} break;
case NGHTTP2_GOAWAY: {
connection->status = 0;
NGHTTP2_DBG("[INFO] C <--------- S (GOAWAY) code = %d\n",frame->goaway.error_code);
} break;
case NGHTTP2_DATA: {
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
NGHTTP2_DBG("end stream flag\r\n");
}
} break;
case NGHTTP2_PING: {
NGHTTP2_DBG("[INFO] C <--------- S (PING)\n");
ping_state = PING_RECVED;
} break;
}
if (connection->cbs && connection->cbs->on_user_frame_recv_cb) {
connection->cbs->on_user_frame_recv_cb(frame->hd.stream_id, frame->hd.type, frame->hd.flags);
}
return 0;
}
/**
* @brief Callback function invoked when the stream |stream_id| is closed.
* We use this function to know if the response is fully received. Since we just fetch 1 resource in this program, after
* the response is received, we submit GOAWAY and close the session.
* @param[in] session: nghttp2 session.
* @param[in] stream_id: stream id.
* @param[in] error_code: The reason of closure.
* Usually one of :enum:`nghttp2_error_code`, but that is not guaranteed. The stream_user_data, which was specified in
* `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still available in this function.
* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
* and `nghttp2_session_mem_send()` functions immediately return :enum:
* `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_h2_stream_close_callback(nghttp2_session *session, int32_t stream_id,
uint32_t error_code,
void *user_data)
{
http2_request *req;
http2_connection_t *connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
req = nghttp2_session_get_stream_user_data(session, stream_id);
if (req) {
int rv;
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
if (rv != 0) {
NGHTTP2_DBG("stream close nghttp2_session_terminate_session\r\n");
}
}
if (connection->cbs && connection->cbs->on_user_stream_close_cb) {
connection->cbs->on_user_stream_close_cb(stream_id, error_code);
}
return 0;
}
/**
* @brief Callback function invoked when a chunk of data in DATA frame is received.
* The implementation of nghttp2_on_data_chunk_recv_callback type. We use this function to print the received response body.
* @param[in] session: nghttp2 session.
* @param[in] flags: no using.
* @param[in] stream_id: the stream ID this DATA frame belongs to.
* @param[in] data: receive data.
* @param[in] len: data length.
* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
* and `nghttp2_session_mem_send()` functions immediately return :enum:
* `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_data_chunk_recv_callback(nghttp2_session *session,
uint8_t flags, int32_t stream_id,
const uint8_t *data, size_t len,
void *user_data)
{
http2_request *req;
http2_connection_t *connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
req = nghttp2_session_get_stream_user_data(session, stream_id);
if (req) {
NGHTTP2_DBG("stream user data is not exist\n");
}
NGHTTP2_DBG("[INFO] C <----------- S (DATA chunk) stream_id [%d] :: %lu bytes\n", stream_id, (unsigned long int)len);
if (connection->cbs && connection->cbs->on_user_chunk_recv_cb) {
connection->cbs->on_user_chunk_recv_cb(stream_id, data, len, flags);
}
nghttp2_session_consume_connection(session, len);
nghttp2_session_consume(session, stream_id, len);
nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, len);
nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, stream_id, len);
nghttp2_session_send(session);
return 0;
}
/**
* @brief Callback function invoked when a header name/value pair is received.
* The implementation of nghttp2_on_data_chunk_recv_callback type. We use this function to print the received response body.
* @param[in] session: nghttp2 session.
* @param[in] frame: nghttp2 frame.
* @param[in] name: header name.
* @param[in] namelen: length of header name.
* @param[in] value: header value.
* @param[in] valuelen: length of header value.
* @param[in] flags: no using.
* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
* and `nghttp2_session_mem_send()` functions immediately return :enum:
* `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_header_callback(nghttp2_session *session,
const nghttp2_frame *frame, const uint8_t *name,
size_t namelen, const uint8_t *value,
size_t valuelen, uint8_t flags,
void *user_data)
{
http2_connection_t *connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
http2_connection_t *connection = (http2_connection_t *)user_data;
/* Print response headers for the initiated request. */
NGHTTP2_DBG("< %s: %s\n", name, value);
if (connection->cbs && connection->cbs->on_user_header_cb) {
connection->cbs->on_user_header_cb(frame->hd.stream_id, (int)frame->headers.cat, name, namelen, value, valuelen, flags);
}
break;
}
}
return 0;
}
/**
* @brief Called when nghttp2 library gets started to receive header block.
* @param[in] session: nghttp2 session.
* @param[in] frame: nghttp2 frame.
* @param[in] user_data: The |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
* and `nghttp2_session_mem_send()` functions immediately return :enum:
* `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_begin_headers_callback(nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
switch (frame->hd.type) {
case NGHTTP2_HEADERS:
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
NGHTTP2_DBG("[INFO] C <--------- S (HEADERS) stream_id [%d]\n", (int)frame->hd.stream_id);
}
break;
}
return 0;
}
/**
* @brief Setup callback functions.
* nghttp2 API offers many callback functions, but most of them are optional. The send_callback is always required.
* Since we use nghttp2_session_recv(), the recv_callback is also required.
* @param[in|out] callbacks: nghttp2 callbacks.
* @return None.
*/
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
{
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
on_frame_send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
on_frame_recv_callback);
nghttp2_session_callbacks_set_on_stream_close_callback(
callbacks, on_h2_stream_close_callback);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
callbacks, on_data_chunk_recv_callback);
nghttp2_session_callbacks_set_on_header_callback(callbacks,
on_header_callback);
nghttp2_session_callbacks_set_on_begin_headers_callback(
callbacks, on_begin_headers_callback);
}
static ssize_t data_read_callback(nghttp2_session *session, int32_t stream_id,
uint8_t *buf, size_t length,
uint32_t *data_flags,
nghttp2_data_source *source,
void *user_data)
{
int len = 0;
http2_connection_t *connection = (http2_connection_t *)user_data;
if (connection == NULL) {
return 0;
}
if (source->ptr == NULL) {
return 0;
}
if (connection != NULL && connection->flag != NGHTTP2_FLAG_END_STREAM) {
*data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
connection->flag = NGHTTP2_FLAG_NONE;
}
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
/*len = strlen((char *)source->ptr);*/
len = source->len;
if (length < len) {
len = length;
}
memcpy(buf, source->ptr, len);
return len;
}
static int http2_nv_copy_nghttp2_nv(nghttp2_nv *nva, int start, http2_header *nva_copy, int end)
{
int i, j;
for (i = start, j = 0; j < end; i++, j++) {
nva[i].flags = NGHTTP2_NV_FLAG_NONE;
nva[i].name = (uint8_t *)nva_copy[j].name;
nva[i].value = (uint8_t *)nva_copy[j].value;
nva[i].namelen = nva_copy[j].namelen;
nva[i].valuelen = nva_copy[j].valuelen;
}
return i;
}
/**
* @brief Connect the SSL client.
* @param[in] pclient: http client.
* @param[in] url. destination url.
* @param[in] port. destination port.
* @param[in] ssl_config: custome config.
* @return The result. 0 is ok.
*/
static int http2_client_conn(httpclient_t *pclient, char *url, int port)
{
int ret = 0;
/*char host[MAX_HTTP2_HOST_LEN] = { 0 };*/
/*http2_parse_host(url, host, sizeof(host));*/
if (0 == pclient->net.handle) {
/* Establish connection if no. */
extern const char *iotx_ca_crt;
ret = iotx_net_init(&pclient->net, url, port, iotx_ca_crt);
if (0 != ret) {
return ret;
}
ret = httpclient_connect(pclient);
if (0 != ret) {
h2_err("http2client_connect is error, ret = %d", ret);
httpclient_close(pclient);
return ret;
}
}
return ret;
}
int iotx_http2_client_send(http2_connection_t *conn, http2_data *h2_data)
{
int send_flag = 0;
int rv = 0;
nghttp2_data_provider data_prd;
nghttp2_nv *nva = NULL;
int nva_size = 0;
http2_header *header = h2_data->header;
int header_count = h2_data->header_count;
char *data = h2_data->data;
int len = h2_data->len;
int stream_id = h2_data->stream_id;
int flags = h2_data->flag;
if (conn == NULL) {
return -1;
}
if (header != NULL && header_count != 0) {
nva = (nghttp2_nv *)HTTP2_STREAM_MALLOC(sizeof(nghttp2_nv) * header_count);
if (nva == NULL) {
return -1;
}
nva_size = http2_nv_copy_nghttp2_nv(nva, nva_size, header, header_count);
}
/*upload to server*/
if (data != NULL && len != 0) {
data_prd.source.ptr = data;
data_prd.source.len = len;
data_prd.read_callback = data_read_callback;
if (nva_size != 0) {
rv = nghttp2_submit_request(conn->session, NULL, nva, nva_size, &data_prd, NULL);
h2_data->stream_id = rv;
} else {
rv = nghttp2_submit_data(conn->session, flags, stream_id, &data_prd);
}
} else {
rv = nghttp2_submit_request(conn->session, NULL, nva, nva_size, NULL, NULL);
h2_data->stream_id = rv;
}
HTTP2_STREAM_FREE(nva);
if (rv < 0) {
return rv;
}
send_flag = nghttp2_session_want_write(conn->session);
if (send_flag) {
rv = nghttp2_session_send(conn->session);
NGHTTP2_DBG("nghttp2_session_send %d\r\n", rv);
}
return rv;
}
int iotx_http2_client_recv(http2_connection_t *conn, char *data, int data_len, int *len, int timeout)
{
int rv = 0;
int read_flag = 0;
if (conn == NULL) {
return -1;
}
set_http2_recv_timeout(timeout);
read_flag = nghttp2_session_want_read(conn->session);
if (read_flag) {
rv = nghttp2_session_recv(conn->session);
NGHTTP2_DBG("nghttp2_client_recv %d\r\n", rv);
if (rv < 0) {
read_flag = 0;
}
}
return rv;
}
/**
* @brief the http2 client connect.
* @param[in] pclient: http client.
* @return http2 client connection handler.
*/
http2_connection_t *iotx_http2_client_connect(void *pclient, char *url, int port)
{
http2_connection_t *connection;
nghttp2_session_callbacks *callbacks;
int rv;
int ret = 0;
connection = HTTP2_STREAM_MALLOC(sizeof(http2_connection_t));
if (connection == NULL) {
return NULL;
}
memset(connection, 0, sizeof(http2_connection_t));
if (0 != (ret = http2_client_conn((httpclient_t *)pclient, url, port))) {
NGHTTP2_DBG("https_client_conn failed %d\r\n", ret);
HTTP2_STREAM_FREE(connection);
return NULL;
}
connection->network = pclient;
rv = nghttp2_session_callbacks_new(&callbacks);
if (rv != 0) {
NGHTTP2_DBG("nghttp2_session_callbacks_new1 %d", rv);
HTTP2_STREAM_FREE(connection);
return NULL;
}
setup_nghttp2_callbacks(callbacks);
rv = nghttp2_session_client_new((nghttp2_session **)&connection->session, callbacks, connection);
if (rv != 0) {
NGHTTP2_DBG("nghttp2_session_client_new3 %d", rv);
HTTP2_STREAM_FREE(connection);
return NULL;
}
nghttp2_session_callbacks_del(callbacks);
nghttp2_submit_settings(connection->session, NGHTTP2_FLAG_NONE, NULL, 0);
#if 0
parse_uri(&uri, url);
request_init(&req, &uri);
/* Submit the HTTP request to the outbound queue. */
submit_request(connection, &req);
#endif
rv = nghttp2_session_send(connection->session);
/*request_free(&req);*/
if (rv < 0) {
NGHTTP2_DBG("nghttp2_session_send fail %d", rv);
HTTP2_STREAM_FREE(connection);
return NULL;
}
connection->status = 1;
return connection;
}
/**
* @brief the http2 client connect.
* @param[in] pclient: http client.
* @return http2 client connection handler.
*/
http2_connection_t *iotx_http2_client_connect_with_cb(void *pclient, char *url, int port, http2_user_cb_t *cb)
{
http2_connection_t *connection;
nghttp2_session_callbacks *callbacks;
int rv;
int ret = 0;
connection = HTTP2_STREAM_MALLOC(sizeof(http2_connection_t));
if (connection == NULL) {
return NULL;
}
memset(connection, 0, sizeof(http2_connection_t));
if (0 != (ret = http2_client_conn((httpclient_t *)pclient, url, port))) {
NGHTTP2_DBG("https_client_conn failed %d\r\n", ret);
HTTP2_STREAM_FREE(connection);
return NULL;
}
connection->network = pclient;
rv = nghttp2_session_callbacks_new(&callbacks);
if (rv != 0) {
NGHTTP2_DBG("nghttp2_session_callbacks_new1 %d", rv);
HTTP2_STREAM_FREE(connection);
return NULL;
}
connection->cbs = cb;
setup_nghttp2_callbacks(callbacks);
rv = nghttp2_session_client_new((nghttp2_session **)&connection->session, callbacks, connection);
if (rv != 0) {
NGHTTP2_DBG("nghttp2_session_client_new3 %d", rv);
nghttp2_session_callbacks_del(callbacks);
HTTP2_STREAM_FREE(connection);
return NULL;
}
nghttp2_session_callbacks_del(callbacks);
nghttp2_submit_settings(connection->session, NGHTTP2_FLAG_NONE, NULL, 0);
#if 0
parse_uri(&uri, url);
request_init(&req, &uri);
/* Submit the HTTP request to the outbound queue. */
submit_request(connection, &req);
#endif
rv = nghttp2_session_send(connection->session);
/*request_free(&req);*/
if (rv < 0) {
nghttp2_session_del(connection->session);
NGHTTP2_DBG("nghttp2_session_send fail %d", rv);
HTTP2_STREAM_FREE(connection);
return NULL;
}
connection->status = 1;
return connection;
}
int iotx_http2_client_disconnect(http2_connection_t *conn)
{
/* Resource cleanup */
if (conn == NULL) {
return -1;
}
httpclient_close((httpclient_t *)conn->network);
nghttp2_session_del(conn->session);
HTTP2_STREAM_FREE(conn);
return 0;
}
int iotx_http2_client_send_ping(http2_connection_t *conn)
{
int rv = 0;
int send_flag;
ping_state = PING_IDLE;
if (conn == NULL) {
return -1;
}
rv = nghttp2_submit_ping(conn->session, NGHTTP2_FLAG_NONE, NULL);
if (rv < 0) {
return rv;
}
send_flag = nghttp2_session_want_write(conn->session);
if (send_flag) {
rv = nghttp2_session_send(conn->session);
NGHTTP2_DBG("nghttp2_session_send %d\r\n", rv);
if (rv < 0) {
return rv;
}
}
ping_state = PING_SENDING;
return 0;
}
int iotx_http2_client_recv_ping(void)
{
if (ping_state == PING_RECVED || ping_state == PING_IDLE) {
NGHTTP2_DBG("ping recv secceed\r\n");
return 0;
}
else {
NGHTTP2_DBG("ping recv timeout");
return -1;
}
}
int iotx_http2_get_available_window_size(http2_connection_t *conn)
{
int windows_size = 0;
if (conn == NULL) {
return -1;
}
windows_size = nghttp2_session_get_remote_window_size(conn->session);
return windows_size;
}
int iotx_http2_update_window_size(http2_connection_t *conn)
{
int rv;
if (conn == NULL) {
return -1;
}
rv = nghttp2_session_recv(conn->session);
if (rv < 0) {
return -1;
}
return 0;
}
/*
* Performs the network I/O.
*/
int iotx_http2_exec_io(http2_connection_t *connection)
{
if (connection == NULL) {
return -1;
}
if (nghttp2_session_want_read(connection->session) /*||
nghttp2_session_want_write(connection->session)*/) {
int rv;
rv = nghttp2_session_recv(connection->session);
if (rv < 0) {
NGHTTP2_DBG("nghttp2_session_recv error");
return -1;
}
/* rv = nghttp2_session_send(connection->session); */
/* if (rv < 0) { */
/* NGHTTP2_DBG("nghttp2_session_send error"); */
/* return -1; */
/* } */
}
return 0;
}
int iotx_http2_reset_stream(http2_connection_t *connection, int32_t stream_id)
{
int rv = 0;
if(connection == NULL){
return -1;
}
if(!nghttp2_session_get_stream_local_close(connection->session,stream_id)) {
rv = nghttp2_submit_rst_stream(connection->session,0, stream_id, NGHTTP2_NO_ERROR);
}
if (rv < 0) {
return rv;
}
rv = nghttp2_session_want_write(connection->session);
if (rv) {
rv = nghttp2_session_send(connection->session);
NGHTTP2_DBG("nghttp2_session_send %d\r\n", rv);
}
return rv;
}