441 lines
13 KiB
C
441 lines
13 KiB
C
|
#include <stdio.h>
|
|||
|
#include <string.h>
|
|||
|
#include <stdlib.h>
|
|||
|
|
|||
|
#include "sockets.h"
|
|||
|
#include "ql_fs.h"
|
|||
|
#include "ql_api_datacall.h"
|
|||
|
#include "ql_api_osi.h"
|
|||
|
#include "ql_http_client.h"
|
|||
|
#include "ql_log.h"
|
|||
|
|
|||
|
#define LOGI(msg, ...) QL_LOG(QL_LOG_LEVEL_INFO, "download", msg, ##__VA_ARGS__)
|
|||
|
#define SIM_ID (0)
|
|||
|
#define NETWORK_REGISTER_RETRY (10)
|
|||
|
#define NETWORK_REGISTER_TIMEOUT (120)
|
|||
|
#define NETWORK_PROFILE_IDX (1)
|
|||
|
#define NETWORK_APN_NAME "uninet"
|
|||
|
#define NETWORK_AUTH_TYPE (0) // 表示不进行身份验证
|
|||
|
#define HTTP_DLOAD_HIGH_LINE (40960)
|
|||
|
#define HTTP_MAX_MSG_CNT (8)
|
|||
|
#define DOWNLOAD_FILENAME "SD:test.txt"
|
|||
|
#define USE_HTTP_URL (1)
|
|||
|
#define HTTP_URL "http://220.180.239.212:8300/10K.txt"
|
|||
|
#define USE_HTTPS_URL (0)
|
|||
|
#define HTTPS_URL "https://220.180.239.212:8301/10K.txt"
|
|||
|
|
|||
|
typedef enum
|
|||
|
{
|
|||
|
QHTTPC_EVENT_RESPONSE = 1001,
|
|||
|
QHTTPC_EVENT_END,
|
|||
|
} qhttpc_event_code_e;
|
|||
|
|
|||
|
typedef struct _qhttpc_ctx_t
|
|||
|
{
|
|||
|
http_client_t http_client;
|
|||
|
ql_queue_t queue;
|
|||
|
|
|||
|
ql_mutex_t simple_lock;
|
|||
|
bool dl_block;
|
|||
|
int dl_high_line;
|
|||
|
int dl_total_len;
|
|||
|
|
|||
|
QFILE dload_fd;
|
|||
|
} qhttpc_ctx_t;
|
|||
|
|
|||
|
static ql_datacall_errcode_e network_err = QL_DATACALL_SUCCESS;
|
|||
|
static QlOSStatus status = 0;
|
|||
|
|
|||
|
void print_info(ql_data_call_info_s info);
|
|||
|
|
|||
|
/*http状态事件回调*/
|
|||
|
static void http_event_cb(http_client_t *client, int evt, int evt_code, void *arg)
|
|||
|
{
|
|||
|
qhttpc_ctx_t *client_ptr = (qhttpc_ctx_t *)arg;
|
|||
|
ql_event_t qhttpc_event_send = {0};
|
|||
|
|
|||
|
LOGI("enter");
|
|||
|
|
|||
|
if (client_ptr == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
LOGI("*client:%d, http_cli:%d", *client, client_ptr->http_client);
|
|||
|
|
|||
|
if (*client != client_ptr->http_client)
|
|||
|
return;
|
|||
|
LOGI("evt:%d, evt_code:%d", evt, evt_code);
|
|||
|
|
|||
|
switch (evt)
|
|||
|
{
|
|||
|
case HTTP_EVENT_SESSION_ESTABLISH:
|
|||
|
{
|
|||
|
if (evt_code != HTTP_SUCCESS)
|
|||
|
{
|
|||
|
LOGI("HTTP session create failed!!!!!");
|
|||
|
qhttpc_event_send.id = QHTTPC_EVENT_END;
|
|||
|
qhttpc_event_send.param1 = (uint32)client_ptr;
|
|||
|
ql_rtos_queue_release(client_ptr->queue, sizeof(ql_event_t), (uint8 *)&qhttpc_event_send, QL_WAIT_FOREVER);
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case HTTP_EVENT_RESPONE_STATE_LINE:
|
|||
|
{
|
|||
|
if (evt_code == HTTP_SUCCESS)
|
|||
|
{
|
|||
|
int resp_code = 0;
|
|||
|
int content_length = 0;
|
|||
|
int chunk_encode = 0;
|
|||
|
char *location = NULL;
|
|||
|
ql_httpc_getinfo(client, HTTP_INFO_RESPONSE_CODE, &resp_code);
|
|||
|
LOGI("response code:%d", resp_code);
|
|||
|
ql_httpc_getinfo(client, HTTP_INFO_CHUNK_ENCODE, &chunk_encode);
|
|||
|
if (chunk_encode == 0)
|
|||
|
{
|
|||
|
ql_httpc_getinfo(client, HTTP_INFO_CONTENT_LEN, &content_length);
|
|||
|
LOGI("content_length:%d", content_length);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGI("http chunk encode!!!");
|
|||
|
}
|
|||
|
|
|||
|
if (resp_code >= 300 && resp_code < 400)
|
|||
|
{
|
|||
|
ql_httpc_getinfo(client, HTTP_INFO_LOCATION, &location);
|
|||
|
LOGI("redirect location:%s", location);
|
|||
|
free(location);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case HTTP_EVENT_SESSION_DISCONNECT:
|
|||
|
{
|
|||
|
if (evt_code == HTTP_SUCCESS)
|
|||
|
{
|
|||
|
LOGI("===http transfer end!!!!");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGI("===http transfer occur exception!!!!!");
|
|||
|
}
|
|||
|
qhttpc_event_send.id = QHTTPC_EVENT_END;
|
|||
|
qhttpc_event_send.param1 = (uint32)client_ptr;
|
|||
|
ql_rtos_queue_release(client_ptr->queue, sizeof(ql_event_t), (uint8 *)&qhttpc_event_send, QL_WAIT_FOREVER);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*http写入响应数据的回调*/
|
|||
|
static int http_write_response_data(http_client_t *client, void *arg, char *data, int size, unsigned char end)
|
|||
|
{
|
|||
|
int ret = size;
|
|||
|
uint32 msg_cnt = 0;
|
|||
|
char *read_buff = NULL;
|
|||
|
qhttpc_ctx_t *client_ptr = (qhttpc_ctx_t *)arg;
|
|||
|
ql_event_t qhttpc_event_send = {0};
|
|||
|
|
|||
|
LOGI("enter");
|
|||
|
|
|||
|
if (client_ptr == NULL)
|
|||
|
return 0;
|
|||
|
|
|||
|
LOGI("*client:%d, http_cli:%d", *client, client_ptr->http_client);
|
|||
|
|
|||
|
if (*client != client_ptr->http_client)
|
|||
|
return 0;
|
|||
|
|
|||
|
read_buff = (char *)malloc(size + 1);
|
|||
|
if (read_buff == NULL)
|
|||
|
{
|
|||
|
LOGI("mem faild");
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
memcpy(read_buff, data, size);
|
|||
|
|
|||
|
if (QL_OSI_SUCCESS != ql_rtos_queue_get_cnt(client_ptr->queue, &msg_cnt))
|
|||
|
{
|
|||
|
free(read_buff);
|
|||
|
LOGI("ql_rtos_queue_get_cnt faild");
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
ql_rtos_mutex_lock(client_ptr->simple_lock, 100);
|
|||
|
if (msg_cnt >= (HTTP_MAX_MSG_CNT - 1) || (client_ptr->dl_total_len + size) >= client_ptr->dl_high_line)
|
|||
|
{
|
|||
|
client_ptr->dl_block = true;
|
|||
|
ret = HTTP_ERR_WOUNDBLOCK;
|
|||
|
}
|
|||
|
ql_rtos_mutex_unlock(client_ptr->simple_lock);
|
|||
|
|
|||
|
LOGI("msg_cnt %d, total_len+size %d", msg_cnt, (client_ptr->dl_total_len + size));
|
|||
|
|
|||
|
qhttpc_event_send.id = QHTTPC_EVENT_RESPONSE;
|
|||
|
qhttpc_event_send.param1 = (uint32)client_ptr;
|
|||
|
qhttpc_event_send.param2 = (uint32)read_buff;
|
|||
|
qhttpc_event_send.param3 = (uint32)size;
|
|||
|
if (QL_OSI_SUCCESS != ql_rtos_queue_release(client_ptr->queue, sizeof(ql_event_t), (uint8 *)&qhttpc_event_send, 0))
|
|||
|
{
|
|||
|
free(read_buff);
|
|||
|
LOGI("ql_rtos_queue_release faild");
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
ql_rtos_mutex_lock(client_ptr->simple_lock, 100);
|
|||
|
client_ptr->dl_total_len += size;
|
|||
|
ql_rtos_mutex_unlock(client_ptr->simple_lock);
|
|||
|
|
|||
|
LOGI("http response :%d bytes data", size);
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
static void http_write_response_data_func(void *param)
|
|||
|
{
|
|||
|
int ret = 0;
|
|||
|
int size = 0;
|
|||
|
QFILE fd = 0;
|
|||
|
bool dload_block = false;
|
|||
|
char *read_buff = NULL;
|
|||
|
qhttpc_ctx_t *client_ptr = NULL;
|
|||
|
ql_event_t *qhttpc_event_recv = (ql_event_t *)param;
|
|||
|
|
|||
|
if(qhttpc_event_recv == NULL || qhttpc_event_recv->param1 == 0 || qhttpc_event_recv->param2 == 0 || qhttpc_event_recv->param3 == 0)
|
|||
|
return;
|
|||
|
|
|||
|
client_ptr = (qhttpc_ctx_t *)qhttpc_event_recv->param1;
|
|||
|
read_buff = (char *)qhttpc_event_recv->param2;
|
|||
|
size = (int)qhttpc_event_recv->param3;
|
|||
|
fd = (QFILE)client_ptr->dload_fd;
|
|||
|
|
|||
|
ret = ql_fwrite(read_buff, size, 1, fd);
|
|||
|
|
|||
|
free(read_buff);
|
|||
|
|
|||
|
ql_rtos_mutex_lock(client_ptr->simple_lock, 100);
|
|||
|
client_ptr->dl_total_len -= size;
|
|||
|
if(client_ptr->dl_total_len < 0)
|
|||
|
client_ptr->dl_total_len = 0;
|
|||
|
if(client_ptr->dl_block == true && client_ptr->dl_total_len < client_ptr->dl_high_line)
|
|||
|
{
|
|||
|
dload_block = client_ptr->dl_block;
|
|||
|
client_ptr->dl_block = false;
|
|||
|
}
|
|||
|
ql_rtos_mutex_unlock(client_ptr->simple_lock);
|
|||
|
|
|||
|
if(dload_block == true)
|
|||
|
ql_httpc_continue_dload(&client_ptr->http_client);
|
|||
|
|
|||
|
LOGI("http write :%d bytes data", ret);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* func:从http下载文件到本地SD卡中
|
|||
|
*/
|
|||
|
uint8_t download_file_to_SD(void)
|
|||
|
{
|
|||
|
LOGI("download_file_to_SD start");
|
|||
|
|
|||
|
uint8_t nSim = 0;
|
|||
|
int profile_idx = NETWORK_PROFILE_IDX;
|
|||
|
|
|||
|
/*等待网络注册*/
|
|||
|
for (uint8_t i = 0; i < 10; i++)
|
|||
|
{
|
|||
|
LOGI("ql_network_register_wait err = %d", ql_network_register_wait(nSim, 120));
|
|||
|
ql_rtos_task_sleep_s(1);
|
|||
|
}
|
|||
|
LOGI("ql_network_register_wait end");
|
|||
|
|
|||
|
/*设置ql_start_data_call和ql_stop_data_call接口的执行模式,并设置异步模式的回调函数*/
|
|||
|
network_err = ql_set_data_call_asyn_mode(nSim, profile_idx, 0);
|
|||
|
if (network_err != 0)
|
|||
|
{
|
|||
|
LOGI("ql_set_data_call_asyn_mode fail,err = %d", network_err);
|
|||
|
return 2;
|
|||
|
}
|
|||
|
LOGI("ql_set_data_call_asyn_mode ok");
|
|||
|
|
|||
|
/*启动拨号*/
|
|||
|
network_err = ql_start_data_call(nSim, profile_idx, QL_PDP_TYPE_IP, NETWORK_APN_NAME, NULL, NULL, NETWORK_AUTH_TYPE);
|
|||
|
if (network_err != 0)
|
|||
|
{
|
|||
|
LOGI("ql_start_data_call fail,err = %d", network_err);
|
|||
|
return 3;
|
|||
|
}
|
|||
|
LOGI("ql_start_data_call ok");
|
|||
|
|
|||
|
/*获取拨号信息*/
|
|||
|
ql_data_call_info_s info = {0};
|
|||
|
network_err = ql_get_data_call_info(nSim, profile_idx, &info);
|
|||
|
if (network_err != 0)
|
|||
|
{
|
|||
|
LOGI("ql_get_data_call_info fail,err = %d", network_err);
|
|||
|
return 4;
|
|||
|
}
|
|||
|
LOGI("ql_get_data_call_info ok");
|
|||
|
|
|||
|
/*打印拨号信息*/
|
|||
|
print_info(info);
|
|||
|
|
|||
|
/*初始化http客户端结构体*/
|
|||
|
qhttpc_ctx_t http_demo_client = {0};
|
|||
|
http_demo_client.dl_block = false;
|
|||
|
http_demo_client.dl_high_line = HTTP_DLOAD_HIGH_LINE;
|
|||
|
|
|||
|
/*创建互斥锁*/
|
|||
|
status = ql_rtos_mutex_create(&http_demo_client.simple_lock);
|
|||
|
if (status != 0)
|
|||
|
{
|
|||
|
LOGI("ql_rtos_mutex_create fail,err = %d", network_err);
|
|||
|
return 5;
|
|||
|
}
|
|||
|
LOGI("ql_rtos_mutex_create ok");
|
|||
|
|
|||
|
/*创建消息队列*/
|
|||
|
status = ql_rtos_queue_create(&http_demo_client.queue, sizeof(ql_event_t), HTTP_MAX_MSG_CNT);
|
|||
|
if (status != 0)
|
|||
|
{
|
|||
|
LOGI("ql_rtos_queue_create fail,err = %d", network_err);
|
|||
|
return 6;
|
|||
|
}
|
|||
|
LOGI("ql_rtos_queue_create ok");
|
|||
|
|
|||
|
/*创建并初始化http_client上下文结构*/
|
|||
|
if (ql_httpc_new(&http_demo_client.http_client, http_event_cb, (void *)&http_demo_client) != HTTP_SUCCESS)
|
|||
|
{
|
|||
|
LOGI("http client create failed");
|
|||
|
return 7;
|
|||
|
}
|
|||
|
LOGI("http client create ok");
|
|||
|
|
|||
|
/*写模式打开文件*/
|
|||
|
http_demo_client.dload_fd = ql_fopen(DOWNLOAD_FILENAME, "w+");
|
|||
|
if (http_demo_client.dload_fd < 0)
|
|||
|
{
|
|||
|
LOGI("open file failed");
|
|||
|
ql_httpc_release(&http_demo_client.http_client);
|
|||
|
return 8;
|
|||
|
}
|
|||
|
|
|||
|
/*配置http上下文*/
|
|||
|
int http_method = HTTP_METHOD_NONE;
|
|||
|
int a = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_SIM_ID, nSim);
|
|||
|
int b = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_PDPCID, profile_idx);
|
|||
|
int c = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_WRITE_FUNC, http_write_response_data);
|
|||
|
int d = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_WRITE_DATA, (void *)&http_demo_client);
|
|||
|
if ((a != 0) || (b != 0) || (c != 0) || (d != 0))
|
|||
|
{
|
|||
|
LOGI("ql_httpc_setopt fail, a = %d, b = %d, c = %d, d = %d", a, b, c, d);
|
|||
|
return 9;
|
|||
|
}
|
|||
|
LOGI("ql_httpc_setopt 1 ok");
|
|||
|
#if USE_HTTP_URL
|
|||
|
http_method = HTTP_METHOD_GET;
|
|||
|
char url[] = HTTP_URL;
|
|||
|
int e = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_METHOD, http_method);
|
|||
|
int f = ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_URL, (char *)url);
|
|||
|
if ((e != 0) || (f != 0))
|
|||
|
{
|
|||
|
LOGI("ql_httpc_setopt fail, e = %d, f = %d", e, f);
|
|||
|
return 10;
|
|||
|
}
|
|||
|
LOGI("ql_httpc_setopt 2 ok");
|
|||
|
#endif
|
|||
|
#if USE_HTTPS_URL
|
|||
|
char url[] = HTTPS_URL;
|
|||
|
http_method = HTTP_METHOD_GET;
|
|||
|
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_METHOD, http_method);
|
|||
|
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_SSLCTXID, 1);
|
|||
|
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_SSL_VERIFY_LEVEL, HTTPS_VERIFY_NONE);
|
|||
|
ql_httpc_setopt(&http_demo_client.http_client, HTTP_CLIENT_OPT_URL, (char *)url);
|
|||
|
#endif
|
|||
|
|
|||
|
/*关联http client此上下文和http的读写回调函数*/
|
|||
|
if (ql_httpc_perform(&http_demo_client.http_client) != HTTP_SUCCESS)
|
|||
|
{
|
|||
|
LOGI("ql_httpc_perform fail");
|
|||
|
return 11;
|
|||
|
}
|
|||
|
LOGI("ql_httpc_perform ok");
|
|||
|
|
|||
|
/*等待事件完成*/
|
|||
|
int flags_break = 0;
|
|||
|
ql_event_t qhttpc_event_msg = {0};
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
memset(&qhttpc_event_msg, 0x00, sizeof(ql_event_t));
|
|||
|
|
|||
|
ql_rtos_queue_wait(http_demo_client.queue, (uint8 *)&qhttpc_event_msg, sizeof(ql_event_t), QL_WAIT_FOREVER);
|
|||
|
|
|||
|
switch (qhttpc_event_msg.id)
|
|||
|
{
|
|||
|
case QHTTPC_EVENT_RESPONSE:
|
|||
|
{
|
|||
|
http_write_response_data_func((void *)&qhttpc_event_msg);
|
|||
|
}
|
|||
|
break;
|
|||
|
case QHTTPC_EVENT_END:
|
|||
|
{
|
|||
|
flags_break = 1;
|
|||
|
}
|
|||
|
break;
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (flags_break)
|
|||
|
break;
|
|||
|
}
|
|||
|
LOGI("event end");
|
|||
|
|
|||
|
/*检测文件状态*/
|
|||
|
struct stat dload_stat = {0};
|
|||
|
memset(&dload_stat, 0x00, sizeof(struct stat));
|
|||
|
ql_fstat(http_demo_client.dload_fd, &dload_stat);
|
|||
|
LOGI("dload_file_size:%d", dload_stat.st_size);
|
|||
|
if (http_demo_client.dload_fd >= 0)
|
|||
|
{
|
|||
|
ql_fclose(http_demo_client.dload_fd);
|
|||
|
http_demo_client.dload_fd = -1;
|
|||
|
}
|
|||
|
|
|||
|
/*释放http client上下文,以及http client上下文所占用内存块*/
|
|||
|
if(ql_httpc_release(&http_demo_client.http_client) != 0){
|
|||
|
LOGI("ql_httpc_release fail");
|
|||
|
return 12;
|
|||
|
}
|
|||
|
http_demo_client.http_client = 0;
|
|||
|
LOGI("ql_httpc_release ok");
|
|||
|
|
|||
|
/*解锁互斥锁*/
|
|||
|
status = ql_rtos_mutex_delete(http_demo_client.simple_lock);
|
|||
|
if(status != 0){
|
|||
|
LOGI("ql_rtos_mutex_delete fail,err = %d",status);
|
|||
|
return 13;
|
|||
|
}
|
|||
|
http_demo_client.simple_lock = NULL;
|
|||
|
LOGI("ql_rtos_mutex_delete ok");
|
|||
|
|
|||
|
LOGI("download_file_to_SD end");
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
void print_info(ql_data_call_info_s info)
|
|||
|
{
|
|||
|
char ip4_addr_str[16] = {0};
|
|||
|
|
|||
|
LOGI("info->profile_idx: %d", info.profile_idx);
|
|||
|
LOGI("info->ip_version: %d", info.ip_version);
|
|||
|
LOGI("info->v4.state: %d", info.v4.state);
|
|||
|
|
|||
|
inet_ntop(AF_INET, &info.v4.addr.ip, ip4_addr_str, sizeof(ip4_addr_str));
|
|||
|
LOGI("info.v4.addr.ip: %s\r\n", ip4_addr_str);
|
|||
|
|
|||
|
inet_ntop(AF_INET, &info.v4.addr.pri_dns, ip4_addr_str, sizeof(ip4_addr_str));
|
|||
|
LOGI("info.v4.addr.pri_dns: %s\r\n", ip4_addr_str);
|
|||
|
|
|||
|
inet_ntop(AF_INET, &info.v4.addr.sec_dns, ip4_addr_str, sizeof(ip4_addr_str));
|
|||
|
LOGI("info.v4.addr.sec_dns: %s\r\n", ip4_addr_str);
|
|||
|
}
|