#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netdb.h>
#include <regex.h>
#include <signal.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <pthread.h>
#include "md5.h"
#include "main.h"
#include "http_utils.h"
#include "read_utils.h"
#include "json_utils.h"
#include "Base64.h"

#define PRINT_TIME_TAG
#define DBG_TAG "http_utils"
#define DBG_LVL DBG_INFO
#include "debug_print.h"
typedef struct
{
	int status_code;        //HTTP/1.1 '200' OK
	char content_type[128]; //Content-Type: application/gzip
	long content_length;    //Content-Length: 11683079
}http_response_t;

int http_parse_url(const char url[1024], char domain[1024], int *port, char file_name[256])
{
	char *patterns[] = {"http://", "https://", NULL};
	int j = 0, i = 0;
	int start = 0;
	int ret = 0;

	if ((url == NULL)||(domain == NULL)||(port == NULL)||(file_name == NULL)) {
		LOG_I("param: NULL\n");
		ret = -1;
		goto error;
	}

	for (i = 0; patterns[i]; i++) {
		if (strncmp(url, patterns[i], strlen(patterns[i])) == 0) {
			start = strlen(patterns[i]);
		}
	}

	//解析域名, 这里处理时域名后面的端口号会保留
	for (i = start, j = 0; url[i] != '/' && url[i] != '\0'; i++, j++) {
		domain[j] = url[i];
		if((i >= (1024 - 1)) || (j >= (1024 - 1))) {
			ret = -2;
			goto error;
		}
	}
	domain[j] = '\0';

	//解析端口号, 如果没有, 那么设置端口为80
	char *pos = strstr(domain, ":");
	if (pos) {
		sscanf(pos, ":%d", port);
	} else {
		*port = 80;
	}

	//删除域名端口号
	for (i = 0; i < strlen(domain); i++) {
		if (domain[i] == ':') {
			domain[i] = '\0';
			break;
		}
	}

	//获取下载文件名
	for (i = start, j = 0; url[i] != '\0'; i++) {
		if (url[i] == '/') {
			if (i != strlen(url) - 1) {
				j = 0;
			}
			continue;
		} else {
			file_name[j++] = url[i];
			if(j >= (256 - 1)) {
				ret = -3;
				goto error;
			}
		}
	}
	file_name[j] = '\0';
error:	
	return ret;	
}

int is_ip_legal(const char *ip)
{
	char str_ip[30] = "";
	regex_t reg;
	const char *pattern = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}";
	int cflags = REG_EXTENDED;
	const size_t nmatch = 1;
	regmatch_t pmatch[1];
	int ret = 0;

	if (ip == NULL) {
		LOG_I("param: NULL\n");
		ret = -1;
		goto error;
	}

	strcpy(str_ip, ip);
	regcomp(&reg, pattern, cflags);
	ret = regexec(&reg, str_ip, nmatch, pmatch, 0);

	if(ret == REG_NOMATCH)
	{
		LOG_I("IP not match\n");
		ret = -2;
		goto error;
	} else if(ret == REG_NOERROR) {
		ret = 0;
	}
	regfree(&reg);

error:	
	return ret;	
}

int get_ip_by_domain(char *domain, char dest[16], int dest_len)
{
	struct hostent *host;
	int ret = 0;

	if ((domain == NULL)||(dest == NULL)) {
		LOG_I("param: NULL\n");
		ret = -1;
		goto error;
	}
	host = gethostbyname(domain);
	if (host == NULL) {
		LOG_I("gethostbyname error\n");
		ret = -2;
		goto error;
	} else {
		if (dest_len >= 16 && dest != NULL) {
			char **phe = NULL;

			for ( phe=host->h_addr_list ; NULL != *phe ; ++phe) {
				inet_ntop(host->h_addrtype, *phe, dest, dest_len);
			}
		}
	}
error:	
	return ret;	
}

