VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/multi.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • 屬性 svn:eol-style 設為 native
檔案大小: 110.8 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, 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 https://curl.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 "psl.h"
35#include "multiif.h"
36#include "sendf.h"
37#include "timeval.h"
38#include "http.h"
39#include "select.h"
40#include "warnless.h"
41#include "speedcheck.h"
42#include "conncache.h"
43#include "multihandle.h"
44#include "sigpipe.h"
45#include "vtls/vtls.h"
46#include "connect.h"
47#include "http_proxy.h"
48#include "http2.h"
49#include "socketpair.h"
50#include "socks.h"
51/* The last 3 #include files should be in this order */
52#include "curl_printf.h"
53#include "curl_memory.h"
54#include "memdebug.h"
55
56/*
57 CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
58 to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
59 CURL handle takes 45-50 K memory, therefore this 3K are not significant.
60*/
61#ifndef CURL_SOCKET_HASH_TABLE_SIZE
62#define CURL_SOCKET_HASH_TABLE_SIZE 911
63#endif
64
65#ifndef CURL_CONNECTION_HASH_SIZE
66#define CURL_CONNECTION_HASH_SIZE 97
67#endif
68
69#define CURL_MULTI_HANDLE 0x000bab1e
70
71#define GOOD_MULTI_HANDLE(x) \
72 ((x) && (x)->magic == CURL_MULTI_HANDLE)
73
74static CURLMcode singlesocket(struct Curl_multi *multi,
75 struct Curl_easy *data);
76static CURLMcode add_next_timeout(struct curltime now,
77 struct Curl_multi *multi,
78 struct Curl_easy *d);
79static CURLMcode multi_timeout(struct Curl_multi *multi,
80 long *timeout_ms);
81static void process_pending_handles(struct Curl_multi *multi);
82
83#ifdef DEBUGBUILD
84static const char * const statename[]={
85 "INIT",
86 "PENDING",
87 "CONNECT",
88 "RESOLVING",
89 "CONNECTING",
90 "TUNNELING",
91 "PROTOCONNECT",
92 "PROTOCONNECTING",
93 "DO",
94 "DOING",
95 "DOING_MORE",
96 "DID",
97 "PERFORMING",
98 "RATELIMITING",
99 "DONE",
100 "COMPLETED",
101 "MSGSENT",
102};
103#endif
104
105/* function pointer called once when switching TO a state */
106typedef void (*init_multistate_func)(struct Curl_easy *data);
107
108/* called in DID state, before PERFORMING state */
109static void before_perform(struct Curl_easy *data)
110{
111 data->req.chunk = FALSE;
112 Curl_pgrsTime(data, TIMER_PRETRANSFER);
113}
114
115static void init_completed(struct Curl_easy *data)
116{
117 /* this is a completed transfer */
118
119 /* Important: reset the conn pointer so that we don't point to memory
120 that could be freed anytime */
121 Curl_detach_connection(data);
122 Curl_expire_clear(data); /* stop all timers */
123}
124
125/* always use this function to change state, to make debugging easier */
126static void mstate(struct Curl_easy *data, CURLMstate state
127#ifdef DEBUGBUILD
128 , int lineno
129#endif
130)
131{
132 CURLMstate oldstate = data->mstate;
133 static const init_multistate_func finit[MSTATE_LAST] = {
134 NULL, /* INIT */
135 NULL, /* PENDING */
136 Curl_init_CONNECT, /* CONNECT */
137 NULL, /* RESOLVING */
138 NULL, /* CONNECTING */
139 NULL, /* TUNNELING */
140 NULL, /* PROTOCONNECT */
141 NULL, /* PROTOCONNECTING */
142 Curl_connect_free, /* DO */
143 NULL, /* DOING */
144 NULL, /* DOING_MORE */
145 before_perform, /* DID */
146 NULL, /* PERFORMING */
147 NULL, /* RATELIMITING */
148 NULL, /* DONE */
149 init_completed, /* COMPLETED */
150 NULL /* MSGSENT */
151 };
152
153#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
154 (void) lineno;
155#endif
156
157 if(oldstate == state)
158 /* don't bother when the new state is the same as the old state */
159 return;
160
161 data->mstate = state;
162
163#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
164 if(data->mstate >= MSTATE_PENDING &&
165 data->mstate < MSTATE_COMPLETED) {
166 long connection_id = -5000;
167
168 if(data->conn)
169 connection_id = data->conn->connection_id;
170
171 infof(data,
172 "STATE: %s => %s handle %p; line %d (connection #%ld)",
173 statename[oldstate], statename[data->mstate],
174 (void *)data, lineno, connection_id);
175 }
176#endif
177
178 if(state == MSTATE_COMPLETED) {
179 /* changing to COMPLETED means there's one less easy handle 'alive' */
180 DEBUGASSERT(data->multi->num_alive > 0);
181 data->multi->num_alive--;
182 }
183
184 /* if this state has an init-function, run it */
185 if(finit[state])
186 finit[state](data);
187}
188
189#ifndef DEBUGBUILD
190#define multistate(x,y) mstate(x,y)
191#else
192#define multistate(x,y) mstate(x,y, __LINE__)
193#endif
194
195/*
196 * We add one of these structs to the sockhash for each socket
197 */
198
199struct Curl_sh_entry {
200 struct Curl_hash transfers; /* hash of transfers using this socket */
201 unsigned int action; /* what combined action READ/WRITE this socket waits
202 for */
203 unsigned int users; /* number of transfers using this */
204 void *socketp; /* settable by users with curl_multi_assign() */
205 unsigned int readers; /* this many transfers want to read */
206 unsigned int writers; /* this many transfers want to write */
207};
208/* bits for 'action' having no bits means this socket is not expecting any
209 action */
210#define SH_READ 1
211#define SH_WRITE 2
212
213/* look up a given socket in the socket hash, skip invalid sockets */
214static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh,
215 curl_socket_t s)
216{
217 if(s != CURL_SOCKET_BAD) {
218 /* only look for proper sockets */
219 return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
220 }
221 return NULL;
222}
223
224#define TRHASH_SIZE 13
225static size_t trhash(void *key, size_t key_length, size_t slots_num)
226{
227 size_t keyval = (size_t)*(struct Curl_easy **)key;
228 (void) key_length;
229
230 return (keyval % slots_num);
231}
232
233static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
234{
235 (void)k1_len;
236 (void)k2_len;
237
238 return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2;
239}
240
241static void trhash_dtor(void *nada)
242{
243 (void)nada;
244}
245
246/*
247 * The sockhash has its own separate subhash in each entry that need to be
248 * safely destroyed first.
249 */
250static void sockhash_destroy(struct Curl_hash *h)
251{
252 struct Curl_hash_iterator iter;
253 struct Curl_hash_element *he;
254
255 DEBUGASSERT(h);
256 Curl_hash_start_iterate(h, &iter);
257 he = Curl_hash_next_element(&iter);
258 while(he) {
259 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr;
260 Curl_hash_destroy(&sh->transfers);
261 he = Curl_hash_next_element(&iter);
262 }
263 Curl_hash_destroy(h);
264}
265
266
267/* make sure this socket is present in the hash for this handle */
268static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
269 curl_socket_t s)
270{
271 struct Curl_sh_entry *there = sh_getentry(sh, s);
272 struct Curl_sh_entry *check;
273
274 if(there) {
275 /* it is present, return fine */
276 return there;
277 }
278
279 /* not present, add it */
280 check = calloc(1, sizeof(struct Curl_sh_entry));
281 if(!check)
282 return NULL; /* major failure */
283
284 Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare,
285 trhash_dtor);
286
287 /* make/add new hash entry */
288 if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
289 Curl_hash_destroy(&check->transfers);
290 free(check);
291 return NULL; /* major failure */
292 }
293
294 return check; /* things are good in sockhash land */
295}
296
297
298/* delete the given socket + handle from the hash */
299static void sh_delentry(struct Curl_sh_entry *entry,
300 struct Curl_hash *sh, curl_socket_t s)
301{
302 Curl_hash_destroy(&entry->transfers);
303
304 /* We remove the hash entry. This will end up in a call to
305 sh_freeentry(). */
306 Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
307}
308
309/*
310 * free a sockhash entry
311 */
312static void sh_freeentry(void *freethis)
313{
314 struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
315
316 free(p);
317}
318
319static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
320{
321 (void) k1_len; (void) k2_len;
322
323 return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
324}
325
326static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
327{
328 curl_socket_t fd = *((curl_socket_t *) key);
329 (void) key_length;
330
331 return (fd % slots_num);
332}
333
334/*
335 * sh_init() creates a new socket hash and returns the handle for it.
336 *
337 * Quote from README.multi_socket:
338 *
339 * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
340 * is somewhat of a bottle neck. Its current implementation may be a bit too
341 * limiting. It simply has a fixed-size array, and on each entry in the array
342 * it has a linked list with entries. So the hash only checks which list to
343 * scan through. The code I had used so for used a list with merely 7 slots
344 * (as that is what the DNS hash uses) but with 7000 connections that would
345 * make an average of 1000 nodes in each list to run through. I upped that to
346 * 97 slots (I believe a prime is suitable) and noticed a significant speed
347 * increase. I need to reconsider the hash implementation or use a rather
348 * large default value like this. At 9000 connections I was still below 10us
349 * per call."
350 *
351 */
352static void sh_init(struct Curl_hash *hash, int hashsize)
353{
354 Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
355 sh_freeentry);
356}
357
358/*
359 * multi_addmsg()
360 *
361 * Called when a transfer is completed. Adds the given msg pointer to
362 * the list kept in the multi handle.
363 */
364static CURLMcode multi_addmsg(struct Curl_multi *multi,
365 struct Curl_message *msg)
366{
367 Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
368 &msg->list);
369 return CURLM_OK;
370}
371
372struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
373 int chashsize) /* connection hash */
374{
375 struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
376
377 if(!multi)
378 return NULL;
379
380 multi->magic = CURL_MULTI_HANDLE;
381
382 Curl_init_dnscache(&multi->hostcache);
383
384 sh_init(&multi->sockhash, hashsize);
385
386 if(Curl_conncache_init(&multi->conn_cache, chashsize))
387 goto error;
388
389 Curl_llist_init(&multi->msglist, NULL);
390 Curl_llist_init(&multi->pending, NULL);
391
392 multi->multiplexing = TRUE;
393
394 /* -1 means it not set by user, use the default value */
395 multi->maxconnects = -1;
396 multi->max_concurrent_streams = 100;
397 multi->ipv6_works = Curl_ipv6works(NULL);
398
399#ifdef USE_WINSOCK
400 multi->wsa_event = WSACreateEvent();
401 if(multi->wsa_event == WSA_INVALID_EVENT)
402 goto error;
403#else
404#ifdef ENABLE_WAKEUP
405 if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) {
406 multi->wakeup_pair[0] = CURL_SOCKET_BAD;
407 multi->wakeup_pair[1] = CURL_SOCKET_BAD;
408 }
409 else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 ||
410 curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) {
411 sclose(multi->wakeup_pair[0]);
412 sclose(multi->wakeup_pair[1]);
413 multi->wakeup_pair[0] = CURL_SOCKET_BAD;
414 multi->wakeup_pair[1] = CURL_SOCKET_BAD;
415 }
416#endif
417#endif
418
419 return multi;
420
421 error:
422
423 sockhash_destroy(&multi->sockhash);
424 Curl_hash_destroy(&multi->hostcache);
425 Curl_conncache_destroy(&multi->conn_cache);
426 Curl_llist_destroy(&multi->msglist, NULL);
427 Curl_llist_destroy(&multi->pending, NULL);
428
429 free(multi);
430 return NULL;
431}
432
433struct Curl_multi *curl_multi_init(void)
434{
435 return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
436 CURL_CONNECTION_HASH_SIZE);
437}
438
439CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
440 struct Curl_easy *data)
441{
442 CURLMcode rc;
443 /* First, make some basic checks that the CURLM handle is a good handle */
444 if(!GOOD_MULTI_HANDLE(multi))
445 return CURLM_BAD_HANDLE;
446
447 /* Verify that we got a somewhat good easy handle too */
448 if(!GOOD_EASY_HANDLE(data))
449 return CURLM_BAD_EASY_HANDLE;
450
451 /* Prevent users from adding same easy handle more than once and prevent
452 adding to more than one multi stack */
453 if(data->multi)
454 return CURLM_ADDED_ALREADY;
455
456 if(multi->in_callback)
457 return CURLM_RECURSIVE_API_CALL;
458
459 if(multi->dead) {
460 /* a "dead" handle cannot get added transfers while any existing easy
461 handles are still alive - but if there are none alive anymore, it is
462 fine to start over and unmark the "deadness" of this handle */
463 if(multi->num_alive)
464 return CURLM_ABORTED_BY_CALLBACK;
465 multi->dead = FALSE;
466 }
467
468 /* Initialize timeout list for this handle */
469 Curl_llist_init(&data->state.timeoutlist, NULL);
470
471 /*
472 * No failure allowed in this function beyond this point. And no
473 * modification of easy nor multi handle allowed before this except for
474 * potential multi's connection cache growing which won't be undone in this
475 * function no matter what.
476 */
477 if(data->set.errorbuffer)
478 data->set.errorbuffer[0] = 0;
479
480 /* make the Curl_easy refer back to this multi handle - before Curl_expire()
481 is called. */
482 data->multi = multi;
483
484 /* Set the timeout for this handle to expire really soon so that it will
485 be taken care of even when this handle is added in the midst of operation
486 when only the curl_multi_socket() API is used. During that flow, only
487 sockets that time-out or have actions will be dealt with. Since this
488 handle has no action yet, we make sure it times out to get things to
489 happen. */
490 Curl_expire(data, 0, EXPIRE_RUN_NOW);
491
492 /* A somewhat crude work-around for a little glitch in Curl_update_timer()
493 that happens if the lastcall time is set to the same time when the handle
494 is removed as when the next handle is added, as then the check in
495 Curl_update_timer() that prevents calling the application multiple times
496 with the same timer info will not trigger and then the new handle's
497 timeout will not be notified to the app.
498
499 The work-around is thus simply to clear the 'lastcall' variable to force
500 Curl_update_timer() to always trigger a callback to the app when a new
501 easy handle is added */
502 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
503
504 rc = Curl_update_timer(multi);
505 if(rc)
506 return rc;
507
508 /* set the easy handle */
509 multistate(data, MSTATE_INIT);
510
511 /* for multi interface connections, we share DNS cache automatically if the
512 easy handle's one is currently not set. */
513 if(!data->dns.hostcache ||
514 (data->dns.hostcachetype == HCACHE_NONE)) {
515 data->dns.hostcache = &multi->hostcache;
516 data->dns.hostcachetype = HCACHE_MULTI;
517 }
518
519 /* Point to the shared or multi handle connection cache */
520 if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
521 data->state.conn_cache = &data->share->conn_cache;
522 else
523 data->state.conn_cache = &multi->conn_cache;
524 data->state.lastconnect_id = -1;
525
526#ifdef USE_LIBPSL
527 /* Do the same for PSL. */
528 if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL)))
529 data->psl = &data->share->psl;
530 else
531 data->psl = &multi->psl;
532#endif
533
534 /* We add the new entry last in the list. */
535 data->next = NULL; /* end of the line */
536 if(multi->easyp) {
537 struct Curl_easy *last = multi->easylp;
538 last->next = data;
539 data->prev = last;
540 multi->easylp = data; /* the new last node */
541 }
542 else {
543 /* first node, make prev NULL! */
544 data->prev = NULL;
545 multi->easylp = multi->easyp = data; /* both first and last */
546 }
547
548 /* increase the node-counter */
549 multi->num_easy++;
550
551 /* increase the alive-counter */
552 multi->num_alive++;
553
554 CONNCACHE_LOCK(data);
555 /* The closure handle only ever has default timeouts set. To improve the
556 state somewhat we clone the timeouts from each added handle so that the
557 closure handle always has the same timeouts as the most recently added
558 easy handle. */
559 data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
560 data->state.conn_cache->closure_handle->set.server_response_timeout =
561 data->set.server_response_timeout;
562 data->state.conn_cache->closure_handle->set.no_signal =
563 data->set.no_signal;
564 CONNCACHE_UNLOCK(data);
565
566 return CURLM_OK;
567}
568
569#if 0
570/* Debug-function, used like this:
571 *
572 * Curl_hash_print(&multi->sockhash, debug_print_sock_hash);
573 *
574 * Enable the hash print function first by editing hash.c
575 */
576static void debug_print_sock_hash(void *p)
577{
578 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
579
580 fprintf(stderr, " [readers %u][writers %u]",
581 sh->readers, sh->writers);
582}
583#endif
584
585static CURLcode multi_done(struct Curl_easy *data,
586 CURLcode status, /* an error if this is called
587 after an error was detected */
588 bool premature)
589{
590 CURLcode result;
591 struct connectdata *conn = data->conn;
592 unsigned int i;
593
594 DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d",
595 (int)status, (int)premature, data->state.done));
596
597 if(data->state.done)
598 /* Stop if multi_done() has already been called */
599 return CURLE_OK;
600
601 /* Stop the resolver and free its own resources (but not dns_entry yet). */
602 Curl_resolver_kill(data);
603
604 /* Cleanup possible redirect junk */
605 Curl_safefree(data->req.newurl);
606 Curl_safefree(data->req.location);
607
608 switch(status) {
609 case CURLE_ABORTED_BY_CALLBACK:
610 case CURLE_READ_ERROR:
611 case CURLE_WRITE_ERROR:
612 /* When we're aborted due to a callback return code it basically have to
613 be counted as premature as there is trouble ahead if we don't. We have
614 many callbacks and protocols work differently, we could potentially do
615 this more fine-grained in the future. */
616 premature = TRUE;
617 default:
618 break;
619 }
620
621 /* this calls the protocol-specific function pointer previously set */
622 if(conn->handler->done)
623 result = conn->handler->done(data, status, premature);
624 else
625 result = status;
626
627 if(CURLE_ABORTED_BY_CALLBACK != result) {
628 /* avoid this if we already aborted by callback to avoid this calling
629 another callback */
630 CURLcode rc = Curl_pgrsDone(data);
631 if(!result && rc)
632 result = CURLE_ABORTED_BY_CALLBACK;
633 }
634
635 process_pending_handles(data->multi); /* connection / multiplex */
636
637 CONNCACHE_LOCK(data);
638 Curl_detach_connection(data);
639 if(CONN_INUSE(conn)) {
640 /* Stop if still used. */
641 CONNCACHE_UNLOCK(data);
642 DEBUGF(infof(data, "Connection still in use %zu, "
643 "no more multi_done now!",
644 conn->easyq.size));
645 return CURLE_OK;
646 }
647
648 data->state.done = TRUE; /* called just now! */
649
650 if(conn->dns_entry) {
651 Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
652 conn->dns_entry = NULL;
653 }
654 Curl_hostcache_prune(data);
655 Curl_safefree(data->state.ulbuf);
656
657 /* if the transfer was completed in a paused state there can be buffered
658 data left to free */
659 for(i = 0; i < data->state.tempcount; i++) {
660 Curl_dyn_free(&data->state.tempwrite[i].b);
661 }
662 data->state.tempcount = 0;
663
664 /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
665 forced us to close this connection. This is ignored for requests taking
666 place in a NTLM/NEGOTIATE authentication handshake
667
668 if conn->bits.close is TRUE, it means that the connection should be
669 closed in spite of all our efforts to be nice, due to protocol
670 restrictions in our or the server's end
671
672 if premature is TRUE, it means this connection was said to be DONE before
673 the entire request operation is complete and thus we can't know in what
674 state it is for re-using, so we're forced to close it. In a perfect world
675 we can add code that keep track of if we really must close it here or not,
676 but currently we have no such detail knowledge.
677 */
678
679 if((data->set.reuse_forbid
680#if defined(USE_NTLM)
681 && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
682 conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
683#endif
684#if defined(USE_SPNEGO)
685 && !(conn->http_negotiate_state == GSS_AUTHRECV ||
686 conn->proxy_negotiate_state == GSS_AUTHRECV)
687#endif
688 ) || conn->bits.close
689 || (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
690 connclose(conn, "disconnecting");
691 Curl_conncache_remove_conn(data, conn, FALSE);
692 CONNCACHE_UNLOCK(data);
693 Curl_disconnect(data, conn, premature);
694 }
695 else {
696 char buffer[256];
697 const char *host =
698#ifndef CURL_DISABLE_PROXY
699 conn->bits.socksproxy ?
700 conn->socks_proxy.host.dispname :
701 conn->bits.httpproxy ? conn->http_proxy.host.dispname :
702#endif
703 conn->bits.conn_to_host ? conn->conn_to_host.dispname :
704 conn->host.dispname;
705 /* create string before returning the connection */
706 long connection_id = conn->connection_id;
707 msnprintf(buffer, sizeof(buffer),
708 "Connection #%ld to host %s left intact",
709 connection_id, host);
710 /* the connection is no longer in use by this transfer */
711 CONNCACHE_UNLOCK(data);
712 if(Curl_conncache_return_conn(data, conn)) {
713 /* remember the most recently used connection */
714 data->state.lastconnect_id = connection_id;
715 infof(data, "%s", buffer);
716 }
717 else
718 data->state.lastconnect_id = -1;
719 }
720
721 Curl_safefree(data->state.buffer);
722 return result;
723}
724
725static int close_connect_only(struct Curl_easy *data,
726 struct connectdata *conn, void *param)
727{
728 (void)param;
729 if(data->state.lastconnect_id != conn->connection_id)
730 return 0;
731
732 if(!conn->bits.connect_only)
733 return 1;
734
735 connclose(conn, "Removing connect-only easy handle");
736
737 return 1;
738}
739
740CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
741 struct Curl_easy *data)
742{
743 struct Curl_easy *easy = data;
744 bool premature;
745 struct Curl_llist_element *e;
746 CURLMcode rc;
747
748 /* First, make some basic checks that the CURLM handle is a good handle */
749 if(!GOOD_MULTI_HANDLE(multi))
750 return CURLM_BAD_HANDLE;
751
752 /* Verify that we got a somewhat good easy handle too */
753 if(!GOOD_EASY_HANDLE(data))
754 return CURLM_BAD_EASY_HANDLE;
755
756 /* Prevent users from trying to remove same easy handle more than once */
757 if(!data->multi)
758 return CURLM_OK; /* it is already removed so let's say it is fine! */
759
760 /* Prevent users from trying to remove an easy handle from the wrong multi */
761 if(data->multi != multi)
762 return CURLM_BAD_EASY_HANDLE;
763
764 if(multi->in_callback)
765 return CURLM_RECURSIVE_API_CALL;
766
767 premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE;
768
769 /* If the 'state' is not INIT or COMPLETED, we might need to do something
770 nice to put the easy_handle in a good known state when this returns. */
771 if(premature) {
772 /* this handle is "alive" so we need to count down the total number of
773 alive connections when this is removed */
774 multi->num_alive--;
775 }
776
777 if(data->conn &&
778 data->mstate > MSTATE_DO &&
779 data->mstate < MSTATE_COMPLETED) {
780 /* Set connection owner so that the DONE function closes it. We can
781 safely do this here since connection is killed. */
782 streamclose(data->conn, "Removed with partial response");
783 }
784
785 if(data->conn) {
786 /* multi_done() clears the association between the easy handle and the
787 connection.
788
789 Note that this ignores the return code simply because there's
790 nothing really useful to do with it anyway! */
791 (void)multi_done(data, data->result, premature);
792 }
793
794 /* The timer must be shut down before data->multi is set to NULL, else the
795 timenode will remain in the splay tree after curl_easy_cleanup is
796 called. Do it after multi_done() in case that sets another time! */
797 Curl_expire_clear(data);
798
799 if(data->connect_queue.ptr)
800 /* the handle was in the pending list waiting for an available connection,
801 so go ahead and remove it */
802 Curl_llist_remove(&multi->pending, &data->connect_queue, NULL);
803
804 if(data->dns.hostcachetype == HCACHE_MULTI) {
805 /* stop using the multi handle's DNS cache, *after* the possible
806 multi_done() call above */
807 data->dns.hostcache = NULL;
808 data->dns.hostcachetype = HCACHE_NONE;
809 }
810
811 Curl_wildcard_dtor(&data->wildcard);
812
813 /* destroy the timeout list that is held in the easy handle, do this *after*
814 multi_done() as that may actually call Curl_expire that uses this */
815 Curl_llist_destroy(&data->state.timeoutlist, NULL);
816
817 /* change state without using multistate(), only to make singlesocket() do
818 what we want */
819 data->mstate = MSTATE_COMPLETED;
820
821 /* This ignores the return code even in case of problems because there's
822 nothing more to do about that, here */
823 (void)singlesocket(multi, easy); /* to let the application know what sockets
824 that vanish with this handle */
825
826 /* Remove the association between the connection and the handle */
827 Curl_detach_connection(data);
828
829 if(data->state.lastconnect_id != -1) {
830 /* Mark any connect-only connection for closure */
831 Curl_conncache_foreach(data, data->state.conn_cache,
832 NULL, close_connect_only);
833 }
834
835#ifdef USE_LIBPSL
836 /* Remove the PSL association. */
837 if(data->psl == &multi->psl)
838 data->psl = NULL;
839#endif
840
841 /* as this was using a shared connection cache we clear the pointer to that
842 since we're not part of that multi handle anymore */
843 data->state.conn_cache = NULL;
844
845 data->multi = NULL; /* clear the association to this multi handle */
846
847 /* make sure there's no pending message in the queue sent from this easy
848 handle */
849
850 for(e = multi->msglist.head; e; e = e->next) {
851 struct Curl_message *msg = e->ptr;
852
853 if(msg->extmsg.easy_handle == easy) {
854 Curl_llist_remove(&multi->msglist, e, NULL);
855 /* there can only be one from this specific handle */
856 break;
857 }
858 }
859
860 /* Remove from the pending list if it is there. Otherwise this will
861 remain on the pending list forever due to the state change. */
862 for(e = multi->pending.head; e; e = e->next) {
863 struct Curl_easy *curr_data = e->ptr;
864
865 if(curr_data == data) {
866 Curl_llist_remove(&multi->pending, e, NULL);
867 break;
868 }
869 }
870
871 /* make the previous node point to our next */
872 if(data->prev)
873 data->prev->next = data->next;
874 else
875 multi->easyp = data->next; /* point to first node */
876
877 /* make our next point to our previous node */
878 if(data->next)
879 data->next->prev = data->prev;
880 else
881 multi->easylp = data->prev; /* point to last node */
882
883 /* NOTE NOTE NOTE
884 We do not touch the easy handle here! */
885 multi->num_easy--; /* one less to care about now */
886
887 process_pending_handles(multi);
888
889 rc = Curl_update_timer(multi);
890 if(rc)
891 return rc;
892 return CURLM_OK;
893}
894
895/* Return TRUE if the application asked for multiplexing */
896bool Curl_multiplex_wanted(const struct Curl_multi *multi)
897{
898 return (multi && (multi->multiplexing));
899}
900
901/*
902 * Curl_detach_connection() removes the given transfer from the connection.
903 *
904 * This is the only function that should clear data->conn. This will
905 * occasionally be called with the data->conn pointer already cleared.
906 */
907void Curl_detach_connection(struct Curl_easy *data)
908{
909 struct connectdata *conn = data->conn;
910 if(conn) {
911 Curl_connect_done(data); /* if mid-CONNECT, shut it down */
912 Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
913 Curl_ssl_detach_conn(data, conn);
914 }
915 data->conn = NULL;
916}
917
918/*
919 * Curl_attach_connection() attaches this transfer to this connection.
920 *
921 * This is the only function that should assign data->conn
922 */
923void Curl_attach_connection(struct Curl_easy *data,
924 struct connectdata *conn)
925{
926 DEBUGASSERT(!data->conn);
927 DEBUGASSERT(conn);
928 data->conn = conn;
929 Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
930 &data->conn_queue);
931 if(conn->handler->attach)
932 conn->handler->attach(data, conn);
933 Curl_ssl_associate_conn(data, conn);
934}
935
936static int waitconnect_getsock(struct connectdata *conn,
937 curl_socket_t *sock)
938{
939 int i;
940 int s = 0;
941 int rc = 0;
942
943#ifdef USE_SSL
944#ifndef CURL_DISABLE_PROXY
945 if(CONNECT_FIRSTSOCKET_PROXY_SSL())
946 return Curl_ssl->getsock(conn, sock);
947#endif
948#endif
949
950 if(SOCKS_STATE(conn->cnnct.state))
951 return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET);
952
953 for(i = 0; i<2; i++) {
954 if(conn->tempsock[i] != CURL_SOCKET_BAD) {
955 sock[s] = conn->tempsock[i];
956 rc |= GETSOCK_WRITESOCK(s);
957#ifdef ENABLE_QUIC
958 if(conn->transport == TRNSPRT_QUIC)
959 /* when connecting QUIC, we want to read the socket too */
960 rc |= GETSOCK_READSOCK(s);
961#endif
962 s++;
963 }
964 }
965
966 return rc;
967}
968
969static int waitproxyconnect_getsock(struct connectdata *conn,
970 curl_socket_t *sock)
971{
972 sock[0] = conn->sock[FIRSTSOCKET];
973
974 if(conn->connect_state)
975 return Curl_connect_getsock(conn);
976
977 return GETSOCK_WRITESOCK(0);
978}
979
980static int domore_getsock(struct Curl_easy *data,
981 struct connectdata *conn,
982 curl_socket_t *socks)
983{
984 if(conn && conn->handler->domore_getsock)
985 return conn->handler->domore_getsock(data, conn, socks);
986 return GETSOCK_BLANK;
987}
988
989static int doing_getsock(struct Curl_easy *data,
990 struct connectdata *conn,
991 curl_socket_t *socks)
992{
993 if(conn && conn->handler->doing_getsock)
994 return conn->handler->doing_getsock(data, conn, socks);
995 return GETSOCK_BLANK;
996}
997
998static int protocol_getsock(struct Curl_easy *data,
999 struct connectdata *conn,
1000 curl_socket_t *socks)
1001{
1002 if(conn->handler->proto_getsock)
1003 return conn->handler->proto_getsock(data, conn, socks);
1004 /* Backup getsock logic. Since there is a live socket in use, we must wait
1005 for it or it will be removed from watching when the multi_socket API is
1006 used. */
1007 socks[0] = conn->sock[FIRSTSOCKET];
1008 return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
1009}
1010
1011/* returns bitmapped flags for this handle and its sockets. The 'socks[]'
1012 array contains MAX_SOCKSPEREASYHANDLE entries. */
1013static int multi_getsock(struct Curl_easy *data,
1014 curl_socket_t *socks)
1015{
1016 struct connectdata *conn = data->conn;
1017 /* The no connection case can happen when this is called from
1018 curl_multi_remove_handle() => singlesocket() => multi_getsock().
1019 */
1020 if(!conn)
1021 return 0;
1022
1023 switch(data->mstate) {
1024 default:
1025 return 0;
1026
1027 case MSTATE_RESOLVING:
1028 return Curl_resolv_getsock(data, socks);
1029
1030 case MSTATE_PROTOCONNECTING:
1031 case MSTATE_PROTOCONNECT:
1032 return protocol_getsock(data, conn, socks);
1033
1034 case MSTATE_DO:
1035 case MSTATE_DOING:
1036 return doing_getsock(data, conn, socks);
1037
1038 case MSTATE_TUNNELING:
1039 return waitproxyconnect_getsock(conn, socks);
1040
1041 case MSTATE_CONNECTING:
1042 return waitconnect_getsock(conn, socks);
1043
1044 case MSTATE_DOING_MORE:
1045 return domore_getsock(data, conn, socks);
1046
1047 case MSTATE_DID: /* since is set after DO is completed, we switch to
1048 waiting for the same as the PERFORMING state */
1049 case MSTATE_PERFORMING:
1050 return Curl_single_getsock(data, conn, socks);
1051 }
1052
1053}
1054
1055CURLMcode curl_multi_fdset(struct Curl_multi *multi,
1056 fd_set *read_fd_set, fd_set *write_fd_set,
1057 fd_set *exc_fd_set, int *max_fd)
1058{
1059 /* Scan through all the easy handles to get the file descriptors set.
1060 Some easy handles may not have connected to the remote host yet,
1061 and then we must make sure that is done. */
1062 struct Curl_easy *data;
1063 int this_max_fd = -1;
1064 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
1065 int i;
1066 (void)exc_fd_set; /* not used */
1067
1068 if(!GOOD_MULTI_HANDLE(multi))
1069 return CURLM_BAD_HANDLE;
1070
1071 if(multi->in_callback)
1072 return CURLM_RECURSIVE_API_CALL;
1073
1074 data = multi->easyp;
1075 while(data) {
1076 int bitmap;
1077#ifdef __clang_analyzer_
1078 /* to prevent "The left operand of '>=' is a garbage value" warnings */
1079 memset(sockbunch, 0, sizeof(sockbunch));
1080#endif
1081 bitmap = multi_getsock(data, sockbunch);
1082
1083 for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
1084 curl_socket_t s = CURL_SOCKET_BAD;
1085
1086 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK(sockbunch[i])) {
1087 if(!FDSET_SOCK(sockbunch[i]))
1088 /* pretend it doesn't exist */
1089 continue;
1090 FD_SET(sockbunch[i], read_fd_set);
1091 s = sockbunch[i];
1092 }
1093 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK(sockbunch[i])) {
1094 if(!FDSET_SOCK(sockbunch[i]))
1095 /* pretend it doesn't exist */
1096 continue;
1097 FD_SET(sockbunch[i], write_fd_set);
1098 s = sockbunch[i];
1099 }
1100 if(s == CURL_SOCKET_BAD)
1101 /* this socket is unused, break out of loop */
1102 break;
1103 if((int)s > this_max_fd)
1104 this_max_fd = (int)s;
1105 }
1106
1107 data = data->next; /* check next handle */
1108 }
1109
1110 *max_fd = this_max_fd;
1111
1112 return CURLM_OK;
1113}
1114
1115#define NUM_POLLS_ON_STACK 10
1116
1117static CURLMcode multi_wait(struct Curl_multi *multi,
1118 struct curl_waitfd extra_fds[],
1119 unsigned int extra_nfds,
1120 int timeout_ms,
1121 int *ret,
1122 bool extrawait, /* when no socket, wait */
1123 bool use_wakeup)
1124{
1125 struct Curl_easy *data;
1126 curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
1127 int bitmap;
1128 unsigned int i;
1129 unsigned int nfds = 0;
1130 unsigned int curlfds;
1131 long timeout_internal;
1132 int retcode = 0;
1133 struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
1134 struct pollfd *ufds = &a_few_on_stack[0];
1135 bool ufds_malloc = FALSE;
1136#ifdef USE_WINSOCK
1137 WSANETWORKEVENTS wsa_events;
1138 DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
1139#endif
1140#ifndef ENABLE_WAKEUP
1141 (void)use_wakeup;
1142#endif
1143
1144 if(!GOOD_MULTI_HANDLE(multi))
1145 return CURLM_BAD_HANDLE;
1146
1147 if(multi->in_callback)
1148 return CURLM_RECURSIVE_API_CALL;
1149
1150 if(timeout_ms < 0)
1151 return CURLM_BAD_FUNCTION_ARGUMENT;
1152
1153 /* Count up how many fds we have from the multi handle */
1154 data = multi->easyp;
1155 while(data) {
1156 bitmap = multi_getsock(data, sockbunch);
1157
1158 for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
1159 curl_socket_t s = CURL_SOCKET_BAD;
1160
1161 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
1162 ++nfds;
1163 s = sockbunch[i];
1164 }
1165 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
1166 ++nfds;
1167 s = sockbunch[i];
1168 }
1169 if(s == CURL_SOCKET_BAD) {
1170 break;
1171 }
1172 }
1173
1174 data = data->next; /* check next handle */
1175 }
1176
1177 /* If the internally desired timeout is actually shorter than requested from
1178 the outside, then use the shorter time! But only if the internal timer
1179 is actually larger than -1! */
1180 (void)multi_timeout(multi, &timeout_internal);
1181 if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
1182 timeout_ms = (int)timeout_internal;
1183
1184 curlfds = nfds; /* number of internal file descriptors */
1185 nfds += extra_nfds; /* add the externally provided ones */
1186
1187#ifdef ENABLE_WAKEUP
1188#ifdef USE_WINSOCK
1189 if(use_wakeup) {
1190#else
1191 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1192#endif
1193 ++nfds;
1194 }
1195#endif
1196
1197 if(nfds > NUM_POLLS_ON_STACK) {
1198 /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
1199 big, so at 2^29 sockets this value might wrap. When a process gets
1200 the capability to actually handle over 500 million sockets this
1201 calculation needs a integer overflow check. */
1202 ufds = malloc(nfds * sizeof(struct pollfd));
1203 if(!ufds)
1204 return CURLM_OUT_OF_MEMORY;
1205 ufds_malloc = TRUE;
1206 }
1207 nfds = 0;
1208
1209 /* only do the second loop if we found descriptors in the first stage run
1210 above */
1211
1212 if(curlfds) {
1213 /* Add the curl handles to our pollfds first */
1214 data = multi->easyp;
1215 while(data) {
1216 bitmap = multi_getsock(data, sockbunch);
1217
1218 for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
1219 curl_socket_t s = CURL_SOCKET_BAD;
1220#ifdef USE_WINSOCK
1221 long mask = 0;
1222#endif
1223 if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
1224 s = sockbunch[i];
1225#ifdef USE_WINSOCK
1226 mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
1227#endif
1228 ufds[nfds].fd = s;
1229 ufds[nfds].events = POLLIN;
1230 ++nfds;
1231 }
1232 if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
1233 s = sockbunch[i];
1234#ifdef USE_WINSOCK
1235 mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
1236 send(s, NULL, 0, 0); /* reset FD_WRITE */
1237#endif
1238 ufds[nfds].fd = s;
1239 ufds[nfds].events = POLLOUT;
1240 ++nfds;
1241 }
1242 /* s is only set if either being readable or writable is checked */
1243 if(s == CURL_SOCKET_BAD) {
1244 /* break on entry not checked for being readable or writable */
1245 break;
1246 }
1247#ifdef USE_WINSOCK
1248 if(WSAEventSelect(s, multi->wsa_event, mask) != 0) {
1249 if(ufds_malloc)
1250 free(ufds);
1251 return CURLM_INTERNAL_ERROR;
1252 }
1253#endif
1254 }
1255
1256 data = data->next; /* check next handle */
1257 }
1258 }
1259
1260 /* Add external file descriptions from poll-like struct curl_waitfd */
1261 for(i = 0; i < extra_nfds; i++) {
1262#ifdef USE_WINSOCK
1263 long mask = 0;
1264 if(extra_fds[i].events & CURL_WAIT_POLLIN)
1265 mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
1266 if(extra_fds[i].events & CURL_WAIT_POLLPRI)
1267 mask |= FD_OOB;
1268 if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
1269 mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
1270 send(extra_fds[i].fd, NULL, 0, 0); /* reset FD_WRITE */
1271 }
1272 if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
1273 if(ufds_malloc)
1274 free(ufds);
1275 return CURLM_INTERNAL_ERROR;
1276 }
1277#endif
1278 ufds[nfds].fd = extra_fds[i].fd;
1279 ufds[nfds].events = 0;
1280 if(extra_fds[i].events & CURL_WAIT_POLLIN)
1281 ufds[nfds].events |= POLLIN;
1282 if(extra_fds[i].events & CURL_WAIT_POLLPRI)
1283 ufds[nfds].events |= POLLPRI;
1284 if(extra_fds[i].events & CURL_WAIT_POLLOUT)
1285 ufds[nfds].events |= POLLOUT;
1286 ++nfds;
1287 }
1288
1289#ifdef ENABLE_WAKEUP
1290#ifndef USE_WINSOCK
1291 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1292 ufds[nfds].fd = multi->wakeup_pair[0];
1293 ufds[nfds].events = POLLIN;
1294 ++nfds;
1295 }
1296#endif
1297#endif
1298
1299#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
1300 if(nfds || use_wakeup) {
1301#else
1302 if(nfds) {
1303#endif
1304 int pollrc;
1305#ifdef USE_WINSOCK
1306 if(nfds)
1307 pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
1308 else
1309 pollrc = 0;
1310 if(pollrc <= 0) /* now wait... if not ready during the pre-check above */
1311 WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
1312#else
1313 pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
1314#endif
1315
1316 if(pollrc > 0) {
1317 retcode = pollrc;
1318#ifdef USE_WINSOCK
1319 }
1320 /* With WinSock, we have to run the following section unconditionally
1321 to call WSAEventSelect(fd, event, 0) on all the sockets */
1322 {
1323#endif
1324 /* copy revents results from the poll to the curl_multi_wait poll
1325 struct, the bit values of the actual underlying poll() implementation
1326 may not be the same as the ones in the public libcurl API! */
1327 for(i = 0; i < extra_nfds; i++) {
1328 unsigned r = ufds[curlfds + i].revents;
1329 unsigned short mask = 0;
1330#ifdef USE_WINSOCK
1331 wsa_events.lNetworkEvents = 0;
1332 if(WSAEnumNetworkEvents(extra_fds[i].fd, NULL, &wsa_events) == 0) {
1333 if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
1334 mask |= CURL_WAIT_POLLIN;
1335 if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
1336 mask |= CURL_WAIT_POLLOUT;
1337 if(wsa_events.lNetworkEvents & FD_OOB)
1338 mask |= CURL_WAIT_POLLPRI;
1339 if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
1340 retcode++;
1341 }
1342 WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0);
1343 if(pollrc <= 0)
1344 continue;
1345#endif
1346 if(r & POLLIN)
1347 mask |= CURL_WAIT_POLLIN;
1348 if(r & POLLOUT)
1349 mask |= CURL_WAIT_POLLOUT;
1350 if(r & POLLPRI)
1351 mask |= CURL_WAIT_POLLPRI;
1352 extra_fds[i].revents = mask;
1353 }
1354
1355#ifdef USE_WINSOCK
1356 /* Count up all our own sockets that had activity,
1357 and remove them from the event. */
1358 if(curlfds) {
1359 data = multi->easyp;
1360 while(data) {
1361 bitmap = multi_getsock(data, sockbunch);
1362
1363 for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
1364 if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) {
1365 wsa_events.lNetworkEvents = 0;
1366 if(WSAEnumNetworkEvents(sockbunch[i], NULL, &wsa_events) == 0) {
1367 if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
1368 retcode++;
1369 }
1370 WSAEventSelect(sockbunch[i], multi->wsa_event, 0);
1371 }
1372 else {
1373 /* break on entry not checked for being readable or writable */
1374 break;
1375 }
1376 }
1377
1378 data = data->next;
1379 }
1380 }
1381
1382 WSAResetEvent(multi->wsa_event);
1383#else
1384#ifdef ENABLE_WAKEUP
1385 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1386 if(ufds[curlfds + extra_nfds].revents & POLLIN) {
1387 char buf[64];
1388 ssize_t nread;
1389 while(1) {
1390 /* the reading socket is non-blocking, try to read
1391 data from it until it receives an error (except EINTR).
1392 In normal cases it will get EAGAIN or EWOULDBLOCK
1393 when there is no more data, breaking the loop. */
1394 nread = sread(multi->wakeup_pair[0], buf, sizeof(buf));
1395 if(nread <= 0) {
1396 if(nread < 0 && EINTR == SOCKERRNO)
1397 continue;
1398 break;
1399 }
1400 }
1401 /* do not count the wakeup socket into the returned value */
1402 retcode--;
1403 }
1404 }
1405#endif
1406#endif
1407 }
1408 }
1409
1410 if(ufds_malloc)
1411 free(ufds);
1412 if(ret)
1413 *ret = retcode;
1414#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
1415 if(extrawait && !nfds && !use_wakeup) {
1416#else
1417 if(extrawait && !nfds) {
1418#endif
1419 long sleep_ms = 0;
1420
1421 /* Avoid busy-looping when there's nothing particular to wait for */
1422 if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) {
1423 if(sleep_ms > timeout_ms)
1424 sleep_ms = timeout_ms;
1425 /* when there are no easy handles in the multi, this holds a -1
1426 timeout */
1427 else if(sleep_ms < 0)
1428 sleep_ms = timeout_ms;
1429 Curl_wait_ms(sleep_ms);
1430 }
1431 }
1432
1433 return CURLM_OK;
1434}
1435
1436CURLMcode curl_multi_wait(struct Curl_multi *multi,
1437 struct curl_waitfd extra_fds[],
1438 unsigned int extra_nfds,
1439 int timeout_ms,
1440 int *ret)
1441{
1442 return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
1443 FALSE);
1444}
1445
1446CURLMcode curl_multi_poll(struct Curl_multi *multi,
1447 struct curl_waitfd extra_fds[],
1448 unsigned int extra_nfds,
1449 int timeout_ms,
1450 int *ret)
1451{
1452 return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
1453 TRUE);
1454}
1455
1456CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
1457{
1458 /* this function is usually called from another thread,
1459 it has to be careful only to access parts of the
1460 Curl_multi struct that are constant */
1461
1462 /* GOOD_MULTI_HANDLE can be safely called */
1463 if(!GOOD_MULTI_HANDLE(multi))
1464 return CURLM_BAD_HANDLE;
1465
1466#ifdef ENABLE_WAKEUP
1467#ifdef USE_WINSOCK
1468 if(WSASetEvent(multi->wsa_event))
1469 return CURLM_OK;
1470#else
1471 /* the wakeup_pair variable is only written during init and cleanup,
1472 making it safe to access from another thread after the init part
1473 and before cleanup */
1474 if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
1475 char buf[1];
1476 buf[0] = 1;
1477 while(1) {
1478 /* swrite() is not thread-safe in general, because concurrent calls
1479 can have their messages interleaved, but in this case the content
1480 of the messages does not matter, which makes it ok to call.
1481
1482 The write socket is set to non-blocking, this way this function
1483 cannot block, making it safe to call even from the same thread
1484 that will call curl_multi_wait(). If swrite() returns that it
1485 would block, it's considered successful because it means that
1486 previous calls to this function will wake up the poll(). */
1487 if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
1488 int err = SOCKERRNO;
1489 int return_success;
1490#ifdef USE_WINSOCK
1491 return_success = WSAEWOULDBLOCK == err;
1492#else
1493 if(EINTR == err)
1494 continue;
1495 return_success = EWOULDBLOCK == err || EAGAIN == err;
1496#endif
1497 if(!return_success)
1498 return CURLM_WAKEUP_FAILURE;
1499 }
1500 return CURLM_OK;
1501 }
1502 }
1503#endif
1504#endif
1505 return CURLM_WAKEUP_FAILURE;
1506}
1507
1508/*
1509 * multi_ischanged() is called
1510 *
1511 * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND
1512 * => CONNECT action.
1513 *
1514 * Set 'clear' to TRUE to have it also clear the state variable.
1515 */
1516static bool multi_ischanged(struct Curl_multi *multi, bool clear)
1517{
1518 bool retval = multi->recheckstate;
1519 if(clear)
1520 multi->recheckstate = FALSE;
1521 return retval;
1522}
1523
1524CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
1525 struct Curl_easy *data,
1526 struct connectdata *conn)
1527{
1528 CURLMcode rc;
1529
1530 if(multi->in_callback)
1531 return CURLM_RECURSIVE_API_CALL;
1532
1533 rc = curl_multi_add_handle(multi, data);
1534 if(!rc) {
1535 struct SingleRequest *k = &data->req;
1536
1537 /* pass in NULL for 'conn' here since we don't want to init the
1538 connection, only this transfer */
1539 Curl_init_do(data, NULL);
1540
1541 /* take this handle to the perform state right away */
1542 multistate(data, MSTATE_PERFORMING);
1543 Curl_attach_connection(data, conn);
1544 k->keepon |= KEEP_RECV; /* setup to receive! */
1545 }
1546 return rc;
1547}
1548
1549static CURLcode multi_do(struct Curl_easy *data, bool *done)
1550{
1551 CURLcode result = CURLE_OK;
1552 struct connectdata *conn = data->conn;
1553
1554 DEBUGASSERT(conn);
1555 DEBUGASSERT(conn->handler);
1556
1557 if(conn->handler->do_it)
1558 /* generic protocol-specific function pointer set in curl_connect() */
1559 result = conn->handler->do_it(data, done);
1560
1561 return result;
1562}
1563
1564/*
1565 * multi_do_more() is called during the DO_MORE multi state. It is basically a
1566 * second stage DO state which (wrongly) was introduced to support FTP's
1567 * second connection.
1568 *
1569 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
1570 * DOING state there's more work to do!
1571 */
1572
1573static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
1574{
1575 CURLcode result = CURLE_OK;
1576 struct connectdata *conn = data->conn;
1577
1578 *complete = 0;
1579
1580 if(conn->handler->do_more)
1581 result = conn->handler->do_more(data, complete);
1582
1583 return result;
1584}
1585
1586/*
1587 * Check whether a timeout occurred, and handle it if it did
1588 */
1589static bool multi_handle_timeout(struct Curl_easy *data,
1590 struct curltime *now,
1591 bool *stream_error,
1592 CURLcode *result,
1593 bool connect_timeout)
1594{
1595 timediff_t timeout_ms;
1596 timeout_ms = Curl_timeleft(data, now, connect_timeout);
1597
1598 if(timeout_ms < 0) {
1599 /* Handle timed out */
1600 if(data->mstate == MSTATE_RESOLVING)
1601 failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
1602 " milliseconds",
1603 Curl_timediff(*now, data->progress.t_startsingle));
1604 else if(data->mstate == MSTATE_CONNECTING)
1605 failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
1606 " milliseconds",
1607 Curl_timediff(*now, data->progress.t_startsingle));
1608 else {
1609 struct SingleRequest *k = &data->req;
1610 if(k->size != -1) {
1611 failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
1612 " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
1613 CURL_FORMAT_CURL_OFF_T " bytes received",
1614 Curl_timediff(*now, data->progress.t_startsingle),
1615 k->bytecount, k->size);
1616 }
1617 else {
1618 failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
1619 " milliseconds with %" CURL_FORMAT_CURL_OFF_T
1620 " bytes received",
1621 Curl_timediff(*now, data->progress.t_startsingle),
1622 k->bytecount);
1623 }
1624 }
1625
1626 /* Force connection closed if the connection has indeed been used */
1627 if(data->mstate > MSTATE_DO) {
1628 streamclose(data->conn, "Disconnected with pending data");
1629 *stream_error = TRUE;
1630 }
1631 *result = CURLE_OPERATION_TIMEDOUT;
1632 (void)multi_done(data, *result, TRUE);
1633 }
1634
1635 return (timeout_ms < 0);
1636}
1637
1638/*
1639 * We are doing protocol-specific connecting and this is being called over and
1640 * over from the multi interface until the connection phase is done on
1641 * protocol layer.
1642 */
1643
1644static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
1645{
1646 CURLcode result = CURLE_OK;
1647 struct connectdata *conn = data->conn;
1648
1649 if(conn && conn->handler->connecting) {
1650 *done = FALSE;
1651 result = conn->handler->connecting(data, done);
1652 }
1653 else
1654 *done = TRUE;
1655
1656 return result;
1657}
1658
1659/*
1660 * We are DOING this is being called over and over from the multi interface
1661 * until the DOING phase is done on protocol layer.
1662 */
1663
1664static CURLcode protocol_doing(struct Curl_easy *data, bool *done)
1665{
1666 CURLcode result = CURLE_OK;
1667 struct connectdata *conn = data->conn;
1668
1669 if(conn && conn->handler->doing) {
1670 *done = FALSE;
1671 result = conn->handler->doing(data, done);
1672 }
1673 else
1674 *done = TRUE;
1675
1676 return result;
1677}
1678
1679/*
1680 * We have discovered that the TCP connection has been successful, we can now
1681 * proceed with some action.
1682 *
1683 */
1684static CURLcode protocol_connect(struct Curl_easy *data,
1685 bool *protocol_done)
1686{
1687 CURLcode result = CURLE_OK;
1688 struct connectdata *conn = data->conn;
1689 DEBUGASSERT(conn);
1690 DEBUGASSERT(protocol_done);
1691
1692 *protocol_done = FALSE;
1693
1694 if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
1695 /* We already are connected, get back. This may happen when the connect
1696 worked fine in the first call, like when we connect to a local server
1697 or proxy. Note that we don't know if the protocol is actually done.
1698
1699 Unless this protocol doesn't have any protocol-connect callback, as
1700 then we know we're done. */
1701 if(!conn->handler->connecting)
1702 *protocol_done = TRUE;
1703
1704 return CURLE_OK;
1705 }
1706
1707 if(!conn->bits.protoconnstart) {
1708#ifndef CURL_DISABLE_PROXY
1709 result = Curl_proxy_connect(data, FIRSTSOCKET);
1710 if(result)
1711 return result;
1712
1713 if(CONNECT_FIRSTSOCKET_PROXY_SSL())
1714 /* wait for HTTPS proxy SSL initialization to complete */
1715 return CURLE_OK;
1716
1717 if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
1718 Curl_connect_ongoing(conn))
1719 /* when using an HTTP tunnel proxy, await complete tunnel establishment
1720 before proceeding further. Return CURLE_OK so we'll be called again */
1721 return CURLE_OK;
1722#endif
1723 if(conn->handler->connect_it) {
1724 /* is there a protocol-specific connect() procedure? */
1725
1726 /* Call the protocol-specific connect function */
1727 result = conn->handler->connect_it(data, protocol_done);
1728 }
1729 else
1730 *protocol_done = TRUE;
1731
1732 /* it has started, possibly even completed but that knowledge isn't stored
1733 in this bit! */
1734 if(!result)
1735 conn->bits.protoconnstart = TRUE;
1736 }
1737
1738 return result; /* pass back status */
1739}
1740
1741/*
1742 * Curl_preconnect() is called immediately before a connect starts. When a
1743 * redirect is followed, this is then called multiple times during a single
1744 * transfer.
1745 */
1746CURLcode Curl_preconnect(struct Curl_easy *data)
1747{
1748 if(!data->state.buffer) {
1749 data->state.buffer = malloc(data->set.buffer_size + 1);
1750 if(!data->state.buffer)
1751 return CURLE_OUT_OF_MEMORY;
1752 }
1753 return CURLE_OK;
1754}
1755
1756static void set_in_callback(struct Curl_multi *multi, bool value)
1757{
1758 multi->in_callback = value;
1759}
1760
1761static CURLMcode multi_runsingle(struct Curl_multi *multi,
1762 struct curltime *nowp,
1763 struct Curl_easy *data)
1764{
1765 struct Curl_message *msg = NULL;
1766 bool connected;
1767 bool async;
1768 bool protocol_connected = FALSE;
1769 bool dophase_done = FALSE;
1770 bool done = FALSE;
1771 CURLMcode rc;
1772 CURLcode result = CURLE_OK;
1773 timediff_t recv_timeout_ms;
1774 timediff_t send_timeout_ms;
1775 int control;
1776
1777 if(!GOOD_EASY_HANDLE(data))
1778 return CURLM_BAD_EASY_HANDLE;
1779
1780 if(multi->dead) {
1781 /* a multi-level callback returned error before, meaning every individual
1782 transfer now has failed */
1783 result = CURLE_ABORTED_BY_CALLBACK;
1784 Curl_posttransfer(data);
1785 multi_done(data, result, FALSE);
1786 multistate(data, MSTATE_COMPLETED);
1787 }
1788
1789 do {
1790 /* A "stream" here is a logical stream if the protocol can handle that
1791 (HTTP/2), or the full connection for older protocols */
1792 bool stream_error = FALSE;
1793 rc = CURLM_OK;
1794
1795 if(multi_ischanged(multi, TRUE)) {
1796 DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue"));
1797 process_pending_handles(multi); /* multiplexed */
1798 }
1799
1800 if(data->mstate > MSTATE_CONNECT &&
1801 data->mstate < MSTATE_COMPLETED) {
1802 /* Make sure we set the connection's current owner */
1803 DEBUGASSERT(data->conn);
1804 if(!data->conn)
1805 return CURLM_INTERNAL_ERROR;
1806 }
1807
1808 if(data->conn &&
1809 (data->mstate >= MSTATE_CONNECT) &&
1810 (data->mstate < MSTATE_COMPLETED)) {
1811 /* Check for overall operation timeout here but defer handling the
1812 * connection timeout to later, to allow for a connection to be set up
1813 * in the window since we last checked timeout. This prevents us
1814 * tearing down a completed connection in the case where we were slow
1815 * to check the timeout (e.g. process descheduled during this loop).
1816 * We set connect_timeout=FALSE to do this. */
1817
1818 /* we need to wait for the connect state as only then is the start time
1819 stored, but we must not check already completed handles */
1820 if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
1821 /* Skip the statemachine and go directly to error handling section. */
1822 goto statemachine_end;
1823 }
1824 }
1825
1826 switch(data->mstate) {
1827 case MSTATE_INIT:
1828 /* init this transfer. */
1829 result = Curl_pretransfer(data);
1830
1831 if(!result) {
1832 /* after init, go CONNECT */
1833 multistate(data, MSTATE_CONNECT);
1834 *nowp = Curl_pgrsTime(data, TIMER_STARTOP);
1835 rc = CURLM_CALL_MULTI_PERFORM;
1836 }
1837 break;
1838
1839 case MSTATE_PENDING:
1840 /* We will stay here until there is a connection available. Then
1841 we try again in the MSTATE_CONNECT state. */
1842 break;
1843
1844 case MSTATE_CONNECT:
1845 /* Connect. We want to get a connection identifier filled in. */
1846 /* init this transfer. */
1847 result = Curl_preconnect(data);
1848 if(result)
1849 break;
1850
1851 *nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
1852 if(data->set.timeout)
1853 Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
1854
1855 if(data->set.connecttimeout)
1856 Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
1857
1858 result = Curl_connect(data, &async, &protocol_connected);
1859 if(CURLE_NO_CONNECTION_AVAILABLE == result) {
1860 /* There was no connection available. We will go to the pending
1861 state and wait for an available connection. */
1862 multistate(data, MSTATE_PENDING);
1863
1864 /* add this handle to the list of connect-pending handles */
1865 Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
1866 &data->connect_queue);
1867 result = CURLE_OK;
1868 break;
1869 }
1870 else if(data->state.previouslypending) {
1871 /* this transfer comes from the pending queue so try move another */
1872 infof(data, "Transfer was pending, now try another");
1873 process_pending_handles(data->multi);
1874 }
1875
1876 if(!result) {
1877 if(async)
1878 /* We're now waiting for an asynchronous name lookup */
1879 multistate(data, MSTATE_RESOLVING);
1880 else {
1881 /* after the connect has been sent off, go WAITCONNECT unless the
1882 protocol connect is already done and we can go directly to
1883 WAITDO or DO! */
1884 rc = CURLM_CALL_MULTI_PERFORM;
1885
1886 if(protocol_connected)
1887 multistate(data, MSTATE_DO);
1888 else {
1889#ifndef CURL_DISABLE_HTTP
1890 if(Curl_connect_ongoing(data->conn))
1891 multistate(data, MSTATE_TUNNELING);
1892 else
1893#endif
1894 multistate(data, MSTATE_CONNECTING);
1895 }
1896 }
1897 }
1898 break;
1899
1900 case MSTATE_RESOLVING:
1901 /* awaiting an asynch name resolve to complete */
1902 {
1903 struct Curl_dns_entry *dns = NULL;
1904 struct connectdata *conn = data->conn;
1905 const char *hostname;
1906
1907 DEBUGASSERT(conn);
1908#ifndef CURL_DISABLE_PROXY
1909 if(conn->bits.httpproxy)
1910 hostname = conn->http_proxy.host.name;
1911 else
1912#endif
1913 if(conn->bits.conn_to_host)
1914 hostname = conn->conn_to_host.name;
1915 else
1916 hostname = conn->host.name;
1917
1918 /* check if we have the name resolved by now */
1919 dns = Curl_fetch_addr(data, hostname, (int)conn->port);
1920
1921 if(dns) {
1922#ifdef CURLRES_ASYNCH
1923 data->state.async.dns = dns;
1924 data->state.async.done = TRUE;
1925#endif
1926 result = CURLE_OK;
1927 infof(data, "Hostname '%s' was found in DNS cache", hostname);
1928 }
1929
1930 if(!dns)
1931 result = Curl_resolv_check(data, &dns);
1932
1933 /* Update sockets here, because the socket(s) may have been
1934 closed and the application thus needs to be told, even if it
1935 is likely that the same socket(s) will again be used further
1936 down. If the name has not yet been resolved, it is likely
1937 that new sockets have been opened in an attempt to contact
1938 another resolver. */
1939 rc = singlesocket(multi, data);
1940 if(rc)
1941 return rc;
1942
1943 if(dns) {
1944 /* Perform the next step in the connection phase, and then move on
1945 to the WAITCONNECT state */
1946 result = Curl_once_resolved(data, &protocol_connected);
1947
1948 if(result)
1949 /* if Curl_once_resolved() returns failure, the connection struct
1950 is already freed and gone */
1951 data->conn = NULL; /* no more connection */
1952 else {
1953 /* call again please so that we get the next socket setup */
1954 rc = CURLM_CALL_MULTI_PERFORM;
1955 if(protocol_connected)
1956 multistate(data, MSTATE_DO);
1957 else {
1958#ifndef CURL_DISABLE_HTTP
1959 if(Curl_connect_ongoing(data->conn))
1960 multistate(data, MSTATE_TUNNELING);
1961 else
1962#endif
1963 multistate(data, MSTATE_CONNECTING);
1964 }
1965 }
1966 }
1967
1968 if(result) {
1969 /* failure detected */
1970 stream_error = TRUE;
1971 break;
1972 }
1973 }
1974 break;
1975
1976#ifndef CURL_DISABLE_HTTP
1977 case MSTATE_TUNNELING:
1978 /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
1979 DEBUGASSERT(data->conn);
1980 result = Curl_http_connect(data, &protocol_connected);
1981#ifndef CURL_DISABLE_PROXY
1982 if(data->conn->bits.proxy_connect_closed) {
1983 rc = CURLM_CALL_MULTI_PERFORM;
1984 /* connect back to proxy again */
1985 result = CURLE_OK;
1986 multi_done(data, CURLE_OK, FALSE);
1987 multistate(data, MSTATE_CONNECT);
1988 }
1989 else
1990#endif
1991 if(!result) {
1992 if(
1993#ifndef CURL_DISABLE_PROXY
1994 (data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
1995 data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
1996#endif
1997 Curl_connect_complete(data->conn)) {
1998 rc = CURLM_CALL_MULTI_PERFORM;
1999 /* initiate protocol connect phase */
2000 multistate(data, MSTATE_PROTOCONNECT);
2001 }
2002 }
2003 else
2004 stream_error = TRUE;
2005 break;
2006#endif
2007
2008 case MSTATE_CONNECTING:
2009 /* awaiting a completion of an asynch TCP connect */
2010 DEBUGASSERT(data->conn);
2011 result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
2012 if(connected && !result) {
2013#ifndef CURL_DISABLE_HTTP
2014 if(
2015#ifndef CURL_DISABLE_PROXY
2016 (data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
2017 !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
2018#endif
2019 Curl_connect_ongoing(data->conn)) {
2020 multistate(data, MSTATE_TUNNELING);
2021 break;
2022 }
2023#endif
2024 rc = CURLM_CALL_MULTI_PERFORM;
2025#ifndef CURL_DISABLE_PROXY
2026 multistate(data,
2027 data->conn->bits.tunnel_proxy?
2028 MSTATE_TUNNELING : MSTATE_PROTOCONNECT);
2029#else
2030 multistate(data, MSTATE_PROTOCONNECT);
2031#endif
2032 }
2033 else if(result) {
2034 /* failure detected */
2035 Curl_posttransfer(data);
2036 multi_done(data, result, TRUE);
2037 stream_error = TRUE;
2038 break;
2039 }
2040 break;
2041
2042 case MSTATE_PROTOCONNECT:
2043 result = protocol_connect(data, &protocol_connected);
2044 if(!result && !protocol_connected)
2045 /* switch to waiting state */
2046 multistate(data, MSTATE_PROTOCONNECTING);
2047 else if(!result) {
2048 /* protocol connect has completed, go WAITDO or DO */
2049 multistate(data, MSTATE_DO);
2050 rc = CURLM_CALL_MULTI_PERFORM;
2051 }
2052 else {
2053 /* failure detected */
2054 Curl_posttransfer(data);
2055 multi_done(data, result, TRUE);
2056 stream_error = TRUE;
2057 }
2058 break;
2059
2060 case MSTATE_PROTOCONNECTING:
2061 /* protocol-specific connect phase */
2062 result = protocol_connecting(data, &protocol_connected);
2063 if(!result && protocol_connected) {
2064 /* after the connect has completed, go WAITDO or DO */
2065 multistate(data, MSTATE_DO);
2066 rc = CURLM_CALL_MULTI_PERFORM;
2067 }
2068 else if(result) {
2069 /* failure detected */
2070 Curl_posttransfer(data);
2071 multi_done(data, result, TRUE);
2072 stream_error = TRUE;
2073 }
2074 break;
2075
2076 case MSTATE_DO:
2077 if(data->set.fprereq) {
2078 int prereq_rc;
2079
2080 /* call the prerequest callback function */
2081 Curl_set_in_callback(data, true);
2082 prereq_rc = data->set.fprereq(data->set.prereq_userp,
2083 data->info.conn_primary_ip,
2084 data->info.conn_local_ip,
2085 data->info.conn_primary_port,
2086 data->info.conn_local_port);
2087 Curl_set_in_callback(data, false);
2088 if(prereq_rc != CURL_PREREQFUNC_OK) {
2089 failf(data, "operation aborted by pre-request callback");
2090 /* failure in pre-request callback - don't do any other processing */
2091 result = CURLE_ABORTED_BY_CALLBACK;
2092 Curl_posttransfer(data);
2093 multi_done(data, result, FALSE);
2094 stream_error = TRUE;
2095 break;
2096 }
2097 }
2098
2099 if(data->set.connect_only) {
2100 /* keep connection open for application to use the socket */
2101 connkeep(data->conn, "CONNECT_ONLY");
2102 multistate(data, MSTATE_DONE);
2103 result = CURLE_OK;
2104 rc = CURLM_CALL_MULTI_PERFORM;
2105 }
2106 else {
2107 /* Perform the protocol's DO action */
2108 result = multi_do(data, &dophase_done);
2109
2110 /* When multi_do() returns failure, data->conn might be NULL! */
2111
2112 if(!result) {
2113 if(!dophase_done) {
2114#ifndef CURL_DISABLE_FTP
2115 /* some steps needed for wildcard matching */
2116 if(data->state.wildcardmatch) {
2117 struct WildcardData *wc = &data->wildcard;
2118 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
2119 /* skip some states if it is important */
2120 multi_done(data, CURLE_OK, FALSE);
2121
2122 /* if there's no connection left, skip the DONE state */
2123 multistate(data, data->conn ?
2124 MSTATE_DONE : MSTATE_COMPLETED);
2125 rc = CURLM_CALL_MULTI_PERFORM;
2126 break;
2127 }
2128 }
2129#endif
2130 /* DO was not completed in one function call, we must continue
2131 DOING... */
2132 multistate(data, MSTATE_DOING);
2133 rc = CURLM_OK;
2134 }
2135
2136 /* after DO, go DO_DONE... or DO_MORE */
2137 else if(data->conn->bits.do_more) {
2138 /* we're supposed to do more, but we need to sit down, relax
2139 and wait a little while first */
2140 multistate(data, MSTATE_DOING_MORE);
2141 rc = CURLM_OK;
2142 }
2143 else {
2144 /* we're done with the DO, now DID */
2145 multistate(data, MSTATE_DID);
2146 rc = CURLM_CALL_MULTI_PERFORM;
2147 }
2148 }
2149 else if((CURLE_SEND_ERROR == result) &&
2150 data->conn->bits.reuse) {
2151 /*
2152 * In this situation, a connection that we were trying to use
2153 * may have unexpectedly died. If possible, send the connection
2154 * back to the CONNECT phase so we can try again.
2155 */
2156 char *newurl = NULL;
2157 followtype follow = FOLLOW_NONE;
2158 CURLcode drc;
2159
2160 drc = Curl_retry_request(data, &newurl);
2161 if(drc) {
2162 /* a failure here pretty much implies an out of memory */
2163 result = drc;
2164 stream_error = TRUE;
2165 }
2166
2167 Curl_posttransfer(data);
2168 drc = multi_done(data, result, FALSE);
2169
2170 /* When set to retry the connection, we must go back to the CONNECT
2171 * state */
2172 if(newurl) {
2173 if(!drc || (drc == CURLE_SEND_ERROR)) {
2174 follow = FOLLOW_RETRY;
2175 drc = Curl_follow(data, newurl, follow);
2176 if(!drc) {
2177 multistate(data, MSTATE_CONNECT);
2178 rc = CURLM_CALL_MULTI_PERFORM;
2179 result = CURLE_OK;
2180 }
2181 else {
2182 /* Follow failed */
2183 result = drc;
2184 }
2185 }
2186 else {
2187 /* done didn't return OK or SEND_ERROR */
2188 result = drc;
2189 }
2190 }
2191 else {
2192 /* Have error handler disconnect conn if we can't retry */
2193 stream_error = TRUE;
2194 }
2195 free(newurl);
2196 }
2197 else {
2198 /* failure detected */
2199 Curl_posttransfer(data);
2200 if(data->conn)
2201 multi_done(data, result, FALSE);
2202 stream_error = TRUE;
2203 }
2204 }
2205 break;
2206
2207 case MSTATE_DOING:
2208 /* we continue DOING until the DO phase is complete */
2209 DEBUGASSERT(data->conn);
2210 result = protocol_doing(data, &dophase_done);
2211 if(!result) {
2212 if(dophase_done) {
2213 /* after DO, go DO_DONE or DO_MORE */
2214 multistate(data, data->conn->bits.do_more?
2215 MSTATE_DOING_MORE : MSTATE_DID);
2216 rc = CURLM_CALL_MULTI_PERFORM;
2217 } /* dophase_done */
2218 }
2219 else {
2220 /* failure detected */
2221 Curl_posttransfer(data);
2222 multi_done(data, result, FALSE);
2223 stream_error = TRUE;
2224 }
2225 break;
2226
2227 case MSTATE_DOING_MORE:
2228 /*
2229 * When we are connected, DOING MORE and then go DID
2230 */
2231 DEBUGASSERT(data->conn);
2232 result = multi_do_more(data, &control);
2233
2234 if(!result) {
2235 if(control) {
2236 /* if positive, advance to DO_DONE
2237 if negative, go back to DOING */
2238 multistate(data, control == 1?
2239 MSTATE_DID : MSTATE_DOING);
2240 rc = CURLM_CALL_MULTI_PERFORM;
2241 }
2242 else
2243 /* stay in DO_MORE */
2244 rc = CURLM_OK;
2245 }
2246 else {
2247 /* failure detected */
2248 Curl_posttransfer(data);
2249 multi_done(data, result, FALSE);
2250 stream_error = TRUE;
2251 }
2252 break;
2253
2254 case MSTATE_DID:
2255 DEBUGASSERT(data->conn);
2256 if(data->conn->bits.multiplex)
2257 /* Check if we can move pending requests to send pipe */
2258 process_pending_handles(multi); /* multiplexed */
2259
2260 /* Only perform the transfer if there's a good socket to work with.
2261 Having both BAD is a signal to skip immediately to DONE */
2262 if((data->conn->sockfd != CURL_SOCKET_BAD) ||
2263 (data->conn->writesockfd != CURL_SOCKET_BAD))
2264 multistate(data, MSTATE_PERFORMING);
2265 else {
2266#ifndef CURL_DISABLE_FTP
2267 if(data->state.wildcardmatch &&
2268 ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
2269 data->wildcard.state = CURLWC_DONE;
2270 }
2271#endif
2272 multistate(data, MSTATE_DONE);
2273 }
2274 rc = CURLM_CALL_MULTI_PERFORM;
2275 break;
2276
2277 case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
2278 DEBUGASSERT(data->conn);
2279 /* if both rates are within spec, resume transfer */
2280 if(Curl_pgrsUpdate(data))
2281 result = CURLE_ABORTED_BY_CALLBACK;
2282 else
2283 result = Curl_speedcheck(data, *nowp);
2284
2285 if(result) {
2286 if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2287 result != CURLE_HTTP2_STREAM)
2288 streamclose(data->conn, "Transfer returned error");
2289
2290 Curl_posttransfer(data);
2291 multi_done(data, result, TRUE);
2292 }
2293 else {
2294 send_timeout_ms = 0;
2295 if(data->set.max_send_speed)
2296 send_timeout_ms =
2297 Curl_pgrsLimitWaitTime(data->progress.uploaded,
2298 data->progress.ul_limit_size,
2299 data->set.max_send_speed,
2300 data->progress.ul_limit_start,
2301 *nowp);
2302
2303 recv_timeout_ms = 0;
2304 if(data->set.max_recv_speed)
2305 recv_timeout_ms =
2306 Curl_pgrsLimitWaitTime(data->progress.downloaded,
2307 data->progress.dl_limit_size,
2308 data->set.max_recv_speed,
2309 data->progress.dl_limit_start,
2310 *nowp);
2311
2312 if(!send_timeout_ms && !recv_timeout_ms) {
2313 multistate(data, MSTATE_PERFORMING);
2314 Curl_ratelimit(data, *nowp);
2315 }
2316 else if(send_timeout_ms >= recv_timeout_ms)
2317 Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
2318 else
2319 Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
2320 }
2321 break;
2322
2323 case MSTATE_PERFORMING:
2324 {
2325 char *newurl = NULL;
2326 bool retry = FALSE;
2327 bool comeback = FALSE;
2328 DEBUGASSERT(data->state.buffer);
2329 /* check if over send speed */
2330 send_timeout_ms = 0;
2331 if(data->set.max_send_speed)
2332 send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
2333 data->progress.ul_limit_size,
2334 data->set.max_send_speed,
2335 data->progress.ul_limit_start,
2336 *nowp);
2337
2338 /* check if over recv speed */
2339 recv_timeout_ms = 0;
2340 if(data->set.max_recv_speed)
2341 recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
2342 data->progress.dl_limit_size,
2343 data->set.max_recv_speed,
2344 data->progress.dl_limit_start,
2345 *nowp);
2346
2347 if(send_timeout_ms || recv_timeout_ms) {
2348 Curl_ratelimit(data, *nowp);
2349 multistate(data, MSTATE_RATELIMITING);
2350 if(send_timeout_ms >= recv_timeout_ms)
2351 Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
2352 else
2353 Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
2354 break;
2355 }
2356
2357 /* read/write data if it is ready to do so */
2358 result = Curl_readwrite(data->conn, data, &done, &comeback);
2359
2360 if(done || (result == CURLE_RECV_ERROR)) {
2361 /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
2362 * condition and the server closed the re-used connection exactly when
2363 * we wanted to use it, so figure out if that is indeed the case.
2364 */
2365 CURLcode ret = Curl_retry_request(data, &newurl);
2366 if(!ret)
2367 retry = (newurl)?TRUE:FALSE;
2368 else if(!result)
2369 result = ret;
2370
2371 if(retry) {
2372 /* if we are to retry, set the result to OK and consider the
2373 request as done */
2374 result = CURLE_OK;
2375 done = TRUE;
2376 }
2377 }
2378 else if((CURLE_HTTP2_STREAM == result) &&
2379 Curl_h2_http_1_1_error(data)) {
2380 CURLcode ret = Curl_retry_request(data, &newurl);
2381
2382 if(!ret) {
2383 infof(data, "Downgrades to HTTP/1.1");
2384 streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
2385 data->state.httpwant = CURL_HTTP_VERSION_1_1;
2386 /* clear the error message bit too as we ignore the one we got */
2387 data->state.errorbuf = FALSE;
2388 if(!newurl)
2389 /* typically for HTTP_1_1_REQUIRED error on first flight */
2390 newurl = strdup(data->state.url);
2391 /* if we are to retry, set the result to OK and consider the request
2392 as done */
2393 retry = TRUE;
2394 result = CURLE_OK;
2395 done = TRUE;
2396 }
2397 else
2398 result = ret;
2399 }
2400
2401 if(result) {
2402 /*
2403 * The transfer phase returned error, we mark the connection to get
2404 * closed to prevent being re-used. This is because we can't possibly
2405 * know if the connection is in a good shape or not now. Unless it is
2406 * a protocol which uses two "channels" like FTP, as then the error
2407 * happened in the data connection.
2408 */
2409
2410 if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2411 result != CURLE_HTTP2_STREAM)
2412 streamclose(data->conn, "Transfer returned error");
2413
2414 Curl_posttransfer(data);
2415 multi_done(data, result, TRUE);
2416 }
2417 else if(done) {
2418
2419 /* call this even if the readwrite function returned error */
2420 Curl_posttransfer(data);
2421
2422 /* When we follow redirects or is set to retry the connection, we must
2423 to go back to the CONNECT state */
2424 if(data->req.newurl || retry) {
2425 followtype follow = FOLLOW_NONE;
2426 if(!retry) {
2427 /* if the URL is a follow-location and not just a retried request
2428 then figure out the URL here */
2429 free(newurl);
2430 newurl = data->req.newurl;
2431 data->req.newurl = NULL;
2432 follow = FOLLOW_REDIR;
2433 }
2434 else
2435 follow = FOLLOW_RETRY;
2436 (void)multi_done(data, CURLE_OK, FALSE);
2437 /* multi_done() might return CURLE_GOT_NOTHING */
2438 result = Curl_follow(data, newurl, follow);
2439 if(!result) {
2440 multistate(data, MSTATE_CONNECT);
2441 rc = CURLM_CALL_MULTI_PERFORM;
2442 }
2443 free(newurl);
2444 }
2445 else {
2446 /* after the transfer is done, go DONE */
2447
2448 /* but first check to see if we got a location info even though we're
2449 not following redirects */
2450 if(data->req.location) {
2451 free(newurl);
2452 newurl = data->req.location;
2453 data->req.location = NULL;
2454 result = Curl_follow(data, newurl, FOLLOW_FAKE);
2455 free(newurl);
2456 if(result) {
2457 stream_error = TRUE;
2458 result = multi_done(data, result, TRUE);
2459 }
2460 }
2461
2462 if(!result) {
2463 multistate(data, MSTATE_DONE);
2464 rc = CURLM_CALL_MULTI_PERFORM;
2465 }
2466 }
2467 }
2468 else if(comeback) {
2469 /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
2470 won't get stuck on this transfer at the expense of other concurrent
2471 transfers */
2472 Curl_expire(data, 0, EXPIRE_RUN_NOW);
2473 rc = CURLM_OK;
2474 }
2475 break;
2476 }
2477
2478 case MSTATE_DONE:
2479 /* this state is highly transient, so run another loop after this */
2480 rc = CURLM_CALL_MULTI_PERFORM;
2481
2482 if(data->conn) {
2483 CURLcode res;
2484
2485 if(data->conn->bits.multiplex)
2486 /* Check if we can move pending requests to connection */
2487 process_pending_handles(multi); /* multiplexing */
2488
2489 /* post-transfer command */
2490 res = multi_done(data, result, FALSE);
2491
2492 /* allow a previously set error code take precedence */
2493 if(!result)
2494 result = res;
2495 }
2496
2497#ifndef CURL_DISABLE_FTP
2498 if(data->state.wildcardmatch) {
2499 if(data->wildcard.state != CURLWC_DONE) {
2500 /* if a wildcard is set and we are not ending -> lets start again
2501 with MSTATE_INIT */
2502 multistate(data, MSTATE_INIT);
2503 break;
2504 }
2505 }
2506#endif
2507 /* after we have DONE what we're supposed to do, go COMPLETED, and
2508 it doesn't matter what the multi_done() returned! */
2509 multistate(data, MSTATE_COMPLETED);
2510 break;
2511
2512 case MSTATE_COMPLETED:
2513 break;
2514
2515 case MSTATE_MSGSENT:
2516 data->result = result;
2517 return CURLM_OK; /* do nothing */
2518
2519 default:
2520 return CURLM_INTERNAL_ERROR;
2521 }
2522
2523 if(data->conn &&
2524 data->mstate >= MSTATE_CONNECT &&
2525 data->mstate < MSTATE_DO &&
2526 rc != CURLM_CALL_MULTI_PERFORM &&
2527 !multi_ischanged(multi, false)) {
2528 /* We now handle stream timeouts if and only if this will be the last
2529 * loop iteration. We only check this on the last iteration to ensure
2530 * that if we know we have additional work to do immediately
2531 * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
2532 * declaring the connection timed out as we may almost have a completed
2533 * connection. */
2534 multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
2535 }
2536
2537 statemachine_end:
2538
2539 if(data->mstate < MSTATE_COMPLETED) {
2540 if(result) {
2541 /*
2542 * If an error was returned, and we aren't in completed state now,
2543 * then we go to completed and consider this transfer aborted.
2544 */
2545
2546 /* NOTE: no attempt to disconnect connections must be made
2547 in the case blocks above - cleanup happens only here */
2548
2549 /* Check if we can move pending requests to send pipe */
2550 process_pending_handles(multi); /* connection */
2551
2552 if(data->conn) {
2553 if(stream_error) {
2554 /* Don't attempt to send data over a connection that timed out */
2555 bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
2556 struct connectdata *conn = data->conn;
2557
2558 /* This is where we make sure that the conn pointer is reset.
2559 We don't have to do this in every case block above where a
2560 failure is detected */
2561 Curl_detach_connection(data);
2562
2563 /* remove connection from cache */
2564 Curl_conncache_remove_conn(data, conn, TRUE);
2565
2566 /* disconnect properly */
2567 Curl_disconnect(data, conn, dead_connection);
2568 }
2569 }
2570 else if(data->mstate == MSTATE_CONNECT) {
2571 /* Curl_connect() failed */
2572 (void)Curl_posttransfer(data);
2573 }
2574
2575 multistate(data, MSTATE_COMPLETED);
2576 rc = CURLM_CALL_MULTI_PERFORM;
2577 }
2578 /* if there's still a connection to use, call the progress function */
2579 else if(data->conn && Curl_pgrsUpdate(data)) {
2580 /* aborted due to progress callback return code must close the
2581 connection */
2582 result = CURLE_ABORTED_BY_CALLBACK;
2583 streamclose(data->conn, "Aborted by callback");
2584
2585 /* if not yet in DONE state, go there, otherwise COMPLETED */
2586 multistate(data, (data->mstate < MSTATE_DONE)?
2587 MSTATE_DONE: MSTATE_COMPLETED);
2588 rc = CURLM_CALL_MULTI_PERFORM;
2589 }
2590 }
2591
2592 if(MSTATE_COMPLETED == data->mstate) {
2593 if(data->set.fmultidone) {
2594 /* signal via callback instead */
2595 data->set.fmultidone(data, result);
2596 }
2597 else {
2598 /* now fill in the Curl_message with this info */
2599 msg = &data->msg;
2600
2601 msg->extmsg.msg = CURLMSG_DONE;
2602 msg->extmsg.easy_handle = data;
2603 msg->extmsg.data.result = result;
2604
2605 rc = multi_addmsg(multi, msg);
2606 DEBUGASSERT(!data->conn);
2607 }
2608 multistate(data, MSTATE_MSGSENT);
2609 }
2610 } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
2611
2612 data->result = result;
2613 return rc;
2614}
2615
2616
2617CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
2618{
2619 struct Curl_easy *data;
2620 CURLMcode returncode = CURLM_OK;
2621 struct Curl_tree *t;
2622 struct curltime now = Curl_now();
2623
2624 if(!GOOD_MULTI_HANDLE(multi))
2625 return CURLM_BAD_HANDLE;
2626
2627 if(multi->in_callback)
2628 return CURLM_RECURSIVE_API_CALL;
2629
2630 data = multi->easyp;
2631 while(data) {
2632 CURLMcode result;
2633 SIGPIPE_VARIABLE(pipe_st);
2634
2635 sigpipe_ignore(data, &pipe_st);
2636 result = multi_runsingle(multi, &now, data);
2637 sigpipe_restore(&pipe_st);
2638
2639 if(result)
2640 returncode = result;
2641
2642 data = data->next; /* operate on next handle */
2643 }
2644
2645 /*
2646 * Simply remove all expired timers from the splay since handles are dealt
2647 * with unconditionally by this function and curl_multi_timeout() requires
2648 * that already passed/handled expire times are removed from the splay.
2649 *
2650 * It is important that the 'now' value is set at the entry of this function
2651 * and not for the current time as it may have ticked a little while since
2652 * then and then we risk this loop to remove timers that actually have not
2653 * been handled!
2654 */
2655 do {
2656 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
2657 if(t)
2658 /* the removed may have another timeout in queue */
2659 (void)add_next_timeout(now, multi, t->payload);
2660
2661 } while(t);
2662
2663 *running_handles = multi->num_alive;
2664
2665 if(CURLM_OK >= returncode)
2666 returncode = Curl_update_timer(multi);
2667
2668 return returncode;
2669}
2670
2671CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
2672{
2673 struct Curl_easy *data;
2674 struct Curl_easy *nextdata;
2675
2676 if(GOOD_MULTI_HANDLE(multi)) {
2677 if(multi->in_callback)
2678 return CURLM_RECURSIVE_API_CALL;
2679
2680 multi->magic = 0; /* not good anymore */
2681
2682 /* First remove all remaining easy handles */
2683 data = multi->easyp;
2684 while(data) {
2685 nextdata = data->next;
2686 if(!data->state.done && data->conn)
2687 /* if DONE was never called for this handle */
2688 (void)multi_done(data, CURLE_OK, TRUE);
2689 if(data->dns.hostcachetype == HCACHE_MULTI) {
2690 /* clear out the usage of the shared DNS cache */
2691 Curl_hostcache_clean(data, data->dns.hostcache);
2692 data->dns.hostcache = NULL;
2693 data->dns.hostcachetype = HCACHE_NONE;
2694 }
2695
2696 /* Clear the pointer to the connection cache */
2697 data->state.conn_cache = NULL;
2698 data->multi = NULL; /* clear the association */
2699
2700#ifdef USE_LIBPSL
2701 if(data->psl == &multi->psl)
2702 data->psl = NULL;
2703#endif
2704
2705 data = nextdata;
2706 }
2707
2708 /* Close all the connections in the connection cache */
2709 Curl_conncache_close_all_connections(&multi->conn_cache);
2710
2711 sockhash_destroy(&multi->sockhash);
2712 Curl_conncache_destroy(&multi->conn_cache);
2713 Curl_llist_destroy(&multi->msglist, NULL);
2714 Curl_llist_destroy(&multi->pending, NULL);
2715
2716 Curl_hash_destroy(&multi->hostcache);
2717 Curl_psl_destroy(&multi->psl);
2718
2719#ifdef USE_WINSOCK
2720 WSACloseEvent(multi->wsa_event);
2721#else
2722#ifdef ENABLE_WAKEUP
2723 sclose(multi->wakeup_pair[0]);
2724 sclose(multi->wakeup_pair[1]);
2725#endif
2726#endif
2727 free(multi);
2728
2729 return CURLM_OK;
2730 }
2731 return CURLM_BAD_HANDLE;
2732}
2733
2734/*
2735 * curl_multi_info_read()
2736 *
2737 * This function is the primary way for a multi/multi_socket application to
2738 * figure out if a transfer has ended. We MUST make this function as fast as
2739 * possible as it will be polled frequently and we MUST NOT scan any lists in
2740 * here to figure out things. We must scale fine to thousands of handles and
2741 * beyond. The current design is fully O(1).
2742 */
2743
2744CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
2745{
2746 struct Curl_message *msg;
2747
2748 *msgs_in_queue = 0; /* default to none */
2749
2750 if(GOOD_MULTI_HANDLE(multi) &&
2751 !multi->in_callback &&
2752 Curl_llist_count(&multi->msglist)) {
2753 /* there is one or more messages in the list */
2754 struct Curl_llist_element *e;
2755
2756 /* extract the head of the list to return */
2757 e = multi->msglist.head;
2758
2759 msg = e->ptr;
2760
2761 /* remove the extracted entry */
2762 Curl_llist_remove(&multi->msglist, e, NULL);
2763
2764 *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
2765
2766 return &msg->extmsg;
2767 }
2768 return NULL;
2769}
2770
2771/*
2772 * singlesocket() checks what sockets we deal with and their "action state"
2773 * and if we have a different state in any of those sockets from last time we
2774 * call the callback accordingly.
2775 */
2776static CURLMcode singlesocket(struct Curl_multi *multi,
2777 struct Curl_easy *data)
2778{
2779 curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
2780 int i;
2781 struct Curl_sh_entry *entry;
2782 curl_socket_t s;
2783 int num;
2784 unsigned int curraction;
2785 unsigned char actions[MAX_SOCKSPEREASYHANDLE];
2786 int rc;
2787
2788 for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
2789 socks[i] = CURL_SOCKET_BAD;
2790
2791 /* Fill in the 'current' struct with the state as it is now: what sockets to
2792 supervise and for what actions */
2793 curraction = multi_getsock(data, socks);
2794
2795 /* We have 0 .. N sockets already and we get to know about the 0 .. M
2796 sockets we should have from now on. Detect the differences, remove no
2797 longer supervised ones and add new ones */
2798
2799 /* walk over the sockets we got right now */
2800 for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
2801 (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
2802 i++) {
2803 unsigned char action = CURL_POLL_NONE;
2804 unsigned char prevaction = 0;
2805 int comboaction;
2806 bool sincebefore = FALSE;
2807
2808 s = socks[i];
2809
2810 /* get it from the hash */
2811 entry = sh_getentry(&multi->sockhash, s);
2812
2813 if(curraction & GETSOCK_READSOCK(i))
2814 action |= CURL_POLL_IN;
2815 if(curraction & GETSOCK_WRITESOCK(i))
2816 action |= CURL_POLL_OUT;
2817
2818 actions[i] = action;
2819 if(entry) {
2820 /* check if new for this transfer */
2821 int j;
2822 for(j = 0; j< data->numsocks; j++) {
2823 if(s == data->sockets[j]) {
2824 prevaction = data->actions[j];
2825 sincebefore = TRUE;
2826 break;
2827 }
2828 }
2829 }
2830 else {
2831 /* this is a socket we didn't have before, add it to the hash! */
2832 entry = sh_addentry(&multi->sockhash, s);
2833 if(!entry)
2834 /* fatal */
2835 return CURLM_OUT_OF_MEMORY;
2836 }
2837 if(sincebefore && (prevaction != action)) {
2838 /* Socket was used already, but different action now */
2839 if(prevaction & CURL_POLL_IN)
2840 entry->readers--;
2841 if(prevaction & CURL_POLL_OUT)
2842 entry->writers--;
2843 if(action & CURL_POLL_IN)
2844 entry->readers++;
2845 if(action & CURL_POLL_OUT)
2846 entry->writers++;
2847 }
2848 else if(!sincebefore) {
2849 /* a new user */
2850 entry->users++;
2851 if(action & CURL_POLL_IN)
2852 entry->readers++;
2853 if(action & CURL_POLL_OUT)
2854 entry->writers++;
2855
2856 /* add 'data' to the transfer hash on this socket! */
2857 if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
2858 sizeof(struct Curl_easy *), data)) {
2859 Curl_hash_destroy(&entry->transfers);
2860 return CURLM_OUT_OF_MEMORY;
2861 }
2862 }
2863
2864 comboaction = (entry->writers? CURL_POLL_OUT : 0) |
2865 (entry->readers ? CURL_POLL_IN : 0);
2866
2867 /* socket existed before and has the same action set as before */
2868 if(sincebefore && ((int)entry->action == comboaction))
2869 /* same, continue */
2870 continue;
2871
2872 if(multi->socket_cb) {
2873 set_in_callback(multi, TRUE);
2874 rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
2875 entry->socketp);
2876 set_in_callback(multi, FALSE);
2877 if(rc == -1) {
2878 multi->dead = TRUE;
2879 return CURLM_ABORTED_BY_CALLBACK;
2880 }
2881 }
2882
2883 entry->action = comboaction; /* store the current action state */
2884 }
2885
2886 num = i; /* number of sockets */
2887
2888 /* when we've walked over all the sockets we should have right now, we must
2889 make sure to detect sockets that are removed */
2890 for(i = 0; i< data->numsocks; i++) {
2891 int j;
2892 bool stillused = FALSE;
2893 s = data->sockets[i];
2894 for(j = 0; j < num; j++) {
2895 if(s == socks[j]) {
2896 /* this is still supervised */
2897 stillused = TRUE;
2898 break;
2899 }
2900 }
2901 if(stillused)
2902 continue;
2903
2904 entry = sh_getentry(&multi->sockhash, s);
2905 /* if this is NULL here, the socket has been closed and notified so
2906 already by Curl_multi_closed() */
2907 if(entry) {
2908 unsigned char oldactions = data->actions[i];
2909 /* this socket has been removed. Decrease user count */
2910 entry->users--;
2911 if(oldactions & CURL_POLL_OUT)
2912 entry->writers--;
2913 if(oldactions & CURL_POLL_IN)
2914 entry->readers--;
2915 if(!entry->users) {
2916 if(multi->socket_cb) {
2917 set_in_callback(multi, TRUE);
2918 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
2919 multi->socket_userp, entry->socketp);
2920 set_in_callback(multi, FALSE);
2921 if(rc == -1) {
2922 multi->dead = TRUE;
2923 return CURLM_ABORTED_BY_CALLBACK;
2924 }
2925 }
2926 sh_delentry(entry, &multi->sockhash, s);
2927 }
2928 else {
2929 /* still users, but remove this handle as a user of this socket */
2930 if(Curl_hash_delete(&entry->transfers, (char *)&data,
2931 sizeof(struct Curl_easy *))) {
2932 DEBUGASSERT(NULL);
2933 }
2934 }
2935 }
2936 } /* for loop over numsocks */
2937
2938 memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
2939 memcpy(data->actions, actions, num*sizeof(char));
2940 data->numsocks = num;
2941 return CURLM_OK;
2942}
2943
2944CURLcode Curl_updatesocket(struct Curl_easy *data)
2945{
2946 if(singlesocket(data->multi, data))
2947 return CURLE_ABORTED_BY_CALLBACK;
2948 return CURLE_OK;
2949}
2950
2951
2952/*
2953 * Curl_multi_closed()
2954 *
2955 * Used by the connect code to tell the multi_socket code that one of the
2956 * sockets we were using is about to be closed. This function will then
2957 * remove it from the sockethash for this handle to make the multi_socket API
2958 * behave properly, especially for the case when libcurl will create another
2959 * socket again and it gets the same file descriptor number.
2960 */
2961
2962void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
2963{
2964 if(data) {
2965 /* if there's still an easy handle associated with this connection */
2966 struct Curl_multi *multi = data->multi;
2967 if(multi) {
2968 /* this is set if this connection is part of a handle that is added to
2969 a multi handle, and only then this is necessary */
2970 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
2971
2972 if(entry) {
2973 int rc = 0;
2974 if(multi->socket_cb) {
2975 set_in_callback(multi, TRUE);
2976 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
2977 multi->socket_userp, entry->socketp);
2978 set_in_callback(multi, FALSE);
2979 }
2980
2981 /* now remove it from the socket hash */
2982 sh_delentry(entry, &multi->sockhash, s);
2983 if(rc == -1)
2984 /* This just marks the multi handle as "dead" without returning an
2985 error code primarily because this function is used from many
2986 places where propagating an error back is tricky. */
2987 multi->dead = TRUE;
2988 }
2989 }
2990 }
2991}
2992
2993/*
2994 * add_next_timeout()
2995 *
2996 * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
2997 * when it has just been removed from the splay tree because the timeout has
2998 * expired. This function is then to advance in the list to pick the next
2999 * timeout to use (skip the already expired ones) and add this node back to
3000 * the splay tree again.
3001 *
3002 * The splay tree only has each sessionhandle as a single node and the nearest
3003 * timeout is used to sort it on.
3004 */
3005static CURLMcode add_next_timeout(struct curltime now,
3006 struct Curl_multi *multi,
3007 struct Curl_easy *d)
3008{
3009 struct curltime *tv = &d->state.expiretime;
3010 struct Curl_llist *list = &d->state.timeoutlist;
3011 struct Curl_llist_element *e;
3012 struct time_node *node = NULL;
3013
3014 /* move over the timeout list for this specific handle and remove all
3015 timeouts that are now passed tense and store the next pending
3016 timeout in *tv */
3017 for(e = list->head; e;) {
3018 struct Curl_llist_element *n = e->next;
3019 timediff_t diff;
3020 node = (struct time_node *)e->ptr;
3021 diff = Curl_timediff(node->time, now);
3022 if(diff <= 0)
3023 /* remove outdated entry */
3024 Curl_llist_remove(list, e, NULL);
3025 else
3026 /* the list is sorted so get out on the first mismatch */
3027 break;
3028 e = n;
3029 }
3030 e = list->head;
3031 if(!e) {
3032 /* clear the expire times within the handles that we remove from the
3033 splay tree */
3034 tv->tv_sec = 0;
3035 tv->tv_usec = 0;
3036 }
3037 else {
3038 /* copy the first entry to 'tv' */
3039 memcpy(tv, &node->time, sizeof(*tv));
3040
3041 /* Insert this node again into the splay. Keep the timer in the list in
3042 case we need to recompute future timers. */
3043 multi->timetree = Curl_splayinsert(*tv, multi->timetree,
3044 &d->state.timenode);
3045 }
3046 return CURLM_OK;
3047}
3048
3049static CURLMcode multi_socket(struct Curl_multi *multi,
3050 bool checkall,
3051 curl_socket_t s,
3052 int ev_bitmask,
3053 int *running_handles)
3054{
3055 CURLMcode result = CURLM_OK;
3056 struct Curl_easy *data = NULL;
3057 struct Curl_tree *t;
3058 struct curltime now = Curl_now();
3059
3060 if(checkall) {
3061 /* *perform() deals with running_handles on its own */
3062 result = curl_multi_perform(multi, running_handles);
3063
3064 /* walk through each easy handle and do the socket state change magic
3065 and callbacks */
3066 if(result != CURLM_BAD_HANDLE) {
3067 data = multi->easyp;
3068 while(data && !result) {
3069 result = singlesocket(multi, data);
3070 data = data->next;
3071 }
3072 }
3073
3074 /* or should we fall-through and do the timer-based stuff? */
3075 return result;
3076 }
3077 if(s != CURL_SOCKET_TIMEOUT) {
3078 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
3079
3080 if(!entry)
3081 /* Unmatched socket, we can't act on it but we ignore this fact. In
3082 real-world tests it has been proved that libevent can in fact give
3083 the application actions even though the socket was just previously
3084 asked to get removed, so thus we better survive stray socket actions
3085 and just move on. */
3086 ;
3087 else {
3088 struct Curl_hash_iterator iter;
3089 struct Curl_hash_element *he;
3090
3091 /* the socket can be shared by many transfers, iterate */
3092 Curl_hash_start_iterate(&entry->transfers, &iter);
3093 for(he = Curl_hash_next_element(&iter); he;
3094 he = Curl_hash_next_element(&iter)) {
3095 data = (struct Curl_easy *)he->ptr;
3096 DEBUGASSERT(data);
3097 DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
3098
3099 if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
3100 /* set socket event bitmask if they're not locked */
3101 data->conn->cselect_bits = ev_bitmask;
3102
3103 Curl_expire(data, 0, EXPIRE_RUN_NOW);
3104 }
3105
3106 /* Now we fall-through and do the timer-based stuff, since we don't want
3107 to force the user to have to deal with timeouts as long as at least
3108 one connection in fact has traffic. */
3109
3110 data = NULL; /* set data to NULL again to avoid calling
3111 multi_runsingle() in case there's no need to */
3112 now = Curl_now(); /* get a newer time since the multi_runsingle() loop
3113 may have taken some time */
3114 }
3115 }
3116 else {
3117 /* Asked to run due to time-out. Clear the 'lastcall' variable to force
3118 Curl_update_timer() to trigger a callback to the app again even if the
3119 same timeout is still the one to run after this call. That handles the
3120 case when the application asks libcurl to run the timeout
3121 prematurely. */
3122 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
3123 }
3124
3125 /*
3126 * The loop following here will go on as long as there are expire-times left
3127 * to process in the splay and 'data' will be re-assigned for every expired
3128 * handle we deal with.
3129 */
3130 do {
3131 /* the first loop lap 'data' can be NULL */
3132 if(data) {
3133 SIGPIPE_VARIABLE(pipe_st);
3134
3135 sigpipe_ignore(data, &pipe_st);
3136 result = multi_runsingle(multi, &now, data);
3137 sigpipe_restore(&pipe_st);
3138
3139 if(CURLM_OK >= result) {
3140 /* get the socket(s) and check if the state has been changed since
3141 last */
3142 result = singlesocket(multi, data);
3143 if(result)
3144 return result;
3145 }
3146 }
3147
3148 /* Check if there's one (more) expired timer to deal with! This function
3149 extracts a matching node if there is one */
3150
3151 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
3152 if(t) {
3153 data = t->payload; /* assign this for next loop */
3154 (void)add_next_timeout(now, multi, t->payload);
3155 }
3156
3157 } while(t);
3158
3159 *running_handles = multi->num_alive;
3160 return result;
3161}
3162
3163#undef curl_multi_setopt
3164CURLMcode curl_multi_setopt(struct Curl_multi *multi,
3165 CURLMoption option, ...)
3166{
3167 CURLMcode res = CURLM_OK;
3168 va_list param;
3169
3170 if(!GOOD_MULTI_HANDLE(multi))
3171 return CURLM_BAD_HANDLE;
3172
3173 if(multi->in_callback)
3174 return CURLM_RECURSIVE_API_CALL;
3175
3176 va_start(param, option);
3177
3178 switch(option) {
3179 case CURLMOPT_SOCKETFUNCTION:
3180 multi->socket_cb = va_arg(param, curl_socket_callback);
3181 break;
3182 case CURLMOPT_SOCKETDATA:
3183 multi->socket_userp = va_arg(param, void *);
3184 break;
3185 case CURLMOPT_PUSHFUNCTION:
3186 multi->push_cb = va_arg(param, curl_push_callback);
3187 break;
3188 case CURLMOPT_PUSHDATA:
3189 multi->push_userp = va_arg(param, void *);
3190 break;
3191 case CURLMOPT_PIPELINING:
3192 multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX;
3193 break;
3194 case CURLMOPT_TIMERFUNCTION:
3195 multi->timer_cb = va_arg(param, curl_multi_timer_callback);
3196 break;
3197 case CURLMOPT_TIMERDATA:
3198 multi->timer_userp = va_arg(param, void *);
3199 break;
3200 case CURLMOPT_MAXCONNECTS:
3201 multi->maxconnects = va_arg(param, long);
3202 break;
3203 case CURLMOPT_MAX_HOST_CONNECTIONS:
3204 multi->max_host_connections = va_arg(param, long);
3205 break;
3206 case CURLMOPT_MAX_TOTAL_CONNECTIONS:
3207 multi->max_total_connections = va_arg(param, long);
3208 break;
3209 /* options formerly used for pipelining */
3210 case CURLMOPT_MAX_PIPELINE_LENGTH:
3211 break;
3212 case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
3213 break;
3214 case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
3215 break;
3216 case CURLMOPT_PIPELINING_SITE_BL:
3217 break;
3218 case CURLMOPT_PIPELINING_SERVER_BL:
3219 break;
3220 case CURLMOPT_MAX_CONCURRENT_STREAMS:
3221 {
3222 long streams = va_arg(param, long);
3223 if(streams < 1)
3224 streams = 100;
3225 multi->max_concurrent_streams = curlx_sltoui(streams);
3226 }
3227 break;
3228 default:
3229 res = CURLM_UNKNOWN_OPTION;
3230 break;
3231 }
3232 va_end(param);
3233 return res;
3234}
3235
3236/* we define curl_multi_socket() in the public multi.h header */
3237#undef curl_multi_socket
3238
3239CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
3240 int *running_handles)
3241{
3242 CURLMcode result;
3243 if(multi->in_callback)
3244 return CURLM_RECURSIVE_API_CALL;
3245 result = multi_socket(multi, FALSE, s, 0, running_handles);
3246 if(CURLM_OK >= result)
3247 result = Curl_update_timer(multi);
3248 return result;
3249}
3250
3251CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
3252 int ev_bitmask, int *running_handles)
3253{
3254 CURLMcode result;
3255 if(multi->in_callback)
3256 return CURLM_RECURSIVE_API_CALL;
3257 result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
3258 if(CURLM_OK >= result)
3259 result = Curl_update_timer(multi);
3260 return result;
3261}
3262
3263CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
3264{
3265 CURLMcode result;
3266 if(multi->in_callback)
3267 return CURLM_RECURSIVE_API_CALL;
3268 result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
3269 if(CURLM_OK >= result)
3270 result = Curl_update_timer(multi);
3271 return result;
3272}
3273
3274static CURLMcode multi_timeout(struct Curl_multi *multi,
3275 long *timeout_ms)
3276{
3277 static const struct curltime tv_zero = {0, 0};
3278
3279 if(multi->dead) {
3280 *timeout_ms = 0;
3281 return CURLM_OK;
3282 }
3283
3284 if(multi->timetree) {
3285 /* we have a tree of expire times */
3286 struct curltime now = Curl_now();
3287
3288 /* splay the lowest to the bottom */
3289 multi->timetree = Curl_splay(tv_zero, multi->timetree);
3290
3291 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
3292 /* some time left before expiration */
3293 timediff_t diff = Curl_timediff(multi->timetree->key, now);
3294 if(diff <= 0)
3295 /*
3296 * Since we only provide millisecond resolution on the returned value
3297 * and the diff might be less than one millisecond here, we don't
3298 * return zero as that may cause short bursts of busyloops on fast
3299 * processors while the diff is still present but less than one
3300 * millisecond! instead we return 1 until the time is ripe.
3301 */
3302 *timeout_ms = 1;
3303 else
3304 /* this should be safe even on 64 bit archs, as we don't use that
3305 overly long timeouts */
3306 *timeout_ms = (long)diff;
3307 }
3308 else
3309 /* 0 means immediately */
3310 *timeout_ms = 0;
3311 }
3312 else
3313 *timeout_ms = -1;
3314
3315 return CURLM_OK;
3316}
3317
3318CURLMcode curl_multi_timeout(struct Curl_multi *multi,
3319 long *timeout_ms)
3320{
3321 /* First, make some basic checks that the CURLM handle is a good handle */
3322 if(!GOOD_MULTI_HANDLE(multi))
3323 return CURLM_BAD_HANDLE;
3324
3325 if(multi->in_callback)
3326 return CURLM_RECURSIVE_API_CALL;
3327
3328 return multi_timeout(multi, timeout_ms);
3329}
3330
3331/*
3332 * Tell the application it should update its timers, if it subscribes to the
3333 * update timer callback.
3334 */
3335CURLMcode Curl_update_timer(struct Curl_multi *multi)
3336{
3337 long timeout_ms;
3338 int rc;
3339
3340 if(!multi->timer_cb || multi->dead)
3341 return CURLM_OK;
3342 if(multi_timeout(multi, &timeout_ms)) {
3343 return CURLM_OK;
3344 }
3345 if(timeout_ms < 0) {
3346 static const struct curltime none = {0, 0};
3347 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
3348 multi->timer_lastcall = none;
3349 /* there's no timeout now but there was one previously, tell the app to
3350 disable it */
3351 set_in_callback(multi, TRUE);
3352 rc = multi->timer_cb(multi, -1, multi->timer_userp);
3353 set_in_callback(multi, FALSE);
3354 if(rc == -1) {
3355 multi->dead = TRUE;
3356 return CURLM_ABORTED_BY_CALLBACK;
3357 }
3358 return CURLM_OK;
3359 }
3360 return CURLM_OK;
3361 }
3362
3363 /* When multi_timeout() is done, multi->timetree points to the node with the
3364 * timeout we got the (relative) time-out time for. We can thus easily check
3365 * if this is the same (fixed) time as we got in a previous call and then
3366 * avoid calling the callback again. */
3367 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
3368 return CURLM_OK;
3369
3370 multi->timer_lastcall = multi->timetree->key;
3371
3372 set_in_callback(multi, TRUE);
3373 rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
3374 set_in_callback(multi, FALSE);
3375 if(rc == -1) {
3376 multi->dead = TRUE;
3377 return CURLM_ABORTED_BY_CALLBACK;
3378 }
3379 return CURLM_OK;
3380}
3381
3382/*
3383 * multi_deltimeout()
3384 *
3385 * Remove a given timestamp from the list of timeouts.
3386 */
3387static void
3388multi_deltimeout(struct Curl_easy *data, expire_id eid)
3389{
3390 struct Curl_llist_element *e;
3391 struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3392 /* find and remove the specific node from the list */
3393 for(e = timeoutlist->head; e; e = e->next) {
3394 struct time_node *n = (struct time_node *)e->ptr;
3395 if(n->eid == eid) {
3396 Curl_llist_remove(timeoutlist, e, NULL);
3397 return;
3398 }
3399 }
3400}
3401
3402/*
3403 * multi_addtimeout()
3404 *
3405 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
3406 * of list is always the timeout nearest in time.
3407 *
3408 */
3409static CURLMcode
3410multi_addtimeout(struct Curl_easy *data,
3411 struct curltime *stamp,
3412 expire_id eid)
3413{
3414 struct Curl_llist_element *e;
3415 struct time_node *node;
3416 struct Curl_llist_element *prev = NULL;
3417 size_t n;
3418 struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3419
3420 node = &data->state.expires[eid];
3421
3422 /* copy the timestamp and id */
3423 memcpy(&node->time, stamp, sizeof(*stamp));
3424 node->eid = eid; /* also marks it as in use */
3425
3426 n = Curl_llist_count(timeoutlist);
3427 if(n) {
3428 /* find the correct spot in the list */
3429 for(e = timeoutlist->head; e; e = e->next) {
3430 struct time_node *check = (struct time_node *)e->ptr;
3431 timediff_t diff = Curl_timediff(check->time, node->time);
3432 if(diff > 0)
3433 break;
3434 prev = e;
3435 }
3436
3437 }
3438 /* else
3439 this is the first timeout on the list */
3440
3441 Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
3442 return CURLM_OK;
3443}
3444
3445/*
3446 * Curl_expire()
3447 *
3448 * given a number of milliseconds from now to use to set the 'act before
3449 * this'-time for the transfer, to be extracted by curl_multi_timeout()
3450 *
3451 * The timeout will be added to a queue of timeouts if it defines a moment in
3452 * time that is later than the current head of queue.
3453 *
3454 * Expire replaces a former timeout using the same id if already set.
3455 */
3456void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
3457{
3458 struct Curl_multi *multi = data->multi;
3459 struct curltime *nowp = &data->state.expiretime;
3460 struct curltime set;
3461
3462 /* this is only interesting while there is still an associated multi struct
3463 remaining! */
3464 if(!multi)
3465 return;
3466
3467 DEBUGASSERT(id < EXPIRE_LAST);
3468
3469 set = Curl_now();
3470 set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */
3471 set.tv_usec += (unsigned int)(milli%1000)*1000;
3472
3473 if(set.tv_usec >= 1000000) {
3474 set.tv_sec++;
3475 set.tv_usec -= 1000000;
3476 }
3477
3478 /* Remove any timer with the same id just in case. */
3479 multi_deltimeout(data, id);
3480
3481 /* Add it to the timer list. It must stay in the list until it has expired
3482 in case we need to recompute the minimum timer later. */
3483 multi_addtimeout(data, &set, id);
3484
3485 if(nowp->tv_sec || nowp->tv_usec) {
3486 /* This means that the struct is added as a node in the splay tree.
3487 Compare if the new time is earlier, and only remove-old/add-new if it
3488 is. */
3489 timediff_t diff = Curl_timediff(set, *nowp);
3490 int rc;
3491
3492 if(diff > 0) {
3493 /* The current splay tree entry is sooner than this new expiry time.
3494 We don't need to update our splay tree entry. */
3495 return;
3496 }
3497
3498 /* Since this is an updated time, we must remove the previous entry from
3499 the splay tree first and then re-add the new value */
3500 rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3501 &multi->timetree);
3502 if(rc)
3503 infof(data, "Internal error removing splay node = %d", rc);
3504 }
3505
3506 /* Indicate that we are in the splay tree and insert the new timer expiry
3507 value since it is our local minimum. */
3508 *nowp = set;
3509 data->state.timenode.payload = data;
3510 multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
3511 &data->state.timenode);
3512}
3513
3514/*
3515 * Curl_expire_done()
3516 *
3517 * Removes the expire timer. Marks it as done.
3518 *
3519 */
3520void Curl_expire_done(struct Curl_easy *data, expire_id id)
3521{
3522 /* remove the timer, if there */
3523 multi_deltimeout(data, id);
3524}
3525
3526/*
3527 * Curl_expire_clear()
3528 *
3529 * Clear ALL timeout values for this handle.
3530 */
3531void Curl_expire_clear(struct Curl_easy *data)
3532{
3533 struct Curl_multi *multi = data->multi;
3534 struct curltime *nowp = &data->state.expiretime;
3535
3536 /* this is only interesting while there is still an associated multi struct
3537 remaining! */
3538 if(!multi)
3539 return;
3540
3541 if(nowp->tv_sec || nowp->tv_usec) {
3542 /* Since this is an cleared time, we must remove the previous entry from
3543 the splay tree */
3544 struct Curl_llist *list = &data->state.timeoutlist;
3545 int rc;
3546
3547 rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3548 &multi->timetree);
3549 if(rc)
3550 infof(data, "Internal error clearing splay node = %d", rc);
3551
3552 /* flush the timeout list too */
3553 while(list->size > 0) {
3554 Curl_llist_remove(list, list->tail, NULL);
3555 }
3556
3557#ifdef DEBUGBUILD
3558 infof(data, "Expire cleared (transfer %p)", data);
3559#endif
3560 nowp->tv_sec = 0;
3561 nowp->tv_usec = 0;
3562 }
3563}
3564
3565
3566
3567
3568CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
3569 void *hashp)
3570{
3571 struct Curl_sh_entry *there = NULL;
3572
3573 there = sh_getentry(&multi->sockhash, s);
3574
3575 if(!there)
3576 return CURLM_BAD_SOCKET;
3577
3578 there->socketp = hashp;
3579
3580 return CURLM_OK;
3581}
3582
3583size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
3584{
3585 return multi ? multi->max_host_connections : 0;
3586}
3587
3588size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
3589{
3590 return multi ? multi->max_total_connections : 0;
3591}
3592
3593/*
3594 * When information about a connection has appeared, call this!
3595 */
3596
3597void Curl_multiuse_state(struct Curl_easy *data,
3598 int bundlestate) /* use BUNDLE_* defines */
3599{
3600 struct connectdata *conn;
3601 DEBUGASSERT(data);
3602 DEBUGASSERT(data->multi);
3603 conn = data->conn;
3604 DEBUGASSERT(conn);
3605 DEBUGASSERT(conn->bundle);
3606
3607 conn->bundle->multiuse = bundlestate;
3608 process_pending_handles(data->multi);
3609}
3610
3611static void process_pending_handles(struct Curl_multi *multi)
3612{
3613 struct Curl_llist_element *e = multi->pending.head;
3614 if(e) {
3615 struct Curl_easy *data = e->ptr;
3616
3617 DEBUGASSERT(data->mstate == MSTATE_PENDING);
3618
3619 multistate(data, MSTATE_CONNECT);
3620
3621 /* Remove this node from the list */
3622 Curl_llist_remove(&multi->pending, e, NULL);
3623
3624 /* Make sure that the handle will be processed soonish. */
3625 Curl_expire(data, 0, EXPIRE_RUN_NOW);
3626
3627 /* mark this as having been in the pending queue */
3628 data->state.previouslypending = TRUE;
3629 }
3630}
3631
3632void Curl_set_in_callback(struct Curl_easy *data, bool value)
3633{
3634 /* might get called when there is no data pointer! */
3635 if(data) {
3636 if(data->multi_easy)
3637 data->multi_easy->in_callback = value;
3638 else if(data->multi)
3639 data->multi->in_callback = value;
3640 }
3641}
3642
3643bool Curl_is_in_callback(struct Curl_easy *easy)
3644{
3645 return ((easy->multi && easy->multi->in_callback) ||
3646 (easy->multi_easy && easy->multi_easy->in_callback));
3647}
3648
3649#ifdef DEBUGBUILD
3650void Curl_multi_dump(struct Curl_multi *multi)
3651{
3652 struct Curl_easy *data;
3653 int i;
3654 fprintf(stderr, "* Multi status: %d handles, %d alive\n",
3655 multi->num_easy, multi->num_alive);
3656 for(data = multi->easyp; data; data = data->next) {
3657 if(data->mstate < MSTATE_COMPLETED) {
3658 /* only display handles that are not completed */
3659 fprintf(stderr, "handle %p, state %s, %d sockets\n",
3660 (void *)data,
3661 statename[data->mstate], data->numsocks);
3662 for(i = 0; i < data->numsocks; i++) {
3663 curl_socket_t s = data->sockets[i];
3664 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
3665
3666 fprintf(stderr, "%d ", (int)s);
3667 if(!entry) {
3668 fprintf(stderr, "INTERNAL CONFUSION\n");
3669 continue;
3670 }
3671 fprintf(stderr, "[%s %s] ",
3672 (entry->action&CURL_POLL_IN)?"RECVING":"",
3673 (entry->action&CURL_POLL_OUT)?"SENDING":"");
3674 }
3675 if(data->numsocks)
3676 fprintf(stderr, "\n");
3677 }
3678 }
3679}
3680#endif
3681
3682unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
3683{
3684 DEBUGASSERT(multi);
3685 return multi->max_concurrent_streams;
3686}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette