socket

#include "httpsocket.h"
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <sys/select.h>
#include <time.h>
#include <errno.h>
#include "mtcota_toolkit.h"
#include "mtcota_interface.h"

#define SOCK_IO_TIMOUT_SECONDS (10) // 收发数据超时秒数

typedef struct
{
int m_nSocket;
char m_acURL[MTC_OTA_512B_SIZE];
char m_acHost[MTC_OTA_32B_SIZE];
unsigned short m_usPort;
int status_code;//HTTP/1.1 '200' OK
char content_type[MTC_OTA_128B_SIZE];//Content-Type: application/gzip
unsigned int content_length;//Content-Length: 11683079
}HttpDLInfo_S;

static int httpParseURL(const char *url, char *host, char *ip, unsigned int *port, char *resource_path)
{
/*通过url解析出域名, 端口, 以及文件名*/
unsigned int i = 0;
int j = 0;
int start = 0;
*port = 80;
char patterns[2][16] = {"http://", "https://"};
struct hostent *sthost = 0;
char hostname[MTC_OTA_128B_SIZE] = {0};

memset(hostname, 0, sizeof(hostname));

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

//解析域名, 这里处理时域名后面的端口号会保留
for (i = start; url[i] != '/' && url[i] != '\0'; i++, j++)
{
host[j] = url[i];
}
host[j] = '\0';

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

strcpy(hostname, host);

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

sthost = gethostbyname(hostname);
if (0 == sthost)
{
ip = NULL;
DbgTrack("gethostbyname hostname:%s is NULL\r\n", hostname);
return -1;
}

for (i = 0; sthost->h_addr_list[i]; i++)
{
strcpy(ip, inet_ntoa( * (struct in_addr*) sthost->h_addr_list[i]));
break;
}

// 获取下载路径
j = 0;
for (i = start; url[i] != '\0'; i++)
{
if (url[i] == '/')
{
strcpy(resource_path, &url[i]);
break;
}
}

return 0;
}

static int httpSocketInit(const char * pcURL, HttpDLInfo_S * pstHttpInfo)
{
struct sockaddr_in serAddr;
int nRt = -1;
int nSocket = -1;
char domain[MTC_OTA_32B_SIZE] = {0};
char ip_addr[MTC_OTA_32B_SIZE] = {0};
unsigned int port = 80;
char resource_path[MTC_OTA_512B_SIZE] = {0};
struct timeval tv_timeout = {0,0};

do
{
nRt = httpParseURL(pcURL, domain, ip_addr, &port, resource_path);
if (nRt != 0)
{
DbgTrack("[%s %d] parse url error! \n", __FUNCTION__, __LINE__);
nRt = -1;
break;
}

DbgTrack("[%s %d]pcURL:[%s]\n", __FUNCTION__, __LINE__, pcURL);
DbgTrack("[%s %d]ip_addr:[%s]\n", __FUNCTION__, __LINE__, ip_addr);
DbgTrack("[%s %d]domain:%s\n", __FUNCTION__, __LINE__, domain);
DbgTrack("[%s %d]port:%d\n", __FUNCTION__, __LINE__, port);
DbgTrack("[%s %d]resource_path:%s\n", __FUNCTION__, __LINE__, resource_path);

nSocket = socket(AF_INET, SOCK_STREAM, 0);
if(nSocket < 0)
{
DbgTrack("[%s %d]nSocket:%d ERROR!!!!!\n", __FUNCTION__, __LINE__, nSocket);
nRt = -4;
break;
}

serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(port);
serAddr.sin_addr.s_addr = inet_addr(ip_addr);

tv_timeout.tv_sec = SOCK_IO_TIMOUT_SECONDS;
tv_timeout.tv_usec = 0;

setsockopt(nSocket, SOL_SOCKET, SO_SNDTIMEO, &tv_timeout, sizeof(tv_timeout)); // send timeout
setsockopt(nSocket, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(tv_timeout)); // recv timeout

DbgTrack("[%s %d]connect tick:%lu >>> \n", __FUNCTION__, __LINE__, MTCOSGetTickCount());
nRt = connect(nSocket, (struct sockaddr * )&serAddr, sizeof(serAddr));
DbgTrack("[%s %d]connect nRt:%d tick:%lu<<< \n", __FUNCTION__, __LINE__, nRt, MTCOSGetTickCount());
if (nRt < 0 )
{
nRt = -4;
break;
}

pstHttpInfo->m_nSocket= nSocket;
pstHttpInfo->m_usPort = port;
strcpy(pstHttpInfo->m_acHost, domain);
strcpy(pstHttpInfo->m_acURL, resource_path);

nRt = 0;

}while(0);

DbgTrack("[%s %d]nRt:%d\n", __FUNCTION__, __LINE__, nRt);

return nRt;
}