int socket_client_connect(int socketfd, char ip[INET_ADDRSTRLEN], int port)
{
	struct sockaddr_in addr;
	int flag = 1;
	fd_set fds;
	struct timeval tv;
	int ret = 0;
	int len = sizeof(ret);

	if (ip == NULL) {
		LOG_I("param: NULL\n");
		ret = -1;
		goto error;
	}

	bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	inet_pton(AF_INET, ip, &addr.sin_addr);

	//当socket进行TCP连接的时候（也就是调用connect时），一旦网络不通，或者是ip地址无效，就可能使整个线程阻塞
	//设置为非阻塞模式
	ioctl(socketfd, FIONBIO, &flag);
	ret = connect(socketfd, (struct sockaddr*)&addr, sizeof(addr));
	if (ret < 0) {
		tv.tv_sec = 1;
		tv.tv_usec = 500*1000;
		FD_ZERO(&fds);
		FD_SET(socketfd, &fds);
		ret = select(FD_SETSIZE, NULL, &fds, NULL, &tv);
		if(ret < 0){
			LOG_I("seclect error\n");
			ret = -2;
			goto error;
		}else if(ret > 0){
			if(FD_ISSET(socketfd, &fds)){
				getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &ret, (socklen_t *)&len);
				if(ret != 0){
					ret = -3;
					goto error;
				}
			}
		}else{//time out
			ret = -4;
			goto error;
		}
	}
	flag = 0;
	ioctl(socketfd, FIONBIO, &flag); //设置为阻塞模式
	ret = socketfd;
error:	
	return ret;
}

int socket_client_open(void)
{
	int socketfd;

	socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if(socketfd < 0){
		LOG_I("socket error\n");
	}
	return socketfd;
}

int socket_client_open_connect(char ip[INET_ADDRSTRLEN], int port)
{
	int socketfd;
	int ret = 0;

	socketfd = socket_client_open();
	ret = socket_client_connect(socketfd, ip, port);
	if(ret < 0){
		LOG_I("socket_client_connect error: %d\n", ret);
		close(socketfd);
		socketfd = -1;
	}
	return socketfd;
}

int get_http_response(const char *response, http_response_t *resp)
{
	int ret = 0;

	if ((response == NULL)||(resp == NULL)) {
		LOG_I("param: NULL\n");
		ret = -1;
		goto error;
	}
        //LOG_I("response:%s\n",response);
	char *pos = strstr(response, "HTTP/");
	if (pos) {
		sscanf(pos, "%*s %d", &resp->status_code); //返回状态码
	} else {
		ret = -2;
		goto error;
	}
		

	pos = strstr(response, "Content-Type:"); //返回内容类型
	if (pos) {
		sscanf(pos, "%*s %s", resp->content_type);
	} else {
		ret = -3;
		goto error;
	}

	pos = strstr(response, "Content-Length:"); //内容的长度(字节)
	if (pos) {
		sscanf(pos, "%*s %ld", &resp->content_length);
	} else {
		ret = -4;
		goto error;
	}

error:	
	return ret;
}

int http_response_debug(http_response_t *resp)
{
	int ret = 0;

	if (resp == NULL) {
		LOG_I("param: NULL\n");
		ret = -1;
		goto error;
	}

	LOG_I("status_code = %d\n", resp->status_code);
	LOG_I("content_type = %s\n", resp->content_type);
	LOG_I("content_length = %ld\n", resp->content_length);

error:	
	return ret;
}

void progress_bar(long cur_size, long total_size)
{
	/*用于显示下载进度条*/
	float percent = cur_size*1.0 / total_size;
	const int numTotal = 50;
	int numShow = (int)(numTotal * percent);

	if (numShow == 0)
		numShow = 1;

	if (numShow > numTotal)
		numShow = numTotal;

	char sign[51] = {0};
	memset(sign, '=', numTotal);

	LOG_I("\r%.2f%%\t[%-*.*s] %ld/%ld", percent * 100, numTotal, numShow, sign, cur_size, total_size);
	fflush(stdout);

	if (numShow == numTotal)
		LOG_I("\n");
}
#if 0
int http_download(int client_socket, char path[256], char file_name[256], http_response_t *http_response)
{
	int length = 0;
	int written_len = 0;
	char receive[2048] = "";
	char path_name[512] = {0};
	int ret = 0;

	if ((path == NULL)||(file_name == NULL)) {
			LOG_I("param: NULL\n");
			ret = -3;
			goto error;
	}
	//创建文件描述符
	snprintf(path_name, sizeof(path_name), "%s/%s", path, file_name);
	int fd = open(path_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXG | S_IRWXO | S_IRWXU);
	if (fd < 0) {
		LOG_I("Create file failed\n");
		ret = -1;
		goto error;
	}

	//从套接字中读取文件流
	while(1) {
		length = read_data_until_time(client_socket, receive, sizeof(receive), 3000, 50);
		if(length < 0){
			LOG_I("read_data_until_str error\n");
			ret = -2;
			goto error;
		}else if(length == 0){
			LOG_I("read_data_until_str end\n");
			break;
		}
		write(fd, receive, length);
		written_len += length;
		progress_bar(written_len, http_response->content_length);
		if(written_len >= http_response->content_length) {
			break;
		}
	}

	if (written_len == http_response->content_length) {
		LOG_I("Download %s successed\n", file_name);
		ret = 0;
	} else {
		LOG_I("Download %s failed\n", file_name);
		ret = -3;
	}
	close(fd);
error:
	return ret;
}

