#include "learnHttp.h" #include "nwy_osi_api.h" #include "nwy_http.h" #include "nwy_ftp.h" #include "log.h" #include "ohpoc.h" #include "base64.h" #include "app.h" #define GET_FILE_MAX_SIZE 10*1024 #define HTTP_TASK_STACK_SIZE (1024*64) #define LEN_SEG "Content-Length: " typedef enum{ HPROC_START, HPROC_BUSY, HPROC_OK, HPROC_FAILED }HTTP_PRO_ENUM; typedef struct{ UHTTP_ENUM httpType; char url[200]; unsigned char lteStatus;//下载文件状态 unsigned char timeout; HTTP_PRO_ENUM processStatus; int fsize; int offset; unsigned short port; HttpCallBack recvCb; unsigned char *data; unsigned int dlength; unsigned char done; }HttpInfoSet; unsigned char *httpDataPtr=NULL; HttpInfoSet httpinfo; nwy_osiThread_t *learnHttpThread=NULL; typedef enum{ HTTP_STATUS_IDLE, HTTP_STATUS_SETUP, HTTP_STATUS_SETUP_OK, HTTP_STATUS_GET, HTTP_STATUS_GET_OK, HTTP_STATUS_DNSERR, HTTP_STATUS_GET_ERR_HEAD, HTTP_STATUS_GET_REJECT_HEAD, HTTP_STATUS_GET_FAILED_HEAD, HTTP_STATUS_GET_ERR_FSIZE, HTTP_STATUS_GET_FAILED_FSIZE, HTTP_STATUS_GET_ERR_OFFSET, HTTP_STATUS_GET_FSIZE_OVER, HTTP_STATUS_POST_BUSY, HTTP_STATUS_POST_BAD, HTTP_STATUS_POST_DONE, HTTP_STATUS_DATA_MALLOC_ERR, HTTP_STATUS_TOUT, HTTP_STATUS_CLOSED }HTTP_STATUS_ENUM; static void learnEntry(void *param); void learn_http_set_status_false(unsigned char newStatus){ MSG_INFO(1, "learn Status:%d",newStatus); httpinfo.lteStatus=newStatus; httpinfo.processStatus=HPROC_FAILED; } void learnHttpStart(UHTTP_ENUM httpType, char *url, unsigned short port, HttpCallBack *httpCb, unsigned char *udata, unsigned int dlen){ if(httpCb==NULL){ MSG_INFO(1, "httpCb is invalid"); return; } if(NULL != learnHttpThread){ MSG_INFO(1, "learnHttp is busy"); return; } memset(&httpinfo, 0, sizeof(HttpInfoSet)); httpinfo.data=udata; httpinfo.dlength=dlen; httpinfo.httpType=httpType; httpinfo.port=port; httpinfo.recvCb=httpCb; snprintf(httpinfo.url, sizeof(httpinfo.url), "%s",url);//120.77.66.129、1.txt 不需要http:头 learnHttpThread=nwy_create_thread("learnHttpThread", learnEntry,NULL,NWY_OSI_PRIORITY_NORMAL,HTTP_TASK_STACK_SIZE,15); if(NULL==learnHttpThread){ MSG_ERR(1,"learnHttpThread thread error");//因为是阻塞的,故需要开线程,且栈要比较大 } } #define USER_DATA_SIZE (1024*3) //每次http post最大用户数据长度 static void nwy_http_result_cb(nwy_ftp_result_t *param); static void learnEntry(void *param){ unsigned char *ptr; int channel=1; int keepalive=1; int pIndex,lLen,pLen,tLen,rLen; unsigned char *postBuf=NULL; char tmp[30]; float tmpSpeed; appSleepCtl(ASLEEP_LEARN, 1); boolean http_https=false;//http nwy_osiEvent_t event = {}; //MSG_INFO(1,"learn thread start:url=%s",httpinfo.url); int result = nwy_http_setup(channel, httpinfo.url, httpinfo.port, nwy_http_result_cb); if(0!=result){ MSG_INFO(1, "learn http setup api failed"); goto HTTP_END; } MSG_INFO(1, "learn http wait setup result"); for(;;){ nwy_wait_thead_event(nwy_get_current_thread(), &event,0); if(OHPOC_EVENT_HTTP==event.id) break; } if(httpinfo.lteStatus==HTTP_STATUS_DNSERR) goto HTTP_END; if(httpinfo.httpType==UHTTP_FILE_GET){ httpinfo.lteStatus=HTTP_STATUS_GET;//start get result = nwy_http_get(keepalive, 0, GET_FILE_MAX_SIZE, http_https); if(result!=0){ MSG_INFO(1,"learn http get api failed"); goto HTTP_END; } MSG_INFO(1, "learn http wait get ack"); for(;;){ nwy_wait_thead_event(nwy_get_current_thread(), &event,0); if(OHPOC_EVENT_HTTP==event.id){ if(httpinfo.lteStatus==HTTP_STATUS_GET_OK || httpinfo.lteStatus==HTTP_STATUS_CLOSED || httpinfo.lteStatus==HTTP_STATUS_TOUT) break; } } }else if(httpinfo.httpType==UHTTP_POST){ httpinfo.processStatus=HPROC_START; pIndex=0; #if 0//强制发送长度为20的测试数据 httpinfo.dlength=20; memset(httpinfo.data, 0x55, httpinfo.dlength); #endif lLen=httpinfo.dlength; postBuf=(unsigned char *)malloc(USER_DATA_SIZE); if(postBuf==NULL){ MSG_ERR(1, "http post malloc failed"); httpinfo.processStatus=HPROC_FAILED; goto HTTP_END; } for(;;){ httpinfo.lteStatus=HTTP_STATUS_POST_BUSY; tmpSpeed=learnGetRecordRecSpeed(); //先填充必须的一些字段信息,数据未填充,包有效数据长度未填(原始数据,非base64后) snprintf(postBuf, USER_DATA_SIZE, "{\"tid\":%s,\"uid\":%d,\"gid\":%d,\"dsv\":%d,\"dss\":%.1f,\"fsize\":%d,\"offset\":%d,\"token\":\"%s\",\"data\":\"", learnGetTid(), getLearnUid(), getLearnGid(), learnGetRecordMaxVolume(), tmpSpeed, httpinfo.dlength, pIndex, getLearnToken()); //计算剩下可以填充多少实际数据,最后预留:","size":3000},即14字节,我们给20字节吧 tLen=USER_DATA_SIZE-strlen(postBuf)-20; //计算tLen最多能装多少个原始数据,每4个base64表示3个原始数据 rLen=tLen/4;//最多能装多少'组'原始数据 rLen *= 3;//最多能装多少字节原始数据 //计算本次填充多少有效数据 if(lLen>rLen) pLen=rLen; else pLen=lLen; //填充有效数据 ptr=httpinfo.data+pIndex; base64_encode(ptr, postBuf+strlen(postBuf), pLen);//结尾会被填充'\0' //添加size字段 snprintf(tmp, sizeof(tmp), "\",\"size\":%d}", pLen); strcat(postBuf, tmp); //MSG_INFO(1, "send:<%s>\r\n", postBuf); //可以发送了(json) result = nwy_http_post(keepalive, 2 , postBuf, strlen(postBuf), http_https); MSG_INFO(1, "Post dataOffset:%d,dataLen:%d,jsonLen:%d %s", pIndex, pLen, strlen(postBuf), (result==0)?"Ok":"Failed"); if(result==0){//执行成功,等待结果 for(;;){ nwy_wait_thead_event(nwy_get_current_thread(), &event,0); if(OHPOC_EVENT_HTTP==event.id){ if(httpinfo.lteStatus==HTTP_STATUS_POST_DONE || httpinfo.lteStatus==HTTP_STATUS_POST_BAD || httpinfo.lteStatus==HTTP_STATUS_CLOSED || httpinfo.lteStatus==HTTP_STATUS_TOUT) break; } } if(httpinfo.lteStatus==HTTP_STATUS_POST_DONE){ pIndex += pLen; lLen -= pLen; MSG_INFO(1, "http post len:%d done", pLen); httpPostResetUserTimer(pIndex*100/httpinfo.dlength); if(lLen<=0){ MSG_INFO(1, "http post done"); httpinfo.processStatus=HPROC_OK; break; } }else if(httpinfo.lteStatus==HTTP_STATUS_POST_BAD){ MSG_INFO(1, "http post ack bad"); httpinfo.processStatus=HPROC_FAILED; break; }else{ MSG_INFO(1, "http connection close/tout"); httpinfo.processStatus=HPROC_FAILED; break; } }else{ MSG_INFO(1, "http post err"); httpinfo.processStatus=HPROC_FAILED; break; } } } MSG_INFO(1, "learn done"); HTTP_END: if(NULL!=postBuf) free(postBuf); MSG_INFO(1, "learn http end"); nwy_http_close(http_https); for(;;){ if(httpinfo.lteStatus==HTTP_STATUS_DNSERR) break;//如果setup未成功,是不会有事件响应的 nwy_wait_thead_event(nwy_get_current_thread(), &event,0); if(OHPOC_EVENT_HTTP==event.id){ if(httpinfo.lteStatus==HTTP_STATUS_GET_OK || httpinfo.lteStatus==HTTP_STATUS_CLOSED || httpinfo.lteStatus==HTTP_STATUS_TOUT) break; } } learnHttpThread=NULL; httpinfo.done=1; appSleepCtl(ASLEEP_LEARN, 0); MSG_INFO(1, "learn http thread exit"); nwy_exit_thread(); } //检测接受到数据是否是成功的 //HTTP/1.1 200 static bool isHttpRecvValid(char *msg){ int i; //检测是否是HTTP/头 if(0!=memcmp(msg, "HTTP/", 5)) return true;//非首包 //找空格后面的串是否是200 for(i=0;ievent); switch(param->event){ case NWY_HTTP_DATA_RECVED: strcat(info,"NWY_HTTP_DATA_RECVED");break; case NWY_HTTP_DNS_ERR: strcat(info,"NWY_HTTP_DNS_ERR");break; case NWY_HTTP_OPEN_FAIL: strcat(info,"NWY_HTTP_OPEN_FAIL");break; case NWY_HTTP_OPENED: strcat(info,"NWY_HTTP_OPENED");break; case NWY_HTTPS_SSL_CONNECTED: strcat(info,"NWY_HTTPS_SSL_CONNECTED");break; case NWY_HTTP_CLOSED_PASV: strcat(info,"NWY_HTTP_CLOSED_PASV");break; case NWY_HTTP_CLOSED: strcat(info,"NWY_HTTP_CLOSED");break; case NWY_HTTP_DATA_SEND_ERR: strcat(info,"NWY_HTTP_DATA_SEND_ERR");break; case NWY_HTTPS_SSL_INIT_ERROR: strcat(info,"NWY_HTTPS_SSL_INIT_ERROR");break; case NWY_HTTPS_SSL_HANDSHAKE_ERROR: strcat(info,"NWY_HTTPS_SSL_HANDSHAKE_ERROR");break; case NWY_HTTPS_SSL_AUTH_FAIL: strcat(info,"NWY_HTTPS_SSL_AUTH_FAIL");break; case NWY_HTTP_DATA_SEND_FINISHED: strcat(info,"NWY_HTTP_DATA_SEND_FINISHED");break; default:strcat(info,"Unknown");break; } MSG_INFO(1, info); switch(param->event){ case NWY_HTTP_DATA_RECVED: //MSG_INFO(1, "httpRecv:%d,%s", param->data_len, param->data); if(httpinfo.httpType==UHTTP_FILE_GET){//发HTTP_GET指令时的响应处理 if(httpinfo.processStatus==HPROC_START){//响应第一包,需要获取总长度,有效数据长度等信息 //检测是否是HTTP/头或非首包 if(false==isHttpRecvValid(param->data)){ MSG_WARN(1, "UHTTP_FILE_GET Recv Ack Not 200"); break; } //获取有效数据总长度 ptr=strstr(param->data, LEN_SEG); if(NULL==ptr){//没有字段,无法提取 MSG_ERR(1, "No '%s' seg!",LEN_SEG); learn_http_set_status_false(HTTP_STATUS_GET_ERR_FSIZE); break; } dlen=atoi(ptr+strlen(LEN_SEG));// if(dlen<=0 || dlen>GET_FILE_MAX_SIZE || dlen==param->data_len){ MSG_ERR(1, "data len invalid:%d",dlen); learn_http_set_status_false(HTTP_STATUS_GET_FSIZE_OVER); break; } MSG_INFO(1, "total data len:%d", dlen); httpDataPtr=(unsigned char *)malloc(dlen+2); if(NULL==httpDataPtr){ MSG_ERR(1, "data malloc err:%d",dlen); learn_http_set_status_false(HTTP_STATUS_DATA_MALLOC_ERR); break; } //获取有效数据开始索引 ptr=strstr(param->data,"\r\n\r\n"); if(NULL==ptr){ MSG_ERR(1, "data offset err"); learn_http_set_status_false(HTTP_STATUS_GET_ERR_OFFSET); free(httpDataPtr); break; } httpinfo.fsize=dlen; httpinfo.offset=0; //提取本包中的有效数据 ptr += 4; i=param->data_len-(ptr-(char *)param->data); memcpy(httpDataPtr+httpinfo.offset, ptr, i); //更新 httpinfo.offset += i; httpinfo.processStatus=HPROC_BUSY; }else if(httpinfo.processStatus==HPROC_BUSY){//第一包以后均为有效数据 memcpy(httpDataPtr+httpinfo.offset, param->data, param->data_len); httpinfo.offset += param->data_len; i=param->data_len; } if(httpinfo.processStatus<=HPROC_BUSY){ MSG_INFO(1, "learn getdata offset:%d, fsize:%d", i, httpinfo.offset,httpinfo.fsize); if(httpinfo.offset>=httpinfo.fsize){ MSG_INFO(1,"learn get data done"); httpinfo.lteStatus=HTTP_STATUS_GET_OK; httpinfo.recvCb(httpDataPtr, httpinfo.fsize); free(httpDataPtr); httpinfo.processStatus=HPROC_OK; } } }else if(httpinfo.httpType==UHTTP_POST){//HTTP_POST时的响应处理接口 //MSG_INFO(1, "httpRecv:%d,%s", param->data_len, param->data); //检测是否是HTTP/头或非首包 if(false==isHttpRecvValid(param->data)){ MSG_WARN(1, "UHTTP_POST Recv Ack Not 200"); httpinfo.lteStatus=HTTP_STATUS_POST_BAD; break; } MSG_INFO(1, "http post get done ack"); httpinfo.lteStatus=HTTP_STATUS_POST_DONE; } break; case NWY_HTTP_DNS_ERR:httpinfo.lteStatus=HTTP_STATUS_DNSERR;break; case NWY_HTTP_OPEN_FAIL: break; case NWY_HTTP_OPENED:httpinfo.lteStatus=HTTP_STATUS_SETUP_OK;break; case NWY_HTTPS_SSL_CONNECTED: break; case NWY_HTTP_CLOSED_PASV: case NWY_HTTP_CLOSED:httpinfo.lteStatus=HTTP_STATUS_CLOSED;break; case NWY_HTTP_DATA_SEND_ERR: break; case NWY_HTTPS_SSL_INIT_ERROR: break; case NWY_HTTPS_SSL_HANDSHAKE_ERROR: break; case NWY_HTTPS_SSL_AUTH_FAIL: break; case NWY_HTTP_DATA_SEND_FINISHED: break; } threadPostEvent(nwy_get_current_thread(),OHPOC_EVENT_HTTP, NULL,NULL,NULL); } void hearnHttpOverTime(void){ if(NULL == learnHttpThread) return; httpinfo.lteStatus=HTTP_STATUS_TOUT; threadPostEvent(learnHttpThread,OHPOC_EVENT_HTTP, NULL,NULL,NULL); } unsigned char getHttpLearnStatus(void){ if(httpinfo.done==0) return 1;//未完成 if(httpinfo.processStatus==HPROC_OK) return 0;//已完成,且获取成功 else return 2;//已完成,且失败 } #include "cJSON.h" void jsonTestNow(void){ char* data = "{\"name\":\"Messi\",\"age\":\"29\"}"; //char* buf = "{\"uid\":12345,\"list\":[{\"tid\":\"5126\"},{\"tid\":\"5127\"},{\"tid\":\"8867\"},{\"tid\":\"8868\"},{\"tid\":\"1221\"},{\"tid\":\"2546\"}]}"; const char * buf="{\"uid\":12348,\"list\":[{\"s\":4,\"c\":\"What is your name?\",\"t\":\"task 1\",\"f\":1,\"tid\":5126},{\"s\":3,\"c\":\"Where are you?\",\"t\":\"task 2\",\"f\":1,\"tid\":5127}]}"; //const char * buf="{\"uid\":12348,\"list\":[{\"s\":\"4\",\"c\":\"What is your name?\",\"t\":\"task 1\",\"f\":\"1\",\"tid\":\"5126\"},{\"s\":\"3\",\"c\":\"Where are you?\",\"t\":\"task 2\",\"f\":\"1\",\"tid\":\"5127\"}]}"; cJSON* root = cJSON_Parse(data); if(NULL==root){ MSG_ERR(1, "root null1"); return; } cJSON* itemName = cJSON_GetObjectItem(root, "name"); if(itemName!=NULL) MSG_INFO(1, "name:%s", itemName->valuestring); else MSG_WARN(1, "name:NULL"); cJSON* itemAge = cJSON_GetObjectItem(root, "age"); if(itemAge!=NULL) MSG_INFO(1, "name:%s", itemAge->valuestring); else MSG_WARN(1, "age:NULL"); cJSON_Delete(root); MSG_INFO(1, "JSON DONE"); root = cJSON_Parse(buf); if(NULL==root){ MSG_ERR(1, "root null2"); return; } MSG_INFO(1, "--------------"); itemName = cJSON_GetObjectItem(root, "list"); if(itemName==NULL){ MSG_WARN(1, "list:NULL"); cJSON_Delete(root); return; } int num=cJSON_GetArraySize(itemName); MSG_INFO(1, "num=%d", num); int i=0; cJSON* tmp,*t; char *buf1; while(1){ tmp=cJSON_GetArrayItem(itemName, i); if(tmp==NULL){ MSG_INFO(1, "NULL"); break; } buf1=cJSON_Print(tmp); MSG_INFO(1, "Detail:%s",buf1); free(buf1); t=cJSON_GetObjectItem(tmp, "tid"); if(t!=NULL) MSG_INFO(1, "element[%d]%s", i++,t->valuestring); else MSG_INFO(1, "element[%d]NULL", i++); } cJSON_Delete(root); MSG_INFO(1, "JSON DONE2"); }