Files
banban/ql-application/threadx/interface/custom_app/http_aofei.c
T

1236 lines
37 KiB
C

#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
#include "ql_http_client.h"
#include "ql_http_client.h"
#include "ql_fota.h"
#include "ql_dev.h"
#include "ql_nw.h"
#include "ql_fs.h"
#include "app_inc.h"
#if 1
const static SSLCertPathPtr rootCA_path =
"\
-----BEGIN CERTIFICATE-----\n\
MIIE5zCCA0+gAwIBAgIJANUsoTOuGtIeMA0GCSqGSIb3DQEBCwUAMIGJMQswCQYD\n\
VQQGEwJDTjELMAkGA1UECAwCQUgxCzAJBgNVBAcMAkhGMRAwDgYDVQQKDAdRVUVD\n\
VEVMMQwwCgYDVQQLDANEVFcxGDAWBgNVBAMMDzIyMC4xODAuMjM5LjIxMjEmMCQG\n\
CSqGSIb3DQEJARYXZWRkaWUuemhhbmdAcXVlY3RlbC5jb20wHhcNMjAwMTAyMTEy\n\
NTQzWhcNMjMwMTAxMTEyNTQzWjCBiTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkFI\n\
MQswCQYDVQQHDAJIRjEQMA4GA1UECgwHUVVFQ1RFTDEMMAoGA1UECwwDRFRXMRgw\n\
FgYDVQQDDA8yMjAuMTgwLjIzOS4yMTIxJjAkBgkqhkiG9w0BCQEWF2VkZGllLnpo\n\
YW5nQHF1ZWN0ZWwuY29tMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA\n\
tDYkNFB5TYS7XZ2F+eW6zGWOmy2xV3OcTpnz10JHUwSdvUI5xWQ//ACCxG9QeN4f\n\
ALAzkj8tVzeKj5oP9Gz8LnVqhIxv13m8GJDO/dVZEXtpBNgjv7DvsXa1TMjy3QcV\n\
bXfqtWuTSzVCovMkvj+R16uWRWgqSMLCG73FLPE2E2vRGlBQVzAVi2fXYPq346QT\n\
ZLyELoFErGCFgVEaAF1Pnwu1R8Ly0CI45y/riC47Sb3bE/MaBUbR0R7+T5jhnK8G\n\
E0GTLorOZq6CBf8NliRjnEQVtjhUniQju1Dx/35Tifel460kK9ThkmxEddn1w+VH\n\
ZQYG9XWuqdPA6am5rBI+AKUCPeoMRVVlY3lK3J7L4OyRTovY0+IyVT4MKucrzK4z\n\
FfnACTgKr151yMxY3Ar4EPI1iQeuKu5Ha2bZuXLnVZau8NohbdUXBSN+ifPH2uu7\n\
BT91jG6zfS9k6AKhBkGncf0dpuT9c6w06UAplxeakSpnSz5p7O9XGeAZeemahq43\n\
AgMBAAGjUDBOMB0GA1UdDgQWBBSHgJS+a77WT6PHLTVoW+qqVK80uTAfBgNVHSME\n\
GDAWgBSHgJS+a77WT6PHLTVoW+qqVK80uTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3\n\
DQEBCwUAA4IBgQA6WSdvLq+MMmNJAAI8XCANzWq69fxcrvRhLl69hipueomivrFx\n\
cqiG6oI38CBxqiPC9y69fXBY9B7f29emMHnjpC5xoOqfBSVKqR+EbhYUx/n0/Ykx\n\
Pcz6Lad0/8JRLa0QthhnLzMPpeAY7Z3HmcHR0mZFu+vu0irw/3E1GkDm2MQ2958Y\n\
5geLGbktFKF2yGueajcoR8qSmeD+tspBqTWqmdPaDEipPNBvLduOzcGqOnQMKy4/\n\
LLQMZ/OuXTjuJjYE4YtN2wV3/ks02Ae94FE8ZaaMYThMHBz4NITKbLhbMn9cP66w\n\
27B+nt5+DG4zc9AYZRuKhaW6AiMfAewAvFxIyofmPxAKMpC+JBwzDxdbo0ez/Dqr\n\
CFbKuQeWAY3YwgG33pdzOuREMphdGZnJgkd1MqUCNFxMGnZF6WhV31I/e1+uCMYr\n\
4Rw86GtDfs697qxBOXHmNBVqLLekayQxGh7d2UxIVghdCuO6rHjTfmkfvzNH/Vxf\n\
t/YY6UlQvij187Q=\n\
-----END CERTIFICATE-----\n\
";
#define QL_DL_HTTP_LOG ql_trace
#define QL_DL_PACK_NAME_MAX_LEN (64)
#define QL_DL_PACK_URL_MAX_LEN (128)
#define TRY_DOWN_TIMES 1
#define WRITE_TO_FILESIZE (1024*4)
typedef enum
{
DL_HTTP_DOWN_INIT, //初始阶段
DL_HTTP_DOWN_DOWNING, //下载中
DL_HTTP_DOWN_INTR, //下载被中断
DL_HTTP_DOWN_DOWNED, //下载完成
DL_HTTP_DOWN_NOSPACE, //没有空间
}e_dl_down_stage;
typedef struct
{
bool is_show; //是否显示进度
uint total_size; //文件总共大小
uint dload_size; //已经下载大小
uint file_size; //上次升级中断保存的文件大小
}dl_http_progress_t;
typedef struct
{
QL_HTTP_CLIENT_T *http_cli; //和http交互创建的struct http_client_s类型的指针
int profile_idx; //cid
uint8_t sim_id; //simid
char dl_path[QL_DL_PACK_NAME_MAX_LEN]; //下载到本地的升级文件的位置
char dl_url[QL_DL_PACK_URL_MAX_LEN];
dl_http_progress_t http_progress; //http进度
e_dl_down_stage e_stage; //http下载固件包的阶段
QFILE *fd; //写文件的文件描述符
int i_save_size; //在一次下载的过程中,分为多次写入,保存的是上次的写入大小,用于控制满多少字节写一次
uint last_precent; //下载最后一次百分比
bool b_is_have_space; //存储空间是否可用
ql_sem_t dl_http_semp;
}dl_http_client_t;
static int dl_http_get_fileszie(char *filename);
static void dl_http_close_fd(dl_http_client_t* dl_http_cli_p);
int dl_dload_file_clran(dl_http_client_t* dl_http_cli_p)
{
if ( dl_http_cli_p->fd == NULL )
{
QL_DL_HTTP_LOG("clran write file [%s] err",dl_http_cli_p->dl_path);
dl_http_cli_p->fd = NULL;
}
else
{
ql_fclose(dl_http_cli_p->fd);
ql_rtos_task_sleep_ms(10);
}
dl_http_cli_p->fd = ql_fopen(dl_http_cli_p->dl_path, "wb+");
if(dl_http_cli_p->fd == NULL)
{
QL_DL_HTTP_LOG("clran open write file [%s] failed",dl_http_cli_p->dl_path);
return -1;
}
dl_http_cli_p->http_progress.file_size = 0;
dl_http_cli_p->http_progress.dload_size = 0;
dl_http_cli_p->http_progress.total_size = 0;
dl_http_cli_p->e_stage = DL_HTTP_DOWN_DOWNING;
dl_http_cli_p->i_save_size = 0;
QL_DL_HTTP_LOG("clran write file [%s] open ",dl_http_cli_p->dl_path);
return 0;
}
static void dl_http_info_cfg(dl_http_client_t* dl_http_cli_p)
{
if ( dl_http_cli_p == NULL )
{
QL_DL_HTTP_LOG("dl_http_cli_p is null");
return;
}
QL_DL_HTTP_LOG("init file name:[%s]",dl_http_cli_p->dl_path);
QL_DL_HTTP_LOG("init file stage:[%d]",dl_http_cli_p->e_stage);
QL_DL_HTTP_LOG("init file download:[%d]",dl_http_cli_p->http_progress.dload_size);
QL_DL_HTTP_LOG("init file file_size:[%d]",dl_http_cli_p->http_progress.file_size);
QL_DL_HTTP_LOG("init file real file_size:[%d]",dl_http_get_fileszie(dl_http_cli_p->dl_path));
QL_DL_HTTP_LOG("init file is_show:[%d]",dl_http_cli_p->http_progress.is_show);
QL_DL_HTTP_LOG("init file last_percent:[%d]",dl_http_cli_p->last_precent);
QL_DL_HTTP_LOG("init file space:[%d]",dl_http_cli_p->b_is_have_space);
}
int dl_http_init(dl_http_client_t* dl_http_cli_p, char *filepath, char *uri)
{
QFILE *fd = NULL;
// 安全修复:检查参数有效性
if(dl_http_cli_p == NULL || filepath == NULL || uri == NULL){
QL_DL_HTTP_LOG("dl_http_init: invalid parameters");
return -1;
}
memset(dl_http_cli_p,0x00,sizeof(dl_http_client_t));
dl_http_cli_p->http_cli = 0; //http连接句柄
dl_http_cli_p->profile_idx = 1; //cid
dl_http_cli_p->sim_id = 0; //simid
dl_http_cli_p->e_stage =DL_HTTP_DOWN_INIT;
dl_http_cli_p->i_save_size = 0;
// 安全修复:使用strncpy并确保字符串结束
size_t path_len = strlen(filepath);
if(path_len >= sizeof(dl_http_cli_p->dl_path)){
QL_DL_HTTP_LOG("dl_http_init: filepath too long");
return -1;
}
strncpy(dl_http_cli_p->dl_path, filepath, sizeof(dl_http_cli_p->dl_path)-1);
dl_http_cli_p->dl_path[sizeof(dl_http_cli_p->dl_path)-1] = '\0';
size_t uri_len = strlen(uri);
if(uri_len >= sizeof(dl_http_cli_p->dl_url)){
QL_DL_HTTP_LOG("dl_http_init: uri too long");
return -1;
}
strncpy(dl_http_cli_p->dl_url, uri, sizeof(dl_http_cli_p->dl_url)-1);
dl_http_cli_p->dl_url[sizeof(dl_http_cli_p->dl_url)-1] = '\0';
ql_rtos_semaphore_create(&dl_http_cli_p->dl_http_semp, 0);
//存储空间开始默认为足够
dl_http_cli_p->b_is_have_space = TRUE;
dl_http_cli_p->http_progress.is_show = FALSE; //设置展示进度
dl_http_cli_p->last_precent = 0;
fd = ql_fopen(dl_http_cli_p->dl_path, "w+");
if(fd == NULL)
{
QL_DL_HTTP_LOG("init file name:[%s] err",dl_http_cli_p->dl_path);
return -1;
}
ql_fclose(fd);
QL_DL_HTTP_LOG("init file name:[%s]",dl_http_cli_p->dl_path);
QL_DL_HTTP_LOG("init file size:[%d]",dl_http_get_fileszie(dl_http_cli_p->dl_path));
QL_DL_HTTP_LOG("init file stage:[%d]",dl_http_cli_p->e_stage);
return 0;
}
static void dl_http_release(dl_http_client_t* dl_http_cli_p)
{
if(dl_http_cli_p->dl_http_semp==NULL)return;
ql_rtos_semaphore_delete(dl_http_cli_p->dl_http_semp);
//不设置成NULL 会导致restart
dl_http_cli_p->dl_http_semp = NULL;
}
static int dl_http_get_fileszie(char *filename)
{
int file_size= 0;
QFILE *fd = ql_fopen(filename,"r");
if ( fd == NULL )
{
QL_DL_HTTP_LOG("open file name:[%s] err",filename);
return -1;
}
file_size = ql_fsize(fd);
ql_fclose(fd);
return file_size;
}
static QFILE *dl_http_get_fd(dl_http_client_t* dl_http_cli_p)
{
if ( dl_http_cli_p->e_stage == DL_HTTP_DOWN_INIT || dl_http_cli_p->e_stage ==DL_HTTP_DOWN_DOWNED \
||dl_http_cli_p->e_stage == DL_HTTP_DOWN_NOSPACE )
{
//已经完成、初始化、或者是没有空间导致的下载中断以覆盖写来打开文件
dl_http_cli_p->fd = ql_fopen(dl_http_cli_p->dl_path, "wb+");
dl_http_cli_p->http_progress.file_size = 0;
dl_http_cli_p->http_progress.dload_size = 0;
dl_http_cli_p->http_progress.total_size = 0;
dl_http_cli_p->e_stage = DL_HTTP_DOWN_INIT;
dl_http_cli_p->i_save_size = 0;
QL_DL_HTTP_LOG("over write file [%s]",dl_http_cli_p->dl_path);
}
else
{
//其他的情况是追加方式打开文件
dl_http_cli_p->fd = ql_fopen(dl_http_cli_p->dl_path, "ab+");
QL_DL_HTTP_LOG("add write file [%s]",dl_http_cli_p->dl_path);
}
if ( dl_http_cli_p->fd == NULL )
{
QL_DL_HTTP_LOG("ql_fopen failed");
}
return dl_http_cli_p->fd;
}
/********************************************************************
* funcname :dl_http_close_fd
* description :
* 关闭下载升级包的文件描述符
* dl_http_cli_p [in] [dl_http_client_t *] fota http客户端结构体
* return:
* 0 -- sucess
* other -- failed
**********************************************************************/
static void dl_http_close_fd(dl_http_client_t* dl_http_cli_p)
{
if ( dl_http_cli_p->fd > 0 )
{
ql_fclose(dl_http_cli_p->fd);
dl_http_cli_p->fd = NULL;
}
}
static int http_dl_response_cb(
QL_HTTP_CLIENT_T *client,
QL_HTTP_CLIENT_EVENT_E event,
int status_code,
char *data,
int data_len,
void *private_data)
{
int ret=0,write_ret=0;
char para[64]={0};
dl_http_client_t* dl_http_cli_p = private_data;
static int recv_len = 0;
switch(event)
{
case QL_HTTP_CLIENT_EVENT_SEND_FAIL:
QL_DL_HTTP_LOG("http send failed!\n");
dl_http_cli_p->e_stage = DL_HTTP_DOWN_INTR;
break;
case QL_HTTP_CLIENT_EVENT_SEND_SUCCESSED:
QL_DL_HTTP_LOG("http send successed!\n");
break;
case QL_HTTP_CLIENT_EVENT_RECV_HEADER_FAIL:
QL_DL_HTTP_LOG("http parse response header failed!\n");
dl_http_cli_p->e_stage = DL_HTTP_DOWN_INTR;
break;
case QL_HTTP_CLIENT_EVENT_RECV_HEADER_FINISHED:
QL_DL_HTTP_LOG("http recv header status_code:%d;header_len:%d!\n",status_code,data_len);
ret=ql_http_client_get_header(data,"Content-Length",0,para,sizeof(para));
if(ret>0){
dl_http_cli_p->http_progress.total_size = atoi(para);
QL_DL_HTTP_LOG("Content-length[]:%d!\n",dl_http_cli_p->http_progress.total_size);
}
if(status_code==200)
QL_DL_HTTP_LOG("http recv response ok!\n");
ret=1; //��������body���ݣ�����0������������body����
break;
case QL_HTTP_CLIENT_EVENT_RECV_BODY:
QL_DL_HTTP_LOG("http recv body status_code:%d;recv_body_len:%d!\n",status_code,data_len);
dl_http_cli_p->http_progress.dload_size+=data_len;
write_ret = ql_fwrite((void *)data, data_len,1,dl_http_cli_p->fd);
QL_DL_HTTP_LOG("write_ret:%d",write_ret);
if(write_ret!=data_len)
{
QL_DL_HTTP_LOG("*** fota image write fail ***");
ret =0;
break;
}
QL_DL_HTTP_LOG("dl progress %d",(dl_http_cli_p->http_progress.dload_size*100)/dl_http_cli_p->http_progress.total_size);
ret=1; //��������body���ݣ�����0������������body����
break;
case QL_HTTP_CLIENT_EVENT_RECV_BODY_FINISHED:
dl_http_cli_p->e_stage = DL_HTTP_DOWN_DOWNED;
QL_DL_HTTP_LOG("http recv body finished!\n");
break;
case QL_HTTP_CLIENT_EVENT_DISCONNECTED:
QL_DL_HTTP_LOG("http be closed by server!\n");
dl_http_cli_p->e_stage = DL_HTTP_DOWN_INTR;
break;
default:
break;
}
return ret;
}
int utils_parse_http_url(char *address, char *host, int *port)
{
const char *data = address;
char *pos = NULL;
char hostname[64] = {0};
// If prefix is 'http://' ?
if (!memcmp(data, "http", 4))
{
if (*(data + 4) == 's')
{
// https ?
if (!memcmp(data, "https://", 8))
{
data += 8;
}
}
else if (*(data + 4) == ':')
{
if (!memcmp(data, "http://", 7))
{
data += 7;
}
}
}
pos = strchr(data, '/');
if (pos == NULL)
{
RLOGD("ftp url is not match");
}
memcpy(hostname, data, pos - data);
pos = strchr(hostname, ':');
if (pos)
{
*port = atoi(pos + 1);
*pos = 0;
strcpy(host,hostname);
}
else
{
*port = 80;
}
}
/***********************************************************
* funcname :dl_http_active
* description :
* 初始化http请求的网络环境,组建http请求报文,发起http请求
* return:
* 0 -- sucess
* other -- failed
************************************************************/
static int dl_http_evn_request(dl_http_client_t* dl_http_cli_p)
{
int ret;
char hostname[128]={0};
int port=80;
//发送http请求前创建存储升级包文件的文件描述符,别忘关闭
if ( dl_http_get_fd(dl_http_cli_p) == NULL )
{
QL_DL_HTTP_LOG("range_request http data done ,file_size[%d]",dl_http_cli_p->http_progress.file_size);
return -1;
}
if (!strncmp(dl_http_cli_p->dl_url,"https:",6)){
SSLConfig sslConfig =
{
.en = 1,
.profileIdx = 1,
.serverName = "220.180.239.212",
.serverPort = 80,
.protocol = 0,
.dbgLevel = 0,
.sessionReuseEn = 0,
.vsn = SSL_VSN_ALL,
.verify = SSL_VERIFY_MODE_OPTIONAL,
.cert.from = SSL_CERT_FROM_BUF,
.cert.path.rootCA = rootCA_path,
.cert.path.clientKey = NULL,
.cert.path.clientCert = NULL,
.cert.clientKeyPwd.data = NULL,
.cert.clientKeyPwd.len = 0,
.cipherList = "ALL",
.CTRDRBGSeed.data = NULL,
.CTRDRBGSeed.len = 0
};
utils_parse_http_url(dl_http_cli_p->dl_url,hostname,&port);
sslConfig.serverName = hostname;
sslConfig.serverPort = port;
QL_DL_HTTP_LOG("server:%s, port %d",sslConfig.serverName,sslConfig.serverPort);
ql_http_client_setopt(dl_http_cli_p->http_cli, QL_HTTP_CLIENT_OPT_SSL_CTX, &sslConfig);
}
ql_http_client_setopt(dl_http_cli_p->http_cli, QL_HTTP_CLIENT_OPT_ASYN, 0); //ͬ��ģʽ
ql_http_client_setopt(dl_http_cli_p->http_cli, QL_HTTP_CLIENT_OPT_PDP_CID, dl_http_cli_p->profile_idx);
ql_http_client_setopt(dl_http_cli_p->http_cli, QL_HTTP_CLIENT_OPT_PROTOCOL_VER, 1);
QL_DL_HTTP_LOG("dl_client:%p address:%s",dl_http_cli_p->http_cli,dl_http_cli_p->dl_url);
ret = ql_http_client_request(dl_http_cli_p->http_cli,dl_http_cli_p->dl_url,QL_HTTP_CLIENT_REQUEST_GET,QL_HTTP_CLIENT_AUTH_TYPE_NONE,NULL,NULL,NULL,0,http_dl_response_cb,dl_http_cli_p);
if (ret == 0)
{
#if 0
//阻塞等待信号量
if (ql_rtos_semaphore_wait(dl_http_cli_p->dl_http_semp, 120000) != 0 )
{
//获取信号量失败
ql_http_client_release(dl_http_cli_p->http_cli);
dl_http_close_fd(dl_http_cli_p);
return -1;
}
#endif
QL_DL_HTTP_LOG("http dload size %d=====End,\n",dl_http_cli_p->http_progress.dload_size);
ql_http_client_release(dl_http_cli_p->http_cli);
QL_DL_HTTP_LOG("http release sucess!!!");
dl_http_close_fd(dl_http_cli_p);
return 0;
}
QL_DL_HTTP_LOG("http ql_http_client_request err %d!!!",ret);
ql_http_client_release(dl_http_cli_p->http_cli);
dl_http_close_fd(dl_http_cli_p);
return -3;
}
static int dl_http_download_customfile(dl_http_client_t* dl_http_cli_p)
{
dl_http_info_cfg(dl_http_cli_p);
//组http请求报文,发送http请求,阻塞到下载完成或异常
if (dl_http_evn_request(dl_http_cli_p) != 0)
{
int file_size = dl_http_get_fileszie(dl_http_cli_p->dl_path);
QL_DL_HTTP_LOG("failed [%s] size[%d]",dl_http_cli_p->dl_path,file_size);
return -1;
}
dl_http_info_cfg(dl_http_cli_p);
return 0;
}
int hal_http_client_download(char *url, char *file_path)
{
int ret = -1;
dl_http_client_t dl_http_cli;
uint8 ui_down_times = TRY_DOWN_TIMES;
INT32 file_free_size = ql_internal_fs_free_size_get();
QL_DL_HTTP_LOG("fs free size get:0x%x",file_free_size);
//下载前初始化
if(dl_http_init(&dl_http_cli,file_path, url) != 0)
{
QL_DL_HTTP_LOG("http download init failed");
goto exit;
}
//尝试下载最多十次
while( ui_down_times-- )
{
QL_DL_HTTP_LOG("start [%d] times download file packge",TRY_DOWN_TIMES-ui_down_times);
if ( dl_http_download_customfile(&dl_http_cli) == 0 )
{
//下载完成
ret = 0;
break;
}
if ( dl_http_cli.b_is_have_space != TRUE )
{
//空间不够,删除文件
ql_remove(dl_http_cli.dl_path);
QL_DL_HTTP_LOG("have no space");
break;
}
//下载失败等待5s重新开始下载
ql_rtos_task_sleep_s(5);
}
exit:
dl_http_release(&dl_http_cli);
QL_DL_HTTP_LOG("exit hal_http_client_download");
return ret;
}
int http_ota_fw_download(char *url)
{
(void)url;
RLOGE("legacy HTTP polling FULLOTA1 is disabled; use MQTT FULLOTA2 command\r\n");
return -1;
}
typedef struct recv_buf
{
uint8_t *buf;
int buf_len;
int recv_len;
int total_len;
}http_recv_buf;
#define PRINT_BUF_SIZE 65
static char print_buf[PRINT_BUF_SIZE];
void print_string(const char * string,int len)
{
int printed = 0;
while (printed != len)
{
if ((len - printed) > (PRINT_BUF_SIZE - 1))
{
memcpy(print_buf, string + printed, (PRINT_BUF_SIZE - 1));
printed += (PRINT_BUF_SIZE - 1);
print_buf[PRINT_BUF_SIZE - 1] = '\0';
}
else
{
snprintf(print_buf,len - printed+1, "%s", string + printed);
printed = len;
}
printf("%s", print_buf);
}
printf("\n");
}
static int response_cb(
QL_HTTP_CLIENT_T *client,
QL_HTTP_CLIENT_EVENT_E event,
int status_code,
char *data,
int data_len,
void *private_data)
{
int ret=0;
char para[64]={0};
http_recv_buf *recvbuf = (http_recv_buf *)private_data;
switch(event)
{
case QL_HTTP_CLIENT_EVENT_SEND_FAIL:
printf("http send failed!\n");
break;
case QL_HTTP_CLIENT_EVENT_SEND_SUCCESSED:
printf("http send successed!\n");
break;
case QL_HTTP_CLIENT_EVENT_RECV_HEADER_FAIL:
printf("http parse response header failed!\n");
break;
case QL_HTTP_CLIENT_EVENT_RECV_HEADER_FINISHED:
printf("http recv header status_code:%d;header_len:%d!\n",status_code,data_len);
print_string(data,data_len);
ret=ql_http_client_get_header(data,"Content-Type",0,para,sizeof(para));
recvbuf->total_len = atoi(para);
if(ret>0)
printf("Content-Type[len:%d]:%s!\n",ret,para);
if(status_code==200)
printf("http recv response ok!\n");
ret=1; //继续接受body数据,返回0,不继续接受body数据
break;
case QL_HTTP_CLIENT_EVENT_RECV_BODY:
printf("http recv body status_code:%d;recv_body_len:%d!\n",status_code,data_len);
print_string(data,data_len);
if(recvbuf->recv_len+data_len<=recvbuf->buf_len){
memcpy(recvbuf->buf+recvbuf->recv_len,data,data_len);
ret=1; //继续接受body数据,返回0,不继续接受body数据
recvbuf->recv_len += data_len;
}else{
ret = 0;
}
break;
case QL_HTTP_CLIENT_EVENT_RECV_BODY_FINISHED:
printf("http recv body finished!\n");
break;
case QL_HTTP_CLIENT_EVENT_DISCONNECTED:
printf("http be closed by server!\n");
break;
default:
break;
}
return ret;
}
int hal_http_client_post(char *url, char *header, char *send, int send_len, char *recvbuf, int *recvlen)
{
int ret;
struct http_client * client = NULL;
struct http_client_list * header_list = NULL;
http_recv_buf httprecvbuf;
httprecvbuf.buf = recvbuf;
httprecvbuf.buf_len = *recvlen;
httprecvbuf.recv_len = 0;
client = ql_http_client_init();
if(client){
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_PDP_CID, 1); /*set PDP cid,if not set,using default PDP*/
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_PROTOCOL_VER, 1); /*"0" is HTTP 1.1, "1" is HTTP 1.0*/
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_ENABLE_COOKIE, 1); /*"0" is HTTP 1.1, "1" is HTTP 1.0*/
header_list=ql_http_client_list_append(header_list, header);
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_HTTPHEADER, header_list);
if(ret==QL_HTTP_CLIENT_ERR_LAST_REQUEST_NOT_FINISH)
{
printf("last request not finish, not to set!\n");
}
ret=ql_http_client_request(client,url,QL_HTTP_CLIENT_REQUEST_POST,QL_HTTP_CLIENT_AUTH_TYPE_NONE,NULL,NULL,send,send_len,response_cb,&httprecvbuf);
if(ret==QL_HTTP_CLIENT_ERR_LAST_REQUEST_NOT_FINISH)
{
printf("last request not finish, can not to request again!\n");
}
ql_http_client_list_destroy(header_list);
ql_http_client_release(client);
*recvlen = httprecvbuf.recv_len;
printf("ql_http_client_request ret=%d!\n",ret);
return ret;
}
return -1;
}
int hal_http_client_get(char *url, char *recvbuf, int *recvlen)
{
int ret;
struct http_client * client = NULL;
//struct http_client_list * header_list = NULL;
http_recv_buf httprecvbuf;
httprecvbuf.buf = recvbuf;
httprecvbuf.buf_len = *recvlen;
httprecvbuf.recv_len = 0;
client = ql_http_client_init();
if(client){
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_PDP_CID, 1); /*set PDP cid,if not set,using default PDP*/
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_PROTOCOL_VER, 1); /*"0" is HTTP 1.1, "1" is HTTP 1.0*/
ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_ENABLE_COOKIE, 1); /*"0" is HTTP 1.1, "1" is HTTP 1.0*/
//header_list=ql_http_client_list_append(header_list, header);
//ret=ql_http_client_setopt(client, QL_HTTP_CLIENT_OPT_HTTPHEADER, header_list);
//if(ret==QL_HTTP_CLIENT_ERR_LAST_REQUEST_NOT_FINISH)
//{
// printf("last request not finish, not to set!\n");
//}
ret=ql_http_client_request(client,url,QL_HTTP_CLIENT_REQUEST_GET,QL_HTTP_CLIENT_AUTH_TYPE_NONE,NULL,NULL,NULL,0,response_cb,&httprecvbuf);
if(ret==QL_HTTP_CLIENT_ERR_LAST_REQUEST_NOT_FINISH)
{
printf("last request not finish, can not to request again!\n");
}
//ql_http_client_list_destroy(header_list);
ql_http_client_release(client);
*recvlen = httprecvbuf.recv_len;
printf("ql_http_client_request ret=%d!\n",ret);
return ret;
}
return -1;
}
///////////////////////////////////////////////////////////OTA//////////////////////////////////////////////////////////////////
int app_http_post_ota_report();
int app_http_post_bind()
{
char sn[32]={0};
char model[32]={0};
int ret = -1;
char *response = NULL;
char *header = NULL;
int resp_len = 0;
char *url = "http://test.afaitoys.com/v1/device/bind";
char *post_data=NULL;
cJSON *recv;
cJSON *root = cJSON_CreateObject();
char *uuid = "testuuid";
hal_os_get_device_id(sn);
hal_os_get_model(model);
cJSON_AddItemToObject(root,"user_uuid",cJSON_CreateString(uuid));
cJSON_AddItemToObject(root,"model",cJSON_CreateString(model));
post_data = cJSON_PrintUnformatted(root);
if(post_data==NULL)goto error;
response = hal_os_malloc(4096);
if(response==NULL)goto error;
resp_len = 4096;
header = hal_os_malloc(1024);
if(header==NULL)goto error;
sprintf(header, "Content-Type: application/json\r\nX-SERIAL-NO: %s", sn);
if (hal_http_client_post(url, header, post_data, strlen(post_data), response, &resp_len) < 0)
{
RLOGE("webclient send post request failed.");
goto error;
}
RLOGD("app_http_post_bind post response data: %s\n",response);
recv = cJSON_Parse(response);
if(recv){
cJSON *status = cJSON_GetObjectItem(recv,"status");
if(status && !strcmp("success",status->valuestring)){
cJSON *code = cJSON_GetObjectItem(recv,"code");
if(code && code->valueint == 200){
ret = 0;
RLOGD("bind okay.");
}else{
ret = -4;
}
}else{
ret = -3;
}
cJSON_Delete(recv);
}else{
RLOGE("bind recv not json error.");
ret = -2;
}
error:
if(post_data){
hal_os_free(post_data);
}
if(root){
cJSON_Delete(root);
}
if (header)
{
hal_os_free(header);
}
if (response)
{
hal_os_free(response);
}
return ret;
}
int replace_str(char *str, char *oldStr, char *newStr, size_t str_buf_size) {
char *start = str;
char *p = strstr(str, oldStr);
size_t oldLen, newLen, remainingLen;
// 安全修复:参数检查
if (str == NULL || oldStr == NULL || newStr == NULL || str_buf_size == 0) {
return -1;
}
if (p == NULL) {
return -1;
}
oldLen = strlen(oldStr);
newLen = strlen(newStr);
while (p) {
remainingLen = strlen(p + oldLen);
// 安全修复:检查缓冲区是否足够
if ((p - str) + newLen + remainingLen >= str_buf_size) {
QL_DL_HTTP_LOG("replace_str: buffer overflow risk");
return -1;
}
// 安全修复:使用memmove(处理重叠内存)和snprintf
memmove(p + newLen, p + oldLen, remainingLen + 1); // +1 for '\0'
memcpy(p, newStr, newLen);
str = p + newLen;
p = strstr(str, oldStr);
}
return 0;
}
int app_http_post_ota_packages(char *durl, char *ver)
{
char sn[32]={0};
char model[32]={0};
int ret = -1;
char *response = NULL;
char *header = NULL;
int resp_len = 0;
char *url = "http://test.afaitoys.com/v1/ota/packages";
char *post_data=NULL;
cJSON *recv;
cJSON *root = cJSON_CreateObject();
hal_os_get_device_id(sn);
hal_os_get_model(model);
cJSON_AddItemToObject(root,"serial_no",cJSON_CreateString(sn));
cJSON_AddItemToObject(root,"model",cJSON_CreateString(model));
cJSON_AddItemToObject(root,"apk_version",cJSON_CreateString(APP_VER));
cJSON_AddItemToObject(root,"rom_version",cJSON_CreateString(ROM_VER));
post_data = cJSON_PrintUnformatted(root);
if(post_data==NULL)goto error;
response = hal_os_malloc(4096);
if(response==NULL)goto error;
resp_len = 4096;
header = hal_os_malloc(1024);
if(header==NULL)goto error;
sprintf(header, "Content-Type: application/json");
if (hal_http_client_post(url, header, post_data, strlen(post_data), response, &resp_len) < 0)
{
RLOGE("webclient send post request failed.");
goto error;
}
RLOGD("ota resp: %s\n",response);
recv = cJSON_Parse(response);
if(recv){
cJSON *status = cJSON_GetObjectItem(recv,"status");
if(status && !strcmp("success",status->valuestring)){
cJSON *code = cJSON_GetObjectItem(recv,"code");
if(code && code->valueint == 200104){
RLOGD("update find.");
cJSON *dataj = cJSON_GetObjectItem(recv,"data");
if(dataj){
cJSON *item = cJSON_GetArrayItem(dataj,0);
if(item){
cJSON *item_url = cJSON_GetObjectItem(item,"download_url");
if(item_url){
replace_str(item_url->valuestring, "https", "http", sizeof(item_url->valuestring));
RLOGD("download url %s",item_url->valuestring);
ret = 0;
strcpy(durl,item_url->valuestring);
}
cJSON *semver_item = cJSON_GetObjectItem(item,"semver");
if(semver_item){
strcpy(ver,semver_item->valuestring);
}
}
}
}else{
ret = -4;
}
}else{
ret = -3;
}
cJSON_Delete(recv);
}else{
RLOGE("app_http_post_ota_packages recv not json error.");
ret = -2;
}
error:
if(post_data){
hal_os_free(post_data);
}
if(root){
cJSON_Delete(root);
}
if (header)
{
hal_os_free(header);
}
if (response)
{
hal_os_free(response);
}
return ret;
}
int app_http_post_ota_packages_check()
{
char url[128]={0};
char ver[32]={0};
int ret = -1;
RLOGD("app_http_post_ota_report 5\r\n");
app_http_post_ota_report();
ret = app_http_post_ota_packages(url,ver);
if(ret==0 && strlen(url)>0){
#ifdef AOFEI_AUDIO_URL_SHEEP
app_audio_player_by_path("http://alphai-ota.oss-cn-beijing.aliyuncs.com/alpha-intelligence/CNLD/TIPS/sheep/enter_ota_no_cut_power.amr");
#endif
#ifdef AOFEI_AUDIO_URL_WOLF
app_audio_player_by_path("http://alphai-ota.oss-cn-beijing.aliyuncs.com/alpha-intelligence/CNLD/TIPS/wolf/enter_ota_no_cut_power.amr");
#endif
#ifdef TEST_AUDIO_URL
app_audio_player_by_path("http://47.113.99.138:7050/TIPS/enter_ota_no_cut_power.amr");
#endif
hal_kv_set("update_ver",ver,strlen(ver)+1);
hal_kv_set("update_flag","1",strlen("1")+1);
ret = http_ota_fw_download(url);
RLOGD("http_ota_fw_download ret:%d\r\n", ret);
if(ret==0){
//固件升级成功,正在重启
#ifdef AOFEI_AUDIO_URL_SHEEP
app_audio_player_by_path("http://alphai-ota.oss-cn-beijing.aliyuncs.com/alpha-intelligence/CNLD/TIPS/sheep/ota_success.amr");
#endif
#ifdef AOFEI_AUDIO_URL_WOLF
app_audio_player_by_path("http://alphai-ota.oss-cn-beijing.aliyuncs.com/alpha-intelligence/CNLD/TIPS/wolf/ota_success.amr");
#endif
#ifdef TEST_AUDIO_URL
app_audio_player_by_path("http://47.113.99.138:7050/TIPS/ota_success.amr");
#endif
RLOGD("ota download ok and reset\r\n");
}else{
//固件升级失败
#ifdef AOFEI_AUDIO_URL_SHEEP
app_audio_player_by_path("http://alphai-ota.oss-cn-beijing.aliyuncs.com/alpha-intelligence/CNLD/TIPS/sheep/ota_fail.amr");
#endif
#ifdef AOFEI_AUDIO_URL_WOLF
app_audio_player_by_path("http://alphai-ota.oss-cn-beijing.aliyuncs.com/alpha-intelligence/CNLD/TIPS/wolf/ota_fail.amr");
#endif
#ifdef TEST_AUDIO_URL
app_audio_player_by_path("http://47.113.99.138:7050/TIPS/ota_fail.amr");
#endif
RLOGD("ota download error and reset\r\n");
}
ret = 1;
}
return ret;
}
int app_http_post_ota_report()
{
char sn[32]={0};
char model[32]={0};
int ret = -1;
char *response = NULL;
char *header = NULL;
int resp_len = 0;
char *url = "http://test.afaitoys.com/v1/ota/report";
char *post_data=NULL;
cJSON *recv;
cJSON *root = NULL;
#if 0
hal_kv_get("update_ver",model,sizeof(model));
if(strlen(model)==0){
return -2;
}
if(strcmp(model,ROM_VER)==0){
RLOGD("ota update okay!!!!!!!!!!!!!!!!!!!!!!!!!");
}
memset(model,0,sizeof(model));
hal_kv_set("update_ver","",1);
#endif
root = cJSON_CreateObject();
hal_os_get_device_id(sn);
hal_os_get_model(model);
cJSON_AddItemToObject(root,"serial_no",cJSON_CreateString(sn));
cJSON_AddItemToObject(root,"model",cJSON_CreateString(model));
cJSON_AddItemToObject(root,"apk_version",cJSON_CreateString(APP_VER));
cJSON_AddItemToObject(root,"rom_version",cJSON_CreateString(ROM_VER));
post_data = cJSON_PrintUnformatted(root);
if(post_data==NULL){
ret = -1;
goto error;
}
response = hal_os_malloc(4096);
if(response==NULL)goto error;
resp_len = 4096;
header = hal_os_malloc(1024);
if(header==NULL)goto error;
sprintf(header, "Content-Type: application/json");
if (hal_http_client_post(url, header, post_data, strlen(post_data), response, &resp_len) < 0)
{
RLOGE("webclient send post request failed.");
ret = -5;
goto error;
}
RLOGD("app_http_post_ota_report post response data: %s\n",response);
recv = cJSON_Parse(response);
if(recv){
cJSON *status = cJSON_GetObjectItem(recv,"status");
if(status && strcmp("success",status->valuestring)){
cJSON *code = cJSON_GetObjectItem(recv,"code");
if(code && code->valueint == 200){
ret = 0;
RLOGD("report okay.");
}else{
ret = -4;
}
}else{
ret = -3;
}
cJSON_Delete(recv);
}else{
RLOGD("app_http_post_ota_report recv not json error.");
ret = -2;
}
error:
if(post_data){
hal_os_free(post_data);
}
if(root){
cJSON_Delete(root);
}
if (header)
{
hal_os_free(header);
}
if (response)
{
hal_os_free(response);
}
return ret;
}
uint8_t story_cnt = 0;
uint8_t app_get_story_cnt(void)
{
return story_cnt;
}
int app_http_get_story(char *uuid, char *story)
{
char tempbuf[128]={0};
int ret = -1;
char *response = NULL;
int resp_len = 0;
char *url = "http://test.afaitoys.com/v1/user/skill/tiny";
cJSON *recv=NULL;
//int index = 0;
story_cnt = 0;
hal_kv_set("story_cnt",&story_cnt,1);
/*删除所有的故事*/
//while(1){
// RLOGD(tempbuf,"/flash0/story_%d.txt",index);
//if(check_audio_file_exist(tempbuf)){
// dfs_file_unlink(tempbuf);
//}
//index++;
//if(index>50) break;
//rt_thread_mdelay(20);
//}
sprintf(tempbuf,"%s?uuid=%s&sign=%s",url,uuid,story);
response = hal_os_malloc(4096);
if(response==NULL)goto error;
resp_len = 4096;
if (hal_http_client_get(tempbuf, response, &resp_len) < 0)
{
RLOGE("webclient send get request failed.");
ret = -5;
goto error;
}
RLOGD("app_http_get_story get response data: %s\n",response);
recv = cJSON_Parse(response);
if(recv){
cJSON *status = cJSON_GetObjectItem(recv,"status");
if(status && !strcmp("success",status->valuestring)){
cJSON *code = cJSON_GetObjectItem(recv,"code");
if(code && code->valueint == 200){
RLOGD("get story okay.");
cJSON *dataj = cJSON_GetObjectItem(recv,"data");
if(dataj){
cJSON *sdataj = cJSON_GetObjectItem(dataj,"storiesData");
if(sdataj){
uint8_t cnt = cJSON_GetArraySize(sdataj);
int i;
char filename[32]={0};
for(i=0;i<cnt;i++){
cJSON *item = cJSON_GetArrayItem(sdataj,i);
if(item){
cJSON *item_url = cJSON_GetObjectItem(item,"audioUrlData");
if(item_url){
sprintf(filename,"/flash0/story_%d.txt",i);
/* // int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
ret = dfs_file_open(&fd, filename, O_WRONLY | O_CREAT | O_TRUNC);
if (ret < 0)
{
rt_kprintf("story file failed, open file(%s) error.", filename);
}else{
int cnt2 = cJSON_GetArraySize(item_url);
for(j=0;j<cnt2;j++){
cJSON *strurl = cJSON_GetArrayItem(item_url,j);
if(strurl){
replace_str(strurl->valuestring,"https","http");
rt_kprintf("story url %s\r\n",strurl->valuestring);
//todo play the url
//strurl->valuestring
ret = 0;
// write(fd,strurl->valuestring,strlen(strurl->valuestring));
dfs_file_write(&fd, strurl->valuestring, strlen(strurl->valuestring));
if(j<cnt2-1){
dfs_file_write(&fd,";",1);
}
}
}
dfs_file_write(&fd,"\0",1);
dfs_file_close(&fd);
} */
}
}
}
if(ret==0){
hal_kv_set("story_cnt",&cnt,1);
story_cnt = cnt;
}
}
}
}else{
ret = -4;
}
}else{
ret = -3;
}
cJSON_Delete(recv);
}else{
RLOGE("app_http_get_story recv not json error.");
ret = -2;
}
error:
if (response)
{
hal_os_free(response);
}
return ret;
}
#endif
static ql_sem_t app_http_aofei_do_sem = NULL;
void app_http_aofei_net_ready()
{
if(app_http_aofei_do_sem)
ql_rtos_semaphore_release(app_http_aofei_do_sem);
}
void app_http_aofei_thread(void *arvg)
{
char *url = "http://47.113.99.138:7050/test.mp3";
char *file_name = "test.mp3";
ql_rtos_semaphore_create(&app_http_aofei_do_sem, 0);
while(1){
ql_rtos_semaphore_wait(app_http_aofei_do_sem, 0xFFFFFFFF);
// app_http_post_bind(); //bind一次
//app_http_post_ota_packages_check();//ota
hal_http_client_download(url, file_name);
}
}
int app_http_aofei_init()
{
ql_task_t appTaskRef = NULL;
ql_rtos_task_create(&appTaskRef, 1024*4, 100, "app_http_aofei", app_http_aofei_thread, NULL);
return 0;
}