int http_get(const char url[1024], const char path[256], char file_dest[512], int file_dest_len)
{
	char domain[1024] = {0};
	char server_ip[20] = {0};
	int server_port = 80;
	char file_name[256] = {0};
	char request[2048] = {0};
	char response[2048] = {0};
	int length = 0;
	int ret = 0;
	int client_socket;
#if 0
	if ((url == NULL)||(path == NULL)) {
		LOG_I("param: NULL\n");
		ret = -7;
		goto error;
	}
#endif
	http_parse_url(url, domain, &server_port, file_name);
	LOG_I("url:%s\n", url);
	LOG_I("domain:%s\n", domain);
	get_ip_by_domain(domain, server_ip, sizeof(server_ip));
	if(is_ip_legal(server_ip)) {
		ret = -1;
		goto error;
	}
	LOG_I("server_ip:%s, port:%d\n", server_ip, server_port);
	LOG_I("file_name:%s\n", file_name);

	//设置http请求头信息
	length = snprintf(request, sizeof(request),
			"GET %s HTTP/1.1\r\n"
			"User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537(KHTML, like Gecko) Chrome/47.0.2526Safari/537.36\r\n"
			"Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"
			"Host:%s\r\n"
			"Connection:close\r\n"
			"\r\n",
			url, domain);

	client_socket = socket_client_open_connect(server_ip, server_port);	
	if(client_socket < 0){
		close(client_socket);
		ret = -2;
		goto error;
	}

	//发送请求消息
	write(client_socket, request, strlen(request));

	length = read_data_until_str(client_socket, response, sizeof(response), "\r\n\r\n", strlen("\r\n\r\n"), 3000, 50);
	if(length < 0){
		LOG_I("read_data_until_str error\n");
		ret = -3;
		goto error;
	}else if(length == 0){
		LOG_I("read_data_until_str end\n");
		ret = -4;
		goto error;
	}
	//print_buffer("\n>>>>response<<<<\n", response, length);
	//print_buffer_char("\n>>>>response<<<<\n", response, length);
	http_response_t http_response;

	get_http_response(response, &http_response);
	http_response_debug(&http_response);	
#if 0
	if(http_response.status_code == 200) {
		if (file_dest != NULL) {
			memset(file_dest, 0, file_dest_len);
			LOG_I("path:[%s]\n", path);
			LOG_I("file_name:[%s]\n", file_name);
			snprintf(file_dest, file_dest_len, "%s/%s", path, file_name);
		}
		ret = http_down(client_socket, (char *)path, file_name, &http_response);
		if(ret < 0){
			LOG_I("http_down error\n");
			ret = -5;
			goto error;
		}
	} else {
		ret = -6;
		goto error;
	}
#endif
error:	
	return ret;
}

#endif

#define UPLOAD_REQUEST	"--myfengefu\r\n"\
			"Content-Disposition: form-data; name=\"file\"; filename=%s\r\n"\
			"Content-Type: application/octet-stream\r\n\r\n"
#define HTTP_HEAD 	"POST %s HTTP/1.1\r\n"\
			"Host: %s\r\n"\
                        "key: device\r\n"\
                        "nonce: %s\r\n"\
                        "timestamp: %s\r\n"\
                        "sign: %s\r\n"\
			"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)\r\n"\
			"Content-Type: multipart/form-data; boundary=myfengefu\r\n"\
                        "Content-Length: %ld\r\n"\
			"Connection: keep-alive\r\n\r\n"

#define HTTP_HEAD_GETDEVINFO 	"POST %s HTTP/1.1\r\n"\
				"Host: %s\r\n"\
                        	"key: device\r\n"\
                        	"nonce: %s\r\n"\
                        	"timestamp: %s\r\n"\
                        	"sign: %s\r\n"\
				"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)\r\n"\
				"Content-Type: application/json\r\n"\
                        	"Content-Length: %ld\r\n"\
				"Connection: keep-alive\r\n\r\n"
