1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, 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 http://curl.haxx.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 ***************************************************************************/ 22 23#include "curl_setup.h" 24 25#include <curl/curl.h> 26 27#include "urldata.h" 28#include "transfer.h" 29#include "url.h" 30#include "connect.h" 31#include "progress.h" 32#include "easyif.h" 33#include "multiif.h" 34#include "sendf.h" 35#include "timeval.h" 36#include "http.h" 37#include "select.h" 38#include "warnless.h" 39#include "speedcheck.h" 40#include "conncache.h" 41#include "bundles.h" 42#include "multihandle.h" 43#include "pipeline.h" 44#include "sigpipe.h" 45 46#define _MPRINTF_REPLACE /* use our functions only */ 47#include <curl/mprintf.h> 48 49#include "curl_memory.h" 50/* The last #include file should be: */ 51#include "memdebug.h" 52 53/* 54 CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97 55 to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every 56 CURL handle takes 45-50 K memory, therefore this 3K are not significant. 57*/ 58#ifndef CURL_SOCKET_HASH_TABLE_SIZE 59#define CURL_SOCKET_HASH_TABLE_SIZE 911 60#endif 61 62#define CURL_CONNECTION_HASH_SIZE 97 63 64#define CURL_MULTI_HANDLE 0x000bab1e 65 66#define GOOD_MULTI_HANDLE(x) \ 67 ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) 68#define GOOD_EASY_HANDLE(x) \ 69 ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) 70 71static void singlesocket(struct Curl_multi *multi, 72 struct SessionHandle *data); 73static int update_timer(struct Curl_multi *multi); 74 75static bool isHandleAtHead(struct SessionHandle *handle, 76 struct curl_llist *pipeline); 77static CURLMcode add_next_timeout(struct timeval now, 78 struct Curl_multi *multi, 79 struct SessionHandle *d); 80static CURLMcode multi_timeout(struct Curl_multi *multi, 81 long *timeout_ms); 82 83#ifdef DEBUGBUILD 84static const char * const statename[]={ 85 "INIT", 86 "CONNECT_PEND", 87 "CONNECT", 88 "WAITRESOLVE", 89 "WAITCONNECT", 90 "WAITPROXYCONNECT", 91 "PROTOCONNECT", 92 "WAITDO", 93 "DO", 94 "DOING", 95 "DO_MORE", 96 "DO_DONE", 97 "WAITPERFORM", 98 "PERFORM", 99 "TOOFAST", 100 "DONE", 101 "COMPLETED", 102 "MSGSENT", 103}; 104#endif 105 106static void multi_freetimeout(void *a, void *b); 107 108/* always use this function to change state, to make debugging easier */ 109static void mstate(struct SessionHandle *data, CURLMstate state 110#ifdef DEBUGBUILD 111 , int lineno 112#endif 113) 114{ 115#ifdef DEBUGBUILD 116 long connection_id = -5000; 117#endif 118 CURLMstate oldstate = data->mstate; 119 120 if(oldstate == state) 121 /* don't bother when the new state is the same as the old state */ 122 return; 123 124 data->mstate = state; 125 126#ifdef DEBUGBUILD 127 if(data->mstate >= CURLM_STATE_CONNECT_PEND && 128 data->mstate < CURLM_STATE_COMPLETED) { 129 if(data->easy_conn) 130 connection_id = data->easy_conn->connection_id; 131 132 infof(data, 133 "STATE: %s => %s handle %p; line %d (connection #%ld) \n", 134 statename[oldstate], statename[data->mstate], 135 (void *)data, lineno, connection_id); 136 } 137#endif 138 if(state == CURLM_STATE_COMPLETED) 139 /* changing to COMPLETED means there's one less easy handle 'alive' */ 140 data->multi->num_alive--; 141} 142 143#ifndef DEBUGBUILD 144#define multistate(x,y) mstate(x,y) 145#else 146#define multistate(x,y) mstate(x,y, __LINE__) 147#endif 148 149/* 150 * We add one of these structs to the sockhash for a particular socket 151 */ 152 153struct Curl_sh_entry { 154 struct SessionHandle *easy; 155 time_t timestamp; 156 int action; /* what action READ/WRITE this socket waits for */ 157 curl_socket_t socket; /* mainly to ease debugging */ 158 void *socketp; /* settable by users with curl_multi_assign() */ 159}; 160/* bits for 'action' having no bits means this socket is not expecting any 161 action */ 162#define SH_READ 1 163#define SH_WRITE 2 164 165/* make sure this socket is present in the hash for this handle */ 166static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, 167 curl_socket_t s, 168 struct SessionHandle *data) 169{ 170 struct Curl_sh_entry *there = 171 Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); 172 struct Curl_sh_entry *check; 173 174 if(there) 175 /* it is present, return fine */ 176 return there; 177 178 /* not present, add it */ 179 check = calloc(1, sizeof(struct Curl_sh_entry)); 180 if(!check) 181 return NULL; /* major failure */ 182 check->easy = data; 183 check->socket = s; 184 185 /* make/add new hash entry */ 186 if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { 187 free(check); 188 return NULL; /* major failure */ 189 } 190 191 return check; /* things are good in sockhash land */ 192} 193 194 195/* delete the given socket + handle from the hash */ 196static void sh_delentry(struct curl_hash *sh, curl_socket_t s) 197{ 198 struct Curl_sh_entry *there = 199 Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t)); 200 201 if(there) { 202 /* this socket is in the hash */ 203 /* We remove the hash entry. (This'll end up in a call to 204 sh_freeentry().) */ 205 Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t)); 206 } 207} 208 209/* 210 * free a sockhash entry 211 */ 212static void sh_freeentry(void *freethis) 213{ 214 struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis; 215 216 if(p) 217 free(p); 218} 219 220static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) 221{ 222 (void) k1_len; (void) k2_len; 223 224 return (*((int *) k1)) == (*((int *) k2)); 225} 226 227static size_t hash_fd(void *key, size_t key_length, size_t slots_num) 228{ 229 int fd = *((int *) key); 230 (void) key_length; 231 232 return (fd % (int)slots_num); 233} 234 235/* 236 * sh_init() creates a new socket hash and returns the handle for it. 237 * 238 * Quote from README.multi_socket: 239 * 240 * "Some tests at 7000 and 9000 connections showed that the socket hash lookup 241 * is somewhat of a bottle neck. Its current implementation may be a bit too 242 * limiting. It simply has a fixed-size array, and on each entry in the array 243 * it has a linked list with entries. So the hash only checks which list to 244 * scan through. The code I had used so for used a list with merely 7 slots 245 * (as that is what the DNS hash uses) but with 7000 connections that would 246 * make an average of 1000 nodes in each list to run through. I upped that to 247 * 97 slots (I believe a prime is suitable) and noticed a significant speed 248 * increase. I need to reconsider the hash implementation or use a rather 249 * large default value like this. At 9000 connections I was still below 10us 250 * per call." 251 * 252 */ 253static struct curl_hash *sh_init(int hashsize) 254{ 255 return Curl_hash_alloc(hashsize, hash_fd, fd_key_compare, 256 sh_freeentry); 257} 258 259/* 260 * multi_addmsg() 261 * 262 * Called when a transfer is completed. Adds the given msg pointer to 263 * the list kept in the multi handle. 264 */ 265static CURLMcode multi_addmsg(struct Curl_multi *multi, 266 struct Curl_message *msg) 267{ 268 if(!Curl_llist_insert_next(multi->msglist, multi->msglist->tail, msg)) 269 return CURLM_OUT_OF_MEMORY; 270 271 return CURLM_OK; 272} 273 274/* 275 * multi_freeamsg() 276 * 277 * Callback used by the llist system when a single list entry is destroyed. 278 */ 279static void multi_freeamsg(void *a, void *b) 280{ 281 (void)a; 282 (void)b; 283} 284 285struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ 286 int chashsize) /* connection hash */ 287{ 288 struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi)); 289 290 if(!multi) 291 return NULL; 292 293 multi->type = CURL_MULTI_HANDLE; 294 295 multi->hostcache = Curl_mk_dnscache(); 296 if(!multi->hostcache) 297 goto error; 298 299 multi->sockhash = sh_init(hashsize); 300 if(!multi->sockhash) 301 goto error; 302 303 multi->conn_cache = Curl_conncache_init(chashsize); 304 if(!multi->conn_cache) 305 goto error; 306 307 multi->msglist = Curl_llist_alloc(multi_freeamsg); 308 if(!multi->msglist) 309 goto error; 310 311 /* allocate a new easy handle to use when closing cached connections */ 312 multi->closure_handle = curl_easy_init(); 313 if(!multi->closure_handle) 314 goto error; 315 316 multi->closure_handle->multi = multi; 317 multi->closure_handle->state.conn_cache = multi->conn_cache; 318 319 multi->max_pipeline_length = 5; 320 321 /* -1 means it not set by user, use the default value */ 322 multi->maxconnects = -1; 323 return (CURLM *) multi; 324 325 error: 326 327 Curl_hash_destroy(multi->sockhash); 328 multi->sockhash = NULL; 329 Curl_hash_destroy(multi->hostcache); 330 multi->hostcache = NULL; 331 Curl_conncache_destroy(multi->conn_cache); 332 multi->conn_cache = NULL; 333 Curl_close(multi->closure_handle); 334 multi->closure_handle = NULL; 335 Curl_llist_destroy(multi->msglist, NULL); 336 337 free(multi); 338 return NULL; 339} 340 341CURLM *curl_multi_init(void) 342{ 343 return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, 344 CURL_CONNECTION_HASH_SIZE); 345} 346 347CURLMcode curl_multi_add_handle(CURLM *multi_handle, 348 CURL *easy_handle) 349{ 350 struct curl_llist *timeoutlist; 351 struct Curl_multi *multi = (struct Curl_multi *)multi_handle; 352 struct SessionHandle *data = (struct SessionHandle *)easy_handle; 353 354 /* First, make some basic checks that the CURLM handle is a good handle */ 355 if(!GOOD_MULTI_HANDLE(multi)) 356 return CURLM_BAD_HANDLE; 357 358 /* Verify that we got a somewhat good easy handle too */ 359 if(!GOOD_EASY_HANDLE(easy_handle)) 360 return CURLM_BAD_EASY_HANDLE; 361 362 /* Prevent users from adding same easy handle more than once and prevent 363 adding to more than one multi stack */ 364 if(data->multi) 365 return CURLM_ADDED_ALREADY; 366 367 /* Allocate and initialize timeout list for easy handle */ 368 timeoutlist = Curl_llist_alloc(multi_freetimeout); 369 if(!timeoutlist) 370 return CURLM_OUT_OF_MEMORY; 371 372 /* 373 * No failure allowed in this function beyond this point. And no 374 * modification of easy nor multi handle allowed before this except for 375 * potential multi's connection cache growing which won't be undone in this 376 * function no matter what. 377 */ 378 379 /* Make easy handle use timeout list initialized above */ 380 data->state.timeoutlist = timeoutlist; 381 timeoutlist = NULL; 382 383 /* set the easy handle */ 384 multistate(data, CURLM_STATE_INIT); 385 386 if((data->set.global_dns_cache) && 387 (data->dns.hostcachetype != HCACHE_GLOBAL)) { 388 /* global dns cache was requested but still isn't */ 389 struct curl_hash *global = Curl_global_host_cache_init(); 390 if(global) { 391 /* only do this if the global cache init works */ 392 data->dns.hostcache = global; 393 data->dns.hostcachetype = HCACHE_GLOBAL; 394 } 395 } 396 /* for multi interface connections, we share DNS cache automatically if the 397 easy handle's one is currently not set. */ 398 else if(!data->dns.hostcache || 399 (data->dns.hostcachetype == HCACHE_NONE)) { 400 data->dns.hostcache = multi->hostcache; 401 data->dns.hostcachetype = HCACHE_MULTI; 402 } 403 404 /* Point to the multi's connection cache */ 405 data->state.conn_cache = multi->conn_cache; 406 407 data->state.infilesize = data->set.filesize; 408 409 /* This adds the new entry at the 'end' of the doubly-linked circular 410 list of SessionHandle structs to try and maintain a FIFO queue so 411 the pipelined requests are in order. */ 412 413 /* We add this new entry last in the list. */ 414 415 data->next = NULL; /* end of the line */ 416 if(multi->easyp) { 417 struct SessionHandle *last = multi->easylp; 418 last->next = data; 419 data->prev = last; 420 multi->easylp = data; /* the new last node */ 421 } 422 else { 423 /* first node, make both prev and next be NULL! */ 424 data->next = NULL; 425 data->prev = NULL; 426 multi->easylp = multi->easyp = data; /* both first and last */ 427 } 428 429 /* make the SessionHandle refer back to this multi handle */ 430 data->multi = multi_handle; 431 432 /* Set the timeout for this handle to expire really soon so that it will 433 be taken care of even when this handle is added in the midst of operation 434 when only the curl_multi_socket() API is used. During that flow, only 435 sockets that time-out or have actions will be dealt with. Since this 436 handle has no action yet, we make sure it times out to get things to 437 happen. */ 438 Curl_expire(data, 1); 439 440 /* increase the node-counter */ 441 multi->num_easy++; 442 443 /* increase the alive-counter */ 444 multi->num_alive++; 445 446 /* A somewhat crude work-around for a little glitch in update_timer() that 447 happens if the lastcall time is set to the same time when the handle is 448 removed as when the next handle is added, as then the check in 449 update_timer() that prevents calling the application multiple times with 450 the same timer infor will not trigger and then the new handle's timeout 451 will not be notified to the app. 452 453 The work-around is thus simply to clear the 'lastcall' variable to force 454 update_timer() to always trigger a callback to the app when a new easy 455 handle is added */ 456 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); 457 458 update_timer(multi); 459 return CURLM_OK; 460} 461 462#if 0 463/* Debug-function, used like this: 464 * 465 * Curl_hash_print(multi->sockhash, debug_print_sock_hash); 466 * 467 * Enable the hash print function first by editing hash.c 468 */ 469static void debug_print_sock_hash(void *p) 470{ 471 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p; 472 473 fprintf(stderr, " [easy %p/magic %x/socket %d]", 474 (void *)sh->data, sh->data->magic, (int)sh->socket); 475} 476#endif 477 478CURLMcode curl_multi_remove_handle(CURLM *multi_handle, 479 CURL *curl_handle) 480{ 481 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 482 struct SessionHandle *easy = curl_handle; 483 struct SessionHandle *data = easy; 484 485 /* First, make some basic checks that the CURLM handle is a good handle */ 486 if(!GOOD_MULTI_HANDLE(multi)) 487 return CURLM_BAD_HANDLE; 488 489 /* Verify that we got a somewhat good easy handle too */ 490 if(!GOOD_EASY_HANDLE(curl_handle)) 491 return CURLM_BAD_EASY_HANDLE; 492 493 /* Prevent users from trying to remove same easy handle more than once */ 494 if(!data->multi) 495 return CURLM_OK; /* it is already removed so let's say it is fine! */ 496 497 if(easy) { 498 bool premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; 499 bool easy_owns_conn = (data->easy_conn && 500 (data->easy_conn->data == easy)) ? 501 TRUE : FALSE; 502 503 /* If the 'state' is not INIT or COMPLETED, we might need to do something 504 nice to put the easy_handle in a good known state when this returns. */ 505 if(premature) 506 /* this handle is "alive" so we need to count down the total number of 507 alive connections when this is removed */ 508 multi->num_alive--; 509 510 if(data->easy_conn && 511 (data->easy_conn->send_pipe->size + 512 data->easy_conn->recv_pipe->size > 1) && 513 data->mstate > CURLM_STATE_WAITDO && 514 data->mstate < CURLM_STATE_COMPLETED) { 515 /* If the handle is in a pipeline and has started sending off its 516 request but not received its response yet, we need to close 517 connection. */ 518 connclose(data->easy_conn, "Removed with partial response"); 519 /* Set connection owner so that Curl_done() closes it. 520 We can sefely do this here since connection is killed. */ 521 data->easy_conn->data = easy; 522 } 523 524 /* The timer must be shut down before data->multi is set to NULL, 525 else the timenode will remain in the splay tree after 526 curl_easy_cleanup is called. */ 527 Curl_expire(data, 0); 528 529 /* destroy the timeout list that is held in the easy handle */ 530 if(data->state.timeoutlist) { 531 Curl_llist_destroy(data->state.timeoutlist, NULL); 532 data->state.timeoutlist = NULL; 533 } 534 535 if(data->dns.hostcachetype == HCACHE_MULTI) { 536 /* stop using the multi handle's DNS cache */ 537 data->dns.hostcache = NULL; 538 data->dns.hostcachetype = HCACHE_NONE; 539 } 540 541 if(data->easy_conn) { 542 543 /* we must call Curl_done() here (if we still "own it") so that we don't 544 leave a half-baked one around */ 545 if(easy_owns_conn) { 546 547 /* Curl_done() clears the conn->data field to lose the association 548 between the easy handle and the connection 549 550 Note that this ignores the return code simply because there's 551 nothing really useful to do with it anyway! */ 552 (void)Curl_done(&data->easy_conn, data->result, premature); 553 } 554 else 555 /* Clear connection pipelines, if Curl_done above was not called */ 556 Curl_getoff_all_pipelines(data, data->easy_conn); 557 } 558 559 Curl_wildcard_dtor(&data->wildcard); 560 561 /* as this was using a shared connection cache we clear the pointer 562 to that since we're not part of that multi handle anymore */ 563 data->state.conn_cache = NULL; 564 565 /* change state without using multistate(), only to make singlesocket() do 566 what we want */ 567 data->mstate = CURLM_STATE_COMPLETED; 568 singlesocket(multi, easy); /* to let the application know what sockets 569 that vanish with this handle */ 570 571 /* Remove the association between the connection and the handle */ 572 if(data->easy_conn) { 573 data->easy_conn->data = NULL; 574 data->easy_conn = NULL; 575 } 576 577 data->multi = NULL; /* clear the association to this multi handle */ 578 579 { 580 /* make sure there's no pending message in the queue sent from this easy 581 handle */ 582 struct curl_llist_element *e; 583 584 for(e = multi->msglist->head; e; e = e->next) { 585 struct Curl_message *msg = e->ptr; 586 587 if(msg->extmsg.easy_handle == easy) { 588 Curl_llist_remove(multi->msglist, e, NULL); 589 /* there can only be one from this specific handle */ 590 break; 591 } 592 } 593 } 594 595 /* make the previous node point to our next */ 596 if(data->prev) 597 data->prev->next = data->next; 598 else 599 multi->easyp = data->next; /* point to first node */ 600 601 /* make our next point to our previous node */ 602 if(data->next) 603 data->next->prev = data->prev; 604 else 605 multi->easylp = data->prev; /* point to last node */ 606 607 /* NOTE NOTE NOTE 608 We do not touch the easy handle here! */ 609 610 multi->num_easy--; /* one less to care about now */ 611 612 update_timer(multi); 613 return CURLM_OK; 614 } 615 else 616 return CURLM_BAD_EASY_HANDLE; /* twasn't found */ 617} 618 619bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi) 620{ 621 return (multi && multi->pipelining_enabled) ? TRUE : FALSE; 622} 623 624void Curl_multi_handlePipeBreak(struct SessionHandle *data) 625{ 626 data->easy_conn = NULL; 627} 628 629static int waitconnect_getsock(struct connectdata *conn, 630 curl_socket_t *sock, 631 int numsocks) 632{ 633 int i; 634 int s=0; 635 int rc=0; 636 637 if(!numsocks) 638 return GETSOCK_BLANK; 639 640 for(i=0; i<2; i++) { 641 if(conn->tempsock[i] != CURL_SOCKET_BAD) { 642 sock[s] = conn->tempsock[i]; 643 rc |= GETSOCK_WRITESOCK(s++); 644 } 645 } 646 647 /* when we've sent a CONNECT to a proxy, we should rather wait for the 648 socket to become readable to be able to get the response headers */ 649 if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) { 650 sock[0] = conn->sock[FIRSTSOCKET]; 651 rc = GETSOCK_READSOCK(0); 652 } 653 654 return rc; 655} 656 657static int domore_getsock(struct connectdata *conn, 658 curl_socket_t *socks, 659 int numsocks) 660{ 661 if(conn && conn->handler->domore_getsock) 662 return conn->handler->domore_getsock(conn, socks, numsocks); 663 return GETSOCK_BLANK; 664} 665 666/* returns bitmapped flags for this handle and its sockets */ 667static int multi_getsock(struct SessionHandle *data, 668 curl_socket_t *socks, /* points to numsocks number 669 of sockets */ 670 int numsocks) 671{ 672 /* If the pipe broke, or if there's no connection left for this easy handle, 673 then we MUST bail out now with no bitmask set. The no connection case can 674 happen when this is called from curl_multi_remove_handle() => 675 singlesocket() => multi_getsock(). 676 */ 677 if(data->state.pipe_broke || !data->easy_conn) 678 return 0; 679 680 if(data->mstate > CURLM_STATE_CONNECT && 681 data->mstate < CURLM_STATE_COMPLETED) { 682 /* Set up ownership correctly */ 683 data->easy_conn->data = data; 684 } 685 686 switch(data->mstate) { 687 default: 688#if 0 /* switch back on these cases to get the compiler to check for all enums 689 to be present */ 690 case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */ 691 case CURLM_STATE_COMPLETED: 692 case CURLM_STATE_MSGSENT: 693 case CURLM_STATE_INIT: 694 case CURLM_STATE_CONNECT: 695 case CURLM_STATE_WAITDO: 696 case CURLM_STATE_DONE: 697 case CURLM_STATE_LAST: 698 /* this will get called with CURLM_STATE_COMPLETED when a handle is 699 removed */ 700#endif 701 return 0; 702 703 case CURLM_STATE_WAITRESOLVE: 704 return Curl_resolver_getsock(data->easy_conn, socks, numsocks); 705 706 case CURLM_STATE_PROTOCONNECT: 707 return Curl_protocol_getsock(data->easy_conn, socks, numsocks); 708 709 case CURLM_STATE_DO: 710 case CURLM_STATE_DOING: 711 return Curl_doing_getsock(data->easy_conn, socks, numsocks); 712 713 case CURLM_STATE_WAITPROXYCONNECT: 714 case CURLM_STATE_WAITCONNECT: 715 return waitconnect_getsock(data->easy_conn, socks, numsocks); 716 717 case CURLM_STATE_DO_MORE: 718 return domore_getsock(data->easy_conn, socks, numsocks); 719 720 case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch 721 to waiting for the same as the *PERFORM 722 states */ 723 case CURLM_STATE_PERFORM: 724 case CURLM_STATE_WAITPERFORM: 725 return Curl_single_getsock(data->easy_conn, socks, numsocks); 726 } 727 728} 729 730CURLMcode curl_multi_fdset(CURLM *multi_handle, 731 fd_set *read_fd_set, fd_set *write_fd_set, 732 fd_set *exc_fd_set, int *max_fd) 733{ 734 /* Scan through all the easy handles to get the file descriptors set. 735 Some easy handles may not have connected to the remote host yet, 736 and then we must make sure that is done. */ 737 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 738 struct SessionHandle *data; 739 int this_max_fd=-1; 740 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; 741 int bitmap; 742 int i; 743 (void)exc_fd_set; /* not used */ 744 745 if(!GOOD_MULTI_HANDLE(multi)) 746 return CURLM_BAD_HANDLE; 747 748 data=multi->easyp; 749 while(data) { 750 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); 751 752 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { 753 curl_socket_t s = CURL_SOCKET_BAD; 754 755 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { 756 FD_SET(sockbunch[i], read_fd_set); 757 s = sockbunch[i]; 758 } 759 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { 760 FD_SET(sockbunch[i], write_fd_set); 761 s = sockbunch[i]; 762 } 763 if(s == CURL_SOCKET_BAD) 764 /* this socket is unused, break out of loop */ 765 break; 766 else { 767 if((int)s > this_max_fd) 768 this_max_fd = (int)s; 769 } 770 } 771 772 data = data->next; /* check next handle */ 773 } 774 775 *max_fd = this_max_fd; 776 777 return CURLM_OK; 778} 779 780CURLMcode curl_multi_wait(CURLM *multi_handle, 781 struct curl_waitfd extra_fds[], 782 unsigned int extra_nfds, 783 int timeout_ms, 784 int *ret) 785{ 786 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 787 struct SessionHandle *data; 788 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; 789 int bitmap; 790 unsigned int i; 791 unsigned int nfds = 0; 792 unsigned int curlfds; 793 struct pollfd *ufds = NULL; 794 long timeout_internal; 795 796 if(!GOOD_MULTI_HANDLE(multi)) 797 return CURLM_BAD_HANDLE; 798 799 /* If the internally desired timeout is actually shorter than requested from 800 the outside, then use the shorter time! But only if the internal timer 801 is actually larger than -1! */ 802 (void)multi_timeout(multi, &timeout_internal); 803 if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) 804 timeout_ms = (int)timeout_internal; 805 806 /* Count up how many fds we have from the multi handle */ 807 data=multi->easyp; 808 while(data) { 809 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); 810 811 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { 812 curl_socket_t s = CURL_SOCKET_BAD; 813 814 if(bitmap & GETSOCK_READSOCK(i)) { 815 ++nfds; 816 s = sockbunch[i]; 817 } 818 if(bitmap & GETSOCK_WRITESOCK(i)) { 819 ++nfds; 820 s = sockbunch[i]; 821 } 822 if(s == CURL_SOCKET_BAD) { 823 break; 824 } 825 } 826 827 data = data->next; /* check next handle */ 828 } 829 830 curlfds = nfds; /* number of internal file descriptors */ 831 nfds += extra_nfds; /* add the externally provided ones */ 832 833 if(nfds || extra_nfds) { 834 ufds = malloc(nfds * sizeof(struct pollfd)); 835 if(!ufds) 836 return CURLM_OUT_OF_MEMORY; 837 } 838 nfds = 0; 839 840 /* only do the second loop if we found descriptors in the first stage run 841 above */ 842 843 if(curlfds) { 844 /* Add the curl handles to our pollfds first */ 845 data=multi->easyp; 846 while(data) { 847 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE); 848 849 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { 850 curl_socket_t s = CURL_SOCKET_BAD; 851 852 if(bitmap & GETSOCK_READSOCK(i)) { 853 ufds[nfds].fd = sockbunch[i]; 854 ufds[nfds].events = POLLIN; 855 ++nfds; 856 s = sockbunch[i]; 857 } 858 if(bitmap & GETSOCK_WRITESOCK(i)) { 859 ufds[nfds].fd = sockbunch[i]; 860 ufds[nfds].events = POLLOUT; 861 ++nfds; 862 s = sockbunch[i]; 863 } 864 if(s == CURL_SOCKET_BAD) { 865 break; 866 } 867 } 868 869 data = data->next; /* check next handle */ 870 } 871 } 872 873 /* Add external file descriptions from poll-like struct curl_waitfd */ 874 for(i = 0; i < extra_nfds; i++) { 875 ufds[nfds].fd = extra_fds[i].fd; 876 ufds[nfds].events = 0; 877 if(extra_fds[i].events & CURL_WAIT_POLLIN) 878 ufds[nfds].events |= POLLIN; 879 if(extra_fds[i].events & CURL_WAIT_POLLPRI) 880 ufds[nfds].events |= POLLPRI; 881 if(extra_fds[i].events & CURL_WAIT_POLLOUT) 882 ufds[nfds].events |= POLLOUT; 883 ++nfds; 884 } 885 886 if(nfds) { 887 /* wait... */ 888 infof(data, "Curl_poll(%d ds, %d ms)\n", nfds, timeout_ms); 889 i = Curl_poll(ufds, nfds, timeout_ms); 890 891 if(i) { 892 unsigned int j; 893 /* copy revents results from the poll to the curl_multi_wait poll 894 struct, the bit values of the actual underlying poll() implementation 895 may not be the same as the ones in the public libcurl API! */ 896 for(j = 0; j < extra_nfds; j++) { 897 unsigned short mask = 0; 898 unsigned r = ufds[curlfds + j].revents; 899 900 if(r & POLLIN) 901 mask |= CURL_WAIT_POLLIN; 902 if(r & POLLOUT) 903 mask |= CURL_WAIT_POLLOUT; 904 if(r & POLLPRI) 905 mask |= CURL_WAIT_POLLPRI; 906 907 extra_fds[j].revents = mask; 908 } 909 } 910 } 911 else 912 i = 0; 913 914 Curl_safefree(ufds); 915 if(ret) 916 *ret = i; 917 return CURLM_OK; 918} 919 920static CURLMcode multi_runsingle(struct Curl_multi *multi, 921 struct timeval now, 922 struct SessionHandle *data) 923{ 924 struct Curl_message *msg = NULL; 925 bool connected; 926 bool async; 927 bool protocol_connect = FALSE; 928 bool dophase_done = FALSE; 929 bool done = FALSE; 930 CURLMcode result = CURLM_OK; 931 struct SingleRequest *k; 932 long timeout_ms; 933 int control; 934 935 if(!GOOD_EASY_HANDLE(data)) 936 return CURLM_BAD_EASY_HANDLE; 937 938 do { 939 /* this is a single-iteration do-while loop just to allow a 940 break to skip to the end of it */ 941 bool disconnect_conn = FALSE; 942 943 /* Handle the case when the pipe breaks, i.e., the connection 944 we're using gets cleaned up and we're left with nothing. */ 945 if(data->state.pipe_broke) { 946 infof(data, "Pipe broke: handle 0x%p, url = %s\n", 947 (void *)data, data->state.path); 948 949 if(data->mstate < CURLM_STATE_COMPLETED) { 950 /* Head back to the CONNECT state */ 951 multistate(data, CURLM_STATE_CONNECT); 952 result = CURLM_CALL_MULTI_PERFORM; 953 data->result = CURLE_OK; 954 } 955 956 data->state.pipe_broke = FALSE; 957 data->easy_conn = NULL; 958 break; 959 } 960 961 if(!data->easy_conn && 962 data->mstate > CURLM_STATE_CONNECT && 963 data->mstate < CURLM_STATE_DONE) { 964 /* In all these states, the code will blindly access 'data->easy_conn' 965 so this is precaution that it isn't NULL. And it silences static 966 analyzers. */ 967 failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate); 968 return CURLM_INTERNAL_ERROR; 969 } 970 971 if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT && 972 data->mstate < CURLM_STATE_COMPLETED) 973 /* Make sure we set the connection's current owner */ 974 data->easy_conn->data = data; 975 976 if(data->easy_conn && 977 (data->mstate >= CURLM_STATE_CONNECT) && 978 (data->mstate < CURLM_STATE_COMPLETED)) { 979 /* we need to wait for the connect state as only then is the start time 980 stored, but we must not check already completed handles */ 981 982 timeout_ms = Curl_timeleft(data, &now, 983 (data->mstate <= CURLM_STATE_WAITDO)? 984 TRUE:FALSE); 985 986 if(timeout_ms < 0) { 987 /* Handle timed out */ 988 if(data->mstate == CURLM_STATE_WAITRESOLVE) 989 failf(data, "Resolving timed out after %ld milliseconds", 990 Curl_tvdiff(now, data->progress.t_startsingle)); 991 else if(data->mstate == CURLM_STATE_WAITCONNECT) 992 failf(data, "Connection timed out after %ld milliseconds", 993 Curl_tvdiff(now, data->progress.t_startsingle)); 994 else { 995 k = &data->req; 996 if(k->size != -1) { 997 failf(data, "Operation timed out after %ld milliseconds with %" 998 CURL_FORMAT_CURL_OFF_T " out of %" 999 CURL_FORMAT_CURL_OFF_T " bytes received", 1000 Curl_tvdiff(k->now, data->progress.t_startsingle), 1001 k->bytecount, k->size); 1002 } 1003 else { 1004 failf(data, "Operation timed out after %ld milliseconds with %" 1005 CURL_FORMAT_CURL_OFF_T " bytes received", 1006 Curl_tvdiff(now, data->progress.t_startsingle), 1007 k->bytecount); 1008 } 1009 } 1010 1011 /* Force the connection closed because the server could continue to 1012 send us stuff at any time. (The disconnect_conn logic used below 1013 doesn't work at this point). */ 1014 connclose(data->easy_conn, "Disconnected with pending data"); 1015 data->result = CURLE_OPERATION_TIMEDOUT; 1016 multistate(data, CURLM_STATE_COMPLETED); 1017 break; 1018 } 1019 } 1020 1021 switch(data->mstate) { 1022 case CURLM_STATE_INIT: 1023 /* init this transfer. */ 1024 data->result=Curl_pretransfer(data); 1025 1026 if(CURLE_OK == data->result) { 1027 /* after init, go CONNECT */ 1028 multistate(data, CURLM_STATE_CONNECT); 1029 Curl_pgrsTime(data, TIMER_STARTOP); 1030 result = CURLM_CALL_MULTI_PERFORM; 1031 } 1032 break; 1033 1034 case CURLM_STATE_CONNECT_PEND: 1035 /* We will stay here until there is a connection available. Then 1036 we try again in the CURLM_STATE_CONNECT state. */ 1037 break; 1038 1039 case CURLM_STATE_CONNECT: 1040 /* Connect. We want to get a connection identifier filled in. */ 1041 Curl_pgrsTime(data, TIMER_STARTSINGLE); 1042 data->result = Curl_connect(data, &data->easy_conn, 1043 &async, &protocol_connect); 1044 if(CURLE_NO_CONNECTION_AVAILABLE == data->result) { 1045 /* There was no connection available. We will go to the pending 1046 state and wait for an available connection. */ 1047 multistate(data, CURLM_STATE_CONNECT_PEND); 1048 data->result = CURLE_OK; 1049 break; 1050 } 1051 1052 if(CURLE_OK == data->result) { 1053 /* Add this handle to the send or pend pipeline */ 1054 data->result = Curl_add_handle_to_pipeline(data, data->easy_conn); 1055 if(CURLE_OK != data->result) 1056 disconnect_conn = TRUE; 1057 else { 1058 if(async) 1059 /* We're now waiting for an asynchronous name lookup */ 1060 multistate(data, CURLM_STATE_WAITRESOLVE); 1061 else { 1062 /* after the connect has been sent off, go WAITCONNECT unless the 1063 protocol connect is already done and we can go directly to 1064 WAITDO or DO! */ 1065 result = CURLM_CALL_MULTI_PERFORM; 1066 1067 if(protocol_connect) 1068 multistate(data, multi->pipelining_enabled? 1069 CURLM_STATE_WAITDO:CURLM_STATE_DO); 1070 else { 1071#ifndef CURL_DISABLE_HTTP 1072 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) 1073 multistate(data, CURLM_STATE_WAITPROXYCONNECT); 1074 else 1075#endif 1076 multistate(data, CURLM_STATE_WAITCONNECT); 1077 } 1078 } 1079 } 1080 } 1081 break; 1082 1083 case CURLM_STATE_WAITRESOLVE: 1084 /* awaiting an asynch name resolve to complete */ 1085 { 1086 struct Curl_dns_entry *dns = NULL; 1087 1088 /* check if we have the name resolved by now */ 1089 data->result = Curl_resolver_is_resolved(data->easy_conn, &dns); 1090 1091 /* Update sockets here, because the socket(s) may have been 1092 closed and the application thus needs to be told, even if it 1093 is likely that the same socket(s) will again be used further 1094 down. If the name has not yet been resolved, it is likely 1095 that new sockets have been opened in an attempt to contact 1096 another resolver. */ 1097 singlesocket(multi, data); 1098 1099 if(dns) { 1100 /* Perform the next step in the connection phase, and then move on 1101 to the WAITCONNECT state */ 1102 data->result = Curl_async_resolved(data->easy_conn, 1103 &protocol_connect); 1104 1105 if(CURLE_OK != data->result) 1106 /* if Curl_async_resolved() returns failure, the connection struct 1107 is already freed and gone */ 1108 data->easy_conn = NULL; /* no more connection */ 1109 else { 1110 /* call again please so that we get the next socket setup */ 1111 result = CURLM_CALL_MULTI_PERFORM; 1112 if(protocol_connect) 1113 multistate(data, multi->pipelining_enabled? 1114 CURLM_STATE_WAITDO:CURLM_STATE_DO); 1115 else { 1116#ifndef CURL_DISABLE_HTTP 1117 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) 1118 multistate(data, CURLM_STATE_WAITPROXYCONNECT); 1119 else 1120#endif 1121 multistate(data, CURLM_STATE_WAITCONNECT); 1122 } 1123 } 1124 } 1125 1126 if(CURLE_OK != data->result) { 1127 /* failure detected */ 1128 disconnect_conn = TRUE; 1129 break; 1130 } 1131 } 1132 break; 1133 1134#ifndef CURL_DISABLE_HTTP 1135 case CURLM_STATE_WAITPROXYCONNECT: 1136 /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */ 1137 data->result = Curl_http_connect(data->easy_conn, &protocol_connect); 1138 1139 if(data->easy_conn->bits.proxy_connect_closed) { 1140 /* reset the error buffer */ 1141 if(data->set.errorbuffer) 1142 data->set.errorbuffer[0] = '\0'; 1143 data->state.errorbuf = FALSE; 1144 1145 data->result = CURLE_OK; 1146 result = CURLM_CALL_MULTI_PERFORM; 1147 multistate(data, CURLM_STATE_CONNECT); 1148 } 1149 else if(CURLE_OK == data->result) { 1150 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) 1151 multistate(data, CURLM_STATE_WAITCONNECT); 1152 } 1153 break; 1154#endif 1155 1156 case CURLM_STATE_WAITCONNECT: 1157 /* awaiting a completion of an asynch connect */ 1158 data->result = Curl_is_connected(data->easy_conn, 1159 FIRSTSOCKET, 1160 &connected); 1161 if(connected) { 1162 1163 if(!data->result) 1164 /* if everything is still fine we do the protocol-specific connect 1165 setup */ 1166 data->result = Curl_protocol_connect(data->easy_conn, 1167 &protocol_connect); 1168 } 1169 1170 if(CURLE_OK != data->result) { 1171 /* failure detected */ 1172 /* Just break, the cleaning up is handled all in one place */ 1173 disconnect_conn = TRUE; 1174 break; 1175 } 1176 1177 if(connected) { 1178 if(!protocol_connect) { 1179 /* We have a TCP connection, but 'protocol_connect' may be false 1180 and then we continue to 'STATE_PROTOCONNECT'. If protocol 1181 connect is TRUE, we move on to STATE_DO. 1182 BUT if we are using a proxy we must change to WAITPROXYCONNECT 1183 */ 1184#ifndef CURL_DISABLE_HTTP 1185 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) 1186 multistate(data, CURLM_STATE_WAITPROXYCONNECT); 1187 else 1188#endif 1189 multistate(data, CURLM_STATE_PROTOCONNECT); 1190 1191 } 1192 else 1193 /* after the connect has completed, go WAITDO or DO */ 1194 multistate(data, multi->pipelining_enabled? 1195 CURLM_STATE_WAITDO:CURLM_STATE_DO); 1196 1197 result = CURLM_CALL_MULTI_PERFORM; 1198 } 1199 break; 1200 1201 case CURLM_STATE_PROTOCONNECT: 1202 /* protocol-specific connect phase */ 1203 data->result = Curl_protocol_connecting(data->easy_conn, 1204 &protocol_connect); 1205 if((data->result == CURLE_OK) && protocol_connect) { 1206 /* after the connect has completed, go WAITDO or DO */ 1207 multistate(data, multi->pipelining_enabled? 1208 CURLM_STATE_WAITDO:CURLM_STATE_DO); 1209 result = CURLM_CALL_MULTI_PERFORM; 1210 } 1211 else if(data->result) { 1212 /* failure detected */ 1213 Curl_posttransfer(data); 1214 Curl_done(&data->easy_conn, data->result, TRUE); 1215 disconnect_conn = TRUE; 1216 } 1217 break; 1218 1219 case CURLM_STATE_WAITDO: 1220 /* Wait for our turn to DO when we're pipelining requests */ 1221#ifdef DEBUGBUILD 1222 infof(data, "WAITDO: Conn %ld send pipe %zu inuse %s athead %s\n", 1223 data->easy_conn->connection_id, 1224 data->easy_conn->send_pipe->size, 1225 data->easy_conn->writechannel_inuse?"TRUE":"FALSE", 1226 isHandleAtHead(data, 1227 data->easy_conn->send_pipe)?"TRUE":"FALSE"); 1228#endif 1229 if(!data->easy_conn->writechannel_inuse && 1230 isHandleAtHead(data, 1231 data->easy_conn->send_pipe)) { 1232 /* Grab the channel */ 1233 data->easy_conn->writechannel_inuse = TRUE; 1234 multistate(data, CURLM_STATE_DO); 1235 result = CURLM_CALL_MULTI_PERFORM; 1236 } 1237 break; 1238 1239 case CURLM_STATE_DO: 1240 if(data->set.connect_only) { 1241 /* keep connection open for application to use the socket */ 1242 connkeep(data->easy_conn, "CONNECT_ONLY"); 1243 multistate(data, CURLM_STATE_DONE); 1244 data->result = CURLE_OK; 1245 result = CURLM_CALL_MULTI_PERFORM; 1246 } 1247 else { 1248 /* Perform the protocol's DO action */ 1249 data->result = Curl_do(&data->easy_conn, &dophase_done); 1250 1251 /* When Curl_do() returns failure, data->easy_conn might be NULL! */ 1252 1253 if(CURLE_OK == data->result) { 1254 if(!dophase_done) { 1255 /* some steps needed for wildcard matching */ 1256 if(data->set.wildcardmatch) { 1257 struct WildcardData *wc = &data->wildcard; 1258 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { 1259 /* skip some states if it is important */ 1260 Curl_done(&data->easy_conn, CURLE_OK, FALSE); 1261 multistate(data, CURLM_STATE_DONE); 1262 result = CURLM_CALL_MULTI_PERFORM; 1263 break; 1264 } 1265 } 1266 /* DO was not completed in one function call, we must continue 1267 DOING... */ 1268 multistate(data, CURLM_STATE_DOING); 1269 result = CURLM_OK; 1270 } 1271 1272 /* after DO, go DO_DONE... or DO_MORE */ 1273 else if(data->easy_conn->bits.do_more) { 1274 /* we're supposed to do more, but we need to sit down, relax 1275 and wait a little while first */ 1276 multistate(data, CURLM_STATE_DO_MORE); 1277 result = CURLM_OK; 1278 } 1279 else { 1280 /* we're done with the DO, now DO_DONE */ 1281 multistate(data, CURLM_STATE_DO_DONE); 1282 result = CURLM_CALL_MULTI_PERFORM; 1283 } 1284 } 1285 else if((CURLE_SEND_ERROR == data->result) && 1286 data->easy_conn->bits.reuse) { 1287 /* 1288 * In this situation, a connection that we were trying to use 1289 * may have unexpectedly died. If possible, send the connection 1290 * back to the CONNECT phase so we can try again. 1291 */ 1292 char *newurl = NULL; 1293 followtype follow=FOLLOW_NONE; 1294 CURLcode drc; 1295 bool retry = FALSE; 1296 1297 drc = Curl_retry_request(data->easy_conn, &newurl); 1298 if(drc) { 1299 /* a failure here pretty much implies an out of memory */ 1300 data->result = drc; 1301 disconnect_conn = TRUE; 1302 } 1303 else 1304 retry = (newurl)?TRUE:FALSE; 1305 1306 Curl_posttransfer(data); 1307 drc = Curl_done(&data->easy_conn, data->result, FALSE); 1308 1309 /* When set to retry the connection, we must to go back to 1310 * the CONNECT state */ 1311 if(retry) { 1312 if((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) { 1313 follow = FOLLOW_RETRY; 1314 drc = Curl_follow(data, newurl, follow); 1315 if(drc == CURLE_OK) { 1316 multistate(data, CURLM_STATE_CONNECT); 1317 result = CURLM_CALL_MULTI_PERFORM; 1318 data->result = CURLE_OK; 1319 } 1320 else { 1321 /* Follow failed */ 1322 data->result = drc; 1323 free(newurl); 1324 } 1325 } 1326 else { 1327 /* done didn't return OK or SEND_ERROR */ 1328 data->result = drc; 1329 free(newurl); 1330 } 1331 } 1332 else { 1333 /* Have error handler disconnect conn if we can't retry */ 1334 disconnect_conn = TRUE; 1335 } 1336 } 1337 else { 1338 /* failure detected */ 1339 Curl_posttransfer(data); 1340 if(data->easy_conn) 1341 Curl_done(&data->easy_conn, data->result, FALSE); 1342 disconnect_conn = TRUE; 1343 } 1344 } 1345 break; 1346 1347 case CURLM_STATE_DOING: 1348 /* we continue DOING until the DO phase is complete */ 1349 data->result = Curl_protocol_doing(data->easy_conn, 1350 &dophase_done); 1351 if(CURLE_OK == data->result) { 1352 if(dophase_done) { 1353 /* after DO, go DO_DONE or DO_MORE */ 1354 multistate(data, data->easy_conn->bits.do_more? 1355 CURLM_STATE_DO_MORE: 1356 CURLM_STATE_DO_DONE); 1357 result = CURLM_CALL_MULTI_PERFORM; 1358 } /* dophase_done */ 1359 } 1360 else { 1361 /* failure detected */ 1362 Curl_posttransfer(data); 1363 Curl_done(&data->easy_conn, data->result, FALSE); 1364 disconnect_conn = TRUE; 1365 } 1366 break; 1367 1368 case CURLM_STATE_DO_MORE: 1369 /* 1370 * When we are connected, DO MORE and then go DO_DONE 1371 */ 1372 data->result = Curl_do_more(data->easy_conn, &control); 1373 1374 /* No need to remove this handle from the send pipeline here since that 1375 is done in Curl_done() */ 1376 if(CURLE_OK == data->result) { 1377 if(control) { 1378 /* if positive, advance to DO_DONE 1379 if negative, go back to DOING */ 1380 multistate(data, control==1? 1381 CURLM_STATE_DO_DONE: 1382 CURLM_STATE_DOING); 1383 result = CURLM_CALL_MULTI_PERFORM; 1384 } 1385 else 1386 /* stay in DO_MORE */ 1387 result = CURLM_OK; 1388 } 1389 else { 1390 /* failure detected */ 1391 Curl_posttransfer(data); 1392 Curl_done(&data->easy_conn, data->result, FALSE); 1393 disconnect_conn = TRUE; 1394 } 1395 break; 1396 1397 case CURLM_STATE_DO_DONE: 1398 /* Move ourselves from the send to recv pipeline */ 1399 Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn); 1400 /* Check if we can move pending requests to send pipe */ 1401 Curl_multi_process_pending_handles(multi); 1402 1403 /* Only perform the transfer if there's a good socket to work with. 1404 Having both BAD is a signal to skip immediately to DONE */ 1405 if((data->easy_conn->sockfd != CURL_SOCKET_BAD) || 1406 (data->easy_conn->writesockfd != CURL_SOCKET_BAD)) 1407 multistate(data, CURLM_STATE_WAITPERFORM); 1408 else 1409 multistate(data, CURLM_STATE_DONE); 1410 result = CURLM_CALL_MULTI_PERFORM; 1411 break; 1412 1413 case CURLM_STATE_WAITPERFORM: 1414 /* Wait for our turn to PERFORM */ 1415 if(!data->easy_conn->readchannel_inuse && 1416 isHandleAtHead(data, 1417 data->easy_conn->recv_pipe)) { 1418 /* Grab the channel */ 1419 data->easy_conn->readchannel_inuse = TRUE; 1420 multistate(data, CURLM_STATE_PERFORM); 1421 result = CURLM_CALL_MULTI_PERFORM; 1422 } 1423#ifdef DEBUGBUILD 1424 else { 1425 infof(data, "WAITPERFORM: Conn %ld recv pipe %zu inuse %s athead %s\n", 1426 data->easy_conn->connection_id, 1427 data->easy_conn->recv_pipe->size, 1428 data->easy_conn->readchannel_inuse?"TRUE":"FALSE", 1429 isHandleAtHead(data, 1430 data->easy_conn->recv_pipe)?"TRUE":"FALSE"); 1431 } 1432#endif 1433 break; 1434 1435 case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ 1436 /* if both rates are within spec, resume transfer */ 1437 if(Curl_pgrsUpdate(data->easy_conn)) 1438 data->result = CURLE_ABORTED_BY_CALLBACK; 1439 else 1440 data->result = Curl_speedcheck(data, now); 1441 1442 if(( (data->set.max_send_speed == 0) || 1443 (data->progress.ulspeed < data->set.max_send_speed )) && 1444 ( (data->set.max_recv_speed == 0) || 1445 (data->progress.dlspeed < data->set.max_recv_speed))) 1446 multistate(data, CURLM_STATE_PERFORM); 1447 break; 1448 1449 case CURLM_STATE_PERFORM: 1450 { 1451 char *newurl = NULL; 1452 bool retry = FALSE; 1453 1454 /* check if over send speed */ 1455 if((data->set.max_send_speed > 0) && 1456 (data->progress.ulspeed > data->set.max_send_speed)) { 1457 int buffersize; 1458 1459 multistate(data, CURLM_STATE_TOOFAST); 1460 1461 /* calculate upload rate-limitation timeout. */ 1462 buffersize = (int)(data->set.buffer_size ? 1463 data->set.buffer_size : BUFSIZE); 1464 timeout_ms = Curl_sleep_time(data->set.max_send_speed, 1465 data->progress.ulspeed, buffersize); 1466 Curl_expire(data, timeout_ms); 1467 break; 1468 } 1469 1470 /* check if over recv speed */ 1471 if((data->set.max_recv_speed > 0) && 1472 (data->progress.dlspeed > data->set.max_recv_speed)) { 1473 int buffersize; 1474 1475 multistate(data, CURLM_STATE_TOOFAST); 1476 1477 /* Calculate download rate-limitation timeout. */ 1478 buffersize = (int)(data->set.buffer_size ? 1479 data->set.buffer_size : BUFSIZE); 1480 timeout_ms = Curl_sleep_time(data->set.max_recv_speed, 1481 data->progress.dlspeed, buffersize); 1482 Curl_expire(data, timeout_ms); 1483 break; 1484 } 1485 1486 /* read/write data if it is ready to do so */ 1487 data->result = Curl_readwrite(data->easy_conn, &done); 1488 1489 k = &data->req; 1490 1491 if(!(k->keepon & KEEP_RECV)) { 1492 /* We're done receiving */ 1493 data->easy_conn->readchannel_inuse = FALSE; 1494 } 1495 1496 if(!(k->keepon & KEEP_SEND)) { 1497 /* We're done sending */ 1498 data->easy_conn->writechannel_inuse = FALSE; 1499 } 1500 1501 if(done || (data->result == CURLE_RECV_ERROR)) { 1502 /* If CURLE_RECV_ERROR happens early enough, we assume it was a race 1503 * condition and the server closed the re-used connection exactly when 1504 * we wanted to use it, so figure out if that is indeed the case. 1505 */ 1506 CURLcode ret = Curl_retry_request(data->easy_conn, &newurl); 1507 if(!ret) 1508 retry = (newurl)?TRUE:FALSE; 1509 1510 if(retry) { 1511 /* if we are to retry, set the result to OK and consider the 1512 request as done */ 1513 data->result = CURLE_OK; 1514 done = TRUE; 1515 } 1516 } 1517 1518 if(data->result) { 1519 /* 1520 * The transfer phase returned error, we mark the connection to get 1521 * closed to prevent being re-used. This is because we can't possibly 1522 * know if the connection is in a good shape or not now. Unless it is 1523 * a protocol which uses two "channels" like FTP, as then the error 1524 * happened in the data connection. 1525 */ 1526 1527 if(!(data->easy_conn->handler->flags & PROTOPT_DUAL)) 1528 connclose(data->easy_conn, "Transfer returned error"); 1529 1530 Curl_posttransfer(data); 1531 Curl_done(&data->easy_conn, data->result, FALSE); 1532 } 1533 else if(done) { 1534 followtype follow=FOLLOW_NONE; 1535 1536 /* call this even if the readwrite function returned error */ 1537 Curl_posttransfer(data); 1538 1539 /* we're no longer receiving */ 1540 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); 1541 1542 /* expire the new receiving pipeline head */ 1543 if(data->easy_conn->recv_pipe->head) 1544 Curl_expire(data->easy_conn->recv_pipe->head->ptr, 1); 1545 1546 /* Check if we can move pending requests to send pipe */ 1547 Curl_multi_process_pending_handles(multi); 1548 1549 /* When we follow redirects or is set to retry the connection, we must 1550 to go back to the CONNECT state */ 1551 if(data->req.newurl || retry) { 1552 if(!retry) { 1553 /* if the URL is a follow-location and not just a retried request 1554 then figure out the URL here */ 1555 newurl = data->req.newurl; 1556 data->req.newurl = NULL; 1557 follow = FOLLOW_REDIR; 1558 } 1559 else 1560 follow = FOLLOW_RETRY; 1561 data->result = Curl_done(&data->easy_conn, CURLE_OK, FALSE); 1562 if(CURLE_OK == data->result) { 1563 data->result = Curl_follow(data, newurl, follow); 1564 if(CURLE_OK == data->result) { 1565 multistate(data, CURLM_STATE_CONNECT); 1566 result = CURLM_CALL_MULTI_PERFORM; 1567 newurl = NULL; /* handed over the memory ownership to 1568 Curl_follow(), make sure we don't free() it 1569 here */ 1570 } 1571 } 1572 } 1573 else { 1574 /* after the transfer is done, go DONE */ 1575 1576 /* but first check to see if we got a location info even though we're 1577 not following redirects */ 1578 if(data->req.location) { 1579 if(newurl) 1580 free(newurl); 1581 newurl = data->req.location; 1582 data->req.location = NULL; 1583 data->result = Curl_follow(data, newurl, FOLLOW_FAKE); 1584 if(CURLE_OK == data->result) 1585 newurl = NULL; /* allocation was handed over Curl_follow() */ 1586 else 1587 disconnect_conn = TRUE; 1588 } 1589 1590 multistate(data, CURLM_STATE_DONE); 1591 result = CURLM_CALL_MULTI_PERFORM; 1592 } 1593 } 1594 1595 if(newurl) 1596 free(newurl); 1597 break; 1598 } 1599 1600 case CURLM_STATE_DONE: 1601 /* this state is highly transient, so run another loop after this */ 1602 result = CURLM_CALL_MULTI_PERFORM; 1603 1604 if(data->easy_conn) { 1605 CURLcode res; 1606 1607 /* Remove ourselves from the receive pipeline, if we are there. */ 1608 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); 1609 /* Check if we can move pending requests to send pipe */ 1610 Curl_multi_process_pending_handles(multi); 1611 1612 /* post-transfer command */ 1613 res = Curl_done(&data->easy_conn, data->result, FALSE); 1614 1615 /* allow a previously set error code take precedence */ 1616 if(!data->result) 1617 data->result = res; 1618 1619 /* 1620 * If there are other handles on the pipeline, Curl_done won't set 1621 * easy_conn to NULL. In such a case, curl_multi_remove_handle() can 1622 * access free'd data, if the connection is free'd and the handle 1623 * removed before we perform the processing in CURLM_STATE_COMPLETED 1624 */ 1625 if(data->easy_conn) 1626 data->easy_conn = NULL; 1627 } 1628 1629 if(data->set.wildcardmatch) { 1630 if(data->wildcard.state != CURLWC_DONE) { 1631 /* if a wildcard is set and we are not ending -> lets start again 1632 with CURLM_STATE_INIT */ 1633 multistate(data, CURLM_STATE_INIT); 1634 break; 1635 } 1636 } 1637 1638 /* after we have DONE what we're supposed to do, go COMPLETED, and 1639 it doesn't matter what the Curl_done() returned! */ 1640 multistate(data, CURLM_STATE_COMPLETED); 1641 break; 1642 1643 case CURLM_STATE_COMPLETED: 1644 /* this is a completed transfer, it is likely to still be connected */ 1645 1646 /* This node should be delinked from the list now and we should post 1647 an information message that we are complete. */ 1648 1649 /* Important: reset the conn pointer so that we don't point to memory 1650 that could be freed anytime */ 1651 data->easy_conn = NULL; 1652 1653 Curl_expire(data, 0); /* stop all timers */ 1654 break; 1655 1656 case CURLM_STATE_MSGSENT: 1657 return CURLM_OK; /* do nothing */ 1658 1659 default: 1660 return CURLM_INTERNAL_ERROR; 1661 } 1662 1663 if(data->mstate < CURLM_STATE_COMPLETED) { 1664 if(CURLE_OK != data->result) { 1665 /* 1666 * If an error was returned, and we aren't in completed state now, 1667 * then we go to completed and consider this transfer aborted. 1668 */ 1669 1670 /* NOTE: no attempt to disconnect connections must be made 1671 in the case blocks above - cleanup happens only here */ 1672 1673 data->state.pipe_broke = FALSE; 1674 1675 if(data->easy_conn) { 1676 /* if this has a connection, unsubscribe from the pipelines */ 1677 data->easy_conn->writechannel_inuse = FALSE; 1678 data->easy_conn->readchannel_inuse = FALSE; 1679 Curl_removeHandleFromPipeline(data, 1680 data->easy_conn->send_pipe); 1681 Curl_removeHandleFromPipeline(data, 1682 data->easy_conn->recv_pipe); 1683 /* Check if we can move pending requests to send pipe */ 1684 Curl_multi_process_pending_handles(multi); 1685 1686 if(disconnect_conn) { 1687 /* disconnect properly */ 1688 Curl_disconnect(data->easy_conn, /* dead_connection */ FALSE); 1689 1690 /* This is where we make sure that the easy_conn pointer is reset. 1691 We don't have to do this in every case block above where a 1692 failure is detected */ 1693 data->easy_conn = NULL; 1694 } 1695 } 1696 else if(data->mstate == CURLM_STATE_CONNECT) { 1697 /* Curl_connect() failed */ 1698 (void)Curl_posttransfer(data); 1699 } 1700 1701 multistate(data, CURLM_STATE_COMPLETED); 1702 } 1703 /* if there's still a connection to use, call the progress function */ 1704 else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) { 1705 /* aborted due to progress callback return code must close the 1706 connection */ 1707 data->result = CURLE_ABORTED_BY_CALLBACK; 1708 connclose(data->easy_conn, "Aborted by callback"); 1709 1710 /* if not yet in DONE state, go there, otherwise COMPLETED */ 1711 multistate(data, (data->mstate < CURLM_STATE_DONE)? 1712 CURLM_STATE_DONE: CURLM_STATE_COMPLETED); 1713 result = CURLM_CALL_MULTI_PERFORM; 1714 } 1715 } 1716 } WHILE_FALSE; /* just to break out from! */ 1717 1718 if(CURLM_STATE_COMPLETED == data->mstate) { 1719 /* now fill in the Curl_message with this info */ 1720 msg = &data->msg; 1721 1722 msg->extmsg.msg = CURLMSG_DONE; 1723 msg->extmsg.easy_handle = data; 1724 msg->extmsg.data.result = data->result; 1725 1726 result = multi_addmsg(multi, msg); 1727 1728 multistate(data, CURLM_STATE_MSGSENT); 1729 } 1730 1731 return result; 1732} 1733 1734 1735CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) 1736{ 1737 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 1738 struct SessionHandle *data; 1739 CURLMcode returncode=CURLM_OK; 1740 struct Curl_tree *t; 1741 struct timeval now = Curl_tvnow(); 1742 1743 if(!GOOD_MULTI_HANDLE(multi)) 1744 return CURLM_BAD_HANDLE; 1745 1746 data=multi->easyp; 1747 while(data) { 1748 CURLMcode result; 1749 struct WildcardData *wc = &data->wildcard; 1750 SIGPIPE_VARIABLE(pipe_st); 1751 1752 if(data->set.wildcardmatch) { 1753 if(!wc->filelist) { 1754 CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */ 1755 if(ret) 1756 return CURLM_OUT_OF_MEMORY; 1757 } 1758 } 1759 1760 sigpipe_ignore(data, &pipe_st); 1761 do 1762 result = multi_runsingle(multi, now, data); 1763 while(CURLM_CALL_MULTI_PERFORM == result); 1764 sigpipe_restore(&pipe_st); 1765 1766 if(data->set.wildcardmatch) { 1767 /* destruct wildcard structures if it is needed */ 1768 if(wc->state == CURLWC_DONE || result) 1769 Curl_wildcard_dtor(wc); 1770 } 1771 1772 if(result) 1773 returncode = result; 1774 1775 data = data->next; /* operate on next handle */ 1776 } 1777 1778 /* 1779 * Simply remove all expired timers from the splay since handles are dealt 1780 * with unconditionally by this function and curl_multi_timeout() requires 1781 * that already passed/handled expire times are removed from the splay. 1782 * 1783 * It is important that the 'now' value is set at the entry of this function 1784 * and not for the current time as it may have ticked a little while since 1785 * then and then we risk this loop to remove timers that actually have not 1786 * been handled! 1787 */ 1788 do { 1789 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); 1790 if(t) 1791 /* the removed may have another timeout in queue */ 1792 (void)add_next_timeout(now, multi, t->payload); 1793 1794 } while(t); 1795 1796 *running_handles = multi->num_alive; 1797 1798 if(CURLM_OK >= returncode) 1799 update_timer(multi); 1800 1801 return returncode; 1802} 1803 1804static void close_all_connections(struct Curl_multi *multi) 1805{ 1806 struct connectdata *conn; 1807 1808 conn = Curl_conncache_find_first_connection(multi->conn_cache); 1809 while(conn) { 1810 SIGPIPE_VARIABLE(pipe_st); 1811 conn->data = multi->closure_handle; 1812 1813 sigpipe_ignore(conn->data, &pipe_st); 1814 /* This will remove the connection from the cache */ 1815 (void)Curl_disconnect(conn, FALSE); 1816 sigpipe_restore(&pipe_st); 1817 1818 conn = Curl_conncache_find_first_connection(multi->conn_cache); 1819 } 1820} 1821 1822CURLMcode curl_multi_cleanup(CURLM *multi_handle) 1823{ 1824 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 1825 struct SessionHandle *data; 1826 struct SessionHandle *nextdata; 1827 1828 if(GOOD_MULTI_HANDLE(multi)) { 1829 bool restore_pipe = FALSE; 1830 SIGPIPE_VARIABLE(pipe_st); 1831 1832 multi->type = 0; /* not good anymore */ 1833 1834 /* Close all the connections in the connection cache */ 1835 close_all_connections(multi); 1836 1837 if(multi->closure_handle) { 1838 sigpipe_ignore(multi->closure_handle, &pipe_st); 1839 restore_pipe = TRUE; 1840 1841 multi->closure_handle->dns.hostcache = multi->hostcache; 1842 Curl_hostcache_clean(multi->closure_handle, 1843 multi->closure_handle->dns.hostcache); 1844 1845 Curl_close(multi->closure_handle); 1846 multi->closure_handle = NULL; 1847 } 1848 1849 Curl_hash_destroy(multi->sockhash); 1850 multi->sockhash = NULL; 1851 1852 Curl_conncache_destroy(multi->conn_cache); 1853 multi->conn_cache = NULL; 1854 1855 /* remove the pending list of messages */ 1856 Curl_llist_destroy(multi->msglist, NULL); 1857 multi->msglist = NULL; 1858 1859 /* remove all easy handles */ 1860 data = multi->easyp; 1861 while(data) { 1862 nextdata=data->next; 1863 if(data->dns.hostcachetype == HCACHE_MULTI) { 1864 /* clear out the usage of the shared DNS cache */ 1865 Curl_hostcache_clean(data, data->dns.hostcache); 1866 data->dns.hostcache = NULL; 1867 data->dns.hostcachetype = HCACHE_NONE; 1868 } 1869 1870 /* Clear the pointer to the connection cache */ 1871 data->state.conn_cache = NULL; 1872 data->multi = NULL; /* clear the association */ 1873 1874 data = nextdata; 1875 } 1876 1877 Curl_hash_destroy(multi->hostcache); 1878 multi->hostcache = NULL; 1879 1880 /* Free the blacklists by setting them to NULL */ 1881 Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl); 1882 Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl); 1883 1884 free(multi); 1885 if(restore_pipe) 1886 sigpipe_restore(&pipe_st); 1887 1888 return CURLM_OK; 1889 } 1890 else 1891 return CURLM_BAD_HANDLE; 1892} 1893 1894/* 1895 * curl_multi_info_read() 1896 * 1897 * This function is the primary way for a multi/multi_socket application to 1898 * figure out if a transfer has ended. We MUST make this function as fast as 1899 * possible as it will be polled frequently and we MUST NOT scan any lists in 1900 * here to figure out things. We must scale fine to thousands of handles and 1901 * beyond. The current design is fully O(1). 1902 */ 1903 1904CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) 1905{ 1906 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 1907 struct Curl_message *msg; 1908 1909 *msgs_in_queue = 0; /* default to none */ 1910 1911 if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) { 1912 /* there is one or more messages in the list */ 1913 struct curl_llist_element *e; 1914 1915 /* extract the head of the list to return */ 1916 e = multi->msglist->head; 1917 1918 msg = e->ptr; 1919 1920 /* remove the extracted entry */ 1921 Curl_llist_remove(multi->msglist, e, NULL); 1922 1923 *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist)); 1924 1925 return &msg->extmsg; 1926 } 1927 else 1928 return NULL; 1929} 1930 1931/* 1932 * singlesocket() checks what sockets we deal with and their "action state" 1933 * and if we have a different state in any of those sockets from last time we 1934 * call the callback accordingly. 1935 */ 1936static void singlesocket(struct Curl_multi *multi, 1937 struct SessionHandle *data) 1938{ 1939 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; 1940 int i; 1941 struct Curl_sh_entry *entry; 1942 curl_socket_t s; 1943 int num; 1944 unsigned int curraction; 1945 bool remove_sock_from_hash; 1946 1947 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) 1948 socks[i] = CURL_SOCKET_BAD; 1949 1950 /* Fill in the 'current' struct with the state as it is now: what sockets to 1951 supervise and for what actions */ 1952 curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE); 1953 1954 /* We have 0 .. N sockets already and we get to know about the 0 .. M 1955 sockets we should have from now on. Detect the differences, remove no 1956 longer supervised ones and add new ones */ 1957 1958 /* walk over the sockets we got right now */ 1959 for(i=0; (i< MAX_SOCKSPEREASYHANDLE) && 1960 (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))); 1961 i++) { 1962 int action = CURL_POLL_NONE; 1963 1964 s = socks[i]; 1965 1966 /* get it from the hash */ 1967 entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); 1968 1969 if(curraction & GETSOCK_READSOCK(i)) 1970 action |= CURL_POLL_IN; 1971 if(curraction & GETSOCK_WRITESOCK(i)) 1972 action |= CURL_POLL_OUT; 1973 1974 if(entry) { 1975 /* yeps, already present so check if it has the same action set */ 1976 if(entry->action == action) 1977 /* same, continue */ 1978 continue; 1979 } 1980 else { 1981 /* this is a socket we didn't have before, add it! */ 1982 entry = sh_addentry(multi->sockhash, s, data); 1983 if(!entry) 1984 /* fatal */ 1985 return; 1986 } 1987 1988 /* we know (entry != NULL) at this point, see the logic above */ 1989 if(multi->socket_cb) 1990 multi->socket_cb(data, 1991 s, 1992 action, 1993 multi->socket_userp, 1994 entry->socketp); 1995 1996 entry->action = action; /* store the current action state */ 1997 } 1998 1999 num = i; /* number of sockets */ 2000 2001 /* when we've walked over all the sockets we should have right now, we must 2002 make sure to detect sockets that are removed */ 2003 for(i=0; i< data->numsocks; i++) { 2004 int j; 2005 s = data->sockets[i]; 2006 for(j=0; j<num; j++) { 2007 if(s == socks[j]) { 2008 /* this is still supervised */ 2009 s = CURL_SOCKET_BAD; 2010 break; 2011 } 2012 } 2013 if(s != CURL_SOCKET_BAD) { 2014 2015 /* this socket has been removed. Tell the app to remove it */ 2016 remove_sock_from_hash = TRUE; 2017 2018 entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); 2019 if(entry) { 2020 /* check if the socket to be removed serves a connection which has 2021 other easy-s in a pipeline. In this case the socket should not be 2022 removed. */ 2023 struct connectdata *easy_conn = data->easy_conn; 2024 if(easy_conn) { 2025 if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) { 2026 /* the handle should not be removed from the pipe yet */ 2027 remove_sock_from_hash = FALSE; 2028 2029 /* Update the sockhash entry to instead point to the next in line 2030 for the recv_pipe, or the first (in case this particular easy 2031 isn't already) */ 2032 if(entry->easy == data) { 2033 if(isHandleAtHead(data, easy_conn->recv_pipe)) 2034 entry->easy = easy_conn->recv_pipe->head->next->ptr; 2035 else 2036 entry->easy = easy_conn->recv_pipe->head->ptr; 2037 } 2038 } 2039 if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) { 2040 /* the handle should not be removed from the pipe yet */ 2041 remove_sock_from_hash = FALSE; 2042 2043 /* Update the sockhash entry to instead point to the next in line 2044 for the send_pipe, or the first (in case this particular easy 2045 isn't already) */ 2046 if(entry->easy == data) { 2047 if(isHandleAtHead(data, easy_conn->send_pipe)) 2048 entry->easy = easy_conn->send_pipe->head->next->ptr; 2049 else 2050 entry->easy = easy_conn->send_pipe->head->ptr; 2051 } 2052 } 2053 /* Don't worry about overwriting recv_pipe head with send_pipe_head, 2054 when action will be asked on the socket (see multi_socket()), the 2055 head of the correct pipe will be taken according to the 2056 action. */ 2057 } 2058 } 2059 else 2060 /* just a precaution, this socket really SHOULD be in the hash already 2061 but in case it isn't, we don't have to tell the app to remove it 2062 either since it never got to know about it */ 2063 remove_sock_from_hash = FALSE; 2064 2065 if(remove_sock_from_hash) { 2066 /* in this case 'entry' is always non-NULL */ 2067 if(multi->socket_cb) 2068 multi->socket_cb(data, 2069 s, 2070 CURL_POLL_REMOVE, 2071 multi->socket_userp, 2072 entry->socketp); 2073 sh_delentry(multi->sockhash, s); 2074 } 2075 2076 } 2077 } 2078 2079 memcpy(data->sockets, socks, num*sizeof(curl_socket_t)); 2080 data->numsocks = num; 2081} 2082 2083/* 2084 * Curl_multi_closed() 2085 * 2086 * Used by the connect code to tell the multi_socket code that one of the 2087 * sockets we were using have just been closed. This function will then 2088 * remove it from the sockethash for this handle to make the multi_socket API 2089 * behave properly, especially for the case when libcurl will create another 2090 * socket again and it gets the same file descriptor number. 2091 */ 2092 2093void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) 2094{ 2095 struct Curl_multi *multi = conn->data->multi; 2096 if(multi) { 2097 /* this is set if this connection is part of a handle that is added to 2098 a multi handle, and only then this is necessary */ 2099 struct Curl_sh_entry *entry = 2100 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); 2101 2102 if(entry) { 2103 if(multi->socket_cb) 2104 multi->socket_cb(conn->data, s, CURL_POLL_REMOVE, 2105 multi->socket_userp, 2106 entry->socketp); 2107 2108 /* now remove it from the socket hash */ 2109 sh_delentry(multi->sockhash, s); 2110 } 2111 } 2112} 2113 2114 2115 2116/* 2117 * add_next_timeout() 2118 * 2119 * Each SessionHandle has a list of timeouts. The add_next_timeout() is called 2120 * when it has just been removed from the splay tree because the timeout has 2121 * expired. This function is then to advance in the list to pick the next 2122 * timeout to use (skip the already expired ones) and add this node back to 2123 * the splay tree again. 2124 * 2125 * The splay tree only has each sessionhandle as a single node and the nearest 2126 * timeout is used to sort it on. 2127 */ 2128static CURLMcode add_next_timeout(struct timeval now, 2129 struct Curl_multi *multi, 2130 struct SessionHandle *d) 2131{ 2132 struct timeval *tv = &d->state.expiretime; 2133 struct curl_llist *list = d->state.timeoutlist; 2134 struct curl_llist_element *e; 2135 2136 /* move over the timeout list for this specific handle and remove all 2137 timeouts that are now passed tense and store the next pending 2138 timeout in *tv */ 2139 for(e = list->head; e; ) { 2140 struct curl_llist_element *n = e->next; 2141 long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); 2142 if(diff <= 0) 2143 /* remove outdated entry */ 2144 Curl_llist_remove(list, e, NULL); 2145 else 2146 /* the list is sorted so get out on the first mismatch */ 2147 break; 2148 e = n; 2149 } 2150 e = list->head; 2151 if(!e) { 2152 /* clear the expire times within the handles that we remove from the 2153 splay tree */ 2154 tv->tv_sec = 0; 2155 tv->tv_usec = 0; 2156 } 2157 else { 2158 /* copy the first entry to 'tv' */ 2159 memcpy(tv, e->ptr, sizeof(*tv)); 2160 2161 /* remove first entry from list */ 2162 Curl_llist_remove(list, e, NULL); 2163 2164 /* insert this node again into the splay */ 2165 multi->timetree = Curl_splayinsert(*tv, multi->timetree, 2166 &d->state.timenode); 2167 } 2168 return CURLM_OK; 2169} 2170 2171static CURLMcode multi_socket(struct Curl_multi *multi, 2172 bool checkall, 2173 curl_socket_t s, 2174 int ev_bitmask, 2175 int *running_handles) 2176{ 2177 CURLMcode result = CURLM_OK; 2178 struct SessionHandle *data = NULL; 2179 struct Curl_tree *t; 2180 struct timeval now = Curl_tvnow(); 2181 2182 if(checkall) { 2183 /* *perform() deals with running_handles on its own */ 2184 result = curl_multi_perform(multi, running_handles); 2185 2186 /* walk through each easy handle and do the socket state change magic 2187 and callbacks */ 2188 if(result != CURLM_BAD_HANDLE) { 2189 data=multi->easyp; 2190 while(data) { 2191 singlesocket(multi, data); 2192 data = data->next; 2193 } 2194 } 2195 2196 /* or should we fall-through and do the timer-based stuff? */ 2197 return result; 2198 } 2199 else if(s != CURL_SOCKET_TIMEOUT) { 2200 2201 struct Curl_sh_entry *entry = 2202 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); 2203 2204 if(!entry) 2205 /* Unmatched socket, we can't act on it but we ignore this fact. In 2206 real-world tests it has been proved that libevent can in fact give 2207 the application actions even though the socket was just previously 2208 asked to get removed, so thus we better survive stray socket actions 2209 and just move on. */ 2210 ; 2211 else { 2212 SIGPIPE_VARIABLE(pipe_st); 2213 2214 data = entry->easy; 2215 2216 if(data->magic != CURLEASY_MAGIC_NUMBER) 2217 /* bad bad bad bad bad bad bad */ 2218 return CURLM_INTERNAL_ERROR; 2219 2220 /* If the pipeline is enabled, take the handle which is in the head of 2221 the pipeline. If we should write into the socket, take the send_pipe 2222 head. If we should read from the socket, take the recv_pipe head. */ 2223 if(data->easy_conn) { 2224 if((ev_bitmask & CURL_POLL_OUT) && 2225 data->easy_conn->send_pipe && 2226 data->easy_conn->send_pipe->head) 2227 data = data->easy_conn->send_pipe->head->ptr; 2228 else if((ev_bitmask & CURL_POLL_IN) && 2229 data->easy_conn->recv_pipe && 2230 data->easy_conn->recv_pipe->head) 2231 data = data->easy_conn->recv_pipe->head->ptr; 2232 } 2233 2234 if(data->easy_conn && 2235 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK)) 2236 /* set socket event bitmask if they're not locked */ 2237 data->easy_conn->cselect_bits = ev_bitmask; 2238 2239 sigpipe_ignore(data, &pipe_st); 2240 do 2241 result = multi_runsingle(multi, now, data); 2242 while(CURLM_CALL_MULTI_PERFORM == result); 2243 sigpipe_restore(&pipe_st); 2244 2245 if(data->easy_conn && 2246 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK)) 2247 /* clear the bitmask only if not locked */ 2248 data->easy_conn->cselect_bits = 0; 2249 2250 if(CURLM_OK >= result) 2251 /* get the socket(s) and check if the state has been changed since 2252 last */ 2253 singlesocket(multi, data); 2254 2255 /* Now we fall-through and do the timer-based stuff, since we don't want 2256 to force the user to have to deal with timeouts as long as at least 2257 one connection in fact has traffic. */ 2258 2259 data = NULL; /* set data to NULL again to avoid calling 2260 multi_runsingle() in case there's no need to */ 2261 now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop 2262 may have taken some time */ 2263 } 2264 } 2265 else { 2266 /* Asked to run due to time-out. Clear the 'lastcall' variable to force 2267 update_timer() to trigger a callback to the app again even if the same 2268 timeout is still the one to run after this call. That handles the case 2269 when the application asks libcurl to run the timeout prematurely. */ 2270 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); 2271 } 2272 2273 /* 2274 * The loop following here will go on as long as there are expire-times left 2275 * to process in the splay and 'data' will be re-assigned for every expired 2276 * handle we deal with. 2277 */ 2278 do { 2279 /* the first loop lap 'data' can be NULL */ 2280 if(data) { 2281 SIGPIPE_VARIABLE(pipe_st); 2282 2283 sigpipe_ignore(data, &pipe_st); 2284 do 2285 result = multi_runsingle(multi, now, data); 2286 while(CURLM_CALL_MULTI_PERFORM == result); 2287 sigpipe_restore(&pipe_st); 2288 2289 if(CURLM_OK >= result) 2290 /* get the socket(s) and check if the state has been changed since 2291 last */ 2292 singlesocket(multi, data); 2293 } 2294 2295 /* Check if there's one (more) expired timer to deal with! This function 2296 extracts a matching node if there is one */ 2297 2298 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t); 2299 if(t) { 2300 data = t->payload; /* assign this for next loop */ 2301 (void)add_next_timeout(now, multi, t->payload); 2302 } 2303 2304 } while(t); 2305 2306 *running_handles = multi->num_alive; 2307 return result; 2308} 2309 2310#undef curl_multi_setopt 2311CURLMcode curl_multi_setopt(CURLM *multi_handle, 2312 CURLMoption option, ...) 2313{ 2314 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 2315 CURLMcode res = CURLM_OK; 2316 va_list param; 2317 2318 if(!GOOD_MULTI_HANDLE(multi)) 2319 return CURLM_BAD_HANDLE; 2320 2321 va_start(param, option); 2322 2323 switch(option) { 2324 case CURLMOPT_SOCKETFUNCTION: 2325 multi->socket_cb = va_arg(param, curl_socket_callback); 2326 break; 2327 case CURLMOPT_SOCKETDATA: 2328 multi->socket_userp = va_arg(param, void *); 2329 break; 2330 case CURLMOPT_PIPELINING: 2331 multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE; 2332 break; 2333 case CURLMOPT_TIMERFUNCTION: 2334 multi->timer_cb = va_arg(param, curl_multi_timer_callback); 2335 break; 2336 case CURLMOPT_TIMERDATA: 2337 multi->timer_userp = va_arg(param, void *); 2338 break; 2339 case CURLMOPT_MAXCONNECTS: 2340 multi->maxconnects = va_arg(param, long); 2341 break; 2342 case CURLMOPT_MAX_HOST_CONNECTIONS: 2343 multi->max_host_connections = va_arg(param, long); 2344 break; 2345 case CURLMOPT_MAX_PIPELINE_LENGTH: 2346 multi->max_pipeline_length = va_arg(param, long); 2347 break; 2348 case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: 2349 multi->content_length_penalty_size = va_arg(param, long); 2350 break; 2351 case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: 2352 multi->chunk_length_penalty_size = va_arg(param, long); 2353 break; 2354 case CURLMOPT_PIPELINING_SITE_BL: 2355 res = Curl_pipeline_set_site_blacklist(va_arg(param, char **), 2356 &multi->pipelining_site_bl); 2357 break; 2358 case CURLMOPT_PIPELINING_SERVER_BL: 2359 res = Curl_pipeline_set_server_blacklist(va_arg(param, char **), 2360 &multi->pipelining_server_bl); 2361 break; 2362 case CURLMOPT_MAX_TOTAL_CONNECTIONS: 2363 multi->max_total_connections = va_arg(param, long); 2364 break; 2365 default: 2366 res = CURLM_UNKNOWN_OPTION; 2367 break; 2368 } 2369 va_end(param); 2370 return res; 2371} 2372 2373/* we define curl_multi_socket() in the public multi.h header */ 2374#undef curl_multi_socket 2375 2376CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, 2377 int *running_handles) 2378{ 2379 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, 2380 0, running_handles); 2381 if(CURLM_OK >= result) 2382 update_timer((struct Curl_multi *)multi_handle); 2383 return result; 2384} 2385 2386CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, 2387 int ev_bitmask, int *running_handles) 2388{ 2389 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, 2390 ev_bitmask, running_handles); 2391 if(CURLM_OK >= result) 2392 update_timer((struct Curl_multi *)multi_handle); 2393 return result; 2394} 2395 2396CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) 2397 2398{ 2399 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, 2400 TRUE, CURL_SOCKET_BAD, 0, running_handles); 2401 if(CURLM_OK >= result) 2402 update_timer((struct Curl_multi *)multi_handle); 2403 return result; 2404} 2405 2406static CURLMcode multi_timeout(struct Curl_multi *multi, 2407 long *timeout_ms) 2408{ 2409 static struct timeval tv_zero = {0,0}; 2410 2411 if(multi->timetree) { 2412 /* we have a tree of expire times */ 2413 struct timeval now = Curl_tvnow(); 2414 2415 /* splay the lowest to the bottom */ 2416 multi->timetree = Curl_splay(tv_zero, multi->timetree); 2417 2418 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { 2419 /* some time left before expiration */ 2420 *timeout_ms = curlx_tvdiff(multi->timetree->key, now); 2421 if(!*timeout_ms) 2422 /* 2423 * Since we only provide millisecond resolution on the returned value 2424 * and the diff might be less than one millisecond here, we don't 2425 * return zero as that may cause short bursts of busyloops on fast 2426 * processors while the diff is still present but less than one 2427 * millisecond! instead we return 1 until the time is ripe. 2428 */ 2429 *timeout_ms=1; 2430 } 2431 else 2432 /* 0 means immediately */ 2433 *timeout_ms = 0; 2434 } 2435 else 2436 *timeout_ms = -1; 2437 2438 return CURLM_OK; 2439} 2440 2441CURLMcode curl_multi_timeout(CURLM *multi_handle, 2442 long *timeout_ms) 2443{ 2444 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 2445 2446 /* First, make some basic checks that the CURLM handle is a good handle */ 2447 if(!GOOD_MULTI_HANDLE(multi)) 2448 return CURLM_BAD_HANDLE; 2449 2450 return multi_timeout(multi, timeout_ms); 2451} 2452 2453/* 2454 * Tell the application it should update its timers, if it subscribes to the 2455 * update timer callback. 2456 */ 2457static int update_timer(struct Curl_multi *multi) 2458{ 2459 long timeout_ms; 2460 2461 if(!multi->timer_cb) 2462 return 0; 2463 if(multi_timeout(multi, &timeout_ms)) { 2464 return -1; 2465 } 2466 if(timeout_ms < 0) { 2467 static const struct timeval none={0,0}; 2468 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) { 2469 multi->timer_lastcall = none; 2470 /* there's no timeout now but there was one previously, tell the app to 2471 disable it */ 2472 return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp); 2473 } 2474 return 0; 2475 } 2476 2477 /* When multi_timeout() is done, multi->timetree points to the node with the 2478 * timeout we got the (relative) time-out time for. We can thus easily check 2479 * if this is the same (fixed) time as we got in a previous call and then 2480 * avoid calling the callback again. */ 2481 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0) 2482 return 0; 2483 2484 multi->timer_lastcall = multi->timetree->key; 2485 2486 return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); 2487} 2488 2489void Curl_multi_set_easy_connection(struct SessionHandle *handle, 2490 struct connectdata *conn) 2491{ 2492 handle->easy_conn = conn; 2493} 2494 2495static bool isHandleAtHead(struct SessionHandle *handle, 2496 struct curl_llist *pipeline) 2497{ 2498 struct curl_llist_element *curr = pipeline->head; 2499 if(curr) 2500 return (curr->ptr == handle) ? TRUE : FALSE; 2501 2502 return FALSE; 2503} 2504 2505/* 2506 * multi_freetimeout() 2507 * 2508 * Callback used by the llist system when a single timeout list entry is 2509 * destroyed. 2510 */ 2511static void multi_freetimeout(void *user, void *entryptr) 2512{ 2513 (void)user; 2514 2515 /* the entry was plain malloc()'ed */ 2516 free(entryptr); 2517} 2518 2519/* 2520 * multi_addtimeout() 2521 * 2522 * Add a timestamp to the list of timeouts. Keep the list sorted so that head 2523 * of list is always the timeout nearest in time. 2524 * 2525 */ 2526static CURLMcode 2527multi_addtimeout(struct curl_llist *timeoutlist, 2528 struct timeval *stamp) 2529{ 2530 struct curl_llist_element *e; 2531 struct timeval *timedup; 2532 struct curl_llist_element *prev = NULL; 2533 2534 timedup = malloc(sizeof(*timedup)); 2535 if(!timedup) 2536 return CURLM_OUT_OF_MEMORY; 2537 2538 /* copy the timestamp */ 2539 memcpy(timedup, stamp, sizeof(*timedup)); 2540 2541 if(Curl_llist_count(timeoutlist)) { 2542 /* find the correct spot in the list */ 2543 for(e = timeoutlist->head; e; e = e->next) { 2544 struct timeval *checktime = e->ptr; 2545 long diff = curlx_tvdiff(*checktime, *timedup); 2546 if(diff > 0) 2547 break; 2548 prev = e; 2549 } 2550 2551 } 2552 /* else 2553 this is the first timeout on the list */ 2554 2555 if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) { 2556 free(timedup); 2557 return CURLM_OUT_OF_MEMORY; 2558 } 2559 2560 return CURLM_OK; 2561} 2562 2563/* 2564 * Curl_expire() 2565 * 2566 * given a number of milliseconds from now to use to set the 'act before 2567 * this'-time for the transfer, to be extracted by curl_multi_timeout() 2568 * 2569 * Note that the timeout will be added to a queue of timeouts if it defines a 2570 * moment in time that is later than the current head of queue. 2571 * 2572 * Pass zero to clear all timeout values for this handle. 2573*/ 2574void Curl_expire(struct SessionHandle *data, long milli) 2575{ 2576 struct Curl_multi *multi = data->multi; 2577 struct timeval *nowp = &data->state.expiretime; 2578 int rc; 2579 2580 /* this is only interesting while there is still an associated multi struct 2581 remaining! */ 2582 if(!multi) 2583 return; 2584 2585 if(!milli) { 2586 /* No timeout, clear the time data. */ 2587 if(nowp->tv_sec || nowp->tv_usec) { 2588 /* Since this is an cleared time, we must remove the previous entry from 2589 the splay tree */ 2590 struct curl_llist *list = data->state.timeoutlist; 2591 2592 rc = Curl_splayremovebyaddr(multi->timetree, 2593 &data->state.timenode, 2594 &multi->timetree); 2595 if(rc) 2596 infof(data, "Internal error clearing splay node = %d\n", rc); 2597 2598 /* flush the timeout list too */ 2599 while(list->size > 0) 2600 Curl_llist_remove(list, list->tail, NULL); 2601 2602#ifdef DEBUGBUILD 2603 infof(data, "Expire cleared\n"); 2604#endif 2605 nowp->tv_sec = 0; 2606 nowp->tv_usec = 0; 2607 } 2608 } 2609 else { 2610 struct timeval set; 2611 2612 set = Curl_tvnow(); 2613 set.tv_sec += milli/1000; 2614 set.tv_usec += (milli%1000)*1000; 2615 2616 if(set.tv_usec >= 1000000) { 2617 set.tv_sec++; 2618 set.tv_usec -= 1000000; 2619 } 2620 2621 if(nowp->tv_sec || nowp->tv_usec) { 2622 /* This means that the struct is added as a node in the splay tree. 2623 Compare if the new time is earlier, and only remove-old/add-new if it 2624 is. */ 2625 long diff = curlx_tvdiff(set, *nowp); 2626 if(diff > 0) { 2627 /* the new expire time was later so just add it to the queue 2628 and get out */ 2629 multi_addtimeout(data->state.timeoutlist, &set); 2630 return; 2631 } 2632 2633 /* the new time is newer than the presently set one, so add the current 2634 to the queue and update the head */ 2635 multi_addtimeout(data->state.timeoutlist, nowp); 2636 2637 /* Since this is an updated time, we must remove the previous entry from 2638 the splay tree first and then re-add the new value */ 2639 rc = Curl_splayremovebyaddr(multi->timetree, 2640 &data->state.timenode, 2641 &multi->timetree); 2642 if(rc) 2643 infof(data, "Internal error removing splay node = %d\n", rc); 2644 } 2645 2646 *nowp = set; 2647 data->state.timenode.payload = data; 2648 multi->timetree = Curl_splayinsert(*nowp, 2649 multi->timetree, 2650 &data->state.timenode); 2651 } 2652#if 0 2653 Curl_splayprint(multi->timetree, 0, TRUE); 2654#endif 2655} 2656 2657CURLMcode curl_multi_assign(CURLM *multi_handle, 2658 curl_socket_t s, void *hashp) 2659{ 2660 struct Curl_sh_entry *there = NULL; 2661 struct Curl_multi *multi = (struct Curl_multi *)multi_handle; 2662 2663 if(s != CURL_SOCKET_BAD) 2664 there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t)); 2665 2666 if(!there) 2667 return CURLM_BAD_SOCKET; 2668 2669 there->socketp = hashp; 2670 2671 return CURLM_OK; 2672} 2673 2674size_t Curl_multi_max_host_connections(struct Curl_multi *multi) 2675{ 2676 return multi ? multi->max_host_connections : 0; 2677} 2678 2679size_t Curl_multi_max_total_connections(struct Curl_multi *multi) 2680{ 2681 return multi ? multi->max_total_connections : 0; 2682} 2683 2684size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi) 2685{ 2686 return multi ? multi->max_pipeline_length : 0; 2687} 2688 2689curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi) 2690{ 2691 return multi ? multi->content_length_penalty_size : 0; 2692} 2693 2694curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi) 2695{ 2696 return multi ? multi->chunk_length_penalty_size : 0; 2697} 2698 2699struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi) 2700{ 2701 return multi->pipelining_site_bl; 2702} 2703 2704struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi) 2705{ 2706 return multi->pipelining_server_bl; 2707} 2708 2709void Curl_multi_process_pending_handles(struct Curl_multi *multi) 2710{ 2711 struct SessionHandle *data; 2712 2713 data=multi->easyp; 2714 while(data) { 2715 if(data->mstate == CURLM_STATE_CONNECT_PEND) { 2716 multistate(data, CURLM_STATE_CONNECT); 2717 /* Make sure that the handle will be processed soonish. */ 2718 Curl_expire(data, 1); 2719 } 2720 data = data->next; /* operate on next handle */ 2721 } 2722} 2723 2724#ifdef DEBUGBUILD 2725void Curl_multi_dump(const struct Curl_multi *multi_handle) 2726{ 2727 struct Curl_multi *multi=(struct Curl_multi *)multi_handle; 2728 struct SessionHandle *data; 2729 int i; 2730 fprintf(stderr, "* Multi status: %d handles, %d alive\n", 2731 multi->num_easy, multi->num_alive); 2732 for(data=multi->easyp; data; data = data->next) { 2733 if(data->mstate < CURLM_STATE_COMPLETED) { 2734 /* only display handles that are not completed */ 2735 fprintf(stderr, "handle %p, state %s, %d sockets\n", 2736 (void *)data, 2737 statename[data->mstate], data->numsocks); 2738 for(i=0; i < data->numsocks; i++) { 2739 curl_socket_t s = data->sockets[i]; 2740 struct Curl_sh_entry *entry = 2741 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); 2742 2743 fprintf(stderr, "%d ", (int)s); 2744 if(!entry) { 2745 fprintf(stderr, "INTERNAL CONFUSION\n"); 2746 continue; 2747 } 2748 fprintf(stderr, "[%s %s] ", 2749 entry->action&CURL_POLL_IN?"RECVING":"", 2750 entry->action&CURL_POLL_OUT?"SENDING":""); 2751 } 2752 if(data->numsocks) 2753 fprintf(stderr, "\n"); 2754 } 2755 } 2756} 2757#endif 2758