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