#define HTTP_HEAD_GETDEVINFO_J 	"POST %s HTTP/1.1\r\n"\
                        	"Host: %s\r\n"\
                        	"x-appKey: d577e7b5024ad20446e10\r\n"\
                        	"x-datadigest: %s\r\n"\
				"Content-Type: application/json\r\n"\
                        	"Content-Length: %ld\r\n"\
				"Connection: keep-alive\r\n\r\n"
#define HTTP_HEAD_GETDEVINFO_T 	"POST %s HTTP/1.1\r\n"\
                        	"Host: %s\r\n\r\n"
#define HTTP_HEAD_GETDEVREGISTERSTATUS  "GET %s HTTP/1.1\r\n"\
                                        "Host: %s\r\n"\
                                        "key: device\r\n"\
                                        "nonce: %s\r\n"\
                                        "timestamp: %s\r\n"\
                                        "sign: %s\r\n"\
                                        "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)\r\n"\
                                        "Content-Type: application/json\r\n"\
                                        "Content-Length: %ld\r\n"\
                                        "Connection: keep-alive\r\n\r\n"
unsigned long get_file_size(const char *path) 
{    
    unsigned long filesize = -1;        
    struct stat statbuff;    
    if(stat(path, &statbuff) < 0){    
        return filesize;    
    }else{    
        filesize = statbuff.st_size;    
    }    
    return filesize;    
}   

void get_rand_str(char s[],int num)
{
    //定义随机生成字符串表
    char *str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    int i,lstr;
    char ss[2] = {0};
    lstr = strlen(str);//计算字符串长度
    srand((unsigned int)time((time_t *)NULL));//使用系统时间来初始化随机数发生器
    for(i = 1; i <= num; i++){//按指定大小返回相应的字符串
        sprintf(ss,"%c",str[(rand()%lstr)]);//rand()%lstr 可随机返回0-71之间的整数, str[0-71]可随机得到其中的字符
        strcat(s,ss);//将随机生成的字符串连接到指定数组后面
    }
}

