| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | #include <stdio.h> | 
|  | 2 | #include <string.h> | 
|  | 3 | #include <stdlib.h> | 
|  | 4 | #include <unistd.h> | 
|  | 5 | #include <sys/stat.h> | 
|  | 6 | #include <sys/socket.h> | 
|  | 7 | #include <netinet/in.h> | 
|  | 8 | #include <arpa/inet.h> | 
|  | 9 | #include <netdb.h> | 
|  | 10 | #include <openssl/ssl.h> | 
|  | 11 | #include <openssl/bio.h> | 
|  | 12 |  | 
|  | 13 | #include "lpa_inner.h" | 
|  | 14 |  | 
|  | 15 |  | 
|  | 16 |  | 
|  | 17 | // http ÇëÇóÍ·ÐÅÏ¢ | 
|  | 18 | static char https_header[] = | 
|  | 19 | "GET %s HTTP/1.1\r\n" | 
|  | 20 | "Host: %s:%d\r\n" | 
|  | 21 | "Connection: Close\r\n" | 
|  | 22 | "Accept: */*\r\n" | 
|  | 23 | "\r\n"; | 
|  | 24 | /* | 
|  | 25 | HTTP POST /gsma/rsp2/es9plus/initiateAuthentication HTTP/1.1 | 
|  | 26 | Host: smdp.gsma.com | 
|  | 27 | User-Agent: gsma-rsp-lpad | 
|  | 28 | X-Admin-Protocol: gsma/rsp/v2.2.0 | 
|  | 29 | Content-Type: application/json | 
|  | 30 | Content-Length: XXX | 
|  | 31 |  | 
|  | 32 | { | 
|  | 33 | "euiccChallenge" : "ZVVpY2NDaGFsbGVuZ2VFeGFtcGxlQmFzZTY0oUFZuQnNZVE5D", | 
|  | 34 | "euiccInfo1" : "RmVHRnRjR3hsUW1GelpUWTBvVUZadVFuTlpWRTU", | 
|  | 35 | "smdpAddress" : "smdp.gsma.com" | 
|  | 36 | } | 
|  | 37 | */ | 
|  | 38 |  | 
|  | 39 | static int create_request_socket(const char* host,const int port) | 
|  | 40 | { | 
|  | 41 | int sockfd; | 
|  | 42 | struct hostent *server; | 
|  | 43 | struct sockaddr_in serv_addr; | 
|  | 44 | struct timeval tv; | 
|  | 45 |  | 
|  | 46 | sockfd = socket(AF_INET, SOCK_STREAM, 0); | 
|  | 47 | if (sockfd < 0) | 
|  | 48 | { | 
|  | 49 | printf("[http] create_request_socket create socket fail.\n"); | 
|  | 50 | return -1; | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | tv.tv_sec = 90; | 
|  | 54 | tv.tv_usec = 0; | 
|  | 55 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { | 
|  | 56 | printf("[http] socket option  SO_RCVTIMEO fail\n"); | 
|  | 57 | close(sockfd); | 
|  | 58 | return -1; | 
|  | 59 | } | 
|  | 60 |  | 
|  | 61 | /* lookup the ip address */ | 
|  | 62 | server = gethostbyname(host); | 
|  | 63 | if(server == NULL) | 
|  | 64 | { | 
|  | 65 | printf("[http] create_request_socket gethostbyname--%s--fail.\n", host); | 
|  | 66 | close(sockfd); | 
|  | 67 | return -1; | 
|  | 68 | } | 
|  | 69 |  | 
|  | 70 | memset(&serv_addr,0,sizeof(serv_addr)); | 
|  | 71 | serv_addr.sin_family = AF_INET; | 
|  | 72 | serv_addr.sin_port = htons(port); | 
|  | 73 | memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); | 
|  | 74 |  | 
|  | 75 | if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) | 
|  | 76 | { | 
|  | 77 | printf("[http] create_request_socket connect fail.\n"); | 
|  | 78 | close(sockfd); | 
|  | 79 | return -1; | 
|  | 80 | } | 
|  | 81 | return sockfd; | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | /** | 
|  | 85 | * @brief https_parser_url  ½âÎö³öhttps ÖеÄÓòÃû¡¢¶Ë¿ÚºÍ·¾¶ | 
|  | 86 | * @param url   ÐèÒª½âÎöµÄurl | 
|  | 87 | * @param host  ½âÎö³öÀ´µÄÓòÃû»òÕßip | 
|  | 88 | * @param port  ¶Ë¿Ú£¬Ã»ÓÐʱĬÈÏ·µ»Ø443 | 
|  | 89 | * @param path  ·¾¶£¬Ö¸µÄÊÇÓòÃûºóÃæµÄλÖà | 
|  | 90 | * @return | 
|  | 91 | */ | 
|  | 92 | int https_parser_url(const char* url,char **host,int *port,char **path) | 
|  | 93 | { | 
|  | 94 | if(url == NULL || strlen(url) < 9 || host == NULL || path == NULL) | 
|  | 95 | { | 
|  | 96 | printf("url or host or path is null.\n"); | 
|  | 97 | return -1; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | //ÅжÏÊDz»ÊÇ https:// | 
|  | 101 | int i = 0; | 
|  | 102 | char https_prefix[] = "https://"; | 
|  | 103 | for(i=0;i<8;i++) | 
|  | 104 | { | 
|  | 105 | if(url[i] != https_prefix[i]) | 
|  | 106 | { | 
|  | 107 | printf("illegal url = %s.\n",url); | 
|  | 108 | return -1; | 
|  | 109 | } | 
|  | 110 | } | 
|  | 111 |  | 
|  | 112 | const char *temp = url+i; | 
|  | 113 | while(*temp != '/')  //next / | 
|  | 114 | { | 
|  | 115 | if(*temp == '\0')  // | 
|  | 116 | { | 
|  | 117 | printf("illegal url = %s.\n",url); | 
|  | 118 | return -1; | 
|  | 119 | } | 
|  | 120 | temp++; | 
|  | 121 | } | 
|  | 122 |  | 
|  | 123 | const char *host_port = url+i; | 
|  | 124 | while(*host_port != ':' && *host_port != '/')  //ÕÒµ½ :»òÕß / ½áÊø | 
|  | 125 | { | 
|  | 126 | host_port ++; | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | int host_len = host_port-url-i;  //¼õµôhttps:// | 
|  | 130 | int path_len = strlen(temp); | 
|  | 131 | char *host_temp = (char *)malloc(host_len + 1);  //¶àÒ»¸ö×Ö·û´®½áÊø±êʶ \0 | 
|  | 132 | if(host_temp == NULL) | 
|  | 133 | { | 
|  | 134 | printf("malloc host fail.\n"); | 
|  | 135 | return -1; | 
|  | 136 | } | 
|  | 137 | if(*host_port++ == ':')  //url ÖÐÓÐ¶Ë¿Ú | 
|  | 138 | { | 
|  | 139 | *port = 0; | 
|  | 140 | while(*host_port !='/' && *host_port !='\0')  //Ê®½øÖÆ×Ö·û´®×ª³ÉÊý×Ö | 
|  | 141 | { | 
|  | 142 | *port *= 10; | 
|  | 143 | *port += (*host_port - '0'); | 
|  | 144 | host_port ++; | 
|  | 145 | } | 
|  | 146 | } | 
|  | 147 | else | 
|  | 148 | { | 
|  | 149 | *port = 443; | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | char *path_temp = (char *)malloc(path_len + 1);  //¶àÒ»¸ö×Ö·û´®½áÊø±êʶ \0 | 
|  | 153 | if(path_temp == NULL) | 
|  | 154 | { | 
|  | 155 | printf("malloc path fail.\n"); | 
|  | 156 | free(host_temp); | 
|  | 157 | return -1; | 
|  | 158 | } | 
|  | 159 | memcpy(host_temp,url+i,host_len); | 
|  | 160 | memcpy(path_temp,temp,path_len); | 
|  | 161 | host_temp[host_len] = '\0'; | 
|  | 162 | path_temp[path_len] = '\0'; | 
|  | 163 | *host = host_temp; | 
|  | 164 | *path = path_temp; | 
|  | 165 | return 0; | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | int https_init(https_context_t *context) | 
|  | 169 | { | 
|  | 170 | int ret = 0; | 
|  | 171 | if(context == NULL) | 
|  | 172 | { | 
|  | 173 | printf("init https_context_t is null.\n"); | 
|  | 174 | return -1; | 
|  | 175 | } | 
|  | 176 | /* | 
|  | 177 | if(https_parser_url(url,&(context->host),&(context->port),&(context->path))) | 
|  | 178 | { | 
|  | 179 | printf("https_parser_url fail.\n"); | 
|  | 180 | return -1; | 
|  | 181 | } | 
|  | 182 | */ | 
|  | 183 | context->sock_fd = create_request_socket(context->host,context->port); | 
|  | 184 | printf("create_request_socket %d.\n",context->sock_fd); | 
|  | 185 | if(context->sock_fd < 0) | 
|  | 186 | { | 
|  | 187 | goto https_init_fail; | 
|  | 188 | } | 
|  | 189 |  | 
|  | 190 | context->ssl_ct = SSL_CTX_new(SSLv23_method()); | 
|  | 191 | printf("SSL_CTX_new %p.\n",context->ssl_ct); //cov m | 
|  | 192 | if(context->ssl_ct == NULL) | 
|  | 193 | { | 
|  | 194 | goto https_init_fail; | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | context->ssl = SSL_new(context->ssl_ct); | 
|  | 198 | printf("SSL_new %p.\n",context->ssl); //cov m | 
|  | 199 | if(context->ssl == NULL) | 
|  | 200 | { | 
|  | 201 | goto https_init_fail; | 
|  | 202 | } | 
|  | 203 | ret = SSL_set_fd(context->ssl,context->sock_fd); | 
|  | 204 | printf("SSL_set_fd ret %d \n",ret); | 
|  | 205 | ret = SSL_connect(context->ssl); | 
|  | 206 | printf("SSL_connect ret %d \n",ret); | 
|  | 207 | if(ret == -1) | 
|  | 208 | { | 
|  | 209 | goto https_init_fail; | 
|  | 210 | } | 
|  | 211 | return 0; | 
|  | 212 | https_init_fail: | 
|  | 213 | https_uninit(context); | 
|  | 214 | return -1; | 
|  | 215 | } | 
|  | 216 |  | 
|  | 217 | int https_read(https_context_t *context,void* buff,int len) | 
|  | 218 | { | 
|  | 219 | if(context == NULL || context->ssl == NULL) | 
|  | 220 | { | 
|  | 221 | printf("read https_context_t or ssl is null.\n"); | 
|  | 222 | return -1; | 
|  | 223 | } | 
|  | 224 | return SSL_read(context->ssl,buff,len); | 
|  | 225 | } | 
|  | 226 |  | 
|  | 227 | int https_write(https_context_t *context,const void* buff,int len) | 
|  | 228 | { | 
|  | 229 | if(context == NULL || context->ssl == NULL) | 
|  | 230 | { | 
|  | 231 | printf("write https_context_t or ssl is null.\n"); | 
|  | 232 | return -1; | 
|  | 233 | } | 
|  | 234 | return SSL_write(context->ssl,buff,len); | 
|  | 235 | } | 
|  | 236 |  | 
|  | 237 | int https_get_status_code(https_context_t *context, int *content_len) | 
|  | 238 | { | 
|  | 239 | int ret; | 
|  | 240 | int flag =0; | 
|  | 241 | int recv_len = 0; | 
|  | 242 | char res_header[1024] = {0}; | 
|  | 243 |  | 
|  | 244 | if(context == NULL || context->ssl == NULL) | 
|  | 245 | { | 
|  | 246 | printf("get status https_context_t or ssl is null.\n"); | 
|  | 247 | return -1; | 
|  | 248 | } | 
|  | 249 |  | 
|  | 250 | while(recv_len < (sizeof(res_header)-1)) | 
|  | 251 | { | 
|  | 252 | ret = SSL_read(context->ssl, res_header+recv_len, 1); | 
|  | 253 | if(ret<1)  // recv fail | 
|  | 254 | { | 
|  | 255 | break; | 
|  | 256 | } | 
|  | 257 | //ÕÒµ½ÏìӦͷµÄÍ·²¿ÐÅÏ¢, Á½¸ö"\r\n"Ϊ·Ö¸îµã | 
|  | 258 | if((res_header[recv_len]=='\r'&&(flag==0||flag==2))||(res_header[recv_len]=='\n'&&(flag==1||flag==3))) | 
|  | 259 | { | 
|  | 260 | flag++; | 
|  | 261 | } | 
|  | 262 | else | 
|  | 263 | { | 
|  | 264 | flag = 0; | 
|  | 265 | } | 
|  | 266 | recv_len+=ret; | 
|  | 267 | if(flag==4) | 
|  | 268 | { | 
|  | 269 | break; | 
|  | 270 | } | 
|  | 271 | } | 
|  | 272 | //printf("[http] recv_len=%d res_header = %s.\n",recv_len,res_header); | 
|  | 273 | /*»ñÈ¡ÏìӦͷµÄÐÅÏ¢*/ | 
|  | 274 | int status_code = -1; | 
|  | 275 | char *pos = strstr(res_header, "HTTP/"); | 
|  | 276 | if(pos) | 
|  | 277 | { | 
|  | 278 | sscanf(pos, "%*s %d", &status_code);//·µ»Ø×´Ì¬Âë | 
|  | 279 | } | 
|  | 280 |  | 
|  | 281 | int cont_len = 0; | 
|  | 282 | pos = strstr(res_header, "Content-Length:"); | 
|  | 283 | if(pos) | 
|  | 284 | { | 
|  | 285 | sscanf(pos, "%*s %d", &cont_len);//·µ»Ø×´Ì¬Âë | 
|  | 286 | } | 
|  | 287 | pos = strstr(res_header, "chunked"); | 
|  | 288 | if(pos)//Transfer-Encoding: chunked | 
|  | 289 | { | 
|  | 290 | cont_len = HTTP_CHUNKED_FLAG; | 
|  | 291 | } | 
|  | 292 | *content_len = cont_len; | 
|  | 293 |  | 
|  | 294 | printf("res_head##%s##\n", res_header); | 
|  | 295 | printf("status_code:%d, Content-Length:%d\n", status_code, cont_len); | 
|  | 296 |  | 
|  | 297 | return status_code; | 
|  | 298 | } | 
|  | 299 |  | 
|  | 300 | int https_read_content(https_context_t *context,char *resp_contet,int max_len) | 
|  | 301 | { | 
|  | 302 | if(context == NULL || context->ssl == NULL) | 
|  | 303 | { | 
|  | 304 | printf("read content https_context_t or ssl is null.\n"); | 
|  | 305 | return -1; | 
|  | 306 | } | 
|  | 307 | int ret ; | 
|  | 308 | int recv_size = 0; | 
|  | 309 | while(recv_size < max_len) | 
|  | 310 | { | 
|  | 311 | ret = SSL_read(context->ssl,resp_contet + recv_size,max_len-recv_size); | 
|  | 312 | if(ret < 1) | 
|  | 313 | { | 
|  | 314 | break; | 
|  | 315 | } | 
|  | 316 | recv_size += ret; | 
|  | 317 | } | 
|  | 318 | return recv_size; | 
|  | 319 | } | 
|  | 320 | //[Chunk´óС][»Ø³µ][ChunkÊý¾ÝÌå][»Ø³µ][Chunk´óС][»Ø³µ][ChunkÊý¾ÝÌå][»Ø³µ][0][»Ø³µ][footerÄÚÈÝ£¨Óеϰ£©][»Ø³µ] | 
|  | 321 | //×¢Òâchunk-sizeÊÇÒÔÊ®Áù½øÖƵÄASCIIÂë±íʾµÄ£¬±ÈÈç86AE£¨Êµ¼ÊµÄÊ®Áù½øÖÆÓ¦¸ÃÊÇ£º38366165£©£¬¼ÆËã³É³¤¶ÈÓ¦¸ÃÊÇ£º34478£¬±íʾ´Ó»Ø³µÖ®ºóÓÐÁ¬ÐøµÄ34478×Ö½ÚµÄÊý¾Ý | 
|  | 322 | int https_read_chunked_content(https_context_t *context,char **resp_contet,int max_len) | 
|  | 323 | { | 
|  | 324 | int ret = 0; | 
|  | 325 | int flag = 0; | 
|  | 326 | int recv_size = 0; | 
|  | 327 |  | 
|  | 328 | int recv_len = 0; | 
|  | 329 | char chunk_header[1024] = {0}; | 
|  | 330 |  | 
|  | 331 | int read_flag = 0; | 
|  | 332 | int read_len = 1; | 
|  | 333 |  | 
|  | 334 | if(context == NULL || context->ssl == NULL) | 
|  | 335 | { | 
|  | 336 | printf("read content https_context_t or ssl is null.\n"); | 
|  | 337 | return -1; | 
|  | 338 | } | 
|  | 339 |  | 
|  | 340 | while(recv_size < max_len) | 
|  | 341 | { | 
|  | 342 | if (read_flag == 0) { | 
|  | 343 | ret = SSL_read(context->ssl, chunk_header+recv_len, read_len); | 
|  | 344 | if(ret < 1)  // recv fail | 
|  | 345 | { | 
|  | 346 | break; | 
|  | 347 | } | 
|  | 348 | printf("chunk_header##%s##\n", chunk_header+recv_len); | 
|  | 349 | //Ò»¸ö"\r\n"Ϊ·Ö¸îµã | 
|  | 350 | if((chunk_header[recv_len]=='\r'&&flag==0)||(chunk_header[recv_len]=='\n'&&flag==1)) | 
|  | 351 | { | 
|  | 352 | flag++; | 
|  | 353 | } | 
|  | 354 | else | 
|  | 355 | { | 
|  | 356 | flag = 0; | 
|  | 357 | } | 
|  | 358 | recv_len += ret; | 
|  | 359 | if(flag == 2) | 
|  | 360 | { | 
|  | 361 | if (strlen(chunk_header) > 2) { | 
|  | 362 | //Ìø¹ý·Ç0~9£¬A~F??? | 
|  | 363 | errno = 0; | 
|  | 364 | int size =strtol(chunk_header, NULL, 16); | 
|  | 365 | if (errno == ERANGE)// kw ERRNO.NOT_CHECKED | 
|  | 366 | { | 
|  | 367 | printf("strtol errno %d: %s\n", errno, strerror(errno)); | 
|  | 368 | } | 
|  | 369 | //sscanf(pos, "%X", &cont_len);//X??? | 
|  | 370 | if (size <= 0 || size >= max_len) { | 
|  | 371 | read_flag = 2; | 
|  | 372 | read_len = sizeof(chunk_header)-1; | 
|  | 373 | } | 
|  | 374 | else { | 
|  | 375 | read_flag = 1; | 
|  | 376 | read_len = size; | 
|  | 377 | } | 
|  | 378 | } | 
|  | 379 | memset(chunk_header, 0, sizeof(chunk_header)); | 
|  | 380 | recv_len = 0; | 
|  | 381 | } | 
|  | 382 | if (recv_len >= (sizeof(chunk_header)-1)) | 
|  | 383 | break; | 
|  | 384 | } | 
|  | 385 | else if(read_flag == 1) { | 
|  | 386 | if(recv_size == 0) { | 
|  | 387 | char *resp_tmp = malloc(read_len + 1);; | 
|  | 388 | if (resp_tmp == NULL) { | 
|  | 389 | printf("resp_tmp is null\n"); | 
|  | 390 | return -1; | 
|  | 391 | } | 
|  | 392 | memset(resp_tmp, 0, read_len + 1); | 
|  | 393 | *resp_contet = resp_tmp; | 
|  | 394 | } | 
|  | 395 | else { | 
|  | 396 | char *resp_tmp = NULL; | 
|  | 397 | resp_tmp = realloc(*resp_contet, recv_size + read_len + 1); | 
|  | 398 | if (resp_tmp == NULL) { | 
|  | 399 | free(*resp_contet); | 
|  | 400 | printf("resp_tmp realloc null\n"); | 
|  | 401 | return -1; | 
|  | 402 | } | 
|  | 403 | *resp_contet = resp_tmp; | 
|  | 404 | } | 
|  | 405 | //read Ö±µ½³¤¶È | 
|  | 406 | ret = https_read_content(context, (*resp_contet)+recv_size, read_len); | 
|  | 407 | if(ret<1)  // recv fail | 
|  | 408 | { | 
|  | 409 | break; | 
|  | 410 | } | 
|  | 411 | read_len = 1; | 
|  | 412 | read_flag = 0; | 
|  | 413 | recv_size += ret; | 
|  | 414 | } | 
|  | 415 | else { | 
|  | 416 | ret = SSL_read(context->ssl, chunk_header, read_len); | 
|  | 417 | printf("chunk_header##%s##\n", chunk_header); | 
|  | 418 | break; | 
|  | 419 | } | 
|  | 420 |  | 
|  | 421 | } | 
|  | 422 | return recv_size; | 
|  | 423 | } | 
|  | 424 |  | 
|  | 425 |  | 
|  | 426 | int https_uninit(https_context_t *context) | 
|  | 427 | { | 
|  | 428 | if(context == NULL) | 
|  | 429 | { | 
|  | 430 | printf("uninit https_context_t is null.\n"); | 
|  | 431 | return -1; | 
|  | 432 | } | 
|  | 433 |  | 
|  | 434 | if(context->host != NULL) | 
|  | 435 | { | 
|  | 436 | //free(context->host); | 
|  | 437 | context->host = NULL; | 
|  | 438 | } | 
|  | 439 |  | 
|  | 440 | if(context->path != NULL) | 
|  | 441 | { | 
|  | 442 | //free(context->path); | 
|  | 443 | context->path = NULL; | 
|  | 444 | } | 
|  | 445 |  | 
|  | 446 | if(context->ssl != NULL) | 
|  | 447 | { | 
|  | 448 | SSL_shutdown(context->ssl); | 
|  | 449 | //SSl_free(context->ssl); | 
|  | 450 | context->ssl = NULL; | 
|  | 451 | } | 
|  | 452 | if(context->ssl_ct != NULL) | 
|  | 453 | { | 
|  | 454 | SSL_CTX_free(context->ssl_ct); | 
|  | 455 | context->ssl_ct = NULL; | 
|  | 456 | } | 
|  | 457 | if(context->sock_fd > 0) | 
|  | 458 | { | 
|  | 459 | close(context->sock_fd); | 
|  | 460 | context->sock_fd = -1; | 
|  | 461 | } | 
|  | 462 | return 0; | 
|  | 463 | } | 
|  | 464 |  |