static int httpSocketTerm(int nSocket)
{
if(nSocket > 0)
{
close(nSocket);
DbgTrack("[%s %d]close nSocket:%d \n", __FUNCTION__, __LINE__, nSocket);
}

return 0;
}

static int httpSendRequest2Server_GET(HttpDLInfo_S * pstHttpInfo)
{
int nRst = -1;
char *pcHttpHead = 0;

do
{
pcHttpHead = malloc(MTC_OTA_1K_SIZE);
if(pcHttpHead == 0)
{
DbgTrack("[%s %d]pcHttpHead malloc MTC_OTA_1K_SIZE failed\n", __FUNCTION__, __LINE__);
break;
}

memset(pcHttpHead, 0, MTC_OTA_1K_SIZE);

strcat(pcHttpHead, "GET ");
strcat(pcHttpHead, pstHttpInfo->m_acURL);
strcat(pcHttpHead, " HTTP/1.1\r\n");
strcat(pcHttpHead, "Accept: */*\r\n");
strcat(pcHttpHead, "Accept-Language: cn\r\n");
strcat(pcHttpHead, "User-Agent: Mozilla/4.0\r\n");
strcat(pcHttpHead, "Host: ");
strcat(pcHttpHead, pstHttpInfo->m_acHost);
strcat(pcHttpHead, "\r\n");
strcat(pcHttpHead, "Cache-Control: no-cache\r\n");
strcat(pcHttpHead, "Connection: Keep-Alive\r\n");
strcat(pcHttpHead, "\r\n");

DbgTrack("[%s %d]GET_cmd: \n<%s> \n", __FUNCTION__, __LINE__,pcHttpHead);

//2发送数据
if ( send(pstHttpInfo->m_nSocket, pcHttpHead, strlen(pcHttpHead), 0) == -1)
{
nRst = -2;
break;
}

nRst = 0;

}while(0);

if(0 != pcHttpHead)
{
free(pcHttpHead);
}

return nRst;
}