int http_post_uploadlog(char *url, char *msg_id,char *logfilename)
{
    char domain[1024] = {0};
    char server_ip[20] = {0};
    int server_port = 80;
    char file_name[256] = {0};
    char response[2048] = {0};
    char fileurl[2048] = {0};
    int sendsuccess = 0;
    int length = 0;
    int ret = 0;
    int client_socket;
    int readbyte=0;

    unsigned char header[1024]={0}; 
    unsigned char send_request[1024]={0};
    unsigned char send_end[1024]={0};
    unsigned char http_boundary[64]={0};
    unsigned char nonce[32]={0};
    unsigned char timestamp[64]={0};
    unsigned char sign[256]={0};
    unsigned char signtmp[256]={0};
    get_rand_str(nonce,6);
    //LOG_I("nonce:%s\n",nonce);
    struct timeval begin;
    gettimeofday(&begin,NULL);
    long long beginTime = (long long)begin.tv_sec * 1000 + (long long)begin.tv_usec / 1000;
    sprintf(timestamp,"%lld",beginTime);
    //LOG_I("timestamp:%s\n",timestamp);

    snprintf(signtmp, sizeof(sign), "device|%s|%s|wdewdilpvy",nonce,timestamp);
    //LOG_I("signtmp:%s\n",signtmp);
    get_md5_from_string(sign, sizeof(sign), signtmp, strlen(signtmp));
    //LOG_I("sign:%s\n",sign);
#if 0
	if ((url == NULL)||(path == NULL)) {
		LOG_I("param: NULL\n");
		ret = -7;
		goto error;
	}
#endif
    //LOG_I("POST\n");
    http_parse_url(url, domain, &server_port, file_name);
    //LOG_I("url:%s\n", url);
    //LOG_I("domain:%s\n", domain);
    get_ip_by_domain(domain, server_ip, sizeof(server_ip));
    if(is_ip_legal(server_ip)) {
	ret = -1;
	goto error;
    }
    //LOG_I("server_ip:%s, port:%d\n", server_ip, server_port);
    //LOG_I("file_name:%s\n", file_name);
    unsigned long totalsize = 0;
    unsigned long filesize = get_file_size(logfilename); //文件大小
    unsigned long request_len = snprintf(send_request,1024,UPLOAD_REQUEST,logfilename); //请求信息
    unsigned long end_len = snprintf(send_end,1024,"\r\n--myfengefu--\r\n"); //结束信息
    totalsize = filesize + request_len + end_len;
 
    //unsigned long head_len = snprintf(header,1024,HTTP_HEAD,"/open/api/device/log/upload",domain,nonce,timestamp,sign,totalsize); //头信息
    unsigned long head_len = snprintf(header,1024,HTTP_HEAD,url,domain,nonce,timestamp,sign,totalsize); //头信息
    totalsize += head_len;
    //LOG_I("filesize:%d,request_len:%d,end_len:%d,head_len:%d,totalsize:%d\n",filesize,request_len,end_len,head_len,totalsize);
 
    char* request = (char*)malloc(totalsize);	//申请内存用于存放要发送的数据
    if (request == NULL){  
        printf("malloc request fail !\r\n");  
        return -1;  
    }  
    request[0] = '\0';
 
    strcat(request,header); 	//http头信息
    strcat(request,send_request);	//文件请求信息
    FILE* fp = fopen(logfilename, "rb+");//打开要上传的文件
    if (fp == NULL){  
        LOG_I("open file fail!\r\n");  
        return -1;  
    }
    readbyte = fread(request+head_len+request_len, 1, filesize, fp);//读取上传的文件信息
    LOG_I("logfile %s size:%d\n",logfilename,readbyte);

    memcpy(request+head_len+request_len+filesize,send_end,end_len);  //http结束信息
    //LOG_I("request:%s\n",request);

    client_socket = socket_client_open_connect(server_ip, server_port);	
    if(client_socket < 0){
        close(client_socket);
        ret = -2;
        goto error;
    }

    if(write(client_socket, request, totalsize)==-1){
        LOG_I("write fail\r\n");
    }

    if((readbyte = read(client_socket,response,2048))==-1){  
       LOG_I("read http ACK fail !\r\n");  
       return -1;  
    }  
    //LOG_I("ACK readbyte:%d\n",readbyte);
    response[readbyte]='\0';
    //LOG_I("response:%s\n",response);
    int index = 0,start_flag = 0;
    int ack_json_len = 0;
    char ack_json[256]={0};
    for(index = 0; index<readbyte; index++){
        if(response[index] == '{'){
	    start_flag = 1;
        }
        if(start_flag)
	    ack_json[ack_json_len++] = response[index];  //遇到左大括号则开始拷贝
    }
    //LOG_I("Receive:%s\n",ack_json);
    if(ack_json_len > 0){
        get_string_from_json_string_by_key_unescape(ack_json, "data", fileurl, sizeof(fileurl));
        //LOG_I("data:%s\n",fileurl);
        get_int_from_json_string_by_key(ack_json, "code", &sendsuccess);
        //LOG_I("code:%d\n",sendsuccess);
    }else{
        ack_json[0] = '\0';
        LOG_I("Receive http ACK fail!!\n");
        //LOG_I("--- ack_json_len = %d\n",ack_json_len);
    }
error:	
	return ret;
}

