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;
332 Curl_llist_destroy(multi->msglist, NULL);
338 CURLM *curl_multi_init(void)
340 return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
341 CURL_CONNECTION_HASH_SIZE);
344 CURLMcode curl_multi_add_handle(CURLM *multi_handle,
347 struct curl_llist *timeoutlist;
348 struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
349 struct SessionHandle *data = (struct SessionHandle *)easy_handle;
351 /* First, make some basic checks that the CURLM handle is a good handle */
352 if(!GOOD_MULTI_HANDLE(multi))
353 return CURLM_BAD_HANDLE;
355 /* Verify that we got a somewhat good easy handle too */
356 if(!GOOD_EASY_HANDLE(easy_handle))
357 return CURLM_BAD_EASY_HANDLE;
359 /* Prevent users from adding same easy handle more than once and prevent
360 adding to more than one multi stack */
362 return CURLM_ADDED_ALREADY;
364 /* Allocate and initialize timeout list for easy handle */
365 timeoutlist = Curl_llist_alloc(multi_freetimeout);
367 return CURLM_OUT_OF_MEMORY;
370 * No failure allowed in this function beyond this point. And no
371 * modification of easy nor multi handle allowed before this except for
372 * potential multi's connection cache growing which won't be undone in this
373 * function no matter what.
376 /* Make easy handle use timeout list initialized above */
377 data->state.timeoutlist = timeoutlist;
380 /* set the easy handle */
381 multistate(data, CURLM_STATE_INIT);
383 if((data->set.global_dns_cache) &&
384 (data->dns.hostcachetype != HCACHE_GLOBAL)) {
385 /* global dns cache was requested but still isn't */
386 struct curl_hash *global = Curl_global_host_cache_init();
388 /* only do this if the global cache init works */
389 data->dns.hostcache = global;
390 data->dns.hostcachetype = HCACHE_GLOBAL;
393 /* for multi interface connections, we share DNS cache automatically if the
394 easy handle's one is currently not set. */
395 else if(!data->dns.hostcache ||
396 (data->dns.hostcachetype == HCACHE_NONE)) {
397 data->dns.hostcache = multi->hostcache;
398 data->dns.hostcachetype = HCACHE_MULTI;
401 /* Point to the multi's connection cache */
402 data->state.conn_cache = multi->conn_cache;
404 /* This adds the new entry at the 'end' of the doubly-linked circular
405 list of SessionHandle structs to try and maintain a FIFO queue so
406 the pipelined requests are in order. */
408 /* We add this new entry last in the list. */
410 data->next = NULL; /* end of the line */
412 struct SessionHandle *last = multi->easylp;
415 multi->easylp = data; /* the new last node */
418 /* first node, make both prev and next be NULL! */
421 multi->easylp = multi->easyp = data; /* both first and last */
424 /* make the SessionHandle refer back to this multi handle */
425 data->multi = multi_handle;
427 /* Set the timeout for this handle to expire really soon so that it will
428 be taken care of even when this handle is added in the midst of operation
429 when only the curl_multi_socket() API is used. During that flow, only
430 sockets that time-out or have actions will be dealt with. Since this
431 handle has no action yet, we make sure it times out to get things to
433 Curl_expire(data, 1);
435 /* increase the node-counter */
438 /* increase the alive-counter */
441 /* A somewhat crude work-around for a little glitch in update_timer() that
442 happens if the lastcall time is set to the same time when the handle is
443 removed as when the next handle is added, as then the check in
444 update_timer() that prevents calling the application multiple times with
445 the same timer infor will not trigger and then the new handle's timeout
446 will not be notified to the app.
448 The work-around is thus simply to clear the 'lastcall' variable to force
449 update_timer() to always trigger a callback to the app when a new easy
451 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
458 /* Debug-function, used like this:
460 * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
462 * Enable the hash print function first by editing hash.c
464 static void debug_print_sock_hash(void *p)
466 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
468 fprintf(stderr, " [easy %p/magic %x/socket %d]",
469 (void *)sh->data, sh->data->magic, (int)sh->socket);
473 CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
476 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
477 struct SessionHandle *easy = curl_handle;
478 struct SessionHandle *data = easy;
480 /* First, make some basic checks that the CURLM handle is a good handle */
481 if(!GOOD_MULTI_HANDLE(multi))
482 return CURLM_BAD_HANDLE;
484 /* Verify that we got a somewhat good easy handle too */
485 if(!GOOD_EASY_HANDLE(curl_handle))
486 return CURLM_BAD_EASY_HANDLE;
488 /* Prevent users from trying to remove same easy handle more than once */
490 return CURLM_OK; /* it is already removed so let's say it is fine! */
493 bool premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
494 bool easy_owns_conn = (data->easy_conn &&
495 (data->easy_conn->data == easy)) ?
498 /* If the 'state' is not INIT or COMPLETED, we might need to do something
499 nice to put the easy_handle in a good known state when this returns. */
501 /* this handle is "alive" so we need to count down the total number of
502 alive connections when this is removed */
505 if(data->easy_conn &&
506 (data->easy_conn->send_pipe->size +
507 data->easy_conn->recv_pipe->size > 1) &&
508 data->mstate > CURLM_STATE_WAITDO &&
509 data->mstate < CURLM_STATE_COMPLETED) {
510 /* If the handle is in a pipeline and has started sending off its
511 request but not received its response yet, we need to close
513 data->easy_conn->bits.close = TRUE;
514 /* Set connection owner so that Curl_done() closes it.
515 We can sefely do this here since connection is killed. */
516 data->easy_conn->data = easy;
519 /* The timer must be shut down before data->multi is set to NULL,
520 else the timenode will remain in the splay tree after
521 curl_easy_cleanup is called. */
522 Curl_expire(data, 0);
524 /* destroy the timeout list that is held in the easy handle */
525 if(data->state.timeoutlist) {
526 Curl_llist_destroy(data->state.timeoutlist, NULL);
527 data->state.timeoutlist = NULL;
530 if(data->dns.hostcachetype == HCACHE_MULTI) {
531 /* stop using the multi handle's DNS cache */
532 data->dns.hostcache = NULL;
533 data->dns.hostcachetype = HCACHE_NONE;
536 if(data->easy_conn) {
538 /* we must call Curl_done() here (if we still "own it") so that we don't
539 leave a half-baked one around */
542 /* Curl_done() clears the conn->data field to lose the association
543 between the easy handle and the connection
545 Note that this ignores the return code simply because there's
546 nothing really useful to do with it anyway! */
547 (void)Curl_done(&data->easy_conn, data->result, premature);
550 /* Clear connection pipelines, if Curl_done above was not called */
551 Curl_getoff_all_pipelines(data, data->easy_conn);
554 Curl_wildcard_dtor(&data->wildcard);
556 /* as this was using a shared connection cache we clear the pointer
557 to that since we're not part of that multi handle anymore */
558 data->state.conn_cache = NULL;
560 /* change state without using multistate(), only to make singlesocket() do
562 data->mstate = CURLM_STATE_COMPLETED;
563 singlesocket(multi, easy); /* to let the application know what sockets
564 that vanish with this handle */
566 /* Remove the association between the connection and the handle */
567 if(data->easy_conn) {
568 data->easy_conn->data = NULL;
569 data->easy_conn = NULL;
572 data->multi = NULL; /* clear the association to this multi handle */
575 /* make sure there's no pending message in the queue sent from this easy
577 struct curl_llist_element *e;
579 for(e = multi->msglist->head; e; e = e->next) {
580 struct Curl_message *msg = e->ptr;
582 if(msg->extmsg.easy_handle == easy) {
583 Curl_llist_remove(multi->msglist, e, NULL);
584 /* there can only be one from this specific handle */
590 /* make the previous node point to our next */
592 data->prev->next = data->next;
594 multi->easyp = data->next; /* point to first node */
596 /* make our next point to our previous node */
598 data->next->prev = data->prev;
600 multi->easylp = data->prev; /* point to last node */
603 We do not touch the easy handle here! */
605 multi->num_easy--; /* one less to care about now */
611 return CURLM_BAD_EASY_HANDLE; /* twasn't found */
614 bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi)
616 return (multi && multi->pipelining_enabled) ? TRUE : FALSE;
619 void Curl_multi_handlePipeBreak(struct SessionHandle *data)
621 data->easy_conn = NULL;
624 static int waitconnect_getsock(struct connectdata *conn,
633 return GETSOCK_BLANK;
636 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
637 sock[s] = conn->tempsock[i];
638 rc |= GETSOCK_WRITESOCK(s++);
642 /* when we've sent a CONNECT to a proxy, we should rather wait for the
643 socket to become readable to be able to get the response headers */
644 if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) {
645 sock[0] = conn->sock[FIRSTSOCKET];
646 rc = GETSOCK_READSOCK(0);
652 static int domore_getsock(struct connectdata *conn,
653 curl_socket_t *socks,
656 if(conn && conn->handler->domore_getsock)
657 return conn->handler->domore_getsock(conn, socks, numsocks);
658 return GETSOCK_BLANK;
661 /* returns bitmapped flags for this handle and its sockets */
662 static int multi_getsock(struct SessionHandle *data,
663 curl_socket_t *socks, /* points to numsocks number
667 /* If the pipe broke, or if there's no connection left for this easy handle,
668 then we MUST bail out now with no bitmask set. The no connection case can
669 happen when this is called from curl_multi_remove_handle() =>
670 singlesocket() => multi_getsock().
672 if(data->state.pipe_broke || !data->easy_conn)
675 if(data->mstate > CURLM_STATE_CONNECT &&
676 data->mstate < CURLM_STATE_COMPLETED) {
677 /* Set up ownership correctly */
678 data->easy_conn->data = data;
681 switch(data->mstate) {
683 #if 0 /* switch back on these cases to get the compiler to check for all enums
685 case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
686 case CURLM_STATE_COMPLETED:
687 case CURLM_STATE_MSGSENT:
688 case CURLM_STATE_INIT:
689 case CURLM_STATE_CONNECT:
690 case CURLM_STATE_WAITDO:
691 case CURLM_STATE_DONE:
692 case CURLM_STATE_LAST:
693 /* this will get called with CURLM_STATE_COMPLETED when a handle is
698 case CURLM_STATE_WAITRESOLVE:
699 return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
701 case CURLM_STATE_PROTOCONNECT:
702 return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
705 case CURLM_STATE_DOING:
706 return Curl_doing_getsock(data->easy_conn, socks, numsocks);
708 case CURLM_STATE_WAITPROXYCONNECT:
709 case CURLM_STATE_WAITCONNECT:
710 return waitconnect_getsock(data->easy_conn, socks, numsocks);
712 case CURLM_STATE_DO_MORE:
713 return domore_getsock(data->easy_conn, socks, numsocks);
715 case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
716 to waiting for the same as the *PERFORM
718 case CURLM_STATE_PERFORM:
719 case CURLM_STATE_WAITPERFORM:
720 return Curl_single_getsock(data->easy_conn, socks, numsocks);
725 CURLMcode curl_multi_fdset(CURLM *multi_handle,
726 fd_set *read_fd_set, fd_set *write_fd_set,
727 fd_set *exc_fd_set, int *max_fd)
729 /* Scan through all the easy handles to get the file descriptors set.
730 Some easy handles may not have connected to the remote host yet,
731 and then we must make sure that is done. */
732 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
733 struct SessionHandle *data;
735 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
738 (void)exc_fd_set; /* not used */
740 if(!GOOD_MULTI_HANDLE(multi))
741 return CURLM_BAD_HANDLE;
745 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
747 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
748 curl_socket_t s = CURL_SOCKET_BAD;
750 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
751 FD_SET(sockbunch[i], read_fd_set);
754 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
755 FD_SET(sockbunch[i], write_fd_set);
758 if(s == CURL_SOCKET_BAD)
759 /* this socket is unused, break out of loop */
762 if((int)s > this_max_fd)
763 this_max_fd = (int)s;
767 data = data->next; /* check next handle */
770 *max_fd = this_max_fd;
775 CURLMcode curl_multi_wait(CURLM *multi_handle,
776 struct curl_waitfd extra_fds[],
777 unsigned int extra_nfds,
781 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
782 struct SessionHandle *data;
783 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
786 unsigned int nfds = 0;
787 unsigned int curlfds;
788 struct pollfd *ufds = NULL;
789 long timeout_internal;
791 if(!GOOD_MULTI_HANDLE(multi))
792 return CURLM_BAD_HANDLE;
794 /* If the internally desired timeout is actually shorter than requested from
795 the outside, then use the shorter time! But only if the internal timer
796 is actually larger than -1! */
797 (void)multi_timeout(multi, &timeout_internal);
798 if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
799 timeout_ms = (int)timeout_internal;
801 /* Count up how many fds we have from the multi handle */
804 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
806 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
807 curl_socket_t s = CURL_SOCKET_BAD;
809 if(bitmap & GETSOCK_READSOCK(i)) {
813 if(bitmap & GETSOCK_WRITESOCK(i)) {
817 if(s == CURL_SOCKET_BAD) {
822 data = data->next; /* check next handle */
825 curlfds = nfds; /* number of internal file descriptors */
826 nfds += extra_nfds; /* add the externally provided ones */
829 ufds = malloc(nfds * sizeof(struct pollfd));
831 return CURLM_OUT_OF_MEMORY;
835 /* only do the second loop if we found descriptors in the first stage run
839 /* Add the curl handles to our pollfds first */
842 bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
844 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
845 curl_socket_t s = CURL_SOCKET_BAD;
847 if(bitmap & GETSOCK_READSOCK(i)) {
848 ufds[nfds].fd = sockbunch[i];
849 ufds[nfds].events = POLLIN;
853 if(bitmap & GETSOCK_WRITESOCK(i)) {
854 ufds[nfds].fd = sockbunch[i];
855 ufds[nfds].events = POLLOUT;
859 if(s == CURL_SOCKET_BAD) {
864 data = data->next; /* check next handle */
868 /* Add external file descriptions from poll-like struct curl_waitfd */
869 for(i = 0; i < extra_nfds; i++) {
870 ufds[nfds].fd = extra_fds[i].fd;
871 ufds[nfds].events = 0;
872 if(extra_fds[i].events & CURL_WAIT_POLLIN)
873 ufds[nfds].events |= POLLIN;
874 if(extra_fds[i].events & CURL_WAIT_POLLPRI)
875 ufds[nfds].events |= POLLPRI;
876 if(extra_fds[i].events & CURL_WAIT_POLLOUT)
877 ufds[nfds].events |= POLLOUT;
883 infof(data, "Curl_poll(%d ds, %d ms)\n", nfds, timeout_ms);
884 i = Curl_poll(ufds, nfds, timeout_ms);
888 /* copy revents results from the poll to the curl_multi_wait poll
889 struct, the bit values of the actual underlying poll() implementation
890 may not be the same as the ones in the public libcurl API! */
891 for(j = 0; j < extra_nfds; j++) {
892 unsigned short mask = 0;
893 unsigned r = ufds[curlfds + j].revents;
896 mask |= CURL_WAIT_POLLIN;
898 mask |= CURL_WAIT_POLLOUT;
900 mask |= CURL_WAIT_POLLPRI;
902 extra_fds[j].revents = mask;
915 static CURLMcode multi_runsingle(struct Curl_multi *multi,
917 struct SessionHandle *data)
919 struct Curl_message *msg = NULL;
922 bool protocol_connect = FALSE;
923 bool dophase_done = FALSE;
925 CURLMcode result = CURLM_OK;
926 struct SingleRequest *k;
930 if(!GOOD_EASY_HANDLE(data))
931 return CURLM_BAD_EASY_HANDLE;
934 /* this is a single-iteration do-while loop just to allow a
935 break to skip to the end of it */
936 bool disconnect_conn = FALSE;
938 /* Handle the case when the pipe breaks, i.e., the connection
939 we're using gets cleaned up and we're left with nothing. */
940 if(data->state.pipe_broke) {
941 infof(data, "Pipe broke: handle 0x%p, url = %s\n",
942 (void *)data, data->state.path);
944 if(data->mstate < CURLM_STATE_COMPLETED) {
945 /* Head back to the CONNECT state */
946 multistate(data, CURLM_STATE_CONNECT);
947 result = CURLM_CALL_MULTI_PERFORM;
948 data->result = CURLE_OK;
951 data->state.pipe_broke = FALSE;
952 data->easy_conn = NULL;
956 if(!data->easy_conn &&
957 data->mstate > CURLM_STATE_CONNECT &&
958 data->mstate < CURLM_STATE_DONE) {
959 /* In all these states, the code will blindly access 'data->easy_conn'
960 so this is precaution that it isn't NULL. And it silences static
962 failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate);
963 return CURLM_INTERNAL_ERROR;
966 if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
967 data->mstate < CURLM_STATE_COMPLETED)
968 /* Make sure we set the connection's current owner */
969 data->easy_conn->data = data;
971 if(data->easy_conn &&
972 (data->mstate >= CURLM_STATE_CONNECT) &&
973 (data->mstate < CURLM_STATE_COMPLETED)) {
974 /* we need to wait for the connect state as only then is the start time
975 stored, but we must not check already completed handles */
977 timeout_ms = Curl_timeleft(data, &now,
978 (data->mstate <= CURLM_STATE_WAITDO)?
982 /* Handle timed out */
983 if(data->mstate == CURLM_STATE_WAITRESOLVE)
984 failf(data, "Resolving timed out after %ld milliseconds",
985 Curl_tvdiff(now, data->progress.t_startsingle));
986 else if(data->mstate == CURLM_STATE_WAITCONNECT)
987 failf(data, "Connection timed out after %ld milliseconds",
988 Curl_tvdiff(now, data->progress.t_startsingle));
992 failf(data, "Operation timed out after %ld milliseconds with %"
993 CURL_FORMAT_CURL_OFF_T " out of %"
994 CURL_FORMAT_CURL_OFF_T " bytes received",
995 Curl_tvdiff(k->now, data->progress.t_startsingle),
996 k->bytecount, k->size);
999 failf(data, "Operation timed out after %ld milliseconds with %"
1000 CURL_FORMAT_CURL_OFF_T " bytes received",
1001 Curl_tvdiff(now, data->progress.t_startsingle),
1006 /* Force the connection closed because the server could continue to
1007 send us stuff at any time. (The disconnect_conn logic used below
1008 doesn't work at this point). */
1009 data->easy_conn->bits.close = TRUE;
1010 data->result = CURLE_OPERATION_TIMEDOUT;
1011 multistate(data, CURLM_STATE_COMPLETED);
1016 switch(data->mstate) {
1017 case CURLM_STATE_INIT:
1018 /* init this transfer. */
1019 data->result=Curl_pretransfer(data);
1021 if(CURLE_OK == data->result) {
1022 /* after init, go CONNECT */
1023 multistate(data, CURLM_STATE_CONNECT);
1024 result = CURLM_CALL_MULTI_PERFORM;
1028 case CURLM_STATE_CONNECT_PEND:
1029 /* We will stay here until there is a connection available. Then
1030 we try again in the CURLM_STATE_CONNECT state. */
1033 case CURLM_STATE_CONNECT:
1034 /* Connect. We want to get a connection identifier filled in. */
1035 Curl_pgrsTime(data, TIMER_STARTSINGLE);
1036 data->result = Curl_connect(data, &data->easy_conn,
1037 &async, &protocol_connect);
1038 if(CURLE_NO_CONNECTION_AVAILABLE == data->result) {
1039 /* There was no connection available. We will go to the pending
1040 state and wait for an available connection. */
1041 multistate(data, CURLM_STATE_CONNECT_PEND);
1042 data->result = CURLE_OK;
1046 if(CURLE_OK == data->result) {
1047 /* Add this handle to the send or pend pipeline */
1048 data->result = Curl_add_handle_to_pipeline(data, data->easy_conn);
1049 if(CURLE_OK != data->result)
1050 disconnect_conn = TRUE;
1053 /* We're now waiting for an asynchronous name lookup */
1054 multistate(data, CURLM_STATE_WAITRESOLVE);
1056 /* after the connect has been sent off, go WAITCONNECT unless the
1057 protocol connect is already done and we can go directly to
1059 result = CURLM_CALL_MULTI_PERFORM;
1061 if(protocol_connect)
1062 multistate(data, multi->pipelining_enabled?
1063 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1065 #ifndef CURL_DISABLE_HTTP
1066 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1067 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
1070 multistate(data, CURLM_STATE_WAITCONNECT);
1077 case CURLM_STATE_WAITRESOLVE:
1078 /* awaiting an asynch name resolve to complete */
1080 struct Curl_dns_entry *dns = NULL;
1082 /* check if we have the name resolved by now */
1083 data->result = Curl_resolver_is_resolved(data->easy_conn, &dns);
1085 /* Update sockets here, because the socket(s) may have been
1086 closed and the application thus needs to be told, even if it
1087 is likely that the same socket(s) will again be used further
1088 down. If the name has not yet been resolved, it is likely
1089 that new sockets have been opened in an attempt to contact
1090 another resolver. */
1091 singlesocket(multi, data);
1094 /* Perform the next step in the connection phase, and then move on
1095 to the WAITCONNECT state */
1096 data->result = Curl_async_resolved(data->easy_conn,
1099 if(CURLE_OK != data->result)
1100 /* if Curl_async_resolved() returns failure, the connection struct
1101 is already freed and gone */
1102 data->easy_conn = NULL; /* no more connection */
1104 /* call again please so that we get the next socket setup */
1105 result = CURLM_CALL_MULTI_PERFORM;
1106 if(protocol_connect)
1107 multistate(data, multi->pipelining_enabled?
1108 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1110 #ifndef CURL_DISABLE_HTTP
1111 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1112 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
1115 multistate(data, CURLM_STATE_WAITCONNECT);
1120 if(CURLE_OK != data->result) {
1121 /* failure detected */
1122 disconnect_conn = TRUE;
1128 #ifndef CURL_DISABLE_HTTP
1129 case CURLM_STATE_WAITPROXYCONNECT:
1130 /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
1131 data->result = Curl_http_connect(data->easy_conn, &protocol_connect);
1133 if(data->easy_conn->bits.proxy_connect_closed) {
1134 /* reset the error buffer */
1135 if(data->set.errorbuffer)
1136 data->set.errorbuffer[0] = '\0';
1137 data->state.errorbuf = FALSE;
1139 data->result = CURLE_OK;
1140 result = CURLM_CALL_MULTI_PERFORM;
1141 multistate(data, CURLM_STATE_CONNECT);
1143 else if(CURLE_OK == data->result) {
1144 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
1145 multistate(data, CURLM_STATE_WAITCONNECT);
1150 case CURLM_STATE_WAITCONNECT:
1151 /* awaiting a completion of an asynch connect */
1152 data->result = Curl_is_connected(data->easy_conn,
1158 /* if everything is still fine we do the protocol-specific connect
1160 data->result = Curl_protocol_connect(data->easy_conn,
1164 if(CURLE_OK != data->result) {
1165 /* failure detected */
1166 /* Just break, the cleaning up is handled all in one place */
1167 disconnect_conn = TRUE;
1172 if(!protocol_connect) {
1173 /* We have a TCP connection, but 'protocol_connect' may be false
1174 and then we continue to 'STATE_PROTOCONNECT'. If protocol
1175 connect is TRUE, we move on to STATE_DO.
1176 BUT if we are using a proxy we must change to WAITPROXYCONNECT
1178 #ifndef CURL_DISABLE_HTTP
1179 if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
1180 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
1183 multistate(data, CURLM_STATE_PROTOCONNECT);
1187 /* after the connect has completed, go WAITDO or DO */
1188 multistate(data, multi->pipelining_enabled?
1189 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1191 result = CURLM_CALL_MULTI_PERFORM;
1195 case CURLM_STATE_PROTOCONNECT:
1196 /* protocol-specific connect phase */
1197 data->result = Curl_protocol_connecting(data->easy_conn,
1199 if((data->result == CURLE_OK) && protocol_connect) {
1200 /* after the connect has completed, go WAITDO or DO */
1201 multistate(data, multi->pipelining_enabled?
1202 CURLM_STATE_WAITDO:CURLM_STATE_DO);
1203 result = CURLM_CALL_MULTI_PERFORM;
1205 else if(data->result) {
1206 /* failure detected */
1207 Curl_posttransfer(data);
1208 Curl_done(&data->easy_conn, data->result, TRUE);
1209 disconnect_conn = TRUE;
1213 case CURLM_STATE_WAITDO:
1214 /* Wait for our turn to DO when we're pipelining requests */
1216 infof(data, "WAITDO: Conn %ld send pipe %zu inuse %s athead %s\n",
1217 data->easy_conn->connection_id,
1218 data->easy_conn->send_pipe->size,
1219 data->easy_conn->writechannel_inuse?"TRUE":"FALSE",
1220 isHandleAtHead(data,
1221 data->easy_conn->send_pipe)?"TRUE":"FALSE");
1223 if(!data->easy_conn->writechannel_inuse &&
1224 isHandleAtHead(data,
1225 data->easy_conn->send_pipe)) {
1226 /* Grab the channel */
1227 data->easy_conn->writechannel_inuse = TRUE;
1228 multistate(data, CURLM_STATE_DO);
1229 result = CURLM_CALL_MULTI_PERFORM;
1233 case CURLM_STATE_DO:
1234 if(data->set.connect_only) {
1235 /* keep connection open for application to use the socket */
1236 data->easy_conn->bits.close = FALSE;
1237 multistate(data, CURLM_STATE_DONE);
1238 data->result = CURLE_OK;
1239 result = CURLM_CALL_MULTI_PERFORM;
1242 /* Perform the protocol's DO action */
1243 data->result = Curl_do(&data->easy_conn, &dophase_done);
1245 /* When Curl_do() returns failure, data->easy_conn might be NULL! */
1247 if(CURLE_OK == data->result) {
1249 /* some steps needed for wildcard matching */
1250 if(data->set.wildcardmatch) {
1251 struct WildcardData *wc = &data->wildcard;
1252 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
1253 /* skip some states if it is important */
1254 Curl_done(&data->easy_conn, CURLE_OK, FALSE);
1255 multistate(data, CURLM_STATE_DONE);
1256 result = CURLM_CALL_MULTI_PERFORM;
1260 /* DO was not completed in one function call, we must continue
1262 multistate(data, CURLM_STATE_DOING);
1266 /* after DO, go DO_DONE... or DO_MORE */
1267 else if(data->easy_conn->bits.do_more) {
1268 /* we're supposed to do more, but we need to sit down, relax
1269 and wait a little while first */
1270 multistate(data, CURLM_STATE_DO_MORE);
1274 /* we're done with the DO, now DO_DONE */
1275 multistate(data, CURLM_STATE_DO_DONE);
1276 result = CURLM_CALL_MULTI_PERFORM;
1279 else if((CURLE_SEND_ERROR == data->result) &&
1280 data->easy_conn->bits.reuse) {
1282 * In this situation, a connection that we were trying to use
1283 * may have unexpectedly died. If possible, send the connection
1284 * back to the CONNECT phase so we can try again.
1286 char *newurl = NULL;
1287 followtype follow=FOLLOW_NONE;
1291 drc = Curl_retry_request(data->easy_conn, &newurl);
1293 /* a failure here pretty much implies an out of memory */
1295 disconnect_conn = TRUE;
1298 retry = (newurl)?TRUE:FALSE;
1300 Curl_posttransfer(data);
1301 drc = Curl_done(&data->easy_conn, data->result, FALSE);
1303 /* When set to retry the connection, we must to go back to
1304 * the CONNECT state */
1306 if((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) {
1307 follow = FOLLOW_RETRY;
1308 drc = Curl_follow(data, newurl, follow);
1309 if(drc == CURLE_OK) {
1310 multistate(data, CURLM_STATE_CONNECT);
1311 result = CURLM_CALL_MULTI_PERFORM;
1312 data->result = CURLE_OK;
1321 /* done didn't return OK or SEND_ERROR */
1327 /* Have error handler disconnect conn if we can't retry */
1328 disconnect_conn = TRUE;
1332 /* failure detected */
1333 Curl_posttransfer(data);
1335 Curl_done(&data->easy_conn, data->result, FALSE);
1336 disconnect_conn = TRUE;
1341 case CURLM_STATE_DOING:
1342 /* we continue DOING until the DO phase is complete */
1343 data->result = Curl_protocol_doing(data->easy_conn,
1345 if(CURLE_OK == data->result) {
1347 /* after DO, go DO_DONE or DO_MORE */
1348 multistate(data, data->easy_conn->bits.do_more?
1349 CURLM_STATE_DO_MORE:
1350 CURLM_STATE_DO_DONE);
1351 result = CURLM_CALL_MULTI_PERFORM;
1352 } /* dophase_done */
1355 /* failure detected */
1356 Curl_posttransfer(data);
1357 Curl_done(&data->easy_conn, data->result, FALSE);
1358 disconnect_conn = TRUE;
1362 case CURLM_STATE_DO_MORE:
1364 * When we are connected, DO MORE and then go DO_DONE
1366 data->result = Curl_do_more(data->easy_conn, &control);
1368 /* No need to remove this handle from the send pipeline here since that
1369 is done in Curl_done() */
1370 if(CURLE_OK == data->result) {
1372 /* if positive, advance to DO_DONE
1373 if negative, go back to DOING */
1374 multistate(data, control==1?
1375 CURLM_STATE_DO_DONE:
1377 result = CURLM_CALL_MULTI_PERFORM;
1380 /* stay in DO_MORE */
1384 /* failure detected */
1385 Curl_posttransfer(data);
1386 Curl_done(&data->easy_conn, data->result, FALSE);
1387 disconnect_conn = TRUE;
1391 case CURLM_STATE_DO_DONE:
1392 /* Move ourselves from the send to recv pipeline */
1393 Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
1394 /* Check if we can move pending requests to send pipe */
1395 Curl_multi_process_pending_handles(multi);
1397 /* Only perform the transfer if there's a good socket to work with.
1398 Having both BAD is a signal to skip immediately to DONE */
1399 if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
1400 (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
1401 multistate(data, CURLM_STATE_WAITPERFORM);
1403 multistate(data, CURLM_STATE_DONE);
1404 result = CURLM_CALL_MULTI_PERFORM;
1407 case CURLM_STATE_WAITPERFORM:
1408 /* Wait for our turn to PERFORM */
1409 if(!data->easy_conn->readchannel_inuse &&
1410 isHandleAtHead(data,
1411 data->easy_conn->recv_pipe)) {
1412 /* Grab the channel */
1413 data->easy_conn->readchannel_inuse = TRUE;
1414 multistate(data, CURLM_STATE_PERFORM);
1415 result = CURLM_CALL_MULTI_PERFORM;
1419 infof(data, "WAITPERFORM: Conn %ld recv pipe %zu inuse %s athead %s\n",
1420 data->easy_conn->connection_id,
1421 data->easy_conn->recv_pipe->size,
1422 data->easy_conn->readchannel_inuse?"TRUE":"FALSE",
1423 isHandleAtHead(data,
1424 data->easy_conn->recv_pipe)?"TRUE":"FALSE");
1429 case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
1430 /* if both rates are within spec, resume transfer */
1431 if(Curl_pgrsUpdate(data->easy_conn))
1432 data->result = CURLE_ABORTED_BY_CALLBACK;
1434 data->result = Curl_speedcheck(data, now);
1436 if(( (data->set.max_send_speed == 0) ||
1437 (data->progress.ulspeed < data->set.max_send_speed )) &&
1438 ( (data->set.max_recv_speed == 0) ||
1439 (data->progress.dlspeed < data->set.max_recv_speed)))
1440 multistate(data, CURLM_STATE_PERFORM);
1443 case CURLM_STATE_PERFORM:
1445 char *newurl = NULL;
1448 /* check if over send speed */
1449 if((data->set.max_send_speed > 0) &&
1450 (data->progress.ulspeed > data->set.max_send_speed)) {
1453 multistate(data, CURLM_STATE_TOOFAST);
1455 /* calculate upload rate-limitation timeout. */
1456 buffersize = (int)(data->set.buffer_size ?
1457 data->set.buffer_size : BUFSIZE);
1458 timeout_ms = Curl_sleep_time(data->set.max_send_speed,
1459 data->progress.ulspeed, buffersize);
1460 Curl_expire(data, timeout_ms);
1464 /* check if over recv speed */
1465 if((data->set.max_recv_speed > 0) &&
1466 (data->progress.dlspeed > data->set.max_recv_speed)) {
1469 multistate(data, CURLM_STATE_TOOFAST);
1471 /* Calculate download rate-limitation timeout. */
1472 buffersize = (int)(data->set.buffer_size ?
1473 data->set.buffer_size : BUFSIZE);
1474 timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
1475 data->progress.dlspeed, buffersize);
1476 Curl_expire(data, timeout_ms);
1480 /* read/write data if it is ready to do so */
1481 data->result = Curl_readwrite(data->easy_conn, &done);
1485 if(!(k->keepon & KEEP_RECV)) {
1486 /* We're done receiving */
1487 data->easy_conn->readchannel_inuse = FALSE;
1490 if(!(k->keepon & KEEP_SEND)) {
1491 /* We're done sending */
1492 data->easy_conn->writechannel_inuse = FALSE;
1495 if(done || (data->result == CURLE_RECV_ERROR)) {
1496 /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
1497 * condition and the server closed the re-used connection exactly when
1498 * we wanted to use it, so figure out if that is indeed the case.
1500 CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
1502 retry = (newurl)?TRUE:FALSE;
1505 /* if we are to retry, set the result to OK and consider the
1507 data->result = CURLE_OK;
1514 * The transfer phase returned error, we mark the connection to get
1515 * closed to prevent being re-used. This is because we can't possibly
1516 * know if the connection is in a good shape or not now. Unless it is
1517 * a protocol which uses two "channels" like FTP, as then the error
1518 * happened in the data connection.
1521 if(!(data->easy_conn->handler->flags & PROTOPT_DUAL))
1522 data->easy_conn->bits.close = TRUE;
1524 Curl_posttransfer(data);
1525 Curl_done(&data->easy_conn, data->result, FALSE);
1528 followtype follow=FOLLOW_NONE;
1530 /* call this even if the readwrite function returned error */
1531 Curl_posttransfer(data);
1533 /* we're no longer receiving */
1534 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
1536 /* expire the new receiving pipeline head */
1537 if(data->easy_conn->recv_pipe->head)
1538 Curl_expire(data->easy_conn->recv_pipe->head->ptr, 1);
1540 /* Check if we can move pending requests to send pipe */
1541 Curl_multi_process_pending_handles(multi);
1543 /* When we follow redirects or is set to retry the connection, we must
1544 to go back to the CONNECT state */
1545 if(data->req.newurl || retry) {
1547 /* if the URL is a follow-location and not just a retried request
1548 then figure out the URL here */
1549 newurl = data->req.newurl;
1550 data->req.newurl = NULL;
1551 follow = FOLLOW_REDIR;
1554 follow = FOLLOW_RETRY;
1555 data->result = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
1556 if(CURLE_OK == data->result) {
1557 data->result = Curl_follow(data, newurl, follow);
1558 if(CURLE_OK == data->result) {
1559 multistate(data, CURLM_STATE_CONNECT);
1560 result = CURLM_CALL_MULTI_PERFORM;
1561 newurl = NULL; /* handed over the memory ownership to
1562 Curl_follow(), make sure we don't free() it
1568 /* after the transfer is done, go DONE */
1570 /* but first check to see if we got a location info even though we're
1571 not following redirects */
1572 if(data->req.location) {
1575 newurl = data->req.location;
1576 data->req.location = NULL;
1577 data->result = Curl_follow(data, newurl, FOLLOW_FAKE);
1578 if(CURLE_OK == data->result)
1579 newurl = NULL; /* allocation was handed over Curl_follow() */
1581 disconnect_conn = TRUE;
1584 multistate(data, CURLM_STATE_DONE);
1585 result = CURLM_CALL_MULTI_PERFORM;
1594 case CURLM_STATE_DONE:
1595 /* this state is highly transient, so run another loop after this */
1596 result = CURLM_CALL_MULTI_PERFORM;
1598 if(data->easy_conn) {
1601 /* Remove ourselves from the receive pipeline, if we are there. */
1602 Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
1603 /* Check if we can move pending requests to send pipe */
1604 Curl_multi_process_pending_handles(multi);
1606 /* post-transfer command */
1607 res = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
1609 /* allow a previously set error code take precedence */
1614 * If there are other handles on the pipeline, Curl_done won't set
1615 * easy_conn to NULL. In such a case, curl_multi_remove_handle() can
1616 * access free'd data, if the connection is free'd and the handle
1617 * removed before we perform the processing in CURLM_STATE_COMPLETED
1620 data->easy_conn = NULL;
1623 if(data->set.wildcardmatch) {
1624 if(data->wildcard.state != CURLWC_DONE) {
1625 /* if a wildcard is set and we are not ending -> lets start again
1626 with CURLM_STATE_INIT */
1627 multistate(data, CURLM_STATE_INIT);
1632 /* after we have DONE what we're supposed to do, go COMPLETED, and
1633 it doesn't matter what the Curl_done() returned! */
1634 multistate(data, CURLM_STATE_COMPLETED);
1637 case CURLM_STATE_COMPLETED:
1638 /* this is a completed transfer, it is likely to still be connected */
1640 /* This node should be delinked from the list now and we should post
1641 an information message that we are complete. */
1643 /* Important: reset the conn pointer so that we don't point to memory
1644 that could be freed anytime */
1645 data->easy_conn = NULL;
1647 Curl_expire(data, 0); /* stop all timers */
1650 case CURLM_STATE_MSGSENT:
1651 return CURLM_OK; /* do nothing */
1654 return CURLM_INTERNAL_ERROR;
1657 if(data->mstate < CURLM_STATE_COMPLETED) {
1658 if(CURLE_OK != data->result) {
1660 * If an error was returned, and we aren't in completed state now,
1661 * then we go to completed and consider this transfer aborted.
1664 /* NOTE: no attempt to disconnect connections must be made
1665 in the case blocks above - cleanup happens only here */
1667 data->state.pipe_broke = FALSE;
1669 if(data->easy_conn) {
1670 /* if this has a connection, unsubscribe from the pipelines */
1671 data->easy_conn->writechannel_inuse = FALSE;
1672 data->easy_conn->readchannel_inuse = FALSE;
1673 Curl_removeHandleFromPipeline(data,
1674 data->easy_conn->send_pipe);
1675 Curl_removeHandleFromPipeline(data,
1676 data->easy_conn->recv_pipe);
1677 /* Check if we can move pending requests to send pipe */
1678 Curl_multi_process_pending_handles(multi);
1680 if(disconnect_conn) {
1681 /* disconnect properly */
1682 Curl_disconnect(data->easy_conn, /* dead_connection */ FALSE);
1684 /* This is where we make sure that the easy_conn pointer is reset.
1685 We don't have to do this in every case block above where a
1686 failure is detected */
1687 data->easy_conn = NULL;
1690 else if(data->mstate == CURLM_STATE_CONNECT) {
1691 /* Curl_connect() failed */
1692 (void)Curl_posttransfer(data);
1695 multistate(data, CURLM_STATE_COMPLETED);
1697 /* if there's still a connection to use, call the progress function */
1698 else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
1699 /* aborted due to progress callback return code must close the
1701 data->result = CURLE_ABORTED_BY_CALLBACK;
1702 data->easy_conn->bits.close = TRUE;
1704 /* if not yet in DONE state, go there, otherwise COMPLETED */
1705 multistate(data, (data->mstate < CURLM_STATE_DONE)?
1706 CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
1707 result = CURLM_CALL_MULTI_PERFORM;
1710 } WHILE_FALSE; /* just to break out from! */
1712 if(CURLM_STATE_COMPLETED == data->mstate) {
1713 /* now fill in the Curl_message with this info */
1716 msg->extmsg.msg = CURLMSG_DONE;
1717 msg->extmsg.easy_handle = data;
1718 msg->extmsg.data.result = data->result;
1720 result = multi_addmsg(multi, msg);
1722 multistate(data, CURLM_STATE_MSGSENT);
1729 CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
1731 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1732 struct SessionHandle *data;
1733 CURLMcode returncode=CURLM_OK;
1734 struct Curl_tree *t;
1735 struct timeval now = Curl_tvnow();
1737 if(!GOOD_MULTI_HANDLE(multi))
1738 return CURLM_BAD_HANDLE;
1743 struct WildcardData *wc = &data->wildcard;
1745 if(data->set.wildcardmatch) {
1747 CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */
1749 return CURLM_OUT_OF_MEMORY;
1754 result = multi_runsingle(multi, now, data);
1755 while(CURLM_CALL_MULTI_PERFORM == result);
1757 if(data->set.wildcardmatch) {
1758 /* destruct wildcard structures if it is needed */
1759 if(wc->state == CURLWC_DONE || result)
1760 Curl_wildcard_dtor(wc);
1764 returncode = result;
1766 data = data->next; /* operate on next handle */
1770 * Simply remove all expired timers from the splay since handles are dealt
1771 * with unconditionally by this function and curl_multi_timeout() requires
1772 * that already passed/handled expire times are removed from the splay.
1774 * It is important that the 'now' value is set at the entry of this function
1775 * and not for the current time as it may have ticked a little while since
1776 * then and then we risk this loop to remove timers that actually have not
1780 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
1782 /* the removed may have another timeout in queue */
1783 (void)add_next_timeout(now, multi, t->payload);
1787 *running_handles = multi->num_alive;
1789 if(CURLM_OK >= returncode)
1790 update_timer(multi);
1795 static void close_all_connections(struct Curl_multi *multi)
1797 struct connectdata *conn;
1799 conn = Curl_conncache_find_first_connection(multi->conn_cache);
1801 conn->data = multi->closure_handle;
1803 /* This will remove the connection from the cache */
1804 (void)Curl_disconnect(conn, FALSE);
1806 conn = Curl_conncache_find_first_connection(multi->conn_cache);
1810 CURLMcode curl_multi_cleanup(CURLM *multi_handle)
1812 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1813 struct SessionHandle *data;
1814 struct SessionHandle *nextdata;
1816 if(GOOD_MULTI_HANDLE(multi)) {
1817 bool restore_pipe = FALSE;
1818 SIGPIPE_VARIABLE(pipe_st);
1820 multi->type = 0; /* not good anymore */
1822 /* Close all the connections in the connection cache */
1823 close_all_connections(multi);
1825 if(multi->closure_handle) {
1826 sigpipe_ignore(multi->closure_handle, &pipe_st);
1827 restore_pipe = TRUE;
1829 multi->closure_handle->dns.hostcache = multi->hostcache;
1830 Curl_hostcache_clean(multi->closure_handle,
1831 multi->closure_handle->dns.hostcache);
1833 Curl_close(multi->closure_handle);
1834 multi->closure_handle = NULL;
1837 Curl_hash_destroy(multi->sockhash);
1838 multi->sockhash = NULL;
1840 Curl_conncache_destroy(multi->conn_cache);
1841 multi->conn_cache = NULL;
1843 /* remove the pending list of messages */
1844 Curl_llist_destroy(multi->msglist, NULL);
1845 multi->msglist = NULL;
1847 /* remove all easy handles */
1848 data = multi->easyp;
1850 nextdata=data->next;
1851 if(data->dns.hostcachetype == HCACHE_MULTI) {
1852 /* clear out the usage of the shared DNS cache */
1853 Curl_hostcache_clean(data, data->dns.hostcache);
1854 data->dns.hostcache = NULL;
1855 data->dns.hostcachetype = HCACHE_NONE;
1858 /* Clear the pointer to the connection cache */
1859 data->state.conn_cache = NULL;
1860 data->multi = NULL; /* clear the association */
1865 Curl_hash_destroy(multi->hostcache);
1866 multi->hostcache = NULL;
1868 /* Free the blacklists by setting them to NULL */
1869 Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
1870 Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
1874 sigpipe_restore(&pipe_st);
1879 return CURLM_BAD_HANDLE;
1883 * curl_multi_info_read()
1885 * This function is the primary way for a multi/multi_socket application to
1886 * figure out if a transfer has ended. We MUST make this function as fast as
1887 * possible as it will be polled frequently and we MUST NOT scan any lists in
1888 * here to figure out things. We must scale fine to thousands of handles and
1889 * beyond. The current design is fully O(1).
1892 CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
1894 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
1895 struct Curl_message *msg;
1897 *msgs_in_queue = 0; /* default to none */
1899 if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) {
1900 /* there is one or more messages in the list */
1901 struct curl_llist_element *e;
1903 /* extract the head of the list to return */
1904 e = multi->msglist->head;
1908 /* remove the extracted entry */
1909 Curl_llist_remove(multi->msglist, e, NULL);
1911 *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist));
1913 return &msg->extmsg;
1920 * singlesocket() checks what sockets we deal with and their "action state"
1921 * and if we have a different state in any of those sockets from last time we
1922 * call the callback accordingly.
1924 static void singlesocket(struct Curl_multi *multi,
1925 struct SessionHandle *data)
1927 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
1929 struct Curl_sh_entry *entry;
1932 unsigned int curraction;
1933 bool remove_sock_from_hash;
1935 for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
1936 socks[i] = CURL_SOCKET_BAD;
1938 /* Fill in the 'current' struct with the state as it is now: what sockets to
1939 supervise and for what actions */
1940 curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE);
1942 /* We have 0 .. N sockets already and we get to know about the 0 .. M
1943 sockets we should have from now on. Detect the differences, remove no
1944 longer supervised ones and add new ones */
1946 /* walk over the sockets we got right now */
1947 for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
1948 (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
1950 int action = CURL_POLL_NONE;
1954 /* get it from the hash */
1955 entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
1957 if(curraction & GETSOCK_READSOCK(i))
1958 action |= CURL_POLL_IN;
1959 if(curraction & GETSOCK_WRITESOCK(i))
1960 action |= CURL_POLL_OUT;
1963 /* yeps, already present so check if it has the same action set */
1964 if(entry->action == action)
1965 /* same, continue */
1969 /* this is a socket we didn't have before, add it! */
1970 entry = sh_addentry(multi->sockhash, s, data);
1976 /* we know (entry != NULL) at this point, see the logic above */
1977 if(multi->socket_cb)
1978 multi->socket_cb(data,
1981 multi->socket_userp,
1984 entry->action = action; /* store the current action state */
1987 num = i; /* number of sockets */
1989 /* when we've walked over all the sockets we should have right now, we must
1990 make sure to detect sockets that are removed */
1991 for(i=0; i< data->numsocks; i++) {
1993 s = data->sockets[i];
1994 for(j=0; j<num; j++) {
1996 /* this is still supervised */
1997 s = CURL_SOCKET_BAD;
2001 if(s != CURL_SOCKET_BAD) {
2003 /* this socket has been removed. Tell the app to remove it */
2004 remove_sock_from_hash = TRUE;
2006 entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2008 /* check if the socket to be removed serves a connection which has
2009 other easy-s in a pipeline. In this case the socket should not be
2011 struct connectdata *easy_conn = data->easy_conn;
2013 if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
2014 /* the handle should not be removed from the pipe yet */
2015 remove_sock_from_hash = FALSE;
2017 /* Update the sockhash entry to instead point to the next in line
2018 for the recv_pipe, or the first (in case this particular easy
2020 if(entry->easy == data) {
2021 if(isHandleAtHead(data, easy_conn->recv_pipe))
2022 entry->easy = easy_conn->recv_pipe->head->next->ptr;
2024 entry->easy = easy_conn->recv_pipe->head->ptr;
2027 if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) {
2028 /* the handle should not be removed from the pipe yet */
2029 remove_sock_from_hash = FALSE;
2031 /* Update the sockhash entry to instead point to the next in line
2032 for the send_pipe, or the first (in case this particular easy
2034 if(entry->easy == data) {
2035 if(isHandleAtHead(data, easy_conn->send_pipe))
2036 entry->easy = easy_conn->send_pipe->head->next->ptr;
2038 entry->easy = easy_conn->send_pipe->head->ptr;
2041 /* Don't worry about overwriting recv_pipe head with send_pipe_head,
2042 when action will be asked on the socket (see multi_socket()), the
2043 head of the correct pipe will be taken according to the
2048 /* just a precaution, this socket really SHOULD be in the hash already
2049 but in case it isn't, we don't have to tell the app to remove it
2050 either since it never got to know about it */
2051 remove_sock_from_hash = FALSE;
2053 if(remove_sock_from_hash) {
2054 /* in this case 'entry' is always non-NULL */
2055 if(multi->socket_cb)
2056 multi->socket_cb(data,
2059 multi->socket_userp,
2061 sh_delentry(multi->sockhash, s);
2067 memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
2068 data->numsocks = num;
2072 * Curl_multi_closed()
2074 * Used by the connect code to tell the multi_socket code that one of the
2075 * sockets we were using have just been closed. This function will then
2076 * remove it from the sockethash for this handle to make the multi_socket API
2077 * behave properly, especially for the case when libcurl will create another
2078 * socket again and it gets the same file descriptor number.
2081 void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
2083 struct Curl_multi *multi = conn->data->multi;
2085 /* this is set if this connection is part of a handle that is added to
2086 a multi handle, and only then this is necessary */
2087 struct Curl_sh_entry *entry =
2088 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2091 if(multi->socket_cb)
2092 multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
2093 multi->socket_userp,
2096 /* now remove it from the socket hash */
2097 sh_delentry(multi->sockhash, s);
2105 * add_next_timeout()
2107 * Each SessionHandle has a list of timeouts. The add_next_timeout() is called
2108 * when it has just been removed from the splay tree because the timeout has
2109 * expired. This function is then to advance in the list to pick the next
2110 * timeout to use (skip the already expired ones) and add this node back to
2111 * the splay tree again.
2113 * The splay tree only has each sessionhandle as a single node and the nearest
2114 * timeout is used to sort it on.
2116 static CURLMcode add_next_timeout(struct timeval now,
2117 struct Curl_multi *multi,
2118 struct SessionHandle *d)
2120 struct timeval *tv = &d->state.expiretime;
2121 struct curl_llist *list = d->state.timeoutlist;
2122 struct curl_llist_element *e;
2124 /* move over the timeout list for this specific handle and remove all
2125 timeouts that are now passed tense and store the next pending
2127 for(e = list->head; e; ) {
2128 struct curl_llist_element *n = e->next;
2129 long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now);
2131 /* remove outdated entry */
2132 Curl_llist_remove(list, e, NULL);
2134 /* the list is sorted so get out on the first mismatch */
2140 /* clear the expire times within the handles that we remove from the
2146 /* copy the first entry to 'tv' */
2147 memcpy(tv, e->ptr, sizeof(*tv));
2149 /* remove first entry from list */
2150 Curl_llist_remove(list, e, NULL);
2152 /* insert this node again into the splay */
2153 multi->timetree = Curl_splayinsert(*tv, multi->timetree,
2154 &d->state.timenode);
2159 static CURLMcode multi_socket(struct Curl_multi *multi,
2163 int *running_handles)
2165 CURLMcode result = CURLM_OK;
2166 struct SessionHandle *data = NULL;
2167 struct Curl_tree *t;
2168 struct timeval now = Curl_tvnow();
2171 /* *perform() deals with running_handles on its own */
2172 result = curl_multi_perform(multi, running_handles);
2174 /* walk through each easy handle and do the socket state change magic
2176 if(result != CURLM_BAD_HANDLE) {
2179 singlesocket(multi, data);
2184 /* or should we fall-through and do the timer-based stuff? */
2187 else if(s != CURL_SOCKET_TIMEOUT) {
2189 struct Curl_sh_entry *entry =
2190 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2193 /* Unmatched socket, we can't act on it but we ignore this fact. In
2194 real-world tests it has been proved that libevent can in fact give
2195 the application actions even though the socket was just previously
2196 asked to get removed, so thus we better survive stray socket actions
2197 and just move on. */
2202 if(data->magic != CURLEASY_MAGIC_NUMBER)
2203 /* bad bad bad bad bad bad bad */
2204 return CURLM_INTERNAL_ERROR;
2206 /* If the pipeline is enabled, take the handle which is in the head of
2207 the pipeline. If we should write into the socket, take the send_pipe
2208 head. If we should read from the socket, take the recv_pipe head. */
2209 if(data->easy_conn) {
2210 if((ev_bitmask & CURL_POLL_OUT) &&
2211 data->easy_conn->send_pipe &&
2212 data->easy_conn->send_pipe->head)
2213 data = data->easy_conn->send_pipe->head->ptr;
2214 else if((ev_bitmask & CURL_POLL_IN) &&
2215 data->easy_conn->recv_pipe &&
2216 data->easy_conn->recv_pipe->head)
2217 data = data->easy_conn->recv_pipe->head->ptr;
2220 if(data->easy_conn &&
2221 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
2222 /* set socket event bitmask if they're not locked */
2223 data->easy_conn->cselect_bits = ev_bitmask;
2226 result = multi_runsingle(multi, now, data);
2227 while(CURLM_CALL_MULTI_PERFORM == result);
2229 if(data->easy_conn &&
2230 !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
2231 /* clear the bitmask only if not locked */
2232 data->easy_conn->cselect_bits = 0;
2234 if(CURLM_OK >= result)
2235 /* get the socket(s) and check if the state has been changed since
2237 singlesocket(multi, data);
2239 /* Now we fall-through and do the timer-based stuff, since we don't want
2240 to force the user to have to deal with timeouts as long as at least
2241 one connection in fact has traffic. */
2243 data = NULL; /* set data to NULL again to avoid calling
2244 multi_runsingle() in case there's no need to */
2245 now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop
2246 may have taken some time */
2250 /* Asked to run due to time-out. Clear the 'lastcall' variable to force
2251 update_timer() to trigger a callback to the app again even if the same
2252 timeout is still the one to run after this call. That handles the case
2253 when the application asks libcurl to run the timeout prematurely. */
2254 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
2258 * The loop following here will go on as long as there are expire-times left
2259 * to process in the splay and 'data' will be re-assigned for every expired
2260 * handle we deal with.
2263 /* the first loop lap 'data' can be NULL */
2266 result = multi_runsingle(multi, now, data);
2267 while(CURLM_CALL_MULTI_PERFORM == result);
2269 if(CURLM_OK >= result)
2270 /* get the socket(s) and check if the state has been changed since
2272 singlesocket(multi, data);
2275 /* Check if there's one (more) expired timer to deal with! This function
2276 extracts a matching node if there is one */
2278 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
2280 data = t->payload; /* assign this for next loop */
2281 (void)add_next_timeout(now, multi, t->payload);
2286 *running_handles = multi->num_alive;
2290 #undef curl_multi_setopt
2291 CURLMcode curl_multi_setopt(CURLM *multi_handle,
2292 CURLMoption option, ...)
2294 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
2295 CURLMcode res = CURLM_OK;
2298 if(!GOOD_MULTI_HANDLE(multi))
2299 return CURLM_BAD_HANDLE;
2301 va_start(param, option);
2304 case CURLMOPT_SOCKETFUNCTION:
2305 multi->socket_cb = va_arg(param, curl_socket_callback);
2307 case CURLMOPT_SOCKETDATA:
2308 multi->socket_userp = va_arg(param, void *);
2310 case CURLMOPT_PIPELINING:
2311 multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
2313 case CURLMOPT_TIMERFUNCTION:
2314 multi->timer_cb = va_arg(param, curl_multi_timer_callback);
2316 case CURLMOPT_TIMERDATA:
2317 multi->timer_userp = va_arg(param, void *);
2319 case CURLMOPT_MAXCONNECTS:
2320 multi->maxconnects = va_arg(param, long);
2322 case CURLMOPT_MAX_HOST_CONNECTIONS:
2323 multi->max_host_connections = va_arg(param, long);
2325 case CURLMOPT_MAX_PIPELINE_LENGTH:
2326 multi->max_pipeline_length = va_arg(param, long);
2328 case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
2329 multi->content_length_penalty_size = va_arg(param, long);
2331 case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
2332 multi->chunk_length_penalty_size = va_arg(param, long);
2334 case CURLMOPT_PIPELINING_SITE_BL:
2335 res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
2336 &multi->pipelining_site_bl);
2338 case CURLMOPT_PIPELINING_SERVER_BL:
2339 res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
2340 &multi->pipelining_server_bl);
2342 case CURLMOPT_MAX_TOTAL_CONNECTIONS:
2343 multi->max_total_connections = va_arg(param, long);
2346 res = CURLM_UNKNOWN_OPTION;
2353 /* we define curl_multi_socket() in the public multi.h header */
2354 #undef curl_multi_socket
2356 CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
2357 int *running_handles)
2359 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
2360 0, running_handles);
2361 if(CURLM_OK >= result)
2362 update_timer((struct Curl_multi *)multi_handle);
2366 CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s,
2367 int ev_bitmask, int *running_handles)
2369 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
2370 ev_bitmask, running_handles);
2371 if(CURLM_OK >= result)
2372 update_timer((struct Curl_multi *)multi_handle);
2376 CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
2379 CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
2380 TRUE, CURL_SOCKET_BAD, 0, running_handles);
2381 if(CURLM_OK >= result)
2382 update_timer((struct Curl_multi *)multi_handle);
2386 static CURLMcode multi_timeout(struct Curl_multi *multi,
2389 static struct timeval tv_zero = {0,0};
2391 if(multi->timetree) {
2392 /* we have a tree of expire times */
2393 struct timeval now = Curl_tvnow();
2395 /* splay the lowest to the bottom */
2396 multi->timetree = Curl_splay(tv_zero, multi->timetree);
2398 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
2399 /* some time left before expiration */
2400 *timeout_ms = curlx_tvdiff(multi->timetree->key, now);
2403 * Since we only provide millisecond resolution on the returned value
2404 * and the diff might be less than one millisecond here, we don't
2405 * return zero as that may cause short bursts of busyloops on fast
2406 * processors while the diff is still present but less than one
2407 * millisecond! instead we return 1 until the time is ripe.
2412 /* 0 means immediately */
2421 CURLMcode curl_multi_timeout(CURLM *multi_handle,
2424 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
2426 /* First, make some basic checks that the CURLM handle is a good handle */
2427 if(!GOOD_MULTI_HANDLE(multi))
2428 return CURLM_BAD_HANDLE;
2430 return multi_timeout(multi, timeout_ms);
2434 * Tell the application it should update its timers, if it subscribes to the
2435 * update timer callback.
2437 static int update_timer(struct Curl_multi *multi)
2441 if(!multi->timer_cb)
2443 if(multi_timeout(multi, &timeout_ms)) {
2446 if(timeout_ms < 0) {
2447 static const struct timeval none={0,0};
2448 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
2449 multi->timer_lastcall = none;
2450 /* there's no timeout now but there was one previously, tell the app to
2452 return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp);
2457 /* When multi_timeout() is done, multi->timetree points to the node with the
2458 * timeout we got the (relative) time-out time for. We can thus easily check
2459 * if this is the same (fixed) time as we got in a previous call and then
2460 * avoid calling the callback again. */
2461 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
2464 multi->timer_lastcall = multi->timetree->key;
2466 return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
2469 void Curl_multi_set_easy_connection(struct SessionHandle *handle,
2470 struct connectdata *conn)
2472 handle->easy_conn = conn;
2475 static bool isHandleAtHead(struct SessionHandle *handle,
2476 struct curl_llist *pipeline)
2478 struct curl_llist_element *curr = pipeline->head;
2480 return (curr->ptr == handle) ? TRUE : FALSE;
2486 * multi_freetimeout()
2488 * Callback used by the llist system when a single timeout list entry is
2491 static void multi_freetimeout(void *user, void *entryptr)
2495 /* the entry was plain malloc()'ed */
2500 * multi_addtimeout()
2502 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
2503 * of list is always the timeout nearest in time.
2507 multi_addtimeout(struct curl_llist *timeoutlist,
2508 struct timeval *stamp)
2510 struct curl_llist_element *e;
2511 struct timeval *timedup;
2512 struct curl_llist_element *prev = NULL;
2514 timedup = malloc(sizeof(*timedup));
2516 return CURLM_OUT_OF_MEMORY;
2518 /* copy the timestamp */
2519 memcpy(timedup, stamp, sizeof(*timedup));
2521 if(Curl_llist_count(timeoutlist)) {
2522 /* find the correct spot in the list */
2523 for(e = timeoutlist->head; e; e = e->next) {
2524 struct timeval *checktime = e->ptr;
2525 long diff = curlx_tvdiff(*checktime, *timedup);
2533 this is the first timeout on the list */
2535 if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) {
2537 return CURLM_OUT_OF_MEMORY;
2546 * given a number of milliseconds from now to use to set the 'act before
2547 * this'-time for the transfer, to be extracted by curl_multi_timeout()
2549 * Note that the timeout will be added to a queue of timeouts if it defines a
2550 * moment in time that is later than the current head of queue.
2552 * Pass zero to clear all timeout values for this handle.
2554 void Curl_expire(struct SessionHandle *data, long milli)
2556 struct Curl_multi *multi = data->multi;
2557 struct timeval *nowp = &data->state.expiretime;
2560 /* this is only interesting while there is still an associated multi struct
2566 /* No timeout, clear the time data. */
2567 if(nowp->tv_sec || nowp->tv_usec) {
2568 /* Since this is an cleared time, we must remove the previous entry from
2570 struct curl_llist *list = data->state.timeoutlist;
2572 rc = Curl_splayremovebyaddr(multi->timetree,
2573 &data->state.timenode,
2576 infof(data, "Internal error clearing splay node = %d\n", rc);
2578 /* flush the timeout list too */
2579 while(list->size > 0)
2580 Curl_llist_remove(list, list->tail, NULL);
2583 infof(data, "Expire cleared\n");
2593 set.tv_sec += milli/1000;
2594 set.tv_usec += (milli%1000)*1000;
2596 if(set.tv_usec >= 1000000) {
2598 set.tv_usec -= 1000000;
2601 if(nowp->tv_sec || nowp->tv_usec) {
2602 /* This means that the struct is added as a node in the splay tree.
2603 Compare if the new time is earlier, and only remove-old/add-new if it
2605 long diff = curlx_tvdiff(set, *nowp);
2607 /* the new expire time was later so just add it to the queue
2609 multi_addtimeout(data->state.timeoutlist, &set);
2613 /* the new time is newer than the presently set one, so add the current
2614 to the queue and update the head */
2615 multi_addtimeout(data->state.timeoutlist, nowp);
2617 /* Since this is an updated time, we must remove the previous entry from
2618 the splay tree first and then re-add the new value */
2619 rc = Curl_splayremovebyaddr(multi->timetree,
2620 &data->state.timenode,
2623 infof(data, "Internal error removing splay node = %d\n", rc);
2627 data->state.timenode.payload = data;
2628 multi->timetree = Curl_splayinsert(*nowp,
2630 &data->state.timenode);
2633 Curl_splayprint(multi->timetree, 0, TRUE);
2637 CURLMcode curl_multi_assign(CURLM *multi_handle,
2638 curl_socket_t s, void *hashp)
2640 struct Curl_sh_entry *there = NULL;
2641 struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
2643 if(s != CURL_SOCKET_BAD)
2644 there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t));
2647 return CURLM_BAD_SOCKET;
2649 there->socketp = hashp;
2654 size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
2656 return multi ? multi->max_host_connections : 0;
2659 size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
2661 return multi ? multi->max_total_connections : 0;
2664 size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi)
2666 return multi ? multi->max_pipeline_length : 0;
2669 curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
2671 return multi ? multi->content_length_penalty_size : 0;
2674 curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
2676 return multi ? multi->chunk_length_penalty_size : 0;
2679 struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
2681 return multi->pipelining_site_bl;
2684 struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
2686 return multi->pipelining_server_bl;
2689 void Curl_multi_process_pending_handles(struct Curl_multi *multi)
2691 struct SessionHandle *data;
2695 if(data->mstate == CURLM_STATE_CONNECT_PEND) {
2696 multistate(data, CURLM_STATE_CONNECT);
2697 /* Make sure that the handle will be processed soonish. */
2698 Curl_expire(data, 1);
2700 data = data->next; /* operate on next handle */
2705 void Curl_multi_dump(const struct Curl_multi *multi_handle)
2707 struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
2708 struct SessionHandle *data;
2710 fprintf(stderr, "* Multi status: %d handles, %d alive\n",
2711 multi->num_easy, multi->num_alive);
2712 for(data=multi->easyp; data; data = data->next) {
2713 if(data->mstate < CURLM_STATE_COMPLETED) {
2714 /* only display handles that are not completed */
2715 fprintf(stderr, "handle %p, state %s, %d sockets\n",
2717 statename[data->mstate], data->numsocks);
2718 for(i=0; i < data->numsocks; i++) {
2719 curl_socket_t s = data->sockets[i];
2720 struct Curl_sh_entry *entry =
2721 Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
2723 fprintf(stderr, "%d ", (int)s);
2725 fprintf(stderr, "INTERNAL CONFUSION\n");
2728 fprintf(stderr, "[%s %s] ",
2729 entry->action&CURL_POLL_IN?"RECVING":"",
2730 entry->action&CURL_POLL_OUT?"SENDING":"");
2733 fprintf(stderr, "\n");