1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #include <curl/curl.h>
39 #include "speedcheck.h"
40 #include "conncache.h"
42 #include "multihandle.h"
46 #define _MPRINTF_REPLACE /* use our functions only */
47 #include <curl/mprintf.h>
49 #include "curl_memory.h"
50 /* The last #include file should be: */
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.
58 #ifndef CURL_SOCKET_HASH_TABLE_SIZE
59 #define CURL_SOCKET_HASH_TABLE_SIZE 911
62 #define CURL_CONNECTION_HASH_SIZE 97
64 #define CURL_MULTI_HANDLE 0x000bab1e
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))
71 static void singlesocket(struct Curl_multi *multi,
72 struct SessionHandle *data);
73 static int update_timer(struct Curl_multi *multi);
75 static bool isHandleAtHead(struct SessionHandle *handle,
76 struct curl_llist *pipeline);
77 static CURLMcode add_next_timeout(struct timeval now,
78 struct Curl_multi *multi,
79 struct SessionHandle *d);
80 static CURLMcode multi_timeout(struct Curl_multi *multi,
84 static const char * const statename[]={
106 static void multi_freetimeout(void *a, void *b);
108 /* always use this function to change state, to make debugging easier */
109 static void mstate(struct SessionHandle *data, CURLMstate state
116 long connection_id = -5000;
118 CURLMstate oldstate = data->mstate;
120 if(oldstate == state)
121 /* don't bother when the new state is the same as the old state */
124 data->mstate = state;
127 if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
128 data->mstate < CURLM_STATE_COMPLETED) {
130 connection_id = data->easy_conn->connection_id;
133 "STATE: %s => %s handle %p; line %d (connection #%ld) \n",
134 statename[oldstate], statename[data->mstate],
135 (void *)data, lineno, connection_id);
138 if(state == CURLM_STATE_COMPLETED)
139 /* changing to COMPLETED means there's one less easy handle 'alive' */
140 data->multi->num_alive--;
144 #define multistate(x,y) mstate(x,y)
146 #define multistate(x,y) mstate(x,y, __LINE__)
150 * We add one of these structs to the sockhash for a particular socket
153 struct Curl_sh_entry {
154 struct SessionHandle *easy;
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() */
160 /* bits for 'action' having no bits means this socket is not expecting any
165 /* make sure this socket is present in the hash for this handle */
166 static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
168 struct SessionHandle *data)
170 struct Curl_sh_entry *there =
171 Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
172 struct Curl_sh_entry *check;
175 /* it is present, return fine */
178 /* not present, add it */
179 check = calloc(1, sizeof(struct Curl_sh_entry));
181 return NULL; /* major failure */
185 /* make/add new hash entry */
186 if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
188 return NULL; /* major failure */
191 return check; /* things are good in sockhash land */
195 /* delete the given socket + handle from the hash */
196 static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
198 struct Curl_sh_entry *there =
199 Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
202 /* this socket is in the hash */
203 /* We remove the hash entry. (This'll end up in a call to
205 Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
210 * free a sockhash entry
212 static void sh_freeentry(void *freethis)
214 struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
220 static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
222 (void) k1_len; (void) k2_len;
224 return (*((int *) k1)) == (*((int *) k2));
227 static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
229 int fd = *((int *) key);
232 return (fd % (int)slots_num);
236 * sh_init() creates a new socket hash and returns the handle for it.
238 * Quote from README.multi_socket:
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
253 static struct curl_hash *sh_init(int hashsize)
255 return Curl_hash_alloc(hashsize, hash_fd, fd_key_compare,
262 * Called when a transfer is completed. Adds the given msg pointer to
263 * the list kept in the multi handle.
265 static CURLMcode multi_addmsg(struct Curl_multi *multi,
266 struct Curl_message *msg)
268 if(!Curl_llist_insert_next(multi->msglist, multi->msglist->tail, msg))
269 return CURLM_OUT_OF_MEMORY;
277 * Callback used by the llist system when a single list entry is destroyed.
279 static void multi_freeamsg(void *a, void *b)
285 struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
286 int chashsize) /* connection hash */
288 struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
293 multi->type = CURL_MULTI_HANDLE;
295 multi->hostcache = Curl_mk_dnscache();
296 if(!multi->hostcache)
299 multi->sockhash = sh_init(hashsize);
303 multi->conn_cache = Curl_conncache_init(chashsize);
304 if(!multi->conn_cache)
307 multi->msglist = Curl_llist_alloc(multi_freeamsg);
311 /* allocate a new easy handle to use when closing cached connections */
312 multi->closure_handle = curl_easy_init();
313 if(!multi->closure_handle)
316 multi->closure_handle->multi = multi;
317 multi->closure_handle->state.conn_cache = multi->conn_cache;
319 multi->max_pipeline_length = 5;
320 return (CURLM *) multi;
324 Curl_hash_destroy(multi->sockhash);
325 multi->sockhash = NULL;
326 Curl_hash_destroy(multi->hostcache);
327 multi->hostcache = NULL;
328 Curl_conncache_destroy(multi->conn_cache);
329 multi->conn_cache = NULL;
330 Curl_close(multi->closure_handle);
331 multi->closure_handle = NULL;
337 CURLM *curl_multi_init(void)
339 return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
340 CURL_CONNECTION_HASH_SIZE);
343 CURLMcode curl_multi_add_handle(CURLM *multi_handle,
346 struct curl_llist *timeoutlist;
347 struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
348 struct SessionHandle *data = (struct SessionHandle *)easy_handle;
350 /* First, make some basic checks that the CURLM handle is a good handle */
351 if(!GOOD_MULTI_HANDLE(multi))
352 return CURLM_BAD_HANDLE;
354 /* Verify that we got a somewhat good easy handle too */
355 if(!GOOD_EASY_HANDLE(easy_handle))
356 return CURLM_BAD_EASY_HANDLE;
358 /* Prevent users from adding same easy handle more than once and prevent
359 adding to more than one multi stack */
361 return CURLM_ADDED_ALREADY;
363 /* Allocate and initialize timeout list for easy handle */
364 timeoutlist = Curl_llist_alloc(multi_freetimeout);
366 return CURLM_OUT_OF_MEMORY;
369 * No failure allowed in this function beyond this point. And no
370 * modification of easy nor multi handle allowed before this except for
371 * potential multi's connection cache growing which won't be undone in this
372 * function no matter what.
375 /* Make easy handle use timeout list initialized above */
376 data->state.timeoutlist = timeoutlist;
379 /* set the easy handle */
380 multistate(data, CURLM_STATE_INIT);
382 if((data->set.global_dns_cache) &&
383 (data->dns.hostcachetype != HCACHE_GLOBAL)) {
384 /* global dns cache was requested but still isn't */
385 struct curl_hash *global = Curl_global_host_cache_init();
387 /* only do this if the global cache init works */
388 data->dns.hostcache = global;
389 data->dns.hostcachetype = HCACHE_GLOBAL;
392 /* for multi interface connections, we share DNS cache automatically if the
393 easy handle's one is currently not set. */
394 else if(!data->dns.hostcache ||
395 (data->dns.hostcachetype == HCACHE_NONE)) {
396 data->dns.hostcache = multi->hostcache;
397 data->dns.hostcachetype = HCACHE_MULTI;
400 /* Point to the multi's connection cache */
401 data->state.conn_cache = multi->conn_cache;
403 /* This adds the new entry at the 'end' of the doubly-linked circular
404 list of SessionHandle structs to try and maintain a FIFO queue so
405 the pipelined requests are in order. */
407 /* We add this new entry last in the list. */
409 data->next = NULL; /* end of the line */
411 struct SessionHandle *last = multi->easylp;
414 multi->easylp = data; /* the new last node */
417 /* first node, make both prev and next be NULL! */
420 multi->easylp = multi->easyp = data; /* both first and last */
423 /* make the SessionHandle refer back to this multi handle */
424 data->multi = multi_handle;
426 /* Set the timeout for this handle to expire really soon so that it will
427 be taken care of even when this handle is added in the midst of operation
428 when only the curl_multi_socket() API is used. During that flow, only
429 sockets that time-out or have actions will be dealt with. Since this
430 handle has no action yet, we make sure it times out to get things to
432 Curl_expire(data, 1);
434 /* increase the node-counter */
437 /* increase the alive-counter */
440 /* A somewhat crude work-around for a little glitch in update_timer() that
441 happens if the lastcall time is set to the same time when the handle is
442 removed as when the next handle is added, as then the check in
443 update_timer() that prevents calling the application multiple times with
444 the same timer infor will not trigger and then the new handle's timeout
445 will not be notified to the app.
447 The work-around is thus simply to clear the 'lastcall' variable to force
448 update_timer() to always trigger a callback to the app when a new easy
450 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
457 /* Debug-function, used like this:
459 * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
461 * Enable the hash print function first by editing hash.c
463 static void debug_print_sock_hash(void *p)
465 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
467 fprintf(stderr, " [easy %p/magic %x/socket %d]",
468 (void *)sh->data, sh->data->magic, (int)sh->socket);
472 CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
475 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
476 struct SessionHandle *easy = curl_handle;
477 struct SessionHandle *data = easy;
479 /* First, make some basic checks that the CURLM handle is a good handle */
480 if(!GOOD_MULTI_HANDLE(multi))
481 return CURLM_BAD_HANDLE;
483 /* Verify that we got a somewhat good easy handle too */
484 if(!GOOD_EASY_HANDLE(curl_handle))
485 return CURLM_BAD_EASY_HANDLE;
487 /* Prevent users from trying to remove same easy handle more than once */
489 return CURLM_OK; /* it is already removed so let's say it is fine! */
492 bool premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
493 bool easy_owns_conn = (data->easy_conn &&
494 (data->easy_conn->data == easy)) ?
497 /* If the 'state' is not INIT or COMPLETED, we might need to do something
498 nice to put the easy_handle in a good known state when this returns. */
500 /* this handle is "alive" so we need to count down the total number of
501 alive connections when this is removed */
504 if(data->easy_conn &&
505 (data->easy_conn->send_pipe->size +
506 data->easy_conn->recv_pipe->size > 1) &&
507 data->mstate > CURLM_STATE_WAITDO &&
508 data->mstate < CURLM_STATE_COMPLETED) {
509 /* If the handle is in a pipeline and has started sending off its
510 request but not received its response yet, we need to close
512 data->easy_conn->bits.close = TRUE;
513 /* Set connection owner so that Curl_done() closes it.
514 We can sefely do this here since connection is killed. */
515 data->easy_conn->data = easy;
518 /* The timer must be shut down before data->multi is set to NULL,
519 else the timenode will remain in the splay tree after
520 curl_easy_cleanup is called. */
521 Curl_expire(data, 0);
523 /* destroy the timeout list that is held in the easy handle */
524 if(data->state.timeoutlist) {
525 Curl_llist_destroy(data->state.timeoutlist, NULL);
526 data->state.timeoutlist = NULL;
529 if(data->dns.hostcachetype == HCACHE_MULTI) {
530 /* stop using the multi handle's DNS cache */
531 data->dns.hostcache = NULL;
532 data->dns.hostcachetype = HCACHE_NONE;
535 if(data->easy_conn) {
537 /* we must call Curl_done() here (if we still "own it") so that we don't
538 leave a half-baked one around */
541 /* Curl_done() clears the conn->data field to lose the association
542 between the easy handle and the connection
544 Note that this ignores the return code simply because there's
545 nothing really useful to do with it anyway! */
546 (void)Curl_done(&data->easy_conn, data->result, premature);
549 /* Clear connection pipelines, if Curl_done above was not called */
550 Curl_getoff_all_pipelines(data, data->easy_conn);
553 /* as this was using a shared connection cache we clear the pointer
554 to that since we're not part of that multi handle anymore */
555 data->state.conn_cache = NULL;
557 /* change state without using multistate(), only to make singlesocket() do
559 data->mstate = CURLM_STATE_COMPLETED;
560 singlesocket(multi, easy); /* to let the application know what sockets
561 that vanish with this handle */
563 /* Remove the association between the connection and the handle */
564 if(data->easy_conn) {
565 data->easy_conn->data = NULL;
566 data->easy_conn = NULL;
569 data->multi = NULL; /* clear the association to this multi handle */
572 /* make sure there's no pending message in the queue sent from this easy
574 struct curl_llist_element *e;
576 for(e = multi->msglist->head; e; e = e->next) {
577 struct Curl_message *msg = e->ptr;
579 if(msg->extmsg.easy_handle == easy) {
580 Curl_llist_remove(multi->msglist, e, NULL);
581 /* there can only be one from this specific handle */
587 /* make the previous node point to our next */
589 data->prev->next = data->next;
591 multi->easyp = data->next; /* point to first node */
593 /* make our next point to our previous node */
595 data->next->prev = data->prev;
597 multi->easylp = data->prev; /* point to last node */
600 We do not touch the easy handle here! */
602 multi->num_easy--; /* one less to care about now */
608 return CURLM_BAD_EASY_HANDLE; /* twasn't found */
611 bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi)
613 return (multi && multi->pipelining_enabled) ? TRUE : FALSE;
616 void Curl_multi_handlePipeBreak(struct SessionHandle *data)
618 data->easy_conn = NULL;
621 static int waitconnect_getsock(struct connectdata *conn,
630 return GETSOCK_BLANK;
633 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
634 sock[s] = conn->tempsock[i];
635 rc |= GETSOCK_WRITESOCK(s++);
639 /* when we've sent a CONNECT to a proxy, we should rather wait for the
640 socket to become readable to be able to get the response headers */
641 if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) {
642 sock[0] = conn->sock[FIRSTSOCKET];
643 rc = GETSOCK_READSOCK(0);
649 static int domore_getsock(struct connectdata *conn,
650 curl_socket_t *socks,
653 if(conn && conn->handler->domore_getsock)
654 return conn->handler->domore_getsock(conn, socks, numsocks);
655 return GETSOCK_BLANK;
658 /* returns bitmapped flags for this handle and its sockets */
659 static int multi_getsock(struct SessionHandle *data,
660 curl_socket_t *socks, /* points to numsocks number
664 /* If the pipe broke, or if there's no connection left for this easy handle,
665 then we MUST bail out now with no bitmask set. The no connection case can
666 happen when this is called from curl_multi_remove_handle() =>
667 singlesocket() => multi_getsock().
669 if(data->state.pipe_broke || !data->easy_conn)
672 if(data->mstate > CURLM_STATE_CONNECT &&
673 data->mstate < CURLM_STATE_COMPLETED) {
674 /* Set up ownership correctly */
675 data->easy_conn->data = data;
678 switch(data->mstate) {
680 #if 0 /* switch back on these cases to get the compiler to check for all enums
682 case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
683 case CURLM_STATE_COMPLETED:
684 case CURLM_STATE_MSGSENT:
685 case CURLM_STATE_INIT:
686 case CURLM_STATE_CONNECT:
687 case CURLM_STATE_WAITDO:
688 case CURLM_STATE_DONE:
689 case CURLM_STATE_LAST:
690 /* this will get called with CURLM_STATE_COMPLETED when a handle is
695 case CURLM_STATE_WAITRESOLVE:
696 return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
698 case CURLM_STATE_PROTOCONNECT:
699 return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
702 case CURLM_STATE_DOING:
703 return Curl_doing_getsock(data->easy_conn, socks, numsocks);
705 case CURLM_STATE_WAITPROXYCONNECT:
706 case CURLM_STATE_WAITCONNECT:
707 return waitconnect_getsock(data->easy_conn, socks, numsocks);
709 case CURLM_STATE_DO_MORE:
710 return domore_getsock(data->easy_conn, socks, numsocks);
712 case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
713 to waiting for the same as the *PERFORM
715 case CURLM_STATE_PERFORM:
716 case CURLM_STATE_WAITPERFORM:
717 return Curl_single_getsock(data->easy_conn, socks, numsocks);
722 CURLMcode curl_multi_fdset(CURLM *multi_handle,
723 fd_set *read_fd_set, fd_set *write_fd_set,
724 fd_set *exc_fd_set, int *max_fd)
726 /* Scan through all the easy handles to get the file descriptors set.
727 Some easy handles may not have connected to the remote host yet,
728 and then we must make sure that is done. */
729 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
730 struct SessionHandle *data;
732 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
735 (void)exc_fd_set; /* not used */
737 if(!GOOD_MULTI_HANDLE(multi))
738 return CURLM_BAD_HANDLE;
742 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
744 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
745 curl_socket_t s = CURL_SOCKET_BAD;
747 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
748 FD_SET(sockbunch[i], read_fd_set);
751 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
752 FD_SET(sockbunch[i], write_fd_set);
755 if(s == CURL_SOCKET_BAD)
756 /* this socket is unused, break out of loop */
759 if((int)s > this_max_fd)
760 this_max_fd = (int)s;
764 data = data->next; /* check next handle */
767 *max_fd = this_max_fd;
772 CURLMcode curl_multi_wait(CURLM *multi_handle,
773 struct curl_waitfd extra_fds[],
774 unsigned int extra_nfds,
778 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
779 struct SessionHandle *data;
780 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
783 unsigned int nfds = 0;
784 unsigned int curlfds;
785 struct pollfd *ufds = NULL;
786 long timeout_internal;
788 if(!GOOD_MULTI_HANDLE(multi))
789 return CURLM_BAD_HANDLE;
791 /* If the internally desired timeout is actually shorter than requested from
792 the outside, then use the shorter time! But only if the internal timer
793 is actually larger than -1! */
794 (void)multi_timeout(multi, &timeout_internal);
795 if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
796 timeout_ms = (int)timeout_internal;
798 /* Count up how many fds we have from the multi handle */
801 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
803 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
804 curl_socket_t s = CURL_SOCKET_BAD;
806 if(bitmap & GETSOCK_READSOCK(i)) {
810 if(bitmap & GETSOCK_WRITESOCK(i)) {
814 if(s == CURL_SOCKET_BAD) {
819 data = data->next; /* check next handle */
822 curlfds = nfds; /* number of internal file descriptors */
823 nfds += extra_nfds; /* add the externally provided ones */
826 ufds = malloc(nfds * sizeof(struct pollfd));
828 return CURLM_OUT_OF_MEMORY;
832 /* only do the second loop if we found descriptors in the first stage run
836 /* Add the curl handles to our pollfds first */
839 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
841 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
842 curl_socket_t s = CURL_SOCKET_BAD;
844 if(bitmap & GETSOCK_READSOCK(i)) {
845 ufds[nfds].fd = sockbunch[i];
846 ufds[nfds].events = POLLIN;
850 if(bitmap & GETSOCK_WRITESOCK(i)) {
851 ufds[nfds].fd = sockbunch[i];
852 ufds[nfds].events = POLLOUT;
856 if(s == CURL_SOCKET_BAD) {
861 data = data->next; /* check next handle */
865 /* Add external file descriptions from poll-like struct curl_waitfd */
866 for(i = 0; i < extra_nfds; i++) {
867 ufds[nfds].fd = extra_fds[i].fd;
868 ufds[nfds].events = 0;
869 if(extra_fds[i].events & CURL_WAIT_POLLIN)
870 ufds[nfds].events |= POLLIN;
871 if(extra_fds[i].events & CURL_WAIT_POLLPRI)
872 ufds[nfds].events |= POLLPRI;
873 if(extra_fds[i].events & CURL_WAIT_POLLOUT)
874 ufds[nfds].events |= POLLOUT;
880 infof(data, "Curl_poll(%d ds, %d ms)\n", nfds, timeout_ms);
881 i = Curl_poll(ufds, nfds, timeout_ms);
885 /* copy revents results from the poll to the curl_multi_wait poll
886 struct, the bit values of the actual underlying poll() implementation
887 may not be the same as the ones in the public libcurl API! */
888 for(j = 0; j < extra_nfds; j++) {
889 unsigned short mask = 0;
890 unsigned r = ufds[curlfds + j].revents;
893 mask |= CURL_WAIT_POLLIN;
895 mask |= CURL_WAIT_POLLOUT;
897 mask |= CURL_WAIT_POLLPRI;
899 extra_fds[j].revents = mask;
912 static CURLMcode multi_runsingle(struct Curl_multi *multi,
914 struct SessionHandle *data)
916 struct Curl_message *msg = NULL;
919 bool protocol_connect = FALSE;
920 bool dophase_done = FALSE;
922 CURLMcode result = CURLM_OK;
923 struct SingleRequest *k;
927 if(!GOOD_EASY_HANDLE(data))
928 return CURLM_BAD_EASY_HANDLE;
931 /* this is a single-iteration do-while loop just to allow a
932 break to skip to the end of it */
933 bool disconnect_conn = FALSE;
935 /* Handle the case when the pipe breaks, i.e., the connection
936 we're using gets cleaned up and we're left with nothing. */
937 if(data->state.pipe_broke) {
938 infof(data, "Pipe broke: handle 0x%p, url = %s\n",
939 (void *)data, data->state.path);
941 if(data->mstate < CURLM_STATE_COMPLETED) {
942 /* Head back to the CONNECT state */
943 multistate(data, CURLM_STATE_CONNECT);
944 result = CURLM_CALL_MULTI_PERFORM;
945 data->result = CURLE_OK;
948 data->state.pipe_broke = FALSE;
949 data->easy_conn = NULL;
953 if(!data->easy_conn &&
954 data->mstate > CURLM_STATE_CONNECT &&
955 data->mstate < CURLM_STATE_DONE) {
956 /* In all these states, the code will blindly access 'data->easy_conn'
957 so this is precaution that it isn't NULL. And it silences static
959 failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate);
960 return CURLM_INTERNAL_ERROR;
963 if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
964 data->mstate < CURLM_STATE_COMPLETED)
965 /* Make sure we set the connection's current owner */
966 data->easy_conn->data = data;
968 if(data->easy_conn &&
969 (data->mstate >= CURLM_STATE_CONNECT) &&
970 (data->mstate < CURLM_STATE_COMPLETED)) {
971 /* we need to wait for the connect state as only then is the start time
972 stored, but we must not check already completed handles */
974 timeout_ms = Curl_timeleft(data, &now,
975 (data->mstate <= CURLM_STATE_WAITDO)?
979 /* Handle timed out */
980 if(data->mstate == CURLM_STATE_WAITRESOLVE)
981 failf(data, "Resolving timed out after %ld milliseconds",
982 Curl_tvdiff(now, data->progress.t_startsingle));
983 else if(data->mstate == CURLM_STATE_WAITCONNECT)
984 failf(data, "Connection timed out after %ld milliseconds",
985 Curl_tvdiff(now, data->progress.t_startsingle));
988 failf(data, "Operation timed out after %ld milliseconds with %"
989 CURL_FORMAT_CURL_OFF_T " out of %"
990 CURL_FORMAT_CURL_OFF_T " bytes received",
991 Curl_tvdiff(now, data->progress.t_startsingle), k->bytecount,
995 /* Force the connection closed because the server could continue to
996 send us stuff at any time. (The disconnect_conn logic used below
997 doesn't work at this point). */
998 data->easy_conn->bits.close = TRUE;
999 data->result = CURLE_OPERATION_TIMEDOUT;
1000 multistate(data, CURLM_STATE_COMPLETED);
1005 switch(data->mstate) {
1006 case CURLM_STATE_INIT:
1007 /* init this transfer. */
1008 data->result=Curl_pretransfer(data);
1010 if(CURLE_OK == data->result) {
1011 /* after init, go CONNECT */
1012 multistate(data, CURLM_STATE_CONNECT);
1013 result = CURLM_CALL_MULTI_PERFORM;
1017 case CURLM_STATE_CONNECT_PEND:
1018 /* We will stay here until there is a connection available. Then
1019 we try again in the CURLM_STATE_CONNECT state. */
1022 case CURLM_STATE_CONNECT:
1023 /* Connect. We want to get a connection identifier filled in. */
1024 Curl_pgrsTime(data, TIMER_STARTSINGLE);
1025 data->result = Curl_connect(data, &data->easy_conn,
1026 &async, &protocol_connect);
1027 if(CURLE_NO_CONNECTION_AVAILABLE == data->result) {
1028 /* There was no connection available. We will go to the pending
1029 state and wait for an available connection. */
1030 multistate(data, CURLM_STATE_CONNECT_PEND);
1031 data->result = CURLE_OK;
1035 if(CURLE_OK == data->result) {
1036 /* Add this handle to the send or pend pipeline */
1037 data->result = Curl_add_handle_to_pipeline(data, data->easy_conn);
1038 if(CURLE_OK != data->result)
1039 disconnect_conn = TRUE;
1042 /* We're now waiting for an asynchronous name lookup */
1043 multistate(data, CURLM_STATE_WAITRESOLVE);
1045 /* after the connect has been sent off, go WAITCONNECT unless the
1046 protocol connect is already done and we can go directly to
1048 result = CURLM_CALL_MULTI_PERFORM;
1050 if(protocol_connect)
1051 multistate(data, multi->pipelining_enabled?
1052 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1054 #ifndef CURL_DISABLE_HTTP
1055 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1056 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
1059 multistate(data, CURLM_STATE_WAITCONNECT);
1066 case CURLM_STATE_WAITRESOLVE:
1067 /* awaiting an asynch name resolve to complete */
1069 struct Curl_dns_entry *dns = NULL;
1071 /* check if we have the name resolved by now */
1072 data->result = Curl_resolver_is_resolved(data->easy_conn, &dns);
1074 /* Update sockets here, because the socket(s) may have been
1075 closed and the application thus needs to be told, even if it
1076 is likely that the same socket(s) will again be used further
1077 down. If the name has not yet been resolved, it is likely
1078 that new sockets have been opened in an attempt to contact
1079 another resolver. */
1080 singlesocket(multi, data);
1083 /* Perform the next step in the connection phase, and then move on
1084 to the WAITCONNECT state */
1085 data->result = Curl_async_resolved(data->easy_conn,
1088 if(CURLE_OK != data->result)
1089 /* if Curl_async_resolved() returns failure, the connection struct
1090 is already freed and gone */
1091 data->easy_conn = NULL; /* no more connection */
1093 /* call again please so that we get the next socket setup */
1094 result = CURLM_CALL_MULTI_PERFORM;
1095 if(protocol_connect)
1096 multistate(data, multi->pipelining_enabled?
1097 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1099 #ifndef CURL_DISABLE_HTTP
1100 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1101 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
1104 multistate(data, CURLM_STATE_WAITCONNECT);
1109 if(CURLE_OK != data->result) {
1110 /* failure detected */
1111 disconnect_conn = TRUE;
1117 #ifndef CURL_DISABLE_HTTP
1118 case CURLM_STATE_WAITPROXYCONNECT:
1119 /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
1120 data->result = Curl_http_connect(data->easy_conn, &protocol_connect);
1122 if(data->easy_conn->bits.proxy_connect_closed) {
1123 /* reset the error buffer */
1124 if(data->set.errorbuffer)
1125 data->set.errorbuffer[0] = '\0';
1126 data->state.errorbuf = FALSE;
1128 data->result = CURLE_OK;
1129 result = CURLM_CALL_MULTI_PERFORM;
1130 multistate(data, CURLM_STATE_CONNECT);
1132 else if(CURLE_OK == data->result) {
1133 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
1134 multistate(data, CURLM_STATE_WAITCONNECT);
1139 case CURLM_STATE_WAITCONNECT:
1140 /* awaiting a completion of an asynch connect */
1141 data->result = Curl_is_connected(data->easy_conn,
1147 /* if everything is still fine we do the protocol-specific connect
1149 data->result = Curl_protocol_connect(data->easy_conn,
1153 if(CURLE_OK != data->result) {
1154 /* failure detected */
1155 /* Just break, the cleaning up is handled all in one place */
1156 disconnect_conn = TRUE;
1161 if(!protocol_connect) {
1162 /* We have a TCP connection, but 'protocol_connect' may be false
1163 and then we continue to 'STATE_PROTOCONNECT'. If protocol
1164 connect is TRUE, we move on to STATE_DO.
1165 BUT if we are using a proxy we must change to WAITPROXYCONNECT
1167 #ifndef CURL_DISABLE_HTTP
1168 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1169 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
1172 multistate(data, CURLM_STATE_PROTOCONNECT);
1176 /* after the connect has completed, go WAITDO or DO */
1177 multistate(data, multi->pipelining_enabled?
1178 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1180 result = CURLM_CALL_MULTI_PERFORM;
1184 case CURLM_STATE_PROTOCONNECT:
1185 /* protocol-specific connect phase */
1186 data->result = Curl_protocol_connecting(data->easy_conn,
1188 if((data->result == CURLE_OK) && protocol_connect) {
1189 /* after the connect has completed, go WAITDO or DO */
1190 multistate(data, multi->pipelining_enabled?
1191 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1192 result = CURLM_CALL_MULTI_PERFORM;
1194 else if(data->result) {
1195 /* failure detected */
1196 Curl_posttransfer(data);
1197 Curl_done(&data->easy_conn, data->result, TRUE);
1198 disconnect_conn = TRUE;
1202 case CURLM_STATE_WAITDO:
1203 /* Wait for our turn to DO when we're pipelining requests */
1205 infof(data, "WAITDO: Conn %ld send pipe %zu inuse %s athead %s\n",
1206 data->easy_conn->connection_id,
1207 data->easy_conn->send_pipe->size,
1208 data->easy_conn->writechannel_inuse?"TRUE":"FALSE",
1209 isHandleAtHead(data,
1210 data->easy_conn->send_pipe)?"TRUE":"FALSE");
1212 if(!data->easy_conn->writechannel_inuse &&
1213 isHandleAtHead(data,
1214 data->easy_conn->send_pipe)) {
1215 /* Grab the channel */
1216 data->easy_conn->writechannel_inuse = TRUE;
1217 multistate(data, CURLM_STATE_DO);
1218 result = CURLM_CALL_MULTI_PERFORM;
1222 case CURLM_STATE_DO:
1223 if(data->set.connect_only) {
1224 /* keep connection open for application to use the socket */
1225 data->easy_conn->bits.close = FALSE;
1226 multistate(data, CURLM_STATE_DONE);
1227 data->result = CURLE_OK;
1228 result = CURLM_CALL_MULTI_PERFORM;
1231 /* Perform the protocol's DO action */
1232 data->result = Curl_do(&data->easy_conn, &dophase_done);
1234 /* When Curl_do() returns failure, data->easy_conn might be NULL! */
1236 if(CURLE_OK == data->result) {
1238 /* some steps needed for wildcard matching */
1239 if(data->set.wildcardmatch) {
1240 struct WildcardData *wc = &data->wildcard;
1241 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
1242 /* skip some states if it is important */
1243 Curl_done(&data->easy_conn, CURLE_OK, FALSE);
1244 multistate(data, CURLM_STATE_DONE);
1245 result = CURLM_CALL_MULTI_PERFORM;
1249 /* DO was not completed in one function call, we must continue
1251 multistate(data, CURLM_STATE_DOING);
1255 /* after DO, go DO_DONE... or DO_MORE */
1256 else if(data->easy_conn->bits.do_more) {
1257 /* we're supposed to do more, but we need to sit down, relax
1258 and wait a little while first */
1259 multistate(data, CURLM_STATE_DO_MORE);
1263 /* we're done with the DO, now DO_DONE */
1264 multistate(data, CURLM_STATE_DO_DONE);
1265 result = CURLM_CALL_MULTI_PERFORM;
1268 else if((CURLE_SEND_ERROR == data->result) &&
1269 data->easy_conn->bits.reuse) {
1271 * In this situation, a connection that we were trying to use
1272 * may have unexpectedly died. If possible, send the connection
1273 * back to the CONNECT phase so we can try again.
1275 char *newurl = NULL;
1276 followtype follow=FOLLOW_NONE;
1280 drc = Curl_retry_request(data->easy_conn, &newurl);
1282 /* a failure here pretty much implies an out of memory */
1284 disconnect_conn = TRUE;
1287 retry = (newurl)?TRUE:FALSE;
1289 Curl_posttransfer(data);
1290 drc = Curl_done(&data->easy_conn, data->result, FALSE);
1292 /* When set to retry the connection, we must to go back to
1293 * the CONNECT state */
1295 if((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) {
1296 follow = FOLLOW_RETRY;
1297 drc = Curl_follow(data, newurl, follow);
1298 if(drc == CURLE_OK) {
1299 multistate(data, CURLM_STATE_CONNECT);
1300 result = CURLM_CALL_MULTI_PERFORM;
1301 data->result = CURLE_OK;
1310 /* done didn't return OK or SEND_ERROR */
1316 /* Have error handler disconnect conn if we can't retry */
1317 disconnect_conn = TRUE;
1321 /* failure detected */
1322 Curl_posttransfer(data);
1324 Curl_done(&data->easy_conn, data->result, FALSE);
1325 disconnect_conn = TRUE;
1330 case CURLM_STATE_DOING:
1331 /* we continue DOING until the DO phase is complete */
1332 data->result = Curl_protocol_doing(data->easy_conn,
1334 if(CURLE_OK == data->result) {
1336 /* after DO, go DO_DONE or DO_MORE */
1337 multistate(data, data->easy_conn->bits.do_more?
1338 CURLM_STATE_DO_MORE:
1339 CURLM_STATE_DO_DONE);
1340 result = CURLM_CALL_MULTI_PERFORM;
1341 } /* dophase_done */
1344 /* failure detected */
1345 Curl_posttransfer(data);
1346 Curl_done(&data->easy_conn, data->result, FALSE);
1347 disconnect_conn = TRUE;
1351 case CURLM_STATE_DO_MORE:
1353 * When we are connected, DO MORE and then go DO_DONE
1355 data->result = Curl_do_more(data->easy_conn, &control);
1357 /* No need to remove this handle from the send pipeline here since that
1358 is done in Curl_done() */
1359 if(CURLE_OK == data->result) {
1361 /* if positive, advance to DO_DONE
1362 if negative, go back to DOING */
1363 multistate(data, control==1?
1364 CURLM_STATE_DO_DONE:
1366 result = CURLM_CALL_MULTI_PERFORM;
1369 /* stay in DO_MORE */
1373 /* failure detected */
1374 Curl_posttransfer(data);
1375 Curl_done(&data->easy_conn, data->result, FALSE);
1376 disconnect_conn = TRUE;
1380 case CURLM_STATE_DO_DONE:
1381 /* Move ourselves from the send to recv pipeline */
1382 Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
1383 /* Check if we can move pending requests to send pipe */
1384 Curl_multi_process_pending_handles(multi);
1386 /* Only perform the transfer if there's a good socket to work with.
1387 Having both BAD is a signal to skip immediately to DONE */
1388 if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
1389 (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
1390 multistate(data, CURLM_STATE_WAITPERFORM);
1392 multistate(data, CURLM_STATE_DONE);
1393 result = CURLM_CALL_MULTI_PERFORM;
1396 case CURLM_STATE_WAITPERFORM:
1397 /* Wait for our turn to PERFORM */
1398 if(!data->easy_conn->readchannel_inuse &&
1399 isHandleAtHead(data,
1400 data->easy_conn->recv_pipe)) {
1401 /* Grab the channel */
1402 data->easy_conn->readchannel_inuse = TRUE;
1403 multistate(data, CURLM_STATE_PERFORM);
1404 result = CURLM_CALL_MULTI_PERFORM;
1408 infof(data, "WAITPERFORM: Conn %ld recv pipe %zu inuse %s athead %s\n",
1409 data->easy_conn->connection_id,
1410 data->easy_conn->recv_pipe->size,
1411 data->easy_conn->readchannel_inuse?"TRUE":"FALSE",
1412 isHandleAtHead(data,
1413 data->easy_conn->recv_pipe)?"TRUE":"FALSE");
1418 case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
1419 /* if both rates are within spec, resume transfer */
1420 if(Curl_pgrsUpdate(data->easy_conn))
1421 data->result = CURLE_ABORTED_BY_CALLBACK;
1423 data->result = Curl_speedcheck(data, now);
1425 if(( (data->set.max_send_speed == 0) ||
1426 (data->progress.ulspeed < data->set.max_send_speed )) &&
1427 ( (data->set.max_recv_speed == 0) ||
1428 (data->progress.dlspeed < data->set.max_recv_speed)))
1429 multistate(data, CURLM_STATE_PERFORM);
1432 case CURLM_STATE_PERFORM:
1434 char *newurl = NULL;
1437 /* check if over send speed */
1438 if((data->set.max_send_speed > 0) &&
1439 (data->progress.ulspeed > data->set.max_send_speed)) {
1442 multistate(data, CURLM_STATE_TOOFAST);
1444 /* calculate upload rate-limitation timeout. */
1445 buffersize = (int)(data->set.buffer_size ?
1446 data->set.buffer_size : BUFSIZE);
1447 timeout_ms = Curl_sleep_time(data->set.max_send_speed,
1448 data->progress.ulspeed, buffersize);
1449 Curl_expire(data, timeout_ms);
1453 /* check if over recv speed */
1454 if((data->set.max_recv_speed > 0) &&
1455 (data->progress.dlspeed > data->set.max_recv_speed)) {
1458 multistate(data, CURLM_STATE_TOOFAST);
1460 /* Calculate download rate-limitation timeout. */
1461 buffersize = (int)(data->set.buffer_size ?
1462 data->set.buffer_size : BUFSIZE);
1463 timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
1464 data->progress.dlspeed, buffersize);
1465 Curl_expire(data, timeout_ms);
1469 /* read/write data if it is ready to do so */
1470 data->result = Curl_readwrite(data->easy_conn, &done);
1474 if(!(k->keepon & KEEP_RECV)) {
1475 /* We're done receiving */
1476 data->easy_conn->readchannel_inuse = FALSE;
1479 if(!(k->keepon & KEEP_SEND)) {
1480 /* We're done sending */
1481 data->easy_conn->writechannel_inuse = FALSE;
1484 if(done || (data->result == CURLE_RECV_ERROR)) {
1485 /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
1486 * condition and the server closed the re-used connection exactly when
1487 * we wanted to use it, so figure out if that is indeed the case.
1489 CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
1491 retry = (newurl)?TRUE:FALSE;
1494 /* if we are to retry, set the result to OK and consider the
1496 data->result = CURLE_OK;
1503 * The transfer phase returned error, we mark the connection to get
1504 * closed to prevent being re-used. This is because we can't possibly
1505 * know if the connection is in a good shape or not now. Unless it is
1506 * a protocol which uses two "channels" like FTP, as then the error
1507 * happened in the data connection.
1510 if(!(data->easy_conn->handler->flags & PROTOPT_DUAL))
1511 data->easy_conn->bits.close = TRUE;
1513 Curl_posttransfer(data);
1514 Curl_done(&data->easy_conn, data->result, FALSE);
1517 followtype follow=FOLLOW_NONE;
1519 /* call this even if the readwrite function returned error */
1520 Curl_posttransfer(data);
1522 /* we're no longer receiving */
1523 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
1525 /* expire the new receiving pipeline head */
1526 if(data->easy_conn->recv_pipe->head)
1527 Curl_expire(data->easy_conn->recv_pipe->head->ptr, 1);
1529 /* Check if we can move pending requests to send pipe */
1530 Curl_multi_process_pending_handles(multi);
1532 /* When we follow redirects or is set to retry the connection, we must
1533 to go back to the CONNECT state */
1534 if(data->req.newurl || retry) {
1536 /* if the URL is a follow-location and not just a retried request
1537 then figure out the URL here */
1538 newurl = data->req.newurl;
1539 data->req.newurl = NULL;
1540 follow = FOLLOW_REDIR;
1543 follow = FOLLOW_RETRY;
1544 data->result = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
1545 if(CURLE_OK == data->result) {
1546 data->result = Curl_follow(data, newurl, follow);
1547 if(CURLE_OK == data->result) {
1548 multistate(data, CURLM_STATE_CONNECT);
1549 result = CURLM_CALL_MULTI_PERFORM;
1550 newurl = NULL; /* handed over the memory ownership to
1551 Curl_follow(), make sure we don't free() it
1557 /* after the transfer is done, go DONE */
1559 /* but first check to see if we got a location info even though we're
1560 not following redirects */
1561 if(data->req.location) {
1564 newurl = data->req.location;
1565 data->req.location = NULL;
1566 data->result = Curl_follow(data, newurl, FOLLOW_FAKE);
1567 if(CURLE_OK == data->result)
1568 newurl = NULL; /* allocation was handed over Curl_follow() */
1570 disconnect_conn = TRUE;
1573 multistate(data, CURLM_STATE_DONE);
1574 result = CURLM_CALL_MULTI_PERFORM;
1583 case CURLM_STATE_DONE:
1584 /* this state is highly transient, so run another loop after this */
1585 result = CURLM_CALL_MULTI_PERFORM;
1587 if(data->easy_conn) {
1590 /* Remove ourselves from the receive pipeline, if we are there. */
1591 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
1592 /* Check if we can move pending requests to send pipe */
1593 Curl_multi_process_pending_handles(multi);
1595 /* post-transfer command */
1596 res = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
1598 /* allow a previously set error code take precedence */
1603 * If there are other handles on the pipeline, Curl_done won't set
1604 * easy_conn to NULL. In such a case, curl_multi_remove_handle() can
1605 * access free'd data, if the connection is free'd and the handle
1606 * removed before we perform the processing in CURLM_STATE_COMPLETED
1609 data->easy_conn = NULL;
1612 if(data->set.wildcardmatch) {
1613 if(data->wildcard.state != CURLWC_DONE) {
1614 /* if a wildcard is set and we are not ending -> lets start again
1615 with CURLM_STATE_INIT */
1616 multistate(data, CURLM_STATE_INIT);
1621 /* after we have DONE what we're supposed to do, go COMPLETED, and
1622 it doesn't matter what the Curl_done() returned! */
1623 multistate(data, CURLM_STATE_COMPLETED);
1626 case CURLM_STATE_COMPLETED:
1627 /* this is a completed transfer, it is likely to still be connected */
1629 /* This node should be delinked from the list now and we should post
1630 an information message that we are complete. */
1632 /* Important: reset the conn pointer so that we don't point to memory
1633 that could be freed anytime */
1634 data->easy_conn = NULL;
1636 Curl_expire(data, 0); /* stop all timers */
1639 case CURLM_STATE_MSGSENT:
1640 return CURLM_OK; /* do nothing */
1643 return CURLM_INTERNAL_ERROR;
1646 if(data->mstate < CURLM_STATE_COMPLETED) {
1647 if(CURLE_OK != data->result) {
1649 * If an error was returned, and we aren't in completed state now,
1650 * then we go to completed and consider this transfer aborted.
1653 /* NOTE: no attempt to disconnect connections must be made
1654 in the case blocks above - cleanup happens only here */
1656 data->state.pipe_broke = FALSE;
1658 if(data->easy_conn) {
1659 /* if this has a connection, unsubscribe from the pipelines */
1660 data->easy_conn->writechannel_inuse = FALSE;
1661 data->easy_conn->readchannel_inuse = FALSE;
1662 Curl_removeHandleFromPipeline(data,
1663 data->easy_conn->send_pipe);
1664 Curl_removeHandleFromPipeline(data,
1665 data->easy_conn->recv_pipe);
1666 /* Check if we can move pending requests to send pipe */
1667 Curl_multi_process_pending_handles(multi);
1669 if(disconnect_conn) {
1670 /* disconnect properly */
1671 Curl_disconnect(data->easy_conn, /* dead_connection */ FALSE);
1673 /* This is where we make sure that the easy_conn pointer is reset.
1674 We don't have to do this in every case block above where a
1675 failure is detected */
1676 data->easy_conn = NULL;
1679 else if(data->mstate == CURLM_STATE_CONNECT) {
1680 /* Curl_connect() failed */
1681 (void)Curl_posttransfer(data);
1684 multistate(data, CURLM_STATE_COMPLETED);
1686 /* if there's still a connection to use, call the progress function */
1687 else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
1688 /* aborted due to progress callback return code must close the
1690 data->result = CURLE_ABORTED_BY_CALLBACK;
1691 data->easy_conn->bits.close = TRUE;
1693 /* if not yet in DONE state, go there, otherwise COMPLETED */
1694 multistate(data, (data->mstate < CURLM_STATE_DONE)?
1695 CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
1696 result = CURLM_CALL_MULTI_PERFORM;
1699 } WHILE_FALSE; /* just to break out from! */
1701 if(CURLM_STATE_COMPLETED == data->mstate) {
1702 /* now fill in the Curl_message with this info */
1705 msg->extmsg.msg = CURLMSG_DONE;
1706 msg->extmsg.easy_handle = data;
1707 msg->extmsg.data.result = data->result;
1709 result = multi_addmsg(multi, msg);
1711 multistate(data, CURLM_STATE_MSGSENT);
1718 CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
1720 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1721 struct SessionHandle *data;
1722 CURLMcode returncode=CURLM_OK;
1723 struct Curl_tree *t;
1724 struct timeval now = Curl_tvnow();
1726 if(!GOOD_MULTI_HANDLE(multi))
1727 return CURLM_BAD_HANDLE;
1732 struct WildcardData *wc = &data->wildcard;
1734 if(data->set.wildcardmatch) {
1736 CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */
1738 return CURLM_OUT_OF_MEMORY;
1743 result = multi_runsingle(multi, now, data);
1744 while(CURLM_CALL_MULTI_PERFORM == result);
1746 if(data->set.wildcardmatch) {
1747 /* destruct wildcard structures if it is needed */
1748 if(wc->state == CURLWC_DONE || result)
1749 Curl_wildcard_dtor(wc);
1753 returncode = result;
1755 data = data->next; /* operate on next handle */
1759 * Simply remove all expired timers from the splay since handles are dealt
1760 * with unconditionally by this function and curl_multi_timeout() requires
1761 * that already passed/handled expire times are removed from the splay.
1763 * It is important that the 'now' value is set at the entry of this function
1764 * and not for the current time as it may have ticked a little while since
1765 * then and then we risk this loop to remove timers that actually have not
1769 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
1771 /* the removed may have another timeout in queue */
1772 (void)add_next_timeout(now, multi, t->payload);
1776 *running_handles = multi->num_alive;
1778 if(CURLM_OK >= returncode)
1779 update_timer(multi);
1784 static void close_all_connections(struct Curl_multi *multi)
1786 struct connectdata *conn;
1788 conn = Curl_conncache_find_first_connection(multi->conn_cache);
1790 conn->data = multi->closure_handle;
1792 /* This will remove the connection from the cache */
1793 (void)Curl_disconnect(conn, FALSE);
1795 conn = Curl_conncache_find_first_connection(multi->conn_cache);
1799 CURLMcode curl_multi_cleanup(CURLM *multi_handle)
1801 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1802 struct SessionHandle *data;
1803 struct SessionHandle *nextdata;
1805 if(GOOD_MULTI_HANDLE(multi)) {
1806 bool restore_pipe = FALSE;
1807 SIGPIPE_VARIABLE(pipe_st);
1809 multi->type = 0; /* not good anymore */
1811 /* Close all the connections in the connection cache */
1812 close_all_connections(multi);
1814 if(multi->closure_handle) {
1815 sigpipe_ignore(multi->closure_handle, &pipe_st);
1816 restore_pipe = TRUE;
1818 multi->closure_handle->dns.hostcache = multi->hostcache;
1819 Curl_hostcache_clean(multi->closure_handle,
1820 multi->closure_handle->dns.hostcache);
1822 Curl_close(multi->closure_handle);
1823 multi->closure_handle = NULL;
1826 Curl_hash_destroy(multi->sockhash);
1827 multi->sockhash = NULL;
1829 Curl_conncache_destroy(multi->conn_cache);
1830 multi->conn_cache = NULL;
1832 /* remove the pending list of messages */
1833 Curl_llist_destroy(multi->msglist, NULL);
1834 multi->msglist = NULL;
1836 /* remove all easy handles */
1837 data = multi->easyp;
1839 nextdata=data->next;
1840 if(data->dns.hostcachetype == HCACHE_MULTI) {
1841 /* clear out the usage of the shared DNS cache */
1842 Curl_hostcache_clean(data, data->dns.hostcache);
1843 data->dns.hostcache = NULL;
1844 data->dns.hostcachetype = HCACHE_NONE;
1847 /* Clear the pointer to the connection cache */
1848 data->state.conn_cache = NULL;
1849 data->multi = NULL; /* clear the association */
1854 Curl_hash_destroy(multi->hostcache);
1855 multi->hostcache = NULL;
1857 /* Free the blacklists by setting them to NULL */
1858 Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
1859 Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
1863 sigpipe_restore(&pipe_st);
1868 return CURLM_BAD_HANDLE;
1872 * curl_multi_info_read()
1874 * This function is the primary way for a multi/multi_socket application to
1875 * figure out if a transfer has ended. We MUST make this function as fast as
1876 * possible as it will be polled frequently and we MUST NOT scan any lists in
1877 * here to figure out things. We must scale fine to thousands of handles and
1878 * beyond. The current design is fully O(1).
1881 CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
1883 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1884 struct Curl_message *msg;
1886 *msgs_in_queue = 0; /* default to none */
1888 if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) {
1889 /* there is one or more messages in the list */
1890 struct curl_llist_element *e;
1892 /* extract the head of the list to return */
1893 e = multi->msglist->head;
1897 /* remove the extracted entry */
1898 Curl_llist_remove(multi->msglist, e, NULL);
1900 *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist));
1902 return &msg->extmsg;
1909 * singlesocket() checks what sockets we deal with and their "action state"
1910 * and if we have a different state in any of those sockets from last time we
1911 * call the callback accordingly.
1913 static void singlesocket(struct Curl_multi *multi,
1914 struct SessionHandle *data)
1916 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
1918 struct Curl_sh_entry *entry;
1921 unsigned int curraction;
1922 bool remove_sock_from_hash;
1924 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
1925 socks[i] = CURL_SOCKET_BAD;
1927 /* Fill in the 'current' struct with the state as it is now: what sockets to
1928 supervise and for what actions */
1929 curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE);
1931 /* We have 0 .. N sockets already and we get to know about the 0 .. M
1932 sockets we should have from now on. Detect the differences, remove no
1933 longer supervised ones and add new ones */
1935 /* walk over the sockets we got right now */
1936 for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
1937 (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
1939 int action = CURL_POLL_NONE;
1943 /* get it from the hash */
1944 entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
1946 if(curraction & GETSOCK_READSOCK(i))
1947 action |= CURL_POLL_IN;
1948 if(curraction & GETSOCK_WRITESOCK(i))
1949 action |= CURL_POLL_OUT;
1952 /* yeps, already present so check if it has the same action set */
1953 if(entry->action == action)
1954 /* same, continue */
1958 /* this is a socket we didn't have before, add it! */
1959 entry = sh_addentry(multi->sockhash, s, data);
1965 /* we know (entry != NULL) at this point, see the logic above */
1966 if(multi->socket_cb)
1967 multi->socket_cb(data,
1970 multi->socket_userp,
1973 entry->action = action; /* store the current action state */
1976 num = i; /* number of sockets */
1978 /* when we've walked over all the sockets we should have right now, we must
1979 make sure to detect sockets that are removed */
1980 for(i=0; i< data->numsocks; i++) {
1982 s = data->sockets[i];
1983 for(j=0; j<num; j++) {
1985 /* this is still supervised */
1986 s = CURL_SOCKET_BAD;
1990 if(s != CURL_SOCKET_BAD) {
1992 /* this socket has been removed. Tell the app to remove it */
1993 remove_sock_from_hash = TRUE;
1995 entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
1997 /* check if the socket to be removed serves a connection which has
1998 other easy-s in a pipeline. In this case the socket should not be
2000 struct connectdata *easy_conn = data->easy_conn;
2002 if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
2003 /* the handle should not be removed from the pipe yet */
2004 remove_sock_from_hash = FALSE;
2006 /* Update the sockhash entry to instead point to the next in line
2007 for the recv_pipe, or the first (in case this particular easy
2009 if(entry->easy == data) {
2010 if(isHandleAtHead(data, easy_conn->recv_pipe))
2011 entry->easy = easy_conn->recv_pipe->head->next->ptr;
2013 entry->easy = easy_conn->recv_pipe->head->ptr;
2016 if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) {
2017 /* the handle should not be removed from the pipe yet */
2018 remove_sock_from_hash = FALSE;
2020 /* Update the sockhash entry to instead point to the next in line
2021 for the send_pipe, or the first (in case this particular easy
2023 if(entry->easy == data) {
2024 if(isHandleAtHead(data, easy_conn->send_pipe))
2025 entry->easy = easy_conn->send_pipe->head->next->ptr;
2027 entry->easy = easy_conn->send_pipe->head->ptr;
2030 /* Don't worry about overwriting recv_pipe head with send_pipe_head,
2031 when action will be asked on the socket (see multi_socket()), the
2032 head of the correct pipe will be taken according to the
2037 /* just a precaution, this socket really SHOULD be in the hash already
2038 but in case it isn't, we don't have to tell the app to remove it
2039 either since it never got to know about it */
2040 remove_sock_from_hash = FALSE;
2042 if(remove_sock_from_hash) {
2043 /* in this case 'entry' is always non-NULL */
2044 if(multi->socket_cb)
2045 multi->socket_cb(data,
2048 multi->socket_userp,
2050 sh_delentry(multi->sockhash, s);
2056 memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
2057 data->numsocks = num;
2061 * Curl_multi_closed()
2063 * Used by the connect code to tell the multi_socket code that one of the
2064 * sockets we were using have just been closed. This function will then
2065 * remove it from the sockethash for this handle to make the multi_socket API
2066 * behave properly, especially for the case when libcurl will create another
2067 * socket again and it gets the same file descriptor number.
2070 void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
2072 struct Curl_multi *multi = conn->data->multi;
2074 /* this is set if this connection is part of a handle that is added to
2075 a multi handle, and only then this is necessary */
2076 struct Curl_sh_entry *entry =
2077 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2080 if(multi->socket_cb)
2081 multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
2082 multi->socket_userp,
2085 /* now remove it from the socket hash */
2086 sh_delentry(multi->sockhash, s);
2094 * add_next_timeout()
2096 * Each SessionHandle has a list of timeouts. The add_next_timeout() is called
2097 * when it has just been removed from the splay tree because the timeout has
2098 * expired. This function is then to advance in the list to pick the next
2099 * timeout to use (skip the already expired ones) and add this node back to
2100 * the splay tree again.
2102 * The splay tree only has each sessionhandle as a single node and the nearest
2103 * timeout is used to sort it on.
2105 static CURLMcode add_next_timeout(struct timeval now,
2106 struct Curl_multi *multi,
2107 struct SessionHandle *d)
2109 struct timeval *tv = &d->state.expiretime;
2110 struct curl_llist *list = d->state.timeoutlist;
2111 struct curl_llist_element *e;
2113 /* move over the timeout list for this specific handle and remove all
2114 timeouts that are now passed tense and store the next pending
2116 for(e = list->head; e; ) {
2117 struct curl_llist_element *n = e->next;
2118 long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now);
2120 /* remove outdated entry */
2121 Curl_llist_remove(list, e, NULL);
2123 /* the list is sorted so get out on the first mismatch */
2129 /* clear the expire times within the handles that we remove from the
2135 /* copy the first entry to 'tv' */
2136 memcpy(tv, e->ptr, sizeof(*tv));
2138 /* remove first entry from list */
2139 Curl_llist_remove(list, e, NULL);
2141 /* insert this node again into the splay */
2142 multi->timetree = Curl_splayinsert(*tv, multi->timetree,
2143 &d->state.timenode);
2148 static CURLMcode multi_socket(struct Curl_multi *multi,
2152 int *running_handles)
2154 CURLMcode result = CURLM_OK;
2155 struct SessionHandle *data = NULL;
2156 struct Curl_tree *t;
2157 struct timeval now = Curl_tvnow();
2160 /* *perform() deals with running_handles on its own */
2161 result = curl_multi_perform(multi, running_handles);
2163 /* walk through each easy handle and do the socket state change magic
2167 singlesocket(multi, data);
2171 /* or should we fall-through and do the timer-based stuff? */
2174 else if(s != CURL_SOCKET_TIMEOUT) {
2176 struct Curl_sh_entry *entry =
2177 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2180 /* Unmatched socket, we can't act on it but we ignore this fact. In
2181 real-world tests it has been proved that libevent can in fact give
2182 the application actions even though the socket was just previously
2183 asked to get removed, so thus we better survive stray socket actions
2184 and just move on. */
2189 if(data->magic != CURLEASY_MAGIC_NUMBER)
2190 /* bad bad bad bad bad bad bad */
2191 return CURLM_INTERNAL_ERROR;
2193 /* If the pipeline is enabled, take the handle which is in the head of
2194 the pipeline. If we should write into the socket, take the send_pipe
2195 head. If we should read from the socket, take the recv_pipe head. */
2196 if(data->easy_conn) {
2197 if((ev_bitmask & CURL_POLL_OUT) &&
2198 data->easy_conn->send_pipe &&
2199 data->easy_conn->send_pipe->head)
2200 data = data->easy_conn->send_pipe->head->ptr;
2201 else if((ev_bitmask & CURL_POLL_IN) &&
2202 data->easy_conn->recv_pipe &&
2203 data->easy_conn->recv_pipe->head)
2204 data = data->easy_conn->recv_pipe->head->ptr;
2207 if(data->easy_conn &&
2208 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
2209 /* set socket event bitmask if they're not locked */
2210 data->easy_conn->cselect_bits = ev_bitmask;
2213 result = multi_runsingle(multi, now, data);
2214 while(CURLM_CALL_MULTI_PERFORM == result);
2216 if(data->easy_conn &&
2217 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
2218 /* clear the bitmask only if not locked */
2219 data->easy_conn->cselect_bits = 0;
2221 if(CURLM_OK >= result)
2222 /* get the socket(s) and check if the state has been changed since
2224 singlesocket(multi, data);
2226 /* Now we fall-through and do the timer-based stuff, since we don't want
2227 to force the user to have to deal with timeouts as long as at least
2228 one connection in fact has traffic. */
2230 data = NULL; /* set data to NULL again to avoid calling
2231 multi_runsingle() in case there's no need to */
2235 /* Compensate for bad precision timers that might've triggered too early.
2237 This precaution was added in commit 2c72732ebf3da5e as a result of bad
2238 resolution in the windows function use(d).
2240 The problematic case here is when using the multi_socket API and libcurl
2241 has told the application about a timeout, and that timeout is what fires
2242 off a bit early. As we don't have any IDs associated with the timeout we
2243 can't tell which timeout that fired off but we only have the times to use
2244 to check what to do. If it fires off too early, we don't run the correct
2245 actions and we don't tell the application again about the same timeout as
2246 was already first in the queue...
2248 Originally we made the timeouts run 40 milliseconds early on all systems,
2249 but now we have an #ifdef setup to provide a decent precaution inaccuracy
2253 now.tv_usec += MULTI_TIMEOUT_INACCURACY;
2254 if(now.tv_usec >= 1000000) {
2256 now.tv_usec -= 1000000;
2260 * The loop following here will go on as long as there are expire-times left
2261 * to process in the splay and 'data' will be re-assigned for every expired
2262 * handle we deal with.
2265 /* the first loop lap 'data' can be NULL */
2268 result = multi_runsingle(multi, now, data);
2269 while(CURLM_CALL_MULTI_PERFORM == result);
2271 if(CURLM_OK >= result)
2272 /* get the socket(s) and check if the state has been changed since
2274 singlesocket(multi, data);
2277 /* Check if there's one (more) expired timer to deal with! This function
2278 extracts a matching node if there is one */
2280 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
2282 data = t->payload; /* assign this for next loop */
2283 (void)add_next_timeout(now, multi, t->payload);
2288 *running_handles = multi->num_alive;
2292 #undef curl_multi_setopt
2293 CURLMcode curl_multi_setopt(CURLM *multi_handle,
2294 CURLMoption option, ...)
2296 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
2297 CURLMcode res = CURLM_OK;
2300 if(!GOOD_MULTI_HANDLE(multi))
2301 return CURLM_BAD_HANDLE;
2303 va_start(param, option);
2306 case CURLMOPT_SOCKETFUNCTION:
2307 multi->socket_cb = va_arg(param, curl_socket_callback);
2309 case CURLMOPT_SOCKETDATA:
2310 multi->socket_userp = va_arg(param, void *);
2312 case CURLMOPT_PIPELINING:
2313 multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
2315 case CURLMOPT_TIMERFUNCTION:
2316 multi->timer_cb = va_arg(param, curl_multi_timer_callback);
2318 case CURLMOPT_TIMERDATA:
2319 multi->timer_userp = va_arg(param, void *);
2321 case CURLMOPT_MAXCONNECTS:
2322 multi->maxconnects = va_arg(param, long);
2324 case CURLMOPT_MAX_HOST_CONNECTIONS:
2325 multi->max_host_connections = va_arg(param, long);
2327 case CURLMOPT_MAX_PIPELINE_LENGTH:
2328 multi->max_pipeline_length = va_arg(param, long);
2330 case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
2331 multi->content_length_penalty_size = va_arg(param, long);
2333 case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
2334 multi->chunk_length_penalty_size = va_arg(param, long);
2336 case CURLMOPT_PIPELINING_SITE_BL:
2337 res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
2338 &multi->pipelining_site_bl);
2340 case CURLMOPT_PIPELINING_SERVER_BL:
2341 res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
2342 &multi->pipelining_server_bl);
2344 case CURLMOPT_MAX_TOTAL_CONNECTIONS:
2345 multi->max_total_connections = va_arg(param, long);
2348 res = CURLM_UNKNOWN_OPTION;
2355 /* we define curl_multi_socket() in the public multi.h header */
2356 #undef curl_multi_socket
2358 CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
2359 int *running_handles)
2361 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
2362 0, running_handles);
2363 if(CURLM_OK >= result)
2364 update_timer((struct Curl_multi *)multi_handle);
2368 CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s,
2369 int ev_bitmask, int *running_handles)
2371 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
2372 ev_bitmask, running_handles);
2373 if(CURLM_OK >= result)
2374 update_timer((struct Curl_multi *)multi_handle);
2378 CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
2381 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
2382 TRUE, CURL_SOCKET_BAD, 0, running_handles);
2383 if(CURLM_OK >= result)
2384 update_timer((struct Curl_multi *)multi_handle);
2388 static CURLMcode multi_timeout(struct Curl_multi *multi,
2391 static struct timeval tv_zero = {0,0};
2393 if(multi->timetree) {
2394 /* we have a tree of expire times */
2395 struct timeval now = Curl_tvnow();
2397 /* splay the lowest to the bottom */
2398 multi->timetree = Curl_splay(tv_zero, multi->timetree);
2400 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
2401 /* some time left before expiration */
2402 *timeout_ms = curlx_tvdiff(multi->timetree->key, now);
2405 * Since we only provide millisecond resolution on the returned value
2406 * and the diff might be less than one millisecond here, we don't
2407 * return zero as that may cause short bursts of busyloops on fast
2408 * processors while the diff is still present but less than one
2409 * millisecond! instead we return 1 until the time is ripe.
2414 /* 0 means immediately */
2423 CURLMcode curl_multi_timeout(CURLM *multi_handle,
2426 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
2428 /* First, make some basic checks that the CURLM handle is a good handle */
2429 if(!GOOD_MULTI_HANDLE(multi))
2430 return CURLM_BAD_HANDLE;
2432 return multi_timeout(multi, timeout_ms);
2436 * Tell the application it should update its timers, if it subscribes to the
2437 * update timer callback.
2439 static int update_timer(struct Curl_multi *multi)
2443 if(!multi->timer_cb)
2445 if(multi_timeout(multi, &timeout_ms)) {
2448 if(timeout_ms < 0) {
2449 static const struct timeval none={0,0};
2450 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
2451 multi->timer_lastcall = none;
2452 /* there's no timeout now but there was one previously, tell the app to
2454 return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp);
2459 /* When multi_timeout() is done, multi->timetree points to the node with the
2460 * timeout we got the (relative) time-out time for. We can thus easily check
2461 * if this is the same (fixed) time as we got in a previous call and then
2462 * avoid calling the callback again. */
2463 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
2466 multi->timer_lastcall = multi->timetree->key;
2468 return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
2471 void Curl_multi_set_easy_connection(struct SessionHandle *handle,
2472 struct connectdata *conn)
2474 handle->easy_conn = conn;
2477 static bool isHandleAtHead(struct SessionHandle *handle,
2478 struct curl_llist *pipeline)
2480 struct curl_llist_element *curr = pipeline->head;
2482 return (curr->ptr == handle) ? TRUE : FALSE;
2488 * multi_freetimeout()
2490 * Callback used by the llist system when a single timeout list entry is
2493 static void multi_freetimeout(void *user, void *entryptr)
2497 /* the entry was plain malloc()'ed */
2502 * multi_addtimeout()
2504 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
2505 * of list is always the timeout nearest in time.
2509 multi_addtimeout(struct curl_llist *timeoutlist,
2510 struct timeval *stamp)
2512 struct curl_llist_element *e;
2513 struct timeval *timedup;
2514 struct curl_llist_element *prev = NULL;
2516 timedup = malloc(sizeof(*timedup));
2518 return CURLM_OUT_OF_MEMORY;
2520 /* copy the timestamp */
2521 memcpy(timedup, stamp, sizeof(*timedup));
2523 if(Curl_llist_count(timeoutlist)) {
2524 /* find the correct spot in the list */
2525 for(e = timeoutlist->head; e; e = e->next) {
2526 struct timeval *checktime = e->ptr;
2527 long diff = curlx_tvdiff(*checktime, *timedup);
2535 this is the first timeout on the list */
2537 if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) {
2539 return CURLM_OUT_OF_MEMORY;
2548 * given a number of milliseconds from now to use to set the 'act before
2549 * this'-time for the transfer, to be extracted by curl_multi_timeout()
2551 * Note that the timeout will be added to a queue of timeouts if it defines a
2552 * moment in time that is later than the current head of queue.
2554 * Pass zero to clear all timeout values for this handle.
2556 void Curl_expire(struct SessionHandle *data, long milli)
2558 struct Curl_multi *multi = data->multi;
2559 struct timeval *nowp = &data->state.expiretime;
2562 /* this is only interesting while there is still an associated multi struct
2568 /* No timeout, clear the time data. */
2569 if(nowp->tv_sec || nowp->tv_usec) {
2570 /* Since this is an cleared time, we must remove the previous entry from
2572 struct curl_llist *list = data->state.timeoutlist;
2574 rc = Curl_splayremovebyaddr(multi->timetree,
2575 &data->state.timenode,
2578 infof(data, "Internal error clearing splay node = %d\n", rc);
2580 /* flush the timeout list too */
2581 while(list->size > 0)
2582 Curl_llist_remove(list, list->tail, NULL);
2585 infof(data, "Expire cleared\n");
2595 set.tv_sec += milli/1000;
2596 set.tv_usec += (milli%1000)*1000;
2598 if(set.tv_usec >= 1000000) {
2600 set.tv_usec -= 1000000;
2603 if(nowp->tv_sec || nowp->tv_usec) {
2604 /* This means that the struct is added as a node in the splay tree.
2605 Compare if the new time is earlier, and only remove-old/add-new if it
2607 long diff = curlx_tvdiff(set, *nowp);
2609 /* the new expire time was later so just add it to the queue
2611 multi_addtimeout(data->state.timeoutlist, &set);
2615 /* the new time is newer than the presently set one, so add the current
2616 to the queue and update the head */
2617 multi_addtimeout(data->state.timeoutlist, nowp);
2619 /* Since this is an updated time, we must remove the previous entry from
2620 the splay tree first and then re-add the new value */
2621 rc = Curl_splayremovebyaddr(multi->timetree,
2622 &data->state.timenode,
2625 infof(data, "Internal error removing splay node = %d\n", rc);
2629 data->state.timenode.payload = data;
2630 multi->timetree = Curl_splayinsert(*nowp,
2632 &data->state.timenode);
2635 Curl_splayprint(multi->timetree, 0, TRUE);
2639 CURLMcode curl_multi_assign(CURLM *multi_handle,
2640 curl_socket_t s, void *hashp)
2642 struct Curl_sh_entry *there = NULL;
2643 struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
2645 if(s != CURL_SOCKET_BAD)
2646 there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t));
2649 return CURLM_BAD_SOCKET;
2651 there->socketp = hashp;
2656 size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
2658 return multi ? multi->max_host_connections : 0;
2661 size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
2663 return multi ? multi->max_total_connections : 0;
2666 size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi)
2668 return multi ? multi->max_pipeline_length : 0;
2671 curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
2673 return multi ? multi->content_length_penalty_size : 0;
2676 curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
2678 return multi ? multi->chunk_length_penalty_size : 0;
2681 struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
2683 return multi->pipelining_site_bl;
2686 struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
2688 return multi->pipelining_server_bl;
2691 void Curl_multi_process_pending_handles(struct Curl_multi *multi)
2693 struct SessionHandle *data;
2697 if(data->mstate == CURLM_STATE_CONNECT_PEND) {
2698 multistate(data, CURLM_STATE_CONNECT);
2699 /* Make sure that the handle will be processed soonish. */
2700 Curl_expire(data, 1);
2702 data = data->next; /* operate on next handle */
2707 void Curl_multi_dump(const struct Curl_multi *multi_handle)
2709 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
2710 struct SessionHandle *data;
2712 fprintf(stderr, "* Multi status: %d handles, %d alive\n",
2713 multi->num_easy, multi->num_alive);
2714 for(data=multi->easyp; data; data = data->next) {
2715 if(data->mstate < CURLM_STATE_COMPLETED) {
2716 /* only display handles that are not completed */
2717 fprintf(stderr, "handle %p, state %s, %d sockets\n",
2719 statename[data->mstate], data->numsocks);
2720 for(i=0; i < data->numsocks; i++) {
2721 curl_socket_t s = data->sockets[i];
2722 struct Curl_sh_entry *entry =
2723 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2725 fprintf(stderr, "%d ", (int)s);
2727 fprintf(stderr, "INTERNAL CONFUSION\n");
2730 fprintf(stderr, "[%s %s] ",
2731 entry->action&CURL_POLL_IN?"RECVING":"",
2732 entry->action&CURL_POLL_OUT?"SENDING":"");
2735 fprintf(stderr, "\n");