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