#include #include #include #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); }