int http_get_getdevregisterstatus(char *url)
{
    char domain[1024] = {0};
    char server_ip[20] = {0};
    int server_port = 80;
    char file_name[256] = {0};
    char response[3072] = {0};
    int sendsuccess = 0;
    int length = 0;
    int ret = 0;
    int client_socket;
    int readbyte=0;

    unsigned char header[1024]={0};
    unsigned char send_request[1024]={0};
    unsigned char send_end[1024]={0};
    unsigned char http_boundary[64]={0};
    unsigned char nonce[32]={0};
    unsigned char timestamp[64]={0};
    unsigned char sign[256]={0};
    unsigned char signtmp[256]={0};
    get_rand_str(nonce,6);
    //LOG_I("nonce:%s\n",nonce);
    struct timeval begin;
    gettimeofday(&begin,NULL);
    long long beginTime = (long long)begin.tv_sec * 1000 + (long long)begin.tv_usec / 1000;
    sprintf(timestamp,"%lld",beginTime);
    //LOG_I("timestamp:%s\n",timestamp);

    snprintf(signtmp, sizeof(sign), "device|%s|%s|wdewdilpvy",nonce,timestamp);
    //LOG_I("signtmp:%s\n",signtmp);
    get_md5_from_string(sign, sizeof(sign), signtmp, strlen(signtmp));
    http_parse_url(url, domain, &server_port, file_name);
    //LOG_I("url:%s\n", url);
    //LOG_I("domain:%s\n", domain);
    get_ip_by_domain(domain, server_ip, sizeof(server_ip));
    if(is_ip_legal(server_ip)) {
        ret = -1;
        goto error;
    }
    //LOG_I("server_ip:%s, port:%d\n", server_ip, server_port);
    //LOG_I("json code:%s\n",devcode);

    unsigned long totalsize = 0;
    unsigned long head_len = snprintf(header,1024,HTTP_HEAD_GETDEVREGISTERSTATUS,url,domain,nonce,timestamp,sign,totalsize); //头信息
    totalsize+=head_len;

    char* request = (char*)malloc(totalsize);   //申请内存用于存放要发送的数据
    if (request == NULL){
        printf("malloc request fail !\r\n");
        ret= -1;
        goto error;
    }
    request[0] = '\0';

    memcpy(request,header,head_len);  //http结束信息
    //LOG_I("request:%s\n",request);

    client_socket = socket_client_open_connect(server_ip, server_port);
    if(client_socket < 0){
        close(client_socket);
        ret = -2;
        goto error;
    }

    if(write(client_socket, request, strlen(request))==-1){
        LOG_I("write fail\r\n");
    }
    if((readbyte = read(client_socket,response,4096))==-1){
       LOG_I("read http ACK fail !\r\n");
       ret= -1;
       goto error;
    }
    //LOG_I("ACK readbyte:%d\n",readbyte);
    response[readbyte]='\0';
    //LOG_I("response:%s\n",response);
#if 1
    int index = 0,start_flag = 0;
    int count=0;
    int ack_json_len = 0;
    int ack_json_tmplen = 0;
    char ack_tmpjson[3072]={0};
    char ack_json[3072]={0};
    for(index = 0; index<readbyte; index++){
        if(response[index] == '{'){
            start_flag = 1;
        }
        if(start_flag)
            ack_tmpjson[ack_json_tmplen++] = response[index];  //遇到左大括号则开始拷贝
    }
    //LOG_I("ack_json_tmplen:%d,ack_tmpjson:%s\n",ack_json_tmplen,ack_tmpjson);
    start_flag=0;

    for(index = 0; index<ack_json_tmplen; index++){
        if(ack_tmpjson[index] == '{'){
            count++;
            if(ack_json_len>2){
                break;
            }
            if(count>=2){
                start_flag = 1;
            }
        }
        if(start_flag)
            ack_json[ack_json_len++] = ack_tmpjson[index];  //遇到左大括号则开始拷贝
    }

    ack_json[ack_json_len]='"';
    ack_json[ack_json_len+1]='}';
    //LOG_I("Receive len:%d\n",ack_json_len);
    //LOG_I("Receive :%s\n",ack_json);
    //LOG_I("Receive :%s\n",ack_json+1650);

    if(ack_json_len > 0){
        //LOG_I("deviceSecret:%s\n",deviceSecrets);
    }else{
        ack_json[0] = '\0';
            LOG_I("Receive http ACK fail!!\n");
        //LOG_I("--- ack_json_len = %d\n",ack_json_len);
        ret=-1;
        goto error;
    }
#endif
    error:
        return ret;
}

