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