| #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; |
| } |
| |