http以及https請求的連接過程

這個過程是解析http跟https協議時請求的過程,已經獲取數據的過程。


#define HTTP_COMMON_TIMEOUT 15000
BOOL HTTP_DoRequestFunc(char *pcUrl, char *pcRequest,
		BOOL (* ParseContent)(char *pcSrc, int iSrcLen, void *pcDst,
				void *pvDstLoc, char *pcReserve, int *piReserveLen, int iTimes, int iRequestType),
		void *pvDstData, int *psk, E_NET_APP_REQUEST_TYPE eRequestType)
{
	BOOL bRet = FALSE;
	int iSockFileDescrip = -1;
	char *pcLoc;
	int iNum;
	int iRemainderLen;
	char *pcBuff;
	char acHostAddr[128] = {0};
	char acFileAddr[1024] = {0};
	unsigned int uiPort;
	int iBuffSize = 16 * 1024;//10 * 1024;
	APPLICATION_LAYER_PROTOCOL_TYPE eProtocolType;
	int iRequestLen;
	unsigned long ulIP = 0;
	struct sockaddr_in stServerAddr;
	SSL *ssl = NULL;
	SSL_CTX *ctx = NULL;
	int iSSL_Ret = 0;

	eProtocolType = parse_url(pcUrl, acHostAddr, acFileAddr, &uiPort);
	if (pcRequest == NULL || eProtocolType == P_INVALID)
	{
		printf("[%s %d] Invalid request. \n", __FUNCTION__, __LINE__);
		return FALSE;
	}
	iRequestLen = strlen(pcRequest);

	ulIP = GSSOCK_host2inetaddr(acHostAddr);
	if(ulIP== 0 )
	{
		printf("[%s %d] gethostbyname error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
		return FALSE;
	}

	if (NULL == (pcBuff = (char *)GSOS_Malloc(iBuffSize)))
	{
		printf("[%s %d] No enough memory.\n", __FUNCTION__, __LINE__);
		return FALSE;
	}

	if(psk && *psk != -1)
	{
		iSockFileDescrip = *psk;
	}
	else
	{
		if ((iSockFileDescrip = GSSOCK_socket(AF_INET, SOCK_STREAM, 0)) == -1)
		{
			printf("[%s %d] socket error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
			goto EXIT;
		}

		if (P_HTTPS == eProtocolType)
		{
			memset(&stServerAddr, 0, sizeof(stServerAddr));
			stServerAddr.sin_family = AF_INET;
			stServerAddr.sin_port = htons(uiPort);
			stServerAddr.sin_addr.s_addr = ulIP;
			fd_set fdW;
			int inNonBlocking = 0;
			int sdret = 0;
			int iReturnValue = GS_HTTP_SUCCESS;
			int SocketErr = 0;
			int len = 0;
			int iTimeOut = 0;
			bool ConnectComplete = false;

			/* set socket to non-blocking mode */
			inNonBlocking = 1;
			if(ioctl(iSockFileDescrip, FIONBIO, &inNonBlocking) < 0)
				return HTTP_SOCKET_ERROR;

			struct timeval waitTime = {};
			waitTime.tv_sec = 5;
			len = sizeof(int);

			/* Not connected  at first time */
			if(connect(iSockFileDescrip, (struct sockaddr*)(&stServerAddr), sizeof(struct sockaddr)) < 0)
			{
				getsockopt(iSockFileDescrip, SOL_SOCKET, SO_ERROR, &SocketErr, (socklen_t*)&len);
				if (SocketErr == EINPROGRESS || SocketErr == ENOERR)
				{
					do
					{
						if(ConnectComplete == false)
						{
							FD_ZERO(&fdW);
							FD_SET(iSockFileDescrip, &fdW);
							sdret = select(iSockFileDescrip+1, NULL, &fdW, NULL, &waitTime);
							printf ("select(), ret = %d\n", sdret);

							switch (sdret)
							{
								case -1:
									//error handled by u;
									printf("Connect error! %s(%d):%s()\n", __FILE__, __LINE__,__FUNCTION__);
									ConnectComplete = true;
									iReturnValue = HTTP_SOCKET_ERROR;
									break;

								case 0:
									iTimeOut++;
									if(iTimeOut == 6)/*noavtek :wait 30 second is enough*/
									{
									    ConnectComplete = true;
									   iReturnValue = HTTP_SOCKET_ERROR;
									}
									break;

								default:
									ConnectComplete = true;
									getsockopt(iSockFileDescrip, SOL_SOCKET, SO_ERROR, &SocketErr, (socklen_t*)&len);

									if(SocketErr == 0)
									{
										iReturnValue = GS_HTTP_SUCCESS;
										printf("Connect SUCCESS, SocketErr = %d\n", SocketErr);
									}
									else
									{
										iReturnValue = HTTP_SOCKET_ERROR;
										printf("Connect FAIL, SocketErr = %d\n", SocketErr);
									}
									break;
							}
						}
					}while(ConnectComplete == false);

					if(ConnectComplete == false)
					{
						printf("Socket Connecting has been interrupted, %d\n", ConnectComplete);
						return HTTP_SOCKET_ERROR;
					}
				}
				else
				{
					printf("connect failed = %x\n", SocketErr);
					return HTTP_SOCKET_ERROR;
				}
			}
			inNonBlocking = 0;
			if(ioctl(iSockFileDescrip, FIONBIO, &inNonBlocking) < 0)
			{
				return HTTP_OTHER_ERROR;
			}
		}
		else
		{
			struct timeval tv;
			tv.tv_sec = HTTP_COMMON_TIMEOUT / 1000;
			tv.tv_usec = HTTP_COMMON_TIMEOUT % 1000;
			setsockopt(iSockFileDescrip, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
			setsockopt(iSockFileDescrip, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));

			if (-1 == GSSOCK_Connect(iSockFileDescrip, ulIP, uiPort))
			{
				printf("[%s %d] Connect Error: %s\n", __FUNCTION__, __LINE__, strerror(errno));
				goto EXIT;
			}
		}
	}

	if (P_HTTPS == eProtocolType)
	{
	    /* SSL initialize */
	    SSL_library_init();
	    SSL_load_error_strings();
	    ctx = SSL_CTX_new(/*TLSv1_method()*/SSLv23_client_method());
	    if (ctx == NULL)
	    {
	        ERR_print_errors_fp(stderr);
	        goto EXIT;
	    }
	    ssl = SSL_new(ctx);
	    if (ssl == NULL)
	    {
	        ERR_print_errors_fp(stderr);
	    	goto EXIT;
	    }

	    /* correlate socket with SSL */
	    iSSL_Ret = SSL_set_fd(ssl, iSockFileDescrip);
	    if (iSSL_Ret == 0)
	    {
	        ERR_print_errors_fp(stderr);
	    	goto EXIT;
	    }

	    RAND_poll();
	    while (RAND_status() == 0)
	    {
	        unsigned short rand_ret = rand() % 65536;
	        RAND_seed(&rand_ret, sizeof(rand_ret));
	    }
	    iSSL_Ret = SSL_connect(ssl);
	    if (iSSL_Ret != 1)
	    {
	    	int test=SSL_get_error(ssl,iSSL_Ret);
	    	printf("[%s %d] SSL_connect fail. test:%d, %d\n", __FUNCTION__, __LINE__, test, iSSL_Ret);
	        ERR_print_errors_fp(stderr);
	    	goto EXIT;
	    }
	}

	pcLoc = pcRequest;
	iRemainderLen = iRequestLen;
	if (P_HTTP == eProtocolType)
	{
		while ((iNum = GSSOCK_send(iSockFileDescrip, (unsigned char *)pcLoc, iRemainderLen, HTTP_COMMON_TIMEOUT)) > 0)
		{
			pcLoc += iNum;
			iRemainderLen -= iNum;
		}
	}
	else if (P_HTTPS == eProtocolType)
	{
		while ((iNum = GSSSL_send(ssl, iSockFileDescrip, (unsigned char *)pcLoc, iRemainderLen, 3000)) > 0)	/* send */
		{
			pcLoc += iNum;
			iRemainderLen -= iNum;
		}
	}

	memset(pcBuff, 0, iBuffSize);
	pcLoc = pcBuff;
	iRemainderLen = iBuffSize;
	if (P_HTTP == eProtocolType)
	{
		int iTimes = 0;
		int iReserveLen = 0;
		char *pcReserve = (char *)GSOS_Malloc(HTTP_RESERVE_BUFFER_SIZE + 1);
		U32 dst_register = 0;
		void *pvDestLoc = &dst_register;

		if (pcReserve == NULL)
		{
			printf("[%s %d] no enough memory. \n", __FUNCTION__, __LINE__);
			goto EXIT;
		}

		while ((iNum = GSSOCK_recv(iSockFileDescrip, (unsigned char *)pcLoc, iRemainderLen, HTTP_COMMON_TIMEOUT)) > 0)
		{
			if (ParseContent != NULL)
			{
				memset(pcReserve, 0, HTTP_RESERVE_BUFFER_SIZE + 1);
				if (ParseContent(pcBuff, iNum + iReserveLen, pvDstData, pvDestLoc, pcReserve, &iReserveLen, iTimes++, eRequestType))
				{
					bRet = TRUE;
					break;
				}
				else
				{
					if (iReserveLen > 0 && iReserveLen <= HTTP_RESERVE_BUFFER_SIZE)
					{
						memcpy(pcBuff, pcReserve, iReserveLen);
						pcLoc = pcBuff + iReserveLen;
						iRemainderLen = iBuffSize - iReserveLen;
						memset(pcLoc, 0, iBuffSize - iReserveLen);
					}
					else
					{
						memset(pcBuff, 0, iBuffSize);
						pcLoc = pcBuff;
					}
				}
			}
			else
			{
				iTimes++;
				bRet = TRUE;
			}
		}
		GSOS_Free(pcReserve);
	}
	else if (P_HTTPS == eProtocolType)
	{
		int iTimes = 0;
		int iReserveLen = 0;
		char *pcReserve = (char *)GSOS_Malloc(HTTP_RESERVE_BUFFER_SIZE + 1);
		U32 dst_register = 0;
		void *pvDestLoc = &dst_register;

		if (pcReserve == NULL)
		{
			goto EXIT;
		}
		while ((iNum = GSSSL_recv(ssl, iSockFileDescrip, (unsigned char *)pcLoc, iRemainderLen, /*3000*/HTTP_COMMON_TIMEOUT)) > 0)
		{
			if (ParseContent != NULL)
			{
				memset(pcReserve, 0, HTTP_RESERVE_BUFFER_SIZE + 1);
				if (ParseContent(pcBuff, iNum + iReserveLen, pvDstData, pvDestLoc, pcReserve, &iReserveLen, iTimes++, eRequestType))
				{
					bRet = TRUE;
					break;
				}
				else
				{
					if (iReserveLen > 0 && iReserveLen <= HTTP_RESERVE_BUFFER_SIZE)
					{
						memcpy(pcBuff, pcReserve, iReserveLen);
						pcLoc = pcBuff + iReserveLen;
						iRemainderLen = iBuffSize - iReserveLen;
						memset(pcLoc, 0, iBuffSize - iReserveLen);
					}
					else
					{
						memset(pcBuff, 0, iBuffSize);
						pcLoc = pcBuff;
					}
				}
			}
			else
			{
				iTimes++;
				bRet = TRUE;
			}
		}
		GSOS_Free(pcReserve);
	}

EXIT:
	if (P_HTTPS == eProtocolType)
	{
		if (ssl != NULL)
		{
			iSSL_Ret = SSL_shutdown(ssl);	//todo: The iSSL_Ret is 0 here. It may be not right.
			if (iSSL_Ret != 1)
			{
				ERR_print_errors_fp(stderr);
			}
			SSL_free(ssl);
		}

		if (ctx != NULL)
		{
			SSL_CTX_free(ctx);
		}

		ERR_free_strings();
	}

	if(psk)
	{
		*psk = iSockFileDescrip;
	}
	else
	{
		if (iSockFileDescrip >= 0)
		{
			close(iSockFileDescrip);
		}
	}

	if (pcBuff != NULL)
	{
		GSOS_Free(pcBuff);
	}

	if (bNginxServerFlg)
	{
		bNginxServerFlg = FALSE;
		bRet = TRUE;
	}

	return bRet;
}


解析url的函數:

APPLICATION_LAYER_PROTOCOL_TYPE parse_url(char *url, char *host, char *file,
		unsigned int *port)
{
	char *p0, *p1, *p3;
	int iIndex = 0;
	APPLICATION_LAYER_PROTOCOL_TYPE protocol_type;

	if (strncasecmp(url, "http://", 7) == 0)
	{
		p0 = url + 7;
		*port = 80;
		protocol_type = P_HTTP;
	}
	else if (strncasecmp(url, "https://", 8) == 0)
	{
		p0 = url + 8;
		*port = 443;
		protocol_type = P_HTTPS;
	}
	else
	{
		//It need to be extended here for other protocol if be used.
		p0 = strstr(url, "//");
		if (p0 != NULL)
		{
			p0 += 2;
		}
		else
		{
			p0 = url;
		}
		*port = 0;
		protocol_type = P_INVALID;
	}

	p1 = strchr(p0, '/');
	if (p1 != NULL)
	{
		memcpy(host, p0, strlen(p0) - strlen(p1));
		p3 = strchr(host, ':');
		if (p3 != NULL)
		{
			*port = atoi(p3 + 1);
			host[p3 - host] = '\0';
		}

		if (*(p1 + 1) != '\0')
		{
			memcpy(file, p1 + 1, strlen(p1) - 1);
			file[strlen(p1) - 1] = 0;
			for (iIndex = 0; iIndex < (strlen(p1) -1); iIndex++)//add:fix url is space,get no date.--fix:xie.
			{
				if (isspace(file[iIndex]))
				{
					file[iIndex] = '+';
				}
			}
		}
	}
	else
	{
		memcpy(host, p0, strlen(p0));
		p3 = strchr(host, ':');
		if (p3 != NULL)
		{
			*port = atoi(p3 + 1);
			host[p3 - host] = '\0';
		}
	}

	return protocol_type;
}


解析地址的函數:
unsigned long GSSOCK_host2inetaddr(const char *host)
{
	unsigned long ulAddr = INADDR_NONE;
	
	if(host)
	{
		ulAddr = inet_addr(host);
		if(ulAddr == INADDR_NONE)
		{
			struct addrinfo hints, *res = NULL;
			memset(&hints, 0, sizeof(hints));
			hints.ai_socktype = SOCK_STREAM;
			hints.ai_family = AF_INET;
			hints.ai_protocol = IPPROTO_TCP;
			int err = getaddrinfo(host, NULL, &hints, &res);
			if (err != 0 || !res || !res->ai_addr)
			{
			
			}
			else
			{
				ulAddr=((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
			}
			if (res) freeaddrinfo(res);
		}
	}
	return ulAddr;
}


在解析https數據時,在connect成功後一定要設置一下取消非柱塞模式,

			if(ioctl(iSockFileDescrip, FIONBIO, &inNonBlocking) < 0)
			{
				return HTTP_OTHER_ERROR;
			}
要不然,就是失敗SSL_connect

	    iSSL_Ret = SSL_connect(ssl);
	    if (iSSL_Ret != 1)
	    {
	    	int test=SSL_get_error(ssl,iSSL_Ret);
	    	printf("[%s %d] SSL_connect fail. test:%d, %d\n", __FUNCTION__, __LINE__, test, iSSL_Ret);
	        ERR_print_errors_fp(stderr);
	    	goto EXIT;
	    }




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章