blob: 54b549b0003e5789e45678aa642295cd6b639d1e [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include "lpa_inner.h"
// http ÇëÇóÍ·ÐÅÏ¢
static char https_header[] =
"GET %s HTTP/1.1\r\n"
"Host: %s:%d\r\n"
"Connection: Close\r\n"
"Accept: */*\r\n"
"\r\n";
/*
HTTP POST /gsma/rsp2/es9plus/initiateAuthentication HTTP/1.1
Host: smdp.gsma.com
User-Agent: gsma-rsp-lpad
X-Admin-Protocol: gsma/rsp/v2.2.0
Content-Type: application/json
Content-Length: XXX
{
"euiccChallenge" : "ZVVpY2NDaGFsbGVuZ2VFeGFtcGxlQmFzZTY0oUFZuQnNZVE5D",
"euiccInfo1" : "RmVHRnRjR3hsUW1GelpUWTBvVUZadVFuTlpWRTU",
"smdpAddress" : "smdp.gsma.com"
}
*/
static int create_request_socket(const char* host,const int port)
{
int sockfd;
struct hostent *server;
struct sockaddr_in serv_addr;
struct timeval tv;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("[http] create_request_socket create socket fail.\n");
return -1;
}
tv.tv_sec = 90;
tv.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
printf("[http] socket option SO_RCVTIMEO fail\n");
close(sockfd);
return -1;
}
/* lookup the ip address */
server = gethostbyname(host);
if(server == NULL)
{
printf("[http] create_request_socket gethostbyname--%s--fail.\n", host);
close(sockfd);
return -1;
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
{
printf("[http] create_request_socket connect fail.\n");
close(sockfd);
return -1;
}
return sockfd;
}
/**
* @brief https_parser_url ½âÎö³öhttps ÖеÄÓòÃû¡¢¶Ë¿ÚºÍ·¾¶
* @param url ÐèÒª½âÎöµÄurl
* @param host ½âÎö³öÀ´µÄÓòÃû»òÕßip
* @param port ¶Ë¿Ú£¬Ã»ÓÐʱĬÈÏ·µ»Ø443
* @param path ·¾¶£¬Ö¸µÄÊÇÓòÃûºóÃæµÄλÖÃ
* @return
*/
int https_parser_url(const char* url,char **host,int *port,char **path)
{
if(url == NULL || strlen(url) < 9 || host == NULL || path == NULL)
{
printf("url or host or path is null.\n");
return -1;
}
//ÅжÏÊDz»ÊÇ https://
int i = 0;
char https_prefix[] = "https://";
for(i=0;i<8;i++)
{
if(url[i] != https_prefix[i])
{
printf("illegal url = %s.\n",url);
return -1;
}
}
const char *temp = url+i;
while(*temp != '/') //next /
{
if(*temp == '\0') //
{
printf("illegal url = %s.\n",url);
return -1;
}
temp++;
}
const char *host_port = url+i;
while(*host_port != ':' && *host_port != '/') //ÕÒµ½ :»òÕß / ½áÊø
{
host_port ++;
}
int host_len = host_port-url-i; //¼õµôhttps://
int path_len = strlen(temp);
char *host_temp = (char *)malloc(host_len + 1); //¶àÒ»¸ö×Ö·û´®½áÊø±êʶ \0
if(host_temp == NULL)
{
printf("malloc host fail.\n");
return -1;
}
if(*host_port++ == ':') //url ÖÐÓж˿Ú
{
*port = 0;
while(*host_port !='/' && *host_port !='\0') //Ê®½øÖÆ×Ö·û´®×ª³ÉÊý×Ö
{
*port *= 10;
*port += (*host_port - '0');
host_port ++;
}
}
else
{
*port = 443;
}
char *path_temp = (char *)malloc(path_len + 1); //¶àÒ»¸ö×Ö·û´®½áÊø±êʶ \0
if(path_temp == NULL)
{
printf("malloc path fail.\n");
free(host_temp);
return -1;
}
memcpy(host_temp,url+i,host_len);
memcpy(path_temp,temp,path_len);
host_temp[host_len] = '\0';
path_temp[path_len] = '\0';
*host = host_temp;
*path = path_temp;
return 0;
}
int https_init(https_context_t *context)
{
int ret = 0;
if(context == NULL)
{
printf("init https_context_t is null.\n");
return -1;
}
/*
if(https_parser_url(url,&(context->host),&(context->port),&(context->path)))
{
printf("https_parser_url fail.\n");
return -1;
}
*/
context->sock_fd = create_request_socket(context->host,context->port);
printf("create_request_socket %d.\n",context->sock_fd);
if(context->sock_fd < 0)
{
goto https_init_fail;
}
context->ssl_ct = SSL_CTX_new(SSLv23_method());
printf("SSL_CTX_new %p.\n",context->ssl_ct); //cov m
if(context->ssl_ct == NULL)
{
goto https_init_fail;
}
context->ssl = SSL_new(context->ssl_ct);
printf("SSL_new %p.\n",context->ssl); //cov m
if(context->ssl == NULL)
{
goto https_init_fail;
}
ret = SSL_set_fd(context->ssl,context->sock_fd);
printf("SSL_set_fd ret %d \n",ret);
ret = SSL_connect(context->ssl);
printf("SSL_connect ret %d \n",ret);
if(ret == -1)
{
goto https_init_fail;
}
return 0;
https_init_fail:
https_uninit(context);
return -1;
}
int https_read(https_context_t *context,void* buff,int len)
{
if(context == NULL || context->ssl == NULL)
{
printf("read https_context_t or ssl is null.\n");
return -1;
}
return SSL_read(context->ssl,buff,len);
}
int https_write(https_context_t *context,const void* buff,int len)
{
if(context == NULL || context->ssl == NULL)
{
printf("write https_context_t or ssl is null.\n");
return -1;
}
return SSL_write(context->ssl,buff,len);
}
int https_get_status_code(https_context_t *context, int *content_len)
{
int ret;
int flag =0;
int recv_len = 0;
char res_header[1024] = {0};
if(context == NULL || context->ssl == NULL)
{
printf("get status https_context_t or ssl is null.\n");
return -1;
}
while(recv_len < (sizeof(res_header)-1))
{
ret = SSL_read(context->ssl, res_header+recv_len, 1);
if(ret<1) // recv fail
{
break;
}
//ÕÒµ½ÏìӦͷµÄÍ·²¿ÐÅÏ¢, Á½¸ö"\r\n"Ϊ·Ö¸îµã
if((res_header[recv_len]=='\r'&&(flag==0||flag==2))||(res_header[recv_len]=='\n'&&(flag==1||flag==3)))
{
flag++;
}
else
{
flag = 0;
}
recv_len+=ret;
if(flag==4)
{
break;
}
}
//printf("[http] recv_len=%d res_header = %s.\n",recv_len,res_header);
/*»ñÈ¡ÏìӦͷµÄÐÅÏ¢*/
int status_code = -1;
char *pos = strstr(res_header, "HTTP/");
if(pos)
{
sscanf(pos, "%*s %d", &status_code);//·µ»Ø×´Ì¬Âë
}
int cont_len = 0;
pos = strstr(res_header, "Content-Length:");
if(pos)
{
sscanf(pos, "%*s %d", &cont_len);//·µ»Ø×´Ì¬Âë
}
pos = strstr(res_header, "chunked");
if(pos)//Transfer-Encoding: chunked
{
cont_len = HTTP_CHUNKED_FLAG;
}
*content_len = cont_len;
printf("res_head##%s##\n", res_header);
printf("status_code:%d, Content-Length:%d\n", status_code, cont_len);
return status_code;
}
int https_read_content(https_context_t *context,char *resp_contet,int max_len)
{
if(context == NULL || context->ssl == NULL)
{
printf("read content https_context_t or ssl is null.\n");
return -1;
}
int ret ;
int recv_size = 0;
while(recv_size < max_len)
{
ret = SSL_read(context->ssl,resp_contet + recv_size,max_len-recv_size);
if(ret < 1)
{
break;
}
recv_size += ret;
}
return recv_size;
}
//[Chunk´óС][»Ø³µ][ChunkÊý¾ÝÌå][»Ø³µ][Chunk´óС][»Ø³µ][ChunkÊý¾ÝÌå][»Ø³µ][0][»Ø³µ][footerÄÚÈÝ£¨Óеϰ£©][»Ø³µ]
//×¢Òâchunk-sizeÊÇÒÔÊ®Áù½øÖƵÄASCIIÂë±íʾµÄ£¬±ÈÈç86AE£¨Êµ¼ÊµÄÊ®Áù½øÖÆÓ¦¸ÃÊÇ£º38366165£©£¬¼ÆËã³É³¤¶ÈÓ¦¸ÃÊÇ£º34478£¬±íʾ´Ó»Ø³µÖ®ºóÓÐÁ¬ÐøµÄ34478×Ö½ÚµÄÊý¾Ý
int https_read_chunked_content(https_context_t *context,char **resp_contet,int max_len)
{
int ret = 0;
int flag = 0;
int recv_size = 0;
int recv_len = 0;
char chunk_header[1024] = {0};
int read_flag = 0;
int read_len = 1;
if(context == NULL || context->ssl == NULL)
{
printf("read content https_context_t or ssl is null.\n");
return -1;
}
while(recv_size < max_len)
{
if (read_flag == 0) {
ret = SSL_read(context->ssl, chunk_header+recv_len, read_len);
if(ret < 1) // recv fail
{
break;
}
printf("chunk_header##%s##\n", chunk_header+recv_len);
//Ò»¸ö"\r\n"Ϊ·Ö¸îµã
if((chunk_header[recv_len]=='\r'&&flag==0)||(chunk_header[recv_len]=='\n'&&flag==1))
{
flag++;
}
else
{
flag = 0;
}
recv_len += ret;
if(flag == 2)
{
if (strlen(chunk_header) > 2) {
//Ìø¹ý·Ç0~9£¬A~F???
errno = 0;
int size =strtol(chunk_header, NULL, 16);
if (errno == ERANGE)// kw ERRNO.NOT_CHECKED
{
printf("strtol errno %d: %s\n", errno, strerror(errno));
}
//sscanf(pos, "%X", &cont_len);//X???
if (size <= 0 || size >= max_len) {
read_flag = 2;
read_len = sizeof(chunk_header)-1;
}
else {
read_flag = 1;
read_len = size;
}
}
memset(chunk_header, 0, sizeof(chunk_header));
recv_len = 0;
}
if (recv_len >= (sizeof(chunk_header)-1))
break;
}
else if(read_flag == 1) {
if(recv_size == 0) {
char *resp_tmp = malloc(read_len + 1);;
if (resp_tmp == NULL) {
printf("resp_tmp is null\n");
return -1;
}
memset(resp_tmp, 0, read_len + 1);
*resp_contet = resp_tmp;
}
else {
char *resp_tmp = NULL;
resp_tmp = realloc(*resp_contet, recv_size + read_len + 1);
if (resp_tmp == NULL) {
free(*resp_contet);
printf("resp_tmp realloc null\n");
return -1;
}
*resp_contet = resp_tmp;
}
//read Ö±µ½³¤¶È
ret = https_read_content(context, (*resp_contet)+recv_size, read_len);
if(ret<1) // recv fail
{
break;
}
read_len = 1;
read_flag = 0;
recv_size += ret;
}
else {
ret = SSL_read(context->ssl, chunk_header, read_len);
printf("chunk_header##%s##\n", chunk_header);
break;
}
}
return recv_size;
}
int https_uninit(https_context_t *context)
{
if(context == NULL)
{
printf("uninit https_context_t is null.\n");
return -1;
}
if(context->host != NULL)
{
//free(context->host);
context->host = NULL;
}
if(context->path != NULL)
{
//free(context->path);
context->path = NULL;
}
if(context->ssl != NULL)
{
SSL_shutdown(context->ssl);
//SSl_free(context->ssl);
context->ssl = NULL;
}
if(context->ssl_ct != NULL)
{
SSL_CTX_free(context->ssl_ct);
context->ssl_ct = NULL;
}
if(context->sock_fd > 0)
{
close(context->sock_fd);
context->sock_fd = -1;
}
return 0;
}