cfilters.c (34042B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "curl_setup.h" 26 27 #include "urldata.h" 28 #include "strerror.h" 29 #include "cfilters.h" 30 #include "connect.h" 31 #include "url.h" 32 #include "sendf.h" 33 #include "sockaddr.h" /* required for Curl_sockaddr_storage */ 34 #include "multiif.h" 35 #include "progress.h" 36 #include "select.h" 37 #include "curlx/warnless.h" 38 #include "curlx/strparse.h" 39 40 /* The last 3 #include files should be in this order */ 41 #include "curl_printf.h" 42 #include "curl_memory.h" 43 #include "memdebug.h" 44 45 static void cf_cntrl_update_info(struct Curl_easy *data, 46 struct connectdata *conn); 47 48 #ifdef UNITTESTS 49 /* used by unit2600.c */ 50 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data) 51 { 52 cf->connected = FALSE; 53 if(cf->next) 54 cf->next->cft->do_close(cf->next, data); 55 } 56 #endif 57 58 CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf, 59 struct Curl_easy *data, bool *done) 60 { 61 (void)cf; 62 (void)data; 63 *done = TRUE; 64 return CURLE_OK; 65 } 66 67 static void conn_report_connect_stats(struct Curl_easy *data, 68 struct connectdata *conn); 69 70 void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, 71 struct Curl_easy *data, 72 struct easy_pollset *ps) 73 { 74 /* NOP */ 75 (void)cf; 76 (void)data; 77 (void)ps; 78 } 79 80 bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, 81 const struct Curl_easy *data) 82 { 83 return cf->next ? 84 cf->next->cft->has_data_pending(cf->next, data) : FALSE; 85 } 86 87 CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, 88 const void *buf, size_t len, bool eos, 89 size_t *pnwritten) 90 { 91 if(cf->next) 92 return cf->next->cft->do_send(cf->next, data, buf, len, eos, pnwritten); 93 *pnwritten = 0; 94 return CURLE_RECV_ERROR; 95 } 96 97 CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, 98 char *buf, size_t len, size_t *pnread) 99 { 100 if(cf->next) 101 return cf->next->cft->do_recv(cf->next, data, buf, len, pnread); 102 *pnread = 0; 103 return CURLE_SEND_ERROR; 104 } 105 106 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf, 107 struct Curl_easy *data, 108 bool *input_pending) 109 { 110 return cf->next ? 111 cf->next->cft->is_alive(cf->next, data, input_pending) : 112 FALSE; /* pessimistic in absence of data */ 113 } 114 115 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf, 116 struct Curl_easy *data) 117 { 118 return cf->next ? 119 cf->next->cft->keep_alive(cf->next, data) : 120 CURLE_OK; 121 } 122 123 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf, 124 struct Curl_easy *data, 125 int query, int *pres1, void *pres2) 126 { 127 return cf->next ? 128 cf->next->cft->query(cf->next, data, query, pres1, pres2) : 129 CURLE_UNKNOWN_OPTION; 130 } 131 132 void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf, 133 struct Curl_easy *data) 134 { 135 struct Curl_cfilter *cfn, *cf = *pcf; 136 137 if(cf) { 138 *pcf = NULL; 139 while(cf) { 140 cfn = cf->next; 141 /* prevent destroying filter to mess with its sub-chain, since 142 * we have the reference now and will call destroy on it. 143 */ 144 cf->next = NULL; 145 cf->cft->destroy(cf, data); 146 free(cf); 147 cf = cfn; 148 } 149 } 150 } 151 152 void Curl_conn_cf_discard_all(struct Curl_easy *data, 153 struct connectdata *conn, int index) 154 { 155 Curl_conn_cf_discard_chain(&conn->cfilter[index], data); 156 } 157 158 void Curl_conn_close(struct Curl_easy *data, int index) 159 { 160 struct Curl_cfilter *cf; 161 162 DEBUGASSERT(data->conn); 163 /* it is valid to call that without filters being present */ 164 cf = data->conn->cfilter[index]; 165 if(cf) { 166 cf->cft->do_close(cf, data); 167 } 168 Curl_shutdown_clear(data, index); 169 } 170 171 CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done) 172 { 173 struct Curl_cfilter *cf; 174 CURLcode result = CURLE_OK; 175 timediff_t timeout_ms; 176 struct curltime now; 177 178 DEBUGASSERT(data->conn); 179 /* Get the first connected filter that is not shut down already. */ 180 cf = data->conn->cfilter[sockindex]; 181 while(cf && (!cf->connected || cf->shutdown)) 182 cf = cf->next; 183 184 if(!cf) { 185 *done = TRUE; 186 return CURLE_OK; 187 } 188 189 *done = FALSE; 190 now = curlx_now(); 191 if(!Curl_shutdown_started(data, sockindex)) { 192 CURL_TRC_M(data, "shutdown start on%s connection", 193 sockindex ? " secondary" : ""); 194 Curl_shutdown_start(data, sockindex, 0, &now); 195 } 196 else { 197 timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now); 198 if(timeout_ms < 0) { 199 /* info message, since this might be regarded as acceptable */ 200 infof(data, "shutdown timeout"); 201 return CURLE_OPERATION_TIMEDOUT; 202 } 203 } 204 205 while(cf) { 206 if(!cf->shutdown) { 207 bool cfdone = FALSE; 208 result = cf->cft->do_shutdown(cf, data, &cfdone); 209 if(result) { 210 CURL_TRC_CF(data, cf, "shut down failed with %d", result); 211 return result; 212 } 213 else if(!cfdone) { 214 CURL_TRC_CF(data, cf, "shut down not done yet"); 215 return CURLE_OK; 216 } 217 CURL_TRC_CF(data, cf, "shut down successfully"); 218 cf->shutdown = TRUE; 219 } 220 cf = cf->next; 221 } 222 *done = (!result); 223 return result; 224 } 225 226 CURLcode Curl_cf_recv(struct Curl_easy *data, int num, char *buf, 227 size_t len, size_t *pnread) 228 { 229 struct Curl_cfilter *cf; 230 231 DEBUGASSERT(data); 232 DEBUGASSERT(data->conn); 233 cf = data->conn->cfilter[num]; 234 while(cf && !cf->connected) 235 cf = cf->next; 236 if(cf) 237 return cf->cft->do_recv(cf, data, buf, len, pnread); 238 failf(data, "recv: no filter connected"); 239 DEBUGASSERT(0); 240 *pnread = 0; 241 return CURLE_FAILED_INIT; 242 } 243 244 CURLcode Curl_cf_send(struct Curl_easy *data, int num, 245 const void *mem, size_t len, bool eos, 246 size_t *pnwritten) 247 { 248 struct Curl_cfilter *cf; 249 250 DEBUGASSERT(data); 251 DEBUGASSERT(data->conn); 252 cf = data->conn->cfilter[num]; 253 while(cf && !cf->connected) 254 cf = cf->next; 255 if(cf) { 256 return cf->cft->do_send(cf, data, mem, len, eos, pnwritten); 257 } 258 failf(data, "send: no filter connected"); 259 DEBUGASSERT(0); 260 *pnwritten = 0; 261 return CURLE_FAILED_INIT; 262 } 263 264 struct cf_io_ctx { 265 struct Curl_easy *data; 266 struct Curl_cfilter *cf; 267 }; 268 269 static CURLcode cf_bufq_reader(void *writer_ctx, 270 unsigned char *buf, size_t blen, 271 size_t *pnread) 272 { 273 struct cf_io_ctx *io = writer_ctx; 274 return Curl_conn_cf_recv(io->cf, io->data, (char *)buf, blen, pnread); 275 } 276 277 CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf, 278 struct Curl_easy *data, 279 struct bufq *bufq, 280 size_t maxlen, 281 size_t *pnread) 282 { 283 struct cf_io_ctx io; 284 285 if(!cf || !data) { 286 *pnread = 0; 287 return CURLE_BAD_FUNCTION_ARGUMENT; 288 } 289 io.data = data; 290 io.cf = cf; 291 return Curl_bufq_sipn(bufq, maxlen, cf_bufq_reader, &io, pnread); 292 } 293 294 static CURLcode cf_bufq_writer(void *writer_ctx, 295 const unsigned char *buf, size_t buflen, 296 size_t *pnwritten) 297 { 298 struct cf_io_ctx *io = writer_ctx; 299 return Curl_conn_cf_send(io->cf, io->data, (const char *)buf, 300 buflen, FALSE, pnwritten); 301 } 302 303 CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf, 304 struct Curl_easy *data, 305 struct bufq *bufq, 306 const unsigned char *buf, size_t blen, 307 size_t *pnwritten) 308 { 309 struct cf_io_ctx io; 310 311 if(!cf || !data) { 312 *pnwritten = 0; 313 return CURLE_BAD_FUNCTION_ARGUMENT; 314 } 315 io.data = data; 316 io.cf = cf; 317 if(buf && blen) 318 return Curl_bufq_write_pass(bufq, buf, blen, cf_bufq_writer, &io, 319 pnwritten); 320 else 321 return Curl_bufq_pass(bufq, cf_bufq_writer, &io, pnwritten); 322 } 323 324 CURLcode Curl_cf_create(struct Curl_cfilter **pcf, 325 const struct Curl_cftype *cft, 326 void *ctx) 327 { 328 struct Curl_cfilter *cf; 329 CURLcode result = CURLE_OUT_OF_MEMORY; 330 331 DEBUGASSERT(cft); 332 cf = calloc(1, sizeof(*cf)); 333 if(!cf) 334 goto out; 335 336 cf->cft = cft; 337 cf->ctx = ctx; 338 result = CURLE_OK; 339 out: 340 *pcf = cf; 341 return result; 342 } 343 344 void Curl_conn_cf_add(struct Curl_easy *data, 345 struct connectdata *conn, 346 int index, 347 struct Curl_cfilter *cf) 348 { 349 (void)data; 350 DEBUGASSERT(conn); 351 DEBUGASSERT(!cf->conn); 352 DEBUGASSERT(!cf->next); 353 354 cf->next = conn->cfilter[index]; 355 cf->conn = conn; 356 cf->sockindex = index; 357 conn->cfilter[index] = cf; 358 CURL_TRC_CF(data, cf, "added"); 359 } 360 361 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at, 362 struct Curl_cfilter *cf_new) 363 { 364 struct Curl_cfilter *tail, **pnext; 365 366 DEBUGASSERT(cf_at); 367 DEBUGASSERT(cf_new); 368 DEBUGASSERT(!cf_new->conn); 369 370 tail = cf_at->next; 371 cf_at->next = cf_new; 372 do { 373 cf_new->conn = cf_at->conn; 374 cf_new->sockindex = cf_at->sockindex; 375 pnext = &cf_new->next; 376 cf_new = cf_new->next; 377 } while(cf_new); 378 *pnext = tail; 379 } 380 381 bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, 382 struct Curl_cfilter *discard, 383 struct Curl_easy *data, 384 bool destroy_always) 385 { 386 struct Curl_cfilter **pprev = &cf->next; 387 bool found = FALSE; 388 389 /* remove from sub-chain and destroy */ 390 DEBUGASSERT(cf); 391 while(*pprev) { 392 if(*pprev == cf) { 393 *pprev = discard->next; 394 discard->next = NULL; 395 found = TRUE; 396 break; 397 } 398 pprev = &((*pprev)->next); 399 } 400 if(found || destroy_always) { 401 discard->next = NULL; 402 discard->cft->destroy(discard, data); 403 free(discard); 404 } 405 return found; 406 } 407 408 CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, 409 struct Curl_easy *data, 410 bool *done) 411 { 412 if(cf) 413 return cf->cft->do_connect(cf, data, done); 414 return CURLE_FAILED_INIT; 415 } 416 417 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) 418 { 419 if(cf) 420 cf->cft->do_close(cf, data); 421 } 422 423 CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, 424 const void *buf, size_t len, bool eos, 425 size_t *pnwritten) 426 { 427 if(cf) 428 return cf->cft->do_send(cf, data, buf, len, eos, pnwritten); 429 *pnwritten = 0; 430 return CURLE_SEND_ERROR; 431 } 432 433 CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, 434 char *buf, size_t len, size_t *pnread) 435 { 436 if(cf) 437 return cf->cft->do_recv(cf, data, buf, len, pnread); 438 *pnread = 0; 439 return CURLE_RECV_ERROR; 440 } 441 442 CURLcode Curl_conn_connect(struct Curl_easy *data, 443 int sockindex, 444 bool blocking, 445 bool *done) 446 { 447 #define CF_CONN_NUM_POLLS_ON_STACK 5 448 struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK]; 449 struct curl_pollfds cpfds; 450 struct Curl_cfilter *cf; 451 CURLcode result = CURLE_OK; 452 453 DEBUGASSERT(data); 454 DEBUGASSERT(data->conn); 455 456 cf = data->conn->cfilter[sockindex]; 457 if(!cf) { 458 *done = FALSE; 459 return CURLE_FAILED_INIT; 460 } 461 462 *done = cf->connected; 463 if(*done) 464 return CURLE_OK; 465 466 Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK); 467 while(!*done) { 468 if(Curl_conn_needs_flush(data, sockindex)) { 469 DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex)); 470 result = Curl_conn_flush(data, sockindex); 471 if(result && (result != CURLE_AGAIN)) 472 return result; 473 } 474 475 result = cf->cft->do_connect(cf, data, done); 476 CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d", 477 blocking, result, *done); 478 if(!result && *done) { 479 /* Now that the complete filter chain is connected, let all filters 480 * persist information at the connection. E.g. cf-socket sets the 481 * socket and ip related information. */ 482 cf_cntrl_update_info(data, data->conn); 483 conn_report_connect_stats(data, data->conn); 484 data->conn->keepalive = curlx_now(); 485 Curl_verboseconnect(data, data->conn, sockindex); 486 goto out; 487 } 488 else if(result) { 489 CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d", 490 result); 491 conn_report_connect_stats(data, data->conn); 492 goto out; 493 } 494 495 if(!blocking) 496 goto out; 497 else { 498 /* check allowed time left */ 499 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); 500 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); 501 struct easy_pollset ps; 502 int rc; 503 504 if(timeout_ms < 0) { 505 /* no need to continue if time already is up */ 506 failf(data, "connect timeout"); 507 result = CURLE_OPERATION_TIMEDOUT; 508 goto out; 509 } 510 511 CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll"); 512 Curl_pollfds_reset(&cpfds); 513 memset(&ps, 0, sizeof(ps)); 514 /* In general, we want to send after connect, wait on that. */ 515 if(sockfd != CURL_SOCKET_BAD) 516 Curl_pollset_set_out_only(data, &ps, sockfd); 517 Curl_conn_adjust_pollset(data, data->conn, &ps); 518 result = Curl_pollfds_add_ps(&cpfds, &ps); 519 if(result) 520 goto out; 521 522 rc = Curl_poll(cpfds.pfds, cpfds.n, 523 CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10))); 524 CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d", 525 rc); 526 if(rc < 0) { 527 result = CURLE_COULDNT_CONNECT; 528 goto out; 529 } 530 /* continue iterating */ 531 } 532 } 533 534 out: 535 Curl_pollfds_cleanup(&cpfds); 536 return result; 537 } 538 539 bool Curl_conn_is_setup(struct connectdata *conn, int sockindex) 540 { 541 return (conn->cfilter[sockindex] != NULL); 542 } 543 544 bool Curl_conn_is_connected(struct connectdata *conn, int sockindex) 545 { 546 struct Curl_cfilter *cf; 547 548 cf = conn->cfilter[sockindex]; 549 return cf && cf->connected; 550 } 551 552 bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex) 553 { 554 struct Curl_cfilter *cf; 555 556 cf = data->conn->cfilter[sockindex]; 557 while(cf) { 558 if(cf->connected) 559 return TRUE; 560 if(cf->cft->flags & CF_TYPE_IP_CONNECT) 561 return FALSE; 562 cf = cf->next; 563 } 564 return FALSE; 565 } 566 567 bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf) 568 { 569 for(; cf; cf = cf->next) { 570 if(cf->cft->flags & CF_TYPE_SSL) 571 return TRUE; 572 if(cf->cft->flags & CF_TYPE_IP_CONNECT) 573 return FALSE; 574 } 575 return FALSE; 576 } 577 578 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) 579 { 580 return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE; 581 } 582 583 bool Curl_conn_get_ssl_info(struct Curl_easy *data, 584 struct connectdata *conn, int sockindex, 585 struct curl_tlssessioninfo *info) 586 { 587 if(Curl_conn_is_ssl(conn, sockindex)) { 588 struct Curl_cfilter *cf = conn->cfilter[sockindex]; 589 CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO, 590 NULL, (void *)info) : CURLE_UNKNOWN_OPTION; 591 return !result; 592 } 593 return FALSE; 594 } 595 596 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) 597 { 598 struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; 599 600 for(; cf; cf = cf->next) { 601 if(cf->cft->flags & CF_TYPE_MULTIPLEX) 602 return TRUE; 603 if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL)) 604 return FALSE; 605 } 606 return FALSE; 607 } 608 609 unsigned char Curl_conn_get_transport(struct Curl_easy *data, 610 struct connectdata *conn) 611 { 612 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; 613 return Curl_conn_cf_get_transport(cf, data); 614 } 615 616 unsigned char Curl_conn_http_version(struct Curl_easy *data, 617 struct connectdata *conn) 618 { 619 struct Curl_cfilter *cf; 620 CURLcode result = CURLE_UNKNOWN_OPTION; 621 unsigned char v = 0; 622 623 cf = conn->cfilter[FIRSTSOCKET]; 624 for(; cf; cf = cf->next) { 625 if(cf->cft->flags & CF_TYPE_HTTP) { 626 int value = 0; 627 result = cf->cft->query(cf, data, CF_QUERY_HTTP_VERSION, &value, NULL); 628 if(!result && ((value < 0) || (value > 255))) 629 result = CURLE_FAILED_INIT; 630 else 631 v = (unsigned char)value; 632 break; 633 } 634 if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL)) 635 break; 636 } 637 return (unsigned char)(result ? 0 : v); 638 } 639 640 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex) 641 { 642 struct Curl_cfilter *cf; 643 644 (void)data; 645 DEBUGASSERT(data); 646 DEBUGASSERT(data->conn); 647 648 cf = data->conn->cfilter[sockindex]; 649 while(cf && !cf->connected) { 650 cf = cf->next; 651 } 652 if(cf) { 653 return cf->cft->has_data_pending(cf, data); 654 } 655 return FALSE; 656 } 657 658 bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, 659 struct Curl_easy *data) 660 { 661 CURLcode result; 662 int pending = 0; 663 result = cf ? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH, 664 &pending, NULL) : CURLE_UNKNOWN_OPTION; 665 return (result || !pending) ? FALSE : TRUE; 666 } 667 668 bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex) 669 { 670 return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data); 671 } 672 673 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, 674 struct Curl_easy *data, 675 struct easy_pollset *ps) 676 { 677 /* Get the lowest not-connected filter, if there are any */ 678 while(cf && !cf->connected && cf->next && !cf->next->connected) 679 cf = cf->next; 680 /* Skip all filters that have already shut down */ 681 while(cf && cf->shutdown) 682 cf = cf->next; 683 /* From there on, give all filters a chance to adjust the pollset. 684 * Lower filters are called later, so they may override */ 685 while(cf) { 686 cf->cft->adjust_pollset(cf, data, ps); 687 cf = cf->next; 688 } 689 } 690 691 void Curl_conn_adjust_pollset(struct Curl_easy *data, 692 struct connectdata *conn, 693 struct easy_pollset *ps) 694 { 695 int i; 696 697 DEBUGASSERT(data); 698 DEBUGASSERT(conn); 699 for(i = 0; i < 2; ++i) { 700 Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps); 701 } 702 } 703 704 int Curl_conn_cf_poll(struct Curl_cfilter *cf, 705 struct Curl_easy *data, 706 timediff_t timeout_ms) 707 { 708 struct easy_pollset ps; 709 struct pollfd pfds[MAX_SOCKSPEREASYHANDLE]; 710 unsigned int i, npfds = 0; 711 712 DEBUGASSERT(cf); 713 DEBUGASSERT(data); 714 DEBUGASSERT(data->conn); 715 memset(&ps, 0, sizeof(ps)); 716 memset(pfds, 0, sizeof(pfds)); 717 718 Curl_conn_cf_adjust_pollset(cf, data, &ps); 719 DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE); 720 for(i = 0; i < ps.num; ++i) { 721 short events = 0; 722 if(ps.actions[i] & CURL_POLL_IN) { 723 events |= POLLIN; 724 } 725 if(ps.actions[i] & CURL_POLL_OUT) { 726 events |= POLLOUT; 727 } 728 if(events) { 729 pfds[npfds].fd = ps.sockets[i]; 730 pfds[npfds].events = events; 731 ++npfds; 732 } 733 } 734 735 if(!npfds) 736 DEBUGF(infof(data, "no sockets to poll!")); 737 return Curl_poll(pfds, npfds, timeout_ms); 738 } 739 740 void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex, 741 const char **phost, int *pport) 742 { 743 struct Curl_cfilter *cf, *cf_proxy = NULL; 744 745 DEBUGASSERT(data->conn); 746 cf = data->conn->cfilter[sockindex]; 747 /* Find the "lowest" tunneling proxy filter that has not connected yet. */ 748 while(cf && !cf->connected) { 749 if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) == 750 (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) 751 cf_proxy = cf; 752 cf = cf->next; 753 } 754 /* cf_proxy (!= NULL) is not connected yet. It is talking 755 * to an interim host and any authentication or other things apply 756 * to this interim host and port. */ 757 if(!cf_proxy || cf_proxy->cft->query(cf_proxy, data, CF_QUERY_HOST_PORT, 758 pport, CURL_UNCONST(phost))) { 759 /* Everything connected or query unsuccessful, the overall 760 * connection's destination is the answer */ 761 *phost = data->conn->host.name; 762 *pport = data->conn->remote_port; 763 } 764 } 765 766 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf, 767 struct Curl_easy *data, 768 int event, int arg1, void *arg2) 769 { 770 (void)cf; 771 (void)data; 772 (void)event; 773 (void)arg1; 774 (void)arg2; 775 return CURLE_OK; 776 } 777 778 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf, 779 struct Curl_easy *data, 780 bool ignore_result, 781 int event, int arg1, void *arg2) 782 { 783 CURLcode result = CURLE_OK; 784 785 for(; cf; cf = cf->next) { 786 if(Curl_cf_def_cntrl == cf->cft->cntrl) 787 continue; 788 result = cf->cft->cntrl(cf, data, event, arg1, arg2); 789 if(!ignore_result && result) 790 break; 791 } 792 return result; 793 } 794 795 curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf, 796 struct Curl_easy *data) 797 { 798 curl_socket_t sock; 799 if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock)) 800 return sock; 801 return CURL_SOCKET_BAD; 802 } 803 804 unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, 805 struct Curl_easy *data) 806 { 807 int transport = 0; 808 if(cf && !cf->cft->query(cf, data, CF_QUERY_TRANSPORT, &transport, NULL)) 809 return (unsigned char)transport; 810 return (unsigned char)(data->conn ? data->conn->transport_wanted : 0); 811 } 812 813 static const struct Curl_sockaddr_ex * 814 cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data) 815 { 816 const struct Curl_sockaddr_ex *remote_addr = NULL; 817 if(cf && 818 !cf->cft->query(cf, data, CF_QUERY_REMOTE_ADDR, NULL, 819 CURL_UNCONST(&remote_addr))) 820 return remote_addr; 821 return NULL; 822 } 823 824 CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf, 825 struct Curl_easy *data, 826 int *is_ipv6, struct ip_quadruple *ipquad) 827 { 828 if(cf) 829 return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad); 830 return CURLE_UNKNOWN_OPTION; 831 } 832 833 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex) 834 { 835 struct Curl_cfilter *cf; 836 837 cf = data->conn ? data->conn->cfilter[sockindex] : NULL; 838 /* if the top filter has not connected, ask it (and its sub-filters) 839 * for the socket. Otherwise conn->sock[sockindex] should have it. 840 */ 841 if(cf && !cf->connected) 842 return Curl_conn_cf_get_socket(cf, data); 843 return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD; 844 } 845 846 const struct Curl_sockaddr_ex * 847 Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex) 848 { 849 struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL; 850 return cf ? cf_get_remote_addr(cf, data) : NULL; 851 } 852 853 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex) 854 { 855 if(data->conn) { 856 struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; 857 if(cf) 858 (void)Curl_conn_cf_cntrl(cf, data, TRUE, 859 CF_CTRL_FORGET_SOCKET, 0, NULL); 860 fake_sclose(data->conn->sock[sockindex]); 861 data->conn->sock[sockindex] = CURL_SOCKET_BAD; 862 } 863 } 864 865 static CURLcode cf_cntrl_all(struct connectdata *conn, 866 struct Curl_easy *data, 867 bool ignore_result, 868 int event, int arg1, void *arg2) 869 { 870 CURLcode result = CURLE_OK; 871 size_t i; 872 873 for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) { 874 result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result, 875 event, arg1, arg2); 876 if(!ignore_result && result) 877 break; 878 } 879 return result; 880 } 881 882 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data) 883 { 884 return cf_cntrl_all(data->conn, data, FALSE, 885 CF_CTRL_DATA_SETUP, 0, NULL); 886 } 887 888 CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data) 889 { 890 return cf_cntrl_all(data->conn, data, FALSE, 891 CF_CTRL_DATA_IDLE, 0, NULL); 892 } 893 894 895 CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex) 896 { 897 return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE, 898 CF_CTRL_FLUSH, 0, NULL); 899 } 900 901 /** 902 * Notify connection filters that the transfer represented by `data` 903 * is done with sending data (e.g. has uploaded everything). 904 */ 905 void Curl_conn_ev_data_done_send(struct Curl_easy *data) 906 { 907 cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL); 908 } 909 910 /** 911 * Notify connection filters that the transfer represented by `data` 912 * is finished - eventually premature, e.g. before being complete. 913 */ 914 void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature) 915 { 916 cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL); 917 } 918 919 CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause) 920 { 921 return cf_cntrl_all(data->conn, data, FALSE, 922 CF_CTRL_DATA_PAUSE, do_pause, NULL); 923 } 924 925 static void cf_cntrl_update_info(struct Curl_easy *data, 926 struct connectdata *conn) 927 { 928 cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL); 929 } 930 931 /** 932 * Update connection statistics 933 */ 934 static void conn_report_connect_stats(struct Curl_easy *data, 935 struct connectdata *conn) 936 { 937 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; 938 if(cf) { 939 struct curltime connected; 940 struct curltime appconnected; 941 942 memset(&connected, 0, sizeof(connected)); 943 cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected); 944 if(connected.tv_sec || connected.tv_usec) 945 Curl_pgrsTimeWas(data, TIMER_CONNECT, connected); 946 947 memset(&appconnected, 0, sizeof(appconnected)); 948 cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected); 949 if(appconnected.tv_sec || appconnected.tv_usec) 950 Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected); 951 } 952 } 953 954 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, 955 bool *input_pending) 956 { 957 struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; 958 return cf && !cf->conn->bits.close && 959 cf->cft->is_alive(cf, data, input_pending); 960 } 961 962 CURLcode Curl_conn_keep_alive(struct Curl_easy *data, 963 struct connectdata *conn, 964 int sockindex) 965 { 966 struct Curl_cfilter *cf = conn->cfilter[sockindex]; 967 return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK; 968 } 969 970 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, 971 struct connectdata *conn, 972 int sockindex) 973 { 974 CURLcode result; 975 int n = 0; 976 977 struct Curl_cfilter *cf = conn->cfilter[sockindex]; 978 result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT, 979 &n, NULL) : CURLE_UNKNOWN_OPTION; 980 return (result || n <= 0) ? 1 : (size_t)n; 981 } 982 983 int Curl_conn_get_stream_error(struct Curl_easy *data, 984 struct connectdata *conn, 985 int sockindex) 986 { 987 CURLcode result; 988 int n = 0; 989 990 struct Curl_cfilter *cf = conn->cfilter[sockindex]; 991 result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR, 992 &n, NULL) : CURLE_UNKNOWN_OPTION; 993 return (result || n < 0) ? 0 : n; 994 } 995 996 int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd) 997 { 998 if(data && data->conn && 999 sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET]) 1000 return SECONDARYSOCKET; 1001 return FIRSTSOCKET; 1002 } 1003 1004 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex, 1005 char *buf, size_t blen, size_t *pnread) 1006 { 1007 DEBUGASSERT(data); 1008 DEBUGASSERT(data->conn); 1009 if(data && data->conn && data->conn->recv[sockindex]) 1010 return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread); 1011 *pnread = 0; 1012 return CURLE_FAILED_INIT; 1013 } 1014 1015 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, 1016 const void *buf, size_t blen, bool eos, 1017 size_t *pnwritten) 1018 { 1019 size_t write_len = blen; 1020 1021 DEBUGASSERT(data); 1022 DEBUGASSERT(data->conn); 1023 DEBUGASSERT(sockindex >= 0 && sockindex < 2); 1024 #ifdef DEBUGBUILD 1025 if(write_len) { 1026 /* Allow debug builds to override this logic to force short sends 1027 */ 1028 const char *p = getenv("CURL_SMALLSENDS"); 1029 if(p) { 1030 curl_off_t altsize; 1031 if(!curlx_str_number(&p, &altsize, write_len)) 1032 write_len = (size_t)altsize; 1033 } 1034 } 1035 #endif 1036 if(write_len != blen) 1037 eos = FALSE; 1038 if(data && data->conn && data->conn->send[sockindex]) 1039 return data->conn->send[sockindex](data, sockindex, buf, write_len, eos, 1040 pnwritten); 1041 *pnwritten = 0; 1042 return CURLE_FAILED_INIT; 1043 } 1044 1045 void Curl_pollset_reset(struct Curl_easy *data, 1046 struct easy_pollset *ps) 1047 { 1048 size_t i; 1049 (void)data; 1050 memset(ps, 0, sizeof(*ps)); 1051 for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) 1052 ps->sockets[i] = CURL_SOCKET_BAD; 1053 } 1054 1055 /** 1056 * 1057 */ 1058 void Curl_pollset_change(struct Curl_easy *data, 1059 struct easy_pollset *ps, curl_socket_t sock, 1060 int add_flags, int remove_flags) 1061 { 1062 unsigned int i; 1063 1064 (void)data; 1065 DEBUGASSERT(VALID_SOCK(sock)); 1066 if(!VALID_SOCK(sock)) 1067 return; 1068 1069 DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); 1070 DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); 1071 DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */ 1072 for(i = 0; i < ps->num; ++i) { 1073 if(ps->sockets[i] == sock) { 1074 ps->actions[i] &= (unsigned char)(~remove_flags); 1075 ps->actions[i] |= (unsigned char)add_flags; 1076 /* all gone? remove socket */ 1077 if(!ps->actions[i]) { 1078 if((i + 1) < ps->num) { 1079 memmove(&ps->sockets[i], &ps->sockets[i + 1], 1080 (ps->num - (i + 1)) * sizeof(ps->sockets[0])); 1081 memmove(&ps->actions[i], &ps->actions[i + 1], 1082 (ps->num - (i + 1)) * sizeof(ps->actions[0])); 1083 } 1084 --ps->num; 1085 } 1086 return; 1087 } 1088 } 1089 /* not present */ 1090 if(add_flags) { 1091 /* Having more SOCKETS per easy handle than what is defined 1092 * is a programming error. This indicates that we need 1093 * to raise this limit, making easy_pollset larger. 1094 * Since we use this in tight loops, we do not want to make 1095 * the pollset dynamic unnecessarily. 1096 * The current maximum in practise is HTTP/3 eyeballing where 1097 * we have up to 4 sockets involved in connection setup. 1098 */ 1099 DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE); 1100 if(i < MAX_SOCKSPEREASYHANDLE) { 1101 ps->sockets[i] = sock; 1102 ps->actions[i] = (unsigned char)add_flags; 1103 ps->num = i + 1; 1104 } 1105 } 1106 } 1107 1108 void Curl_pollset_set(struct Curl_easy *data, 1109 struct easy_pollset *ps, curl_socket_t sock, 1110 bool do_in, bool do_out) 1111 { 1112 Curl_pollset_change(data, ps, sock, 1113 (do_in ? CURL_POLL_IN : 0)| 1114 (do_out ? CURL_POLL_OUT : 0), 1115 (!do_in ? CURL_POLL_IN : 0)| 1116 (!do_out ? CURL_POLL_OUT : 0)); 1117 } 1118 1119 static void ps_add(struct Curl_easy *data, struct easy_pollset *ps, 1120 int bitmap, curl_socket_t *socks) 1121 { 1122 if(bitmap) { 1123 int i; 1124 for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) { 1125 if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) { 1126 break; 1127 } 1128 if(bitmap & GETSOCK_READSOCK(i)) { 1129 if(bitmap & GETSOCK_WRITESOCK(i)) 1130 Curl_pollset_add_inout(data, ps, socks[i]); 1131 else 1132 /* is READ, since we checked MASK_RW above */ 1133 Curl_pollset_add_in(data, ps, socks[i]); 1134 } 1135 else 1136 Curl_pollset_add_out(data, ps, socks[i]); 1137 } 1138 } 1139 } 1140 1141 void Curl_pollset_add_socks(struct Curl_easy *data, 1142 struct easy_pollset *ps, 1143 int (*get_socks_cb)(struct Curl_easy *data, 1144 curl_socket_t *socks)) 1145 { 1146 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; 1147 int bitmap; 1148 1149 bitmap = get_socks_cb(data, socks); 1150 ps_add(data, ps, bitmap, socks); 1151 } 1152 1153 void Curl_pollset_check(struct Curl_easy *data, 1154 struct easy_pollset *ps, curl_socket_t sock, 1155 bool *pwant_read, bool *pwant_write) 1156 { 1157 unsigned int i; 1158 1159 (void)data; 1160 DEBUGASSERT(VALID_SOCK(sock)); 1161 for(i = 0; i < ps->num; ++i) { 1162 if(ps->sockets[i] == sock) { 1163 *pwant_read = !!(ps->actions[i] & CURL_POLL_IN); 1164 *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT); 1165 return; 1166 } 1167 } 1168 *pwant_read = *pwant_write = FALSE; 1169 } 1170 1171 bool Curl_pollset_want_read(struct Curl_easy *data, 1172 struct easy_pollset *ps, 1173 curl_socket_t sock) 1174 { 1175 unsigned int i; 1176 (void)data; 1177 for(i = 0; i < ps->num; ++i) { 1178 if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN)) 1179 return TRUE; 1180 } 1181 return FALSE; 1182 }