int http_post_getdevinfo(char *url, char *devcodetmp,char *devcode)
{
    char domain[1024] = {0};
    char server_ip[20] = {0};
    int server_port = 80;
    char file_name[256] = {0};
    char response[2048] = {0};
    char tmpdata[2048] = {0};
    char jsondata[2048] = {0};
    int sendsuccess = 0;
    int length = 0;
    int ret = 0;
    int client_socket;
    int readbyte=0;

    unsigned char header[1024]={0};
    unsigned char send_request[1024]={0};
    unsigned char send_end[1024]={0};
    unsigned char http_boundary[64]={0};
    unsigned char nonce[32]={0};
    unsigned char timestamp[64]={0};
    char signbase64[256]={0};
    char signtmp[256]={0};
    get_rand_str(nonce,6);
    //LOG_I("nonce:%s\n",nonce);
    struct timeval begin;
    gettimeofday(&begin,NULL);
    long long beginTime = (long long)begin.tv_sec * 1000 + (long long)begin.tv_usec / 1000;
    sprintf(timestamp,"%lld",beginTime);
    //LOG_I("timestamp:%s\n",timestamp);
    strcpy(signtmp,devcodetmp);
    strcat(signtmp,"0e8e9457d493666ee2f5adb783e69abb");
    //strcpy(signtmp,"0e8e9457d493666ee2f5adb783e69abb");
    
    LOG_I("signtmp:%s\n",signtmp);
    get_base64_md5_from_string(signbase64, sizeof(signbase64), signtmp, strlen(signtmp));
    LOG_I("signbase64:%s\n",signbase64);
    sprintf(send_request,"curl -X POST -H 'x-appKey:d577e7b5024ad20446e10' -H 'x-datadigest:%s' -H 'Content-Type: application/json' -d '%s' %s",signbase64,devcodetmp,url);
    LOG_I("send_request:%s\n",send_request);
    //system(send_request);

    FILE *fp;
    char buffer[128];
    fp=popen(send_request,"r");
    fgets(buffer,sizeof(buffer),fp);
    get_string_from_json_string_by_key_unescape(buffer, "message", tmpdata, sizeof(tmpdata));
    LOG_I("hyx %s\n",tmpdata);
#if 0
    http_parse_url(url, domain, &server_port, file_name);
    LOG_I("url:%s\n", url);
    LOG_I("domain:%s\n", domain);
    get_ip_by_domain(domain, server_ip, sizeof(server_ip));
    if(is_ip_legal(server_ip)) {
        playAudio(SND_DEVSNGETFAIL);
        ret = -1;
        goto error;
    }
    LOG_I("server_ip:%s, port:%d\n", server_ip, server_port);
    LOG_I("json code:%s\n",devcode);

    unsigned long totalsize = 0;
    unsigned long jsonsize = strlen(devcode);
    totalsize = jsonsize;
    LOG_I("totalsize1:%d\n",totalsize);
    unsigned long head_len = snprintf(header,1024,HTTP_HEAD_GETDEVINFO_J,"/device/modifyRegisterInfo",domain,signbase64); //头信息
    totalsize += head_len;
    LOG_I("totalsize2:%d\n",totalsize);

    char* request = (char*)malloc(totalsize);   //申请内存用于存放要发送的数据
    if (request == NULL){
        printf("malloc request fail !\r\n");
        ret= -1;
        goto error;
    }
    request[0] = '\0';

    memcpy(request,header,head_len);  //http结束信息
    memcpy(request+head_len,devcode,jsonsize);  //http结束信息
    LOG_I("request:%s\n",request);

    client_socket = socket_client_open_connect(server_ip, server_port);
    if(client_socket < 0){
        LOG_I("socket error\r\n");
        close(client_socket);
        //playAudio(SND_DEVSNGETFAIL);
        ret = -2;
        goto error;
    }

    if(write(client_socket, request, strlen(request))==-1){
        LOG_I("write fail\r\n");
    }

    if((readbyte = read(client_socket,response,2048))==-1){
       LOG_I("read http ACK fail !\r\n");
       //playAudio(SND_DEVSNGETFAIL);
       ret= -1;
       goto error;
    }
    LOG_I("ACK readbyte:%d\n",readbyte);
    response[readbyte]='\0';
    LOG_I("response:%s\n",response);
#if 1
    int index = 0,start_flag = 0;
    int ack_json_len = 0;
    char ack_json[512]={0};
    for(index = 0; index<readbyte; index++){
        if(response[index] == '{'){
            start_flag = 1;
        }
        if(start_flag)
            ack_json[ack_json_len++] = response[index];  //遇到左大括号则开始拷贝
        //if(response[index] == '}'){
        //    ack_json[ack_json_len] = '\0';
        //    break;
        //}
    }
    //LOG_I("Receive:%s\n",ack_json);
    if(ack_json_len > 0){
        get_string_from_json_string_by_key_unescape(ack_json, "data", tmpdata, sizeof(tmpdata));
        snprintf(jsondata, sizeof(jsondata), "{%s}", tmpdata);
        //LOG_I("jsondata:%s\n",jsondata);
        memset(devOwnSn,0,64);   
        get_string_from_json_string_by_key_unescape(jsondata, "devOwnSn", devOwnSn, sizeof(devOwnSn));
        LOG_I("devOwnSn:%s\n",devOwnSn);
        if(strcmp(devOwnSn,"")!=0){
            memset(devOwnSn_save,0,64);   
            strcpy(devOwnSn_save,devOwnSn);
            LOG_I("devOwnSn_save:%s\n",devOwnSn_save);
            if(!hgz_judge_sn_exist_devin(devOwnSn_save)){
                if(optBatchIn){
                    openDoorWaited=false;
                    playAudio(SND_SCANSUCCESS);
                }else{
                    int len=0;
                    char *result=NULL;
                    result=file_to_buffer(devOwnSn,&len);
                    if(result==NULL){
                        //LOG_I("devOwnSn file not exist\n");
                        char openCell[4]={0};
                        if(hgz_judge_sn_exist_devout(devOwnSn_save,openCell)){
                            playAudio(SND_SCANSUCCESS);
                            returnDevs_multy(openCell);
                        }else{
                            LOG_I("dev not in\n");
                            //playAudio(SND_DEVNOTBORROWED);
                        }
                    }else{
                        //LOG_I("devOwnSn file exist:%s\n",result);
                        playAudio(SND_SCANSUCCESS);
                        repairReturnDevs_multy(result);
                    }
                }
            }else{
                playAudio(SND_DEVSNALREADYEXIST);
            }
        }else{
            playAudio(SND_DEVSNGETFAIL);
        }
        //get_string_from_json_string_by_key_unescape(jsondata, "devPro", devPRO, sizeof(devPRO));
        //LOG_I("devPro:%s\n",devPRO);
        //get_string_from_json_string_by_key_unescape(jsondata, "devMfg", devMFG, sizeof(devMFG));
        //LOG_I("devMfg:%s\n",devMFG);
    }else{
        ack_json[0] = '\0';
        LOG_I("Receive http ACK fail!!\n");
        //LOG_I("--- ack_json_len = %d\n",ack_json_len);
        //playAudio(SND_DEVSNGETFAIL);
        ret=-1;
        goto error;
    }
#endif
#endif
    error:
        return ret;
}

