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