static int httpSendRequest2Server_POST(const char *pcBody, HttpDLInfo_S * pstHttpInfo)
{
int nRst = -1;
char *pcHttpHead = 0;
unsigned int len = 0;
char cContentLen[MTC_OTA_32B_SIZE] = {0};

len = strlen(pcBody);

do
{
pcHttpHead = malloc(MTC_OTA_1K_SIZE);
if(pcHttpHead == 0)
{
DbgTrack("[%s %d]pcHttpHead malloc MTC_OTA_1K_SIZE failed\n", __FUNCTION__, __LINE__);
break;
}

memset(pcHttpHead, 0, MTC_OTA_1K_SIZE);

sprintf(cContentLen, "Content-Length: %d\r\n", len);

strcat(pcHttpHead, "POST ");
strcat(pcHttpHead, pstHttpInfo->m_acURL);
strcat(pcHttpHead, " HTTP/1.1\r\n");
strcat(pcHttpHead, "Accept: */*\r\n");
strcat(pcHttpHead, "Accept-Language: cn\r\n");
strcat(pcHttpHead, cContentLen);
strcat(pcHttpHead, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(pcHttpHead, "User-Agent: Mozilla/4.0\r\n");
strcat(pcHttpHead, "Host: ");
strcat(pcHttpHead, pstHttpInfo->m_acHost);
strcat(pcHttpHead, "\r\n");
strcat(pcHttpHead, "Cache-Control: no-cache\r\n");
strcat(pcHttpHead, "Connection: Keep-Alive\r\n");
strcat(pcHttpHead, "\r\n");
strcat(pcHttpHead, pcBody);

DbgTrack("[%s %d]POST_cmd: \n<%s> \n", __FUNCTION__, __LINE__,pcHttpHead);

//2发送数据
if ( send(pstHttpInfo->m_nSocket, pcHttpHead, strlen(pcHttpHead), 0) == -1)
{
nRst = -2;
break;
}

nRst = 0;

}while(0);

if(0 != pcHttpHead)
{
free(pcHttpHead);
}

return nRst;
}

static int httpGetRespHeaderInfo(char *response, HttpDLInfo_S * pstHttpInfo)
{
char *pos = 0;

pos = strstr(response, "HTTP/");
if (0 != pos)
{
sscanf(pos, "%*s %d", &pstHttpInfo->status_code);//返回状态码
}

pos = strstr(response, "Content-Type:");//返回内容类型
if (0 != pos)
{
sscanf(pos, "%*s %s", pstHttpInfo->content_type);
}

pos = strstr(response, "Content-Length:");//内容的长度(字节)
if (0 != pos)
{
sscanf(pos, "%*s %u", &pstHttpInfo->content_length);
}

return 0;
}

static int httpReceiveDataFromServer(HttpDLInfo_S * pstHttpInfo, unsigned char **ppucResponse, unsigned int *punResponseSize, DLProgressCallback fnProgress)
{
int nRst = -1;
int length = 0;
int len = 0;
char *buf = (char *) malloc(MTC_OTA_4K_SIZE);
char *response = (char *) malloc(MTC_OTA_4K_SIZE);
unsigned char *pucHttpContent = 0;
int flag = 0;
int i = 0;

do
{
if((buf == 0) || (response == 0))
{
DbgTrack("[]buf:%p response:%p ERROR\n", buf, response);
nRst = -1;
break;
}

// 必须清空数据,否则概率问题
memset(buf, 0, MTC_OTA_4K_SIZE);
memset(response, 0, MTC_OTA_4K_SIZE);

// download http head
length = 0;
while (1)
{
len = recv(pstHttpInfo->m_nSocket, buf, 1,0);
if(len <= 0)
{
DbgTrack("recv len:%d ERROR\n", len);
nRst = -1;
break;
}

if (length + len > MTC_OTA_4K_SIZE)
{
DbgTrack("head overflow failed\n");
nRst = -1;
break;
}

buf[len] = '\0';
strcat(response, buf);

length += len;

//找到响应头的头部信息, 两个"\r\n"为分割点
if(length > 4)
{
if((response[length-4] =='\r')&&(response[length-3] =='\n')&&(response[length-2] =='\r')&&(response[length-1] =='\n'))
{
DbgTrack("head get finish 00--00 length:%d\n", length);
nRst = 0;
break;
}
}
}

if(0 != nRst)
{
DbgTrack("Head get failed nRst:%d ERROR\n", nRst);
nRst = -1;
break;
}

DbgTrack("\n>>>>Response header length:%d:<<<<\n<%s>\n", length, response);
httpGetRespHeaderInfo(response, pstHttpInfo);
DbgTrack("pstHttpInfo->status_code:%d \n", pstHttpInfo->status_code);
DbgTrack("pstHttpInfo->content_type:%s \n", pstHttpInfo->content_type);
DbgTrack("pstHttpInfo->content_length:%d \n", pstHttpInfo->content_length);

if(0 == pstHttpInfo->content_length)
{
DbgTrack("pstHttpInfo->content_length == 0 ERROR\n");
nRst = -1;
break;
}

if(200 != pstHttpInfo->status_code)
{
DbgTrack("pstHttpInfo->status_code:%d ERROR\n", pstHttpInfo->status_code);
nRst = -1;
break;
}

// download file content
pucHttpContent = (unsigned char *)malloc((pstHttpInfo->content_length + 16 +0xf)&(~0xf));
if(0 == pucHttpContent)
{
break;
}

memset(pucHttpContent, 0, ((pstHttpInfo->content_length + 16 +0xf)&(~0xf)));

length = 0;
while(1)
{
len = recv(pstHttpInfo->m_nSocket, buf, 4096,0);
if(len <= 0)
{
DbgTrack("recv len:%d ERROR\n", len);
nRst = -1;
break;
}

if((length+len) <= pstHttpInfo->content_length)
{
memcpy(&pucHttpContent[length], buf, len);
}

length += len;

if(0 != fnProgress)
{
fnProgress(length, pstHttpInfo->content_length);
}

if(length >= pstHttpInfo->content_length)
{
if(length == pstHttpInfo->content_length)
{
nRst = 0;
}
else
{
nRst = -1;
}
break;
}
}

}while(0);

DbgTrack("[%s %d]OVER length:%u, pstHttpInfo.content_length:%u nRst:%d \n",__FUNCTION__, __LINE__, length, pstHttpInfo->content_length, nRst);

if(0 != response)
{
free(response);
}

if(0 != buf)
{
free(buf);
}

if(0==nRst)
{
*punResponseSize = pstHttpInfo->content_length;
*ppucResponse = pucHttpContent;
}
else
{
*punResponseSize = 0;
*ppucResponse = 0;
if(0 != pucHttpContent)
{
free(pucHttpContent);
pucHttpContent = 0;

}
}

return nRst;
}

int HttpGET(const char * pcURL, unsigned char **ppucResponse, unsigned int *punResponseSize, DLProgressCallback fnProgress)
{
int nRst = 0;
HttpDLInfo_S stHttpInfo;

memset(&stHttpInfo, 0, sizeof(stHttpInfo));
stHttpInfo.m_nSocket = -1;
stHttpInfo.m_usPort = 0;

do
{
// 1. init socket
nRst = httpSocketInit(pcURL, &stHttpInfo);
DbgTrack("[%s %d]httpSocketInit nSocket:%d, nRst:%d\n", __FUNCTION__, __LINE__, stHttpInfo.m_nSocket, nRst);
if(0 != nRst)
{
nRst = -1;
break;
}

// 2. send request
nRst = httpSendRequest2Server_GET(&stHttpInfo);
DbgTrack("[%s %d]httpSendRequest2Server_GET nSocket:%d, nRst:%d\n", __FUNCTION__, __LINE__, stHttpInfo.m_nSocket, nRst);
if(0 != nRst)
{
nRst = -1;
break;
}

// 3. download file
nRst = httpReceiveDataFromServer(&stHttpInfo, ppucResponse, punResponseSize, fnProgress);
if(0 != nRst)
{
nRst = -1;
break;
}

nRst = 0;
}while(0);

// 4. close socket
httpSocketTerm(stHttpInfo.m_nSocket);

DbgTrack("[%s %d]nRst:%d \n", __FUNCTION__, __LINE__, nRst);

return nRst;
}

int HttpPOST(const char * pcURL, const char *pcBody, unsigned char **ppucResponse, unsigned int *punResponseSize)
{
int nRst = 0;
HttpDLInfo_S stHttpInfo;

memset(&stHttpInfo, 0, sizeof(stHttpInfo));
stHttpInfo.m_nSocket = -1;
stHttpInfo.m_usPort = 0;

do
{
// 1. init socket
nRst = httpSocketInit(pcURL, &stHttpInfo);
DbgTrack("[%s %d]httpSocketInit nSocket:%d, nRst:%d\n", __FUNCTION__, __LINE__, stHttpInfo.m_nSocket, nRst);
if(0 != nRst)
{
nRst = -1;
break;
}

// 2. send request
nRst = httpSendRequest2Server_POST(pcBody, &stHttpInfo);
DbgTrack("[%s %d]httpSendRequest2Server_POST nSocket:%d, nRst:%d\n", __FUNCTION__, __LINE__, stHttpInfo.m_nSocket, nRst);
if(0 != nRst)
{
nRst = -1;
break;
}

// 3. get response
nRst = httpReceiveDataFromServer(&stHttpInfo, ppucResponse, punResponseSize, 0);
if(0 != nRst)
{
nRst = -1;
break;
}

nRst = 0;
}while(0);

// 4. close socket
httpSocketTerm(stHttpInfo.m_nSocket);

DbgTrack("[%s %d]nRst:%d \n", __FUNCTION__, __LINE__, nRst);

return nRst;
}

 

posted on 2020-04-17 09:21  baicailong  阅读(173)  评论(0)    收藏  举报

导航