int http_download(char *url, char *msg_id,int task_id,char *filepath)
{
    int length = 0;
    int written_len = 0;
    char receive[2048] = "";
    char path_name[512] = {0};
    int ret = 0;
    char domain[1024] = {0};
    char server_ip[20] = {0};
    int server_port = 80;
    int client_socket;
    char request[2048] = {0};
    char response[2048] = {0};
    char file_name[256] = {0};
    //创建文件描述符
    int fd = open(filepath, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXG | S_IRWXO | S_IRWXU);
    if (fd < 0) {
        LOG_I("Create file failed\n");
        ret = -1;
        goto error;
    }

    sscanf(url, "%*[^//]//%[^/]%s", domain, file_name);

    LOG_I("msgid:%s\n", msg_id);
    LOG_I("taskid:%d\n", task_id);
    LOG_I("filepath:%s\n", filepath);
    LOG_I("url:%s\n", url);
    LOG_I("domain:%s\n", domain);
    LOG_I("file_name:%s\n", file_name);
    get_ip_by_domain(domain, server_ip, sizeof(server_ip));
    LOG_I("server_ip:%s\n",server_ip);
    if(is_ip_legal(server_ip)) {
        ret = -1;
        goto error;
    }
    //设置http请求头信息
    length = snprintf(request, sizeof(request),
        "GET %s HTTP/1.1\r\n"
        "HOST: %s\r\n"
	"Cache-Control: no-cache\r\n"
	"Connection: close\r\n\r\n",
        file_name, domain);

    client_socket = socket_client_open_connect(server_ip, server_port);     
    if(client_socket < 0){
        close(client_socket);
        ret = -2;
        goto error;
    }

    //发送请求消息
    write(client_socket, request, strlen(request));

    length = read_data_until_str(client_socket, response, sizeof(response), "\r\n\r\n", strlen("\r\n\r\n"), 3000, 50);
    if(length < 0){
        LOG_I("read_data_until_str error\n");
        ret = -3;
        goto error;
    }else if(length == 0){
        LOG_I("read_data_until_str end\n");
        ret = -4;
        goto error;
    }

    http_response_t http_response;

    get_http_response(response, &http_response);
    http_response_debug(&http_response);    

    if(http_response.status_code == 200){
        while(1) {
            length = read_data_until_time(client_socket, receive, sizeof(receive), 3000, 50);
            if(length < 0){
                LOG_I("read_data_until_str error\n");
                ret = -2;
                goto error;
            }else if(length == 0){
                LOG_I("read_data_until_str end\n");
                break;
            }
            write(fd, receive, length);
            written_len += length;
            //progress_bar(written_len, http_response.content_length);
            if(written_len >= http_response.content_length) {
                break;
            }
        }

        if (written_len == http_response.content_length) {
            LOG_I("Download %s successed\n", file_name);
            sleep(2);
            //newappDownloaded=true;
            ret = 0;
        } else {
            LOG_I("Download %s failed\n", file_name);
            ret = -3;
        }
    }else{
        LOG_I("code not 200\n");
    }
     
    close(fd);
error:
    return ret;
}
