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