1 /* 2 * 3 * Copyright (c) 2012 Tatsuhiro Tsujikawa 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 /** 26 * @file mhd2spdy_spdy.c 27 * @brief SPDY part of the proxy. libspdylay is used for the client side. 28 * The example spdycli.c from spdylay was used as basis; 29 * however, multiple changes were made. 30 * @author Tatsuhiro Tsujikawa 31 * @author Andrey Uzunov 32 */ 33 34 #include "mhd2spdy_structures.h" 35 #include "mhd2spdy_spdy.h" 36 #include "mhd2spdy_http.h" 37 38 39 /* 40 * Prints error containing the function name |func| and message |msg| 41 * and exit. 42 */ 43 static void 44 spdy_dief(const char *func, 45 const char *msg) 46 { 47 fprintf(stderr, "FATAL: %s: %s\n", func, msg); 48 exit(EXIT_FAILURE); 49 } 50 51 52 /* 53 * Prints error containing the function name |func| and error code 54 * |error_code| and exit. 55 */ 56 void 57 spdy_diec(const char *func, 58 int error_code) 59 { 60 fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code, 61 spdylay_strerror(error_code)); 62 exit(EXIT_FAILURE); 63 } 64 65 66 static ssize_t 67 spdy_cb_data_source_read(spdylay_session *session, int32_t stream_id, uint8_t *buf, size_t length, int *eof, spdylay_data_source *source, void *user_data) 68 { 69 (void)session; 70 (void)stream_id; 71 (void)user_data; 72 73 ssize_t ret; 74 assert(NULL != source); 75 assert(NULL != source->ptr); 76 struct Proxy *proxy = (struct Proxy *)(source->ptr); 77 void *newbody; 78 79 80 if(length < 1) 81 { 82 PRINT_INFO("spdy_cb_data_source_read: length is 0"); 83 return 0; 84 } 85 86 if(!proxy->received_body_size)//nothing to write now 87 { 88 if(proxy->receiving_done) 89 { 90 PRINT_INFO("POST spdy EOF"); 91 *eof = 1; 92 } 93 PRINT_INFO("POST SPDYLAY_ERR_DEFERRED"); 94 return SPDYLAY_ERR_DEFERRED;//TODO SPDYLAY_ERR_DEFERRED should be used 95 } 96 97 if(length >= proxy->received_body_size) 98 { 99 ret = proxy->received_body_size; 100 newbody = NULL; 101 } 102 else 103 { 104 ret = length; 105 if(NULL == (newbody = malloc(proxy->received_body_size - length))) 106 { 107 PRINT_INFO("no memory"); 108 return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE; 109 } 110 memcpy(newbody, proxy->received_body + length, proxy->received_body_size - length); 111 } 112 memcpy(buf, proxy->received_body, ret); 113 free(proxy->received_body); 114 proxy->received_body = newbody; 115 proxy->received_body_size -= ret; 116 117 if(0 == proxy->received_body_size && proxy->receiving_done) 118 { 119 PRINT_INFO("POST spdy EOF"); 120 *eof = 1; 121 } 122 123 PRINT_INFO2("given POST bytes to spdylay: %zd", ret); 124 125 return ret; 126 } 127 128 129 /* 130 * The implementation of spdylay_send_callback type. Here we write 131 * |data| with size |length| to the network and return the number of 132 * bytes actually written. See the documentation of 133 * spdylay_send_callback for the details. 134 */ 135 static ssize_t 136 spdy_cb_send(spdylay_session *session, 137 const uint8_t *data, 138 size_t length, 139 int flags, 140 void *user_data) 141 { 142 (void)session; 143 (void)flags; 144 145 //PRINT_INFO("spdy_cb_send called"); 146 struct SPDY_Connection *connection; 147 ssize_t rv; 148 connection = (struct SPDY_Connection*)user_data; 149 connection->want_io = IO_NONE; 150 151 if(glob_opt.ignore_rst_stream 152 && 16 == length 153 && 0x80 == data[0] 154 && 0x00 == data[2] 155 && 0x03 == data[3] 156 ) 157 { 158 PRINT_INFO2("ignoring RST_STREAM for stream_id %i %i %i %i", data[8], data[9], data[10], data[11]); 159 glob_opt.ignore_rst_stream = false; 160 return 16; 161 } 162 glob_opt.ignore_rst_stream = false; 163 164 if(connection->is_tls) 165 { 166 ERR_clear_error(); 167 rv = SSL_write(connection->ssl, data, length); 168 if(rv < 0) { 169 int err = SSL_get_error(connection->ssl, rv); 170 if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { 171 connection->want_io |= (err == SSL_ERROR_WANT_READ ? 172 WANT_READ : WANT_WRITE); 173 rv = SPDYLAY_ERR_WOULDBLOCK; 174 } else { 175 rv = SPDYLAY_ERR_CALLBACK_FAILURE; 176 } 177 } 178 } 179 else 180 { 181 rv = write(connection->fd, 182 data, 183 length); 184 185 if (rv < 0) 186 { 187 switch(errno) 188 { 189 case EAGAIN: 190 #if EAGAIN != EWOULDBLOCK 191 case EWOULDBLOCK: 192 #endif 193 connection->want_io |= WANT_WRITE; 194 rv = SPDYLAY_ERR_WOULDBLOCK; 195 break; 196 197 default: 198 rv = SPDYLAY_ERR_CALLBACK_FAILURE; 199 } 200 } 201 } 202 203 PRINT_INFO2("%zd bytes written by spdy", rv); 204 205 if(rv > 0) 206 UPDATE_STAT(glob_stat.spdy_bytes_sent, rv); 207 208 return rv; 209 } 210 211 212 /* 213 * The implementation of spdylay_recv_callback type. Here we read data 214 * from the network and write them in |buf|. The capacity of |buf| is 215 * |length| bytes. Returns the number of bytes stored in |buf|. See 216 * the documentation of spdylay_recv_callback for the details. 217 */ 218 static ssize_t 219 spdy_cb_recv(spdylay_session *session, 220 uint8_t *buf, 221 size_t length, 222 int flags, 223 void *user_data) 224 { 225 (void)session; 226 (void)flags; 227 228 struct SPDY_Connection *connection; 229 ssize_t rv; 230 231 connection = (struct SPDY_Connection*)user_data; 232 //prevent monopolizing everything 233 if(!(++connection->counter % 10)) return SPDYLAY_ERR_WOULDBLOCK; 234 connection->want_io = IO_NONE; 235 if(connection->is_tls) 236 { 237 ERR_clear_error(); 238 rv = SSL_read(connection->ssl, buf, length); 239 if(rv < 0) { 240 int err = SSL_get_error(connection->ssl, rv); 241 if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { 242 connection->want_io |= (err == SSL_ERROR_WANT_READ ? 243 WANT_READ : WANT_WRITE); 244 rv = SPDYLAY_ERR_WOULDBLOCK; 245 } else { 246 rv = SPDYLAY_ERR_CALLBACK_FAILURE; 247 } 248 } else if(rv == 0) { 249 rv = SPDYLAY_ERR_EOF; 250 } 251 } 252 else 253 { 254 rv = read(connection->fd, 255 buf, 256 length); 257 258 if (rv < 0) 259 { 260 switch(errno) 261 { 262 case EAGAIN: 263 #if EAGAIN != EWOULDBLOCK 264 case EWOULDBLOCK: 265 #endif 266 connection->want_io |= WANT_READ; 267 rv = SPDYLAY_ERR_WOULDBLOCK; 268 break; 269 270 default: 271 rv = SPDYLAY_ERR_CALLBACK_FAILURE; 272 } 273 } 274 else if(rv == 0) 275 rv = SPDYLAY_ERR_EOF; 276 } 277 278 if(rv > 0) 279 UPDATE_STAT(glob_stat.spdy_bytes_received, rv); 280 281 return rv; 282 } 283 284 285 static void 286 spdy_cb_before_ctrl_send(spdylay_session *session, 287 spdylay_frame_type type, 288 spdylay_frame *frame, 289 void *user_data) 290 { 291 (void)user_data; 292 293 int32_t stream_id; 294 struct Proxy *proxy; 295 296 switch(type) { 297 case SPDYLAY_SYN_STREAM: 298 stream_id = frame->syn_stream.stream_id; 299 proxy = spdylay_session_get_stream_user_data(session, stream_id); 300 proxy->stream_id = stream_id; 301 ++glob_opt.streams_opened; 302 ++proxy->spdy_connection->streams_opened; 303 PRINT_INFO2("opening stream: str open %i; %s", glob_opt.streams_opened, proxy->url); 304 break; 305 case SPDYLAY_RST_STREAM: 306 //try to ignore duplicate RST_STREAMs 307 //TODO this will ignore RST_STREAMs also for bogus data 308 glob_opt.ignore_rst_stream = NULL==spdylay_session_get_stream_user_data(session, frame->rst_stream.stream_id); 309 PRINT_INFO2("sending RST_STREAM for %i; ignore %i; status %i", 310 frame->rst_stream.stream_id, 311 glob_opt.ignore_rst_stream, 312 frame->rst_stream.status_code); 313 break; 314 default: 315 break; 316 } 317 } 318 319 320 void 321 spdy_cb_on_ctrl_recv(spdylay_session *session, 322 spdylay_frame_type type, 323 spdylay_frame *frame, 324 void *user_data) 325 { 326 (void)user_data; 327 328 char **nv; 329 int32_t stream_id; 330 struct Proxy * proxy; 331 332 switch(type) { 333 case SPDYLAY_SYN_REPLY: 334 nv = frame->syn_reply.nv; 335 stream_id = frame->syn_reply.stream_id; 336 break; 337 case SPDYLAY_RST_STREAM: 338 stream_id = frame->rst_stream.stream_id; 339 break; 340 case SPDYLAY_HEADERS: 341 nv = frame->headers.nv; 342 stream_id = frame->headers.stream_id; 343 break; 344 default: 345 return; 346 break; 347 } 348 349 proxy = spdylay_session_get_stream_user_data(session, stream_id); 350 if(NULL == proxy) 351 { 352 PRINT_INFO2("received frame type %i for unkonwn stream id %i", type, stream_id); 353 return; 354 //DIE("no proxy obj"); 355 } 356 357 switch(type) { 358 case SPDYLAY_SYN_REPLY: 359 PRINT_INFO2("received headers for %s", proxy->url); 360 http_create_response(proxy, nv); 361 break; 362 case SPDYLAY_RST_STREAM: 363 PRINT_INFO2("received reset stream for %s", proxy->url); 364 proxy->spdy_error = true; 365 break; 366 case SPDYLAY_HEADERS: 367 PRINT_INFO2("received headers for %s", proxy->url); 368 http_create_response(proxy, nv); 369 break; 370 default: 371 return; 372 break; 373 } 374 375 glob_opt.spdy_data_received = true; 376 } 377 378 379 /* 380 * The implementation of spdylay_on_stream_close_callback type. We use 381 * this function to know the response is fully received. Since we just 382 * fetch 1 resource in this program, after reception of the response, 383 * we submit GOAWAY and close the session. 384 */ 385 static void 386 spdy_cb_on_stream_close(spdylay_session *session, 387 int32_t stream_id, 388 spdylay_status_code status_code, 389 void *user_data) 390 { 391 (void)status_code; 392 (void)user_data; 393 394 struct Proxy * proxy = spdylay_session_get_stream_user_data(session, stream_id); 395 396 assert(NULL != proxy); 397 398 --glob_opt.streams_opened; 399 --proxy->spdy_connection->streams_opened; 400 PRINT_INFO2("closing stream: str opened %i; remove proxy %i", glob_opt.streams_opened, proxy->id); 401 402 DLL_remove(proxy->spdy_connection->proxies_head, proxy->spdy_connection->proxies_tail, proxy); 403 if(proxy->http_active) 404 { 405 proxy->spdy_active = false; 406 } 407 else 408 { 409 free_proxy(proxy); 410 } 411 } 412 413 414 /* 415 * The implementation of spdylay_on_data_chunk_recv_callback type. We 416 * use this function to print the received response body. 417 */ 418 static void 419 spdy_cb_on_data_chunk_recv(spdylay_session *session, 420 uint8_t flags, 421 int32_t stream_id, 422 const uint8_t *data, 423 size_t len, 424 void *user_data) 425 { 426 (void)flags; 427 (void)user_data; 428 429 struct Proxy *proxy; 430 proxy = spdylay_session_get_stream_user_data(session, stream_id); 431 432 if(NULL == proxy) 433 { 434 PRINT_INFO("proxy in spdy_cb_on_data_chunk_recv is NULL)"); 435 return; 436 } 437 438 if(!copy_buffer(data, len, &proxy->http_body, &proxy->http_body_size)) 439 { 440 //TODO handle it better? 441 PRINT_INFO("not enough memory (malloc/realloc returned NULL)"); 442 return; 443 } 444 /* 445 if(NULL == proxy->http_body) 446 proxy->http_body = au_malloc(len); 447 else 448 proxy->http_body = realloc(proxy->http_body, proxy->http_body_size + len); 449 if(NULL == proxy->http_body) 450 { 451 PRINT_INFO("not enough memory (realloc returned NULL)"); 452 return ; 453 } 454 455 memcpy(proxy->http_body + proxy->http_body_size, data, len); 456 proxy->http_body_size += len; 457 */ 458 PRINT_INFO2("received data for %s; %zu bytes", proxy->url, len); 459 glob_opt.spdy_data_received = true; 460 } 461 462 463 static void 464 spdy_cb_on_data_recv(spdylay_session *session, 465 uint8_t flags, 466 int32_t stream_id, 467 int32_t length, 468 void *user_data) 469 { 470 (void)length; 471 (void)user_data; 472 473 if(flags & SPDYLAY_DATA_FLAG_FIN) 474 { 475 struct Proxy *proxy; 476 proxy = spdylay_session_get_stream_user_data(session, stream_id); 477 proxy->done = true; 478 PRINT_INFO2("last data frame received for %s", proxy->url); 479 } 480 } 481 482 483 /* 484 * Setup callback functions. Spdylay API offers many callback 485 * functions, but most of them are optional. The send_callback is 486 * always required. Since we use spdylay_session_recv(), the 487 * recv_callback is also required. 488 */ 489 static void 490 spdy_setup_spdylay_callbacks(spdylay_session_callbacks *callbacks) 491 { 492 memset(callbacks, 0, sizeof(spdylay_session_callbacks)); 493 callbacks->send_callback = spdy_cb_send; 494 callbacks->recv_callback = spdy_cb_recv; 495 callbacks->before_ctrl_send_callback = spdy_cb_before_ctrl_send; 496 callbacks->on_ctrl_recv_callback = spdy_cb_on_ctrl_recv; 497 callbacks->on_stream_close_callback = spdy_cb_on_stream_close; 498 callbacks->on_data_chunk_recv_callback = spdy_cb_on_data_chunk_recv; 499 callbacks->on_data_recv_callback = spdy_cb_on_data_recv; 500 } 501 502 503 /* 504 * Callback function for SSL/TLS NPN. Since this program only supports 505 * SPDY protocol, if server does not offer SPDY protocol the Spdylay 506 * library supports, we terminate program. 507 */ 508 static int 509 spdy_cb_ssl_select_next_proto(SSL* ssl, 510 unsigned char **out, 511 unsigned char *outlen, 512 const unsigned char *in, 513 unsigned int inlen, 514 void *arg) 515 { 516 (void)ssl; 517 518 int rv; 519 uint16_t *spdy_proto_version; 520 521 /* spdylay_select_next_protocol() selects SPDY protocol version the 522 Spdylay library supports. */ 523 rv = spdylay_select_next_protocol(out, outlen, in, inlen); 524 if(rv <= 0) { 525 PRINT_INFO("Server did not advertise spdy/2 or spdy/3 protocol."); 526 return rv; 527 } 528 spdy_proto_version = (uint16_t*)arg; 529 *spdy_proto_version = rv; 530 return SSL_TLSEXT_ERR_OK; 531 } 532 533 534 /* 535 * Setup SSL context. We pass |spdy_proto_version| to get negotiated 536 * SPDY protocol version in NPN callback. 537 */ 538 void 539 spdy_ssl_init_ssl_ctx(SSL_CTX *ssl_ctx, 540 uint16_t *spdy_proto_version) 541 { 542 /* Disable SSLv2 and enable all workarounds for buggy servers */ 543 SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION); 544 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); 545 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); 546 /* Set NPN callback */ 547 SSL_CTX_set_next_proto_select_cb(ssl_ctx, spdy_cb_ssl_select_next_proto, 548 spdy_proto_version); 549 } 550 551 552 static int 553 spdy_ssl_handshake(SSL *ssl, 554 int fd) 555 { 556 int rv; 557 558 if(SSL_set_fd(ssl, fd) == 0) 559 spdy_dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL)); 560 561 ERR_clear_error(); 562 rv = SSL_connect(ssl); 563 if(rv <= 0) 564 PRINT_INFO2("SSL_connect %s", ERR_error_string(ERR_get_error(), NULL)); 565 566 return rv; 567 } 568 569 570 /* 571 * Connects to the host |host| and port |port|. This function returns 572 * the file descriptor of the client socket. 573 */ 574 static int 575 spdy_socket_connect_to(const char *host, 576 uint16_t port) 577 { 578 struct addrinfo hints; 579 int fd = -1; 580 int rv; 581 char service[NI_MAXSERV]; 582 struct addrinfo *res, *rp; 583 584 //TODO checks 585 snprintf(service, sizeof(service), "%u", port); 586 memset(&hints, 0, sizeof(struct addrinfo)); 587 hints.ai_family = AF_UNSPEC; 588 hints.ai_socktype = SOCK_STREAM; 589 rv = getaddrinfo(host, service, &hints, &res); 590 if(rv != 0) 591 { 592 printf("%s\n",host); 593 spdy_dief("getaddrinfo", gai_strerror(rv)); 594 } 595 for(rp = res; rp; rp = rp->ai_next) 596 { 597 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 598 if(fd == -1) 599 continue; 600 while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 && 601 errno == EINTR); 602 if(rv == 0) 603 break; 604 close(fd); 605 fd = -1; 606 } 607 freeaddrinfo(res); 608 609 return fd; 610 } 611 612 613 static void 614 spdy_socket_make_non_block(int fd) 615 { 616 int flags; 617 int rv; 618 619 while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR); 620 621 if(flags == -1) 622 spdy_dief("fcntl", strerror(errno)); 623 624 while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR); 625 626 if(rv == -1) 627 spdy_dief("fcntl", strerror(errno)); 628 } 629 630 631 /* 632 * Setting TCP_NODELAY is not mandatory for the SPDY protocol. 633 */ 634 static void 635 spdy_socket_set_tcp_nodelay(int fd) 636 { 637 int val = 1; 638 int rv; 639 640 rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); 641 if(rv == -1) 642 spdy_dief("setsockopt", strerror(errno)); 643 } 644 645 /* 646 * Update |pollfd| based on the state of |connection|. 647 */ 648 /* 649 void 650 spdy_ctl_poll(struct pollfd *pollfd, 651 struct SPDY_Connection *connection) 652 { 653 pollfd->events = 0; 654 if(spdylay_session_want_read(connection->session) || 655 connection->want_io & WANT_READ) 656 { 657 pollfd->events |= POLLIN; 658 } 659 if(spdylay_session_want_write(connection->session) || 660 connection->want_io & WANT_WRITE) 661 { 662 pollfd->events |= POLLOUT; 663 } 664 }*/ 665 666 667 /* 668 * Update |selectfd| based on the state of |connection|. 669 */ 670 bool 671 spdy_ctl_select(fd_set * read_fd_set, 672 fd_set * write_fd_set, 673 fd_set * except_fd_set, 674 struct SPDY_Connection *connection) 675 { 676 (void)except_fd_set; 677 678 bool ret = false; 679 680 if(spdylay_session_want_read(connection->session) || 681 connection->want_io & WANT_READ) 682 { 683 FD_SET(connection->fd, read_fd_set); 684 ret = true; 685 } 686 if(spdylay_session_want_write(connection->session) || 687 connection->want_io & WANT_WRITE) 688 { 689 FD_SET(connection->fd, write_fd_set); 690 ret = true; 691 } 692 693 return ret; 694 } 695 696 697 /* 698 * Performs the network I/O. 699 */ 700 int 701 spdy_exec_io(struct SPDY_Connection *connection) 702 { 703 int rv; 704 705 rv = spdylay_session_recv(connection->session); 706 if(rv != 0) 707 { 708 PRINT_INFO2("spdylay_session_recv %i", rv); 709 return rv; 710 } 711 rv = spdylay_session_send(connection->session); 712 if(rv != 0) 713 PRINT_INFO2("spdylay_session_send %i", rv); 714 715 return rv; 716 } 717 718 719 /* 720 * Fetches the resource denoted by |uri|. 721 */ 722 struct SPDY_Connection * 723 spdy_connect(const struct URI *uri, 724 uint16_t port, 725 bool is_tls) 726 { 727 spdylay_session_callbacks callbacks; 728 int fd; 729 SSL *ssl=NULL; 730 struct SPDY_Connection * connection = NULL; 731 int rv; 732 733 spdy_setup_spdylay_callbacks(&callbacks); 734 735 /* Establish connection and setup SSL */ 736 PRINT_INFO2("connecting to %s:%i", uri->host, port); 737 fd = spdy_socket_connect_to(uri->host, port); 738 if(fd == -1) 739 { 740 PRINT_INFO("Could not open file descriptor"); 741 return NULL; 742 } 743 744 if(is_tls) 745 { 746 ssl = SSL_new(glob_opt.ssl_ctx); 747 if(ssl == NULL) { 748 spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); 749 } 750 751 //TODO non-blocking 752 /* To simplify the program, we perform SSL/TLS handshake in blocking 753 I/O. */ 754 glob_opt.spdy_proto_version = 0; 755 rv = spdy_ssl_handshake(ssl, fd); 756 if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2)) 757 { 758 PRINT_INFO("Closing SSL"); 759 //no spdy on the other side 760 goto free_and_fail; 761 } 762 } 763 else 764 { 765 glob_opt.spdy_proto_version = 3; 766 } 767 768 if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection)))) 769 goto free_and_fail; 770 771 connection->is_tls = is_tls; 772 connection->ssl = ssl; 773 connection->want_io = IO_NONE; 774 if(NULL == (connection->host = strdup(uri->host))) 775 goto free_and_fail; 776 777 /* Here make file descriptor non-block */ 778 spdy_socket_make_non_block(fd); 779 spdy_socket_set_tcp_nodelay(fd); 780 781 PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version); 782 rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version, 783 &callbacks, connection); 784 if(rv != 0) { 785 spdy_diec("spdylay_session_client_new", rv); 786 } 787 788 connection->fd = fd; 789 790 return connection; 791 792 //for GOTO 793 free_and_fail: 794 if(NULL != connection) 795 { 796 free(connection->host); 797 free(connection); 798 } 799 800 if(is_tls) 801 SSL_shutdown(ssl); 802 803 close(fd); 804 805 if(is_tls) 806 SSL_free(ssl); 807 808 return NULL; 809 } 810 811 812 void 813 spdy_free_connection(struct SPDY_Connection * connection) 814 { 815 struct Proxy *proxy; 816 struct Proxy *proxy_next; 817 818 if(NULL != connection) 819 { 820 for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy_next) 821 { 822 proxy_next = proxy->next; 823 DLL_remove(connection->proxies_head, connection->proxies_tail, proxy); 824 proxy->spdy_active = false; 825 proxy->spdy_error = true; 826 PRINT_INFO2("spdy_free_connection for id %i", proxy->id); 827 if(!proxy->http_active) 828 { 829 free_proxy(proxy); 830 } 831 } 832 spdylay_session_del(connection->session); 833 SSL_free(connection->ssl); 834 free(connection->host); 835 free(connection); 836 //connection->session = NULL; 837 } 838 } 839 840 841 int 842 spdy_request(const char **nv, 843 struct Proxy *proxy, 844 bool with_body) 845 { 846 int ret; 847 uint16_t port; 848 struct SPDY_Connection *connection; 849 spdylay_data_provider post_data; 850 851 if(glob_opt.only_proxy) 852 { 853 connection = glob_opt.spdy_connection; 854 } 855 else 856 { 857 connection = glob_opt.spdy_connections_head; 858 while(NULL != connection) 859 { 860 if(0 == strcasecmp(proxy->uri->host, connection->host)) 861 break; 862 connection = connection->next; 863 } 864 865 if(NULL == connection) 866 { 867 //connect to host 868 port = proxy->uri->port; 869 if(0 == port) port = 443; 870 connection = spdy_connect(proxy->uri, port, true); 871 if(NULL != connection) 872 { 873 DLL_insert(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); 874 glob_opt.total_spdy_connections++; 875 } 876 else 877 connection = glob_opt.spdy_connection; 878 } 879 } 880 881 if(NULL == connection) 882 { 883 PRINT_INFO("there is no proxy!"); 884 return -1; 885 } 886 887 proxy->spdy_connection = connection; 888 if(with_body) 889 { 890 post_data.source.ptr = proxy; 891 post_data.read_callback = &spdy_cb_data_source_read; 892 ret = spdylay_submit_request(connection->session, 0, nv, &post_data, proxy); 893 } 894 else 895 ret = spdylay_submit_request(connection->session, 0, nv, NULL, proxy); 896 897 if(ret != 0) { 898 spdy_diec("spdylay_spdy_submit_request", ret); 899 } 900 PRINT_INFO2("adding proxy %i", proxy->id); 901 if(NULL != connection->proxies_head) 902 PRINT_INFO2("before proxy %i", connection->proxies_head->id); 903 DLL_insert(connection->proxies_head, connection->proxies_tail, proxy); 904 905 return ret; 906 } 907 908 /* 909 void 910 spdy_get_pollfdset(struct pollfd fds[], 911 struct SPDY_Connection *connections[], 912 unsigned int max_size, 913 nfds_t *real_size) 914 { 915 struct SPDY_Connection *connection; 916 struct Proxy *proxy; 917 918 *real_size = 0; 919 if(max_size<1) 920 return; 921 922 if(NULL != glob_opt.spdy_connection) 923 { 924 spdy_ctl_poll(&(fds[*real_size]), glob_opt.spdy_connection); 925 if(!fds[*real_size].events) 926 { 927 //PRINT_INFO("TODO drop connection"); 928 glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened; 929 930 for(proxy = glob_opt.spdy_connection->proxies_head; NULL != proxy; proxy=proxy->next) 931 { 932 abort(); 933 DLL_remove(glob_opt.spdy_connection->proxies_head, glob_opt.spdy_connection->proxies_tail, proxy); 934 proxy->spdy_active = false; 935 } 936 spdy_free_connection(glob_opt.spdy_connection); 937 glob_opt.spdy_connection = NULL; 938 } 939 else 940 { 941 fds[*real_size].fd = glob_opt.spdy_connection->fd; 942 connections[*real_size] = glob_opt.spdy_connection; 943 ++(*real_size); 944 } 945 } 946 947 connection = glob_opt.spdy_connections_head; 948 949 while(NULL != connection && *real_size < max_size) 950 { 951 assert(!glob_opt.only_proxy); 952 spdy_ctl_poll(&(fds[*real_size]), connection); 953 if(!fds[*real_size].events) 954 { 955 //PRINT_INFO("TODO drop connection"); 956 glob_opt.streams_opened -= connection->streams_opened; 957 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); 958 glob_opt.total_spdy_connections--; 959 960 for(proxy = connection->proxies_head; NULL != proxy; proxy=proxy->next) 961 { 962 abort(); 963 DLL_remove(connection->proxies_head, connection->proxies_tail, proxy); 964 proxy->spdy_active = false; 965 } 966 spdy_free_connection(connection); 967 } 968 else 969 { 970 fds[*real_size].fd = connection->fd; 971 connections[*real_size] = connection; 972 ++(*real_size); 973 } 974 connection = connection->next; 975 } 976 977 //, "TODO max num of conn reached; close something" 978 assert(NULL == connection); 979 } 980 */ 981 982 int 983 spdy_get_selectfdset(fd_set * read_fd_set, 984 fd_set * write_fd_set, 985 fd_set * except_fd_set, 986 struct SPDY_Connection *connections[], 987 unsigned int max_size, 988 nfds_t *real_size) 989 { 990 struct SPDY_Connection *connection; 991 struct SPDY_Connection *next_connection; 992 bool ret; 993 int maxfd = 0; 994 995 *real_size = 0; 996 if(max_size<1) 997 return 0; 998 999 if(NULL != glob_opt.spdy_connection) 1000 { 1001 ret = spdy_ctl_select(read_fd_set, 1002 write_fd_set, 1003 except_fd_set, glob_opt.spdy_connection); 1004 if(!ret) 1005 { 1006 glob_opt.streams_opened -= glob_opt.spdy_connection->streams_opened; 1007 1008 PRINT_INFO("spdy_free_connection in spdy_get_selectfdset"); 1009 spdy_free_connection(glob_opt.spdy_connection); 1010 glob_opt.spdy_connection = NULL; 1011 } 1012 else 1013 { 1014 connections[*real_size] = glob_opt.spdy_connection; 1015 ++(*real_size); 1016 if(maxfd < glob_opt.spdy_connection->fd) maxfd = glob_opt.spdy_connection->fd; 1017 } 1018 } 1019 1020 connection = glob_opt.spdy_connections_head; 1021 1022 while(NULL != connection && *real_size < max_size) 1023 { 1024 assert(!glob_opt.only_proxy); 1025 ret = spdy_ctl_select(read_fd_set, 1026 write_fd_set, 1027 except_fd_set, connection); 1028 1029 next_connection = connection->next; 1030 if(!ret) 1031 { 1032 glob_opt.streams_opened -= connection->streams_opened; 1033 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connection); 1034 glob_opt.total_spdy_connections--; 1035 1036 PRINT_INFO("spdy_free_connection in spdy_get_selectfdset"); 1037 spdy_free_connection(connection); 1038 } 1039 else 1040 { 1041 connections[*real_size] = connection; 1042 ++(*real_size); 1043 if(maxfd < connection->fd) maxfd = connection->fd; 1044 } 1045 connection = next_connection; 1046 } 1047 1048 //, "TODO max num of conn reached; close something" 1049 assert(NULL == connection); 1050 1051 return maxfd; 1052 } 1053 1054 /* 1055 void 1056 spdy_run(struct pollfd fds[], 1057 struct SPDY_Connection *connections[], 1058 int size) 1059 { 1060 int i; 1061 int ret; 1062 struct Proxy *proxy; 1063 1064 for(i=0; i<size; ++i) 1065 { 1066 // PRINT_INFO2("exec about to be called for %s", connections[i]->host); 1067 if(fds[i].revents & (POLLIN | POLLOUT)) 1068 { 1069 ret = spdy_exec_io(connections[i]); 1070 //PRINT_INFO2("%i",ret); 1071 //if((spdy_pollfds[i].revents & POLLHUP) || (spdy_pollfds[0].revents & POLLERR)) 1072 // PRINT_INFO("SPDY SPDY_Connection error"); 1073 1074 //TODO POLLRDHUP 1075 // always close on ret != 0? 1076 1077 if(0 != ret) 1078 { 1079 glob_opt.streams_opened -= connections[i]->streams_opened; 1080 if(connections[i] == glob_opt.spdy_connection) 1081 { 1082 glob_opt.spdy_connection = NULL; 1083 } 1084 else 1085 { 1086 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]); 1087 glob_opt.total_spdy_connections--; 1088 } 1089 for(proxy = connections[i]->proxies_head; NULL != proxy; proxy=proxy->next) 1090 { 1091 abort(); 1092 DLL_remove(connections[i]->proxies_head, connections[i]->proxies_tail, proxy); 1093 proxy->spdy_active = false; 1094 proxy->spdy_error = true; 1095 PRINT_INFO2("spdy_free_connection for id %i", proxy->id); 1096 } 1097 PRINT_INFO("spdy_free_connection in loop"); 1098 spdy_free_connection(connections[i]); 1099 } 1100 } 1101 else 1102 PRINT_INFO("not called"); 1103 } 1104 } 1105 */ 1106 1107 void 1108 spdy_run_select(fd_set * read_fd_set, 1109 fd_set * write_fd_set, 1110 fd_set * except_fd_set, 1111 struct SPDY_Connection *connections[], 1112 int size) 1113 { 1114 int i; 1115 int ret; 1116 1117 for(i=0; i<size; ++i) 1118 { 1119 // PRINT_INFO2("exec about to be called for %s", connections[i]->host); 1120 if(FD_ISSET(connections[i]->fd, read_fd_set) || FD_ISSET(connections[i]->fd, write_fd_set) || FD_ISSET(connections[i]->fd, except_fd_set)) 1121 { 1122 //raise(SIGINT); 1123 ret = spdy_exec_io(connections[i]); 1124 1125 if(0 != ret) 1126 { 1127 glob_opt.streams_opened -= connections[i]->streams_opened; 1128 if(connections[i] == glob_opt.spdy_connection) 1129 { 1130 glob_opt.spdy_connection = NULL; 1131 } 1132 else 1133 { 1134 DLL_remove(glob_opt.spdy_connections_head, glob_opt.spdy_connections_tail, connections[i]); 1135 glob_opt.total_spdy_connections--; 1136 } 1137 PRINT_INFO("in spdy_run_select"); 1138 spdy_free_connection(connections[i]); 1139 } 1140 } 1141 else 1142 { 1143 PRINT_INFO("not called"); 1144 //PRINT_INFO2("connection->want_io %i",connections[i]->want_io); 1145 //PRINT_INFO2("read %i",spdylay_session_want_read(connections[i]->session)); 1146 //PRINT_INFO2("write %i",spdylay_session_want_write(connections[i]->session)); 1147 //raise(SIGINT); 1148 } 1149 } 1150 } 1151