Lines Matching +full:getsockopt +full:- +full:timeouts
21 * SPDX-License-Identifier: curl
60 to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
61 CURL handle takes 45-50 K memory, therefore this 3K are not significant.
82 (((x) && (x)->magic == CURL_MULTI_HANDLE)? TRUE: \
86 ((x) && (x)->magic == CURL_MULTI_HANDLE)
127 data->req.chunk = FALSE; in before_perform()
148 CURLMstate oldstate = data->mstate; in mstate()
177 data->mstate = state; in mstate()
180 if(data->mstate >= MSTATE_PENDING && in mstate()
181 data->mstate < MSTATE_COMPLETED) { in mstate()
184 multi_statename[oldstate], multi_statename[data->mstate], in mstate()
191 DEBUGASSERT(data->multi->num_alive > 0); in mstate()
192 data->multi->num_alive--; in mstate()
193 if(!data->multi->num_alive) { in mstate()
195 multi_xfer_bufs_free(data->multi); in mstate()
199 /* if this state has an init-function, run it */ in mstate()
270 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr; in sockhash_destroy()
271 Curl_hash_destroy(&sh->transfers); in sockhash_destroy()
295 Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare, in sh_addentry()
300 Curl_hash_destroy(&check->transfers); in sh_addentry()
313 Curl_hash_destroy(&entry->transfers); in sh_delentry()
352 * limiting. It simply has a fixed-size array, and on each entry in the array
377 Curl_llist_append(&multi->msglist, msg, &msg->list); in multi_addmsg()
389 multi->magic = CURL_MULTI_HANDLE; in Curl_multi_handle()
391 Curl_init_dnscache(&multi->hostcache, dnssize); in Curl_multi_handle()
393 sh_init(&multi->sockhash, hashsize); in Curl_multi_handle()
395 if(Curl_conncache_init(&multi->conn_cache, chashsize)) in Curl_multi_handle()
398 Curl_llist_init(&multi->msglist, NULL); in Curl_multi_handle()
399 Curl_llist_init(&multi->pending, NULL); in Curl_multi_handle()
400 Curl_llist_init(&multi->msgsent, NULL); in Curl_multi_handle()
402 multi->multiplexing = TRUE; in Curl_multi_handle()
403 multi->max_concurrent_streams = 100; in Curl_multi_handle()
406 multi->wsa_event = WSACreateEvent(); in Curl_multi_handle()
407 if(multi->wsa_event == WSA_INVALID_EVENT) in Curl_multi_handle()
411 if(wakeup_create(multi->wakeup_pair) < 0) { in Curl_multi_handle()
412 multi->wakeup_pair[0] = CURL_SOCKET_BAD; in Curl_multi_handle()
413 multi->wakeup_pair[1] = CURL_SOCKET_BAD; in Curl_multi_handle()
415 else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 || in Curl_multi_handle()
416 curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) { in Curl_multi_handle()
417 wakeup_close(multi->wakeup_pair[0]); in Curl_multi_handle()
418 wakeup_close(multi->wakeup_pair[1]); in Curl_multi_handle()
419 multi->wakeup_pair[0] = CURL_SOCKET_BAD; in Curl_multi_handle()
420 multi->wakeup_pair[1] = CURL_SOCKET_BAD; in Curl_multi_handle()
429 sockhash_destroy(&multi->sockhash); in Curl_multi_handle()
430 Curl_hash_destroy(&multi->hostcache); in Curl_multi_handle()
431 Curl_conncache_destroy(&multi->conn_cache); in Curl_multi_handle()
446 if(!multi->warned) { in multi_warn_debug()
450 multi->warned = true; in multi_warn_debug()
461 return ((data->mstate != MSTATE_PENDING) && in in_main_list()
462 (data->mstate != MSTATE_MSGSENT)); in in_main_list()
469 data->next = NULL; /* end of the line */ in link_easy()
470 if(multi->easyp) { in link_easy()
471 struct Curl_easy *last = multi->easylp; in link_easy()
472 last->next = data; in link_easy()
473 data->prev = last; in link_easy()
474 multi->easylp = data; /* the new last node */ in link_easy()
478 data->prev = NULL; in link_easy()
479 multi->easylp = multi->easyp = data; /* both first and last */ in link_easy()
488 if(data->prev) in unlink_easy()
489 data->prev->next = data->next; in unlink_easy()
491 multi->easyp = data->next; /* point to first node */ in unlink_easy()
494 if(data->next) in unlink_easy()
495 data->next->prev = data->prev; in unlink_easy()
497 multi->easylp = data->prev; /* point to last node */ in unlink_easy()
499 data->prev = data->next = NULL; in unlink_easy()
517 if(data->multi) in curl_multi_add_handle()
520 if(multi->in_callback) in curl_multi_add_handle()
523 if(multi->dead) { in curl_multi_add_handle()
525 handles are still alive - but if there are none alive anymore, it is in curl_multi_add_handle()
527 if(multi->num_alive) in curl_multi_add_handle()
529 multi->dead = FALSE; in curl_multi_add_handle()
532 if(data->multi_easy) { in curl_multi_add_handle()
535 curl_multi_cleanup(data->multi_easy); in curl_multi_add_handle()
536 data->multi_easy = NULL; in curl_multi_add_handle()
540 Curl_llist_init(&data->state.timeoutlist, NULL); in curl_multi_add_handle()
548 if(data->set.errorbuffer) in curl_multi_add_handle()
549 data->set.errorbuffer[0] = 0; in curl_multi_add_handle()
551 data->state.os_errno = 0; in curl_multi_add_handle()
553 /* make the Curl_easy refer back to this multi handle - before Curl_expire() in curl_multi_add_handle()
555 data->multi = multi; in curl_multi_add_handle()
560 sockets that time-out or have actions will be dealt with. Since this in curl_multi_add_handle()
565 /* A somewhat crude work-around for a little glitch in Curl_update_timer() in curl_multi_add_handle()
572 The work-around is thus simply to clear the 'lastcall' variable to force in curl_multi_add_handle()
575 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); in curl_multi_add_handle()
586 if(!data->dns.hostcache || in curl_multi_add_handle()
587 (data->dns.hostcachetype == HCACHE_NONE)) { in curl_multi_add_handle()
588 data->dns.hostcache = &multi->hostcache; in curl_multi_add_handle()
589 data->dns.hostcachetype = HCACHE_MULTI; in curl_multi_add_handle()
593 if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT))) in curl_multi_add_handle()
594 data->state.conn_cache = &data->share->conn_cache; in curl_multi_add_handle()
596 data->state.conn_cache = &multi->conn_cache; in curl_multi_add_handle()
597 data->state.lastconnect_id = -1; in curl_multi_add_handle()
601 if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL))) in curl_multi_add_handle()
602 data->psl = &data->share->psl; in curl_multi_add_handle()
604 data->psl = &multi->psl; in curl_multi_add_handle()
609 /* increase the node-counter */ in curl_multi_add_handle()
610 multi->num_easy++; in curl_multi_add_handle()
612 /* increase the alive-counter */ in curl_multi_add_handle()
613 multi->num_alive++; in curl_multi_add_handle()
616 /* The closure handle only ever has default timeouts set. To improve the in curl_multi_add_handle()
617 state somewhat we clone the timeouts from each added handle so that the in curl_multi_add_handle()
618 closure handle always has the same timeouts as the most recently added in curl_multi_add_handle()
620 data->state.conn_cache->closure_handle->set.timeout = data->set.timeout; in curl_multi_add_handle()
621 data->state.conn_cache->closure_handle->set.server_response_timeout = in curl_multi_add_handle()
622 data->set.server_response_timeout; in curl_multi_add_handle()
623 data->state.conn_cache->closure_handle->set.no_signal = in curl_multi_add_handle()
624 data->set.no_signal; in curl_multi_add_handle()
625 data->id = data->state.conn_cache->next_easy_id++; in curl_multi_add_handle()
626 if(data->state.conn_cache->next_easy_id <= 0) in curl_multi_add_handle()
627 data->state.conn_cache->next_easy_id = 0; in curl_multi_add_handle()
636 /* Debug-function, used like this:
638 * Curl_hash_print(&multi->sockhash, debug_print_sock_hash);
647 sh->readers, sh->writers);
657 struct connectdata *conn = data->conn; in multi_done()
661 multi_statename[data->mstate], in multi_done()
662 (int)status, (int)premature, data->state.done)); in multi_done()
665 (int)status, (int)premature, data->state.done)); in multi_done()
668 if(data->state.done) in multi_done()
676 Curl_safefree(data->req.newurl); in multi_done()
677 Curl_safefree(data->req.location); in multi_done()
686 this more fine-grained in the future. */ in multi_done()
693 /* this calls the protocol-specific function pointer previously set */ in multi_done()
694 if(conn->handler->done) in multi_done()
695 result = conn->handler->done(data, status, premature); in multi_done()
715 process_pending_handles(data->multi); /* connection / multiplex */ in multi_done()
718 result = Curl_req_done(&data->req, data, premature); in multi_done()
727 conn->easyq.size)); in multi_done()
731 data->state.done = TRUE; /* called just now! */ in multi_done()
733 if(conn->dns_entry) { in multi_done()
734 Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ in multi_done()
735 conn->dns_entry = NULL; in multi_done()
739 /* if data->set.reuse_forbid is TRUE, it means the libcurl client has in multi_done()
743 if conn->bits.close is TRUE, it means that the connection should be in multi_done()
754 data->state.recent_conn_id = conn->connection_id; in multi_done()
755 if((data->set.reuse_forbid in multi_done()
757 && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 || in multi_done()
758 conn->proxy_ntlm_state == NTLMSTATE_TYPE2) in multi_done()
761 && !(conn->http_negotiate_state == GSS_AUTHRECV || in multi_done()
762 conn->proxy_negotiate_state == GSS_AUTHRECV) in multi_done()
764 ) || conn->bits.close in multi_done()
769 conn->connection_id, in multi_done()
770 data->set.reuse_forbid, conn->bits.close, premature, in multi_done()
781 conn->bits.socksproxy ? in multi_done()
782 conn->socks_proxy.host.dispname : in multi_done()
783 conn->bits.httpproxy ? conn->http_proxy.host.dispname : in multi_done()
785 conn->bits.conn_to_host ? conn->conn_to_host.dispname : in multi_done()
786 conn->host.dispname; in multi_done()
788 curl_off_t connection_id = conn->connection_id; in multi_done()
796 data->state.lastconnect_id = connection_id; in multi_done()
797 data->state.recent_conn_id = connection_id; in multi_done()
801 data->state.lastconnect_id = -1; in multi_done()
811 if(data->state.lastconnect_id != conn->connection_id) in close_connect_only()
814 if(!conn->connect_only) in close_connect_only()
817 connclose(conn, "Removing connect-only easy handle"); in close_connect_only()
839 if(!data->multi) in curl_multi_remove_handle()
843 if(data->multi != multi) in curl_multi_remove_handle()
846 if(multi->in_callback) in curl_multi_remove_handle()
849 premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE; in curl_multi_remove_handle()
856 multi->num_alive--; in curl_multi_remove_handle()
859 if(data->conn && in curl_multi_remove_handle()
860 data->mstate > MSTATE_DO && in curl_multi_remove_handle()
861 data->mstate < MSTATE_COMPLETED) { in curl_multi_remove_handle()
864 streamclose(data->conn, "Removed with partial response"); in curl_multi_remove_handle()
867 if(data->conn) { in curl_multi_remove_handle()
873 (void)multi_done(data, data->result, premature); in curl_multi_remove_handle()
876 /* The timer must be shut down before data->multi is set to NULL, else the in curl_multi_remove_handle()
881 if(data->connect_queue.ptr) { in curl_multi_remove_handle()
884 if(data->mstate == MSTATE_PENDING) in curl_multi_remove_handle()
885 Curl_llist_remove(&multi->pending, &data->connect_queue, NULL); in curl_multi_remove_handle()
887 Curl_llist_remove(&multi->msgsent, &data->connect_queue, NULL); in curl_multi_remove_handle()
892 if(data->dns.hostcachetype == HCACHE_MULTI) { in curl_multi_remove_handle()
895 data->dns.hostcache = NULL; in curl_multi_remove_handle()
896 data->dns.hostcachetype = HCACHE_NONE; in curl_multi_remove_handle()
899 Curl_wildcard_dtor(&data->wildcard); in curl_multi_remove_handle()
903 data->mstate = MSTATE_COMPLETED; in curl_multi_remove_handle()
913 if(data->set.connect_only && !data->multi_easy) { in curl_multi_remove_handle()
931 if(data->state.lastconnect_id != -1) { in curl_multi_remove_handle()
932 /* Mark any connect-only connection for closure */ in curl_multi_remove_handle()
933 Curl_conncache_foreach(data, data->state.conn_cache, in curl_multi_remove_handle()
939 if(data->psl == &multi->psl) in curl_multi_remove_handle()
940 data->psl = NULL; in curl_multi_remove_handle()
945 data->state.conn_cache = NULL; in curl_multi_remove_handle()
947 data->multi = NULL; /* clear the association to this multi handle */ in curl_multi_remove_handle()
951 for(e = multi->msglist.head; e; e = e->next) { in curl_multi_remove_handle()
952 struct Curl_message *msg = e->ptr; in curl_multi_remove_handle()
954 if(msg->extmsg.easy_handle == easy) { in curl_multi_remove_handle()
955 Curl_llist_remove(&multi->msglist, e, NULL); in curl_multi_remove_handle()
963 multi->num_easy--; /* one less to care about now */ in curl_multi_remove_handle()
976 return (multi && (multi->multiplexing)); in Curl_multiplex_wanted()
982 * This is the only function that should clear data->conn. This will
983 * occasionally be called with the data->conn pointer already cleared.
987 struct connectdata *conn = data->conn; in Curl_detach_connection()
990 Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); in Curl_detach_connection()
992 data->conn = NULL; in Curl_detach_connection()
998 * This is the only function that should assign data->conn
1003 DEBUGASSERT(!data->conn); in Curl_attach_connection()
1005 data->conn = conn; in Curl_attach_connection()
1006 Curl_llist_append(&conn->easyq, data, &data->conn_queue); in Curl_attach_connection()
1007 if(conn->handler && conn->handler->attach) in Curl_attach_connection()
1008 conn->handler->attach(data, conn); in Curl_attach_connection()
1014 struct connectdata *conn = data->conn; in connecting_getsock()
1016 /* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes in connecting_getsock()
1018 if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) { in connecting_getsock()
1020 socks[0] = conn->sock[FIRSTSOCKET]; in connecting_getsock()
1028 struct connectdata *conn = data->conn; in protocol_getsock()
1029 if(conn && conn->handler->proto_getsock) in protocol_getsock()
1030 return conn->handler->proto_getsock(data, conn, socks); in protocol_getsock()
1031 else if(conn && conn->sockfd != CURL_SOCKET_BAD) { in protocol_getsock()
1033 socks[0] = conn->sockfd; in protocol_getsock()
1041 struct connectdata *conn = data->conn; in domore_getsock()
1042 if(conn && conn->handler->domore_getsock) in domore_getsock()
1043 return conn->handler->domore_getsock(data, conn, socks); in domore_getsock()
1044 else if(conn && conn->sockfd != CURL_SOCKET_BAD) { in domore_getsock()
1046 socks[0] = conn->sockfd; in domore_getsock()
1054 struct connectdata *conn = data->conn; in doing_getsock()
1055 if(conn && conn->handler->doing_getsock) in doing_getsock()
1056 return conn->handler->doing_getsock(data, conn, socks); in doing_getsock()
1057 else if(conn && conn->sockfd != CURL_SOCKET_BAD) { in doing_getsock()
1059 socks[0] = conn->sockfd; in doing_getsock()
1067 struct connectdata *conn = data->conn; in perform_getsock()
1071 else if(conn->handler->perform_getsock) in perform_getsock()
1072 return conn->handler->perform_getsock(data, conn, sock); in perform_getsock()
1074 /* Default is to obey the data->req.keepon flags for send/recv */ in perform_getsock()
1078 DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); in perform_getsock()
1080 sock[sockindex] = conn->sockfd; in perform_getsock()
1084 if((conn->sockfd != conn->writesockfd) || in perform_getsock()
1091 DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); in perform_getsock()
1092 sock[sockindex] = conn->writesockfd; in perform_getsock()
1109 if(!data->conn) in multi_getsock()
1112 switch(data->mstate) { in multi_getsock()
1164 failf(data, "multi_getsock: unexpected multi state %d", data->mstate); in multi_getsock()
1178 int this_max_fd = -1; in curl_multi_fdset()
1186 if(multi->in_callback) in curl_multi_fdset()
1190 for(data = multi->easyp; data; data = data->next) { in curl_multi_fdset()
1230 if(multi->in_callback) in curl_multi_waitfds()
1234 for(data = multi->easyp; data; data = data->next) { in curl_multi_waitfds()
1240 int fd_idx = -1; in curl_multi_waitfds()
1252 ufd->fd = ps.sockets[i]; in curl_multi_waitfds()
1253 ufd->events = 0; in curl_multi_waitfds()
1259 ufd->events |= CURL_WAIT_POLLIN; in curl_multi_waitfds()
1261 ufd->events |= CURL_WAIT_POLLOUT; in curl_multi_waitfds()
1284 if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM) in reset_socket_fdwrite()
1334 DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
1343 if(multi->in_callback)
1351 is actually larger than -1! */
1360 for(data = multi->easyp; data; data = data->next) {
1382 if(nfds && ps.sockets[i] == ufds[nfds-1].fd) {
1383 ufds[nfds-1].events |= events;
1398 if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
1410 /* Add external file descriptions from poll-like struct curl_waitfd */
1422 if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
1446 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1452 ufds[nfds].fd = multi->wakeup_pair[0];
1467 pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
1480 else { /* now wait... if not ready during the pre-check (pollrc == 0) */
1481 WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
1506 WSAEventSelect(s, multi->wsa_event, 0);
1526 for(data = multi->easyp; data; data = data->next) {
1536 WSAEventSelect(ps.sockets[i], multi->wsa_event, 0);
1541 WSAResetEvent(multi->wsa_event);
1544 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1549 /* the reading socket is non-blocking, try to read
1553 nread = wakeup_read(multi->wakeup_pair[0], buf, sizeof(buf));
1561 retcode--;
1580 /* Avoid busy-looping when there's nothing particular to wait for */
1584 /* when there are no easy handles in the multi, this holds a -1
1627 if(WSASetEvent(multi->wsa_event))
1633 if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
1637 /* swrite() is not thread-safe in general, because concurrent calls
1641 The write socket is set to non-blocking, this way this function
1646 if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
1677 bool retval = multi->recheckstate;
1679 multi->recheckstate = FALSE;
1692 multi->recheckstate = TRUE;
1701 if(multi->in_callback)
1706 struct SingleRequest *k = &data->req;
1715 k->keepon |= KEEP_RECV; /* setup to receive! */
1723 struct connectdata *conn = data->conn;
1726 DEBUGASSERT(conn->handler);
1728 if(conn->handler->do_it)
1729 result = conn->handler->do_it(data, done);
1739 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
1746 struct connectdata *conn = data->conn;
1750 if(conn->handler->do_more)
1751 result = conn->handler->do_more(data, complete);
1770 since = data->progress.t_startsingle;
1772 since = data->progress.t_startop;
1773 if(data->mstate == MSTATE_RESOLVING)
1776 else if(data->mstate == MSTATE_CONNECTING)
1780 struct SingleRequest *k = &data->req;
1781 if(k->size != -1) {
1785 Curl_timediff(*now, since), k->bytecount, k->size);
1790 " bytes received", Curl_timediff(*now, since), k->bytecount);
1794 if(data->conn) {
1796 if(data->mstate > MSTATE_DO) {
1797 streamclose(data->conn, "Disconnect due to timeout");
1809 * We are doing protocol-specific connecting and this is being called over and
1817 struct connectdata *conn = data->conn;
1819 if(conn && conn->handler->connecting) {
1821 result = conn->handler->connecting(data, done);
1837 struct connectdata *conn = data->conn;
1839 if(conn && conn->handler->doing) {
1841 result = conn->handler->doing(data, done);
1858 struct connectdata *conn = data->conn;
1865 && conn->bits.protoconnstart) {
1870 Unless this protocol doesn't have any protocol-connect callback, as
1872 if(!conn->handler->connecting)
1878 if(!conn->bits.protoconnstart) {
1879 if(conn->handler->connect_it) {
1880 /* is there a protocol-specific connect() procedure? */
1882 /* Call the protocol-specific connect function */
1883 result = conn->handler->connect_it(data, protocol_done);
1891 conn->bits.protoconnstart = TRUE;
1899 multi->in_callback = value;
1920 if(multi->dead) {
1921 /* a multi-level callback returned error before, meaning every individual
1942 if(data->mstate > MSTATE_CONNECT &&
1943 data->mstate < MSTATE_COMPLETED) {
1945 DEBUGASSERT(data->conn);
1946 if(!data->conn)
1952 if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
1957 switch(data->mstate) {
1973 if(data->set.timeout)
1974 Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
1976 if(data->set.connecttimeout)
1977 Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
1983 /* add this handle to the list of connect-pending handles */
1984 Curl_llist_append(&multi->pending, data, &data->connect_queue);
1990 else if(data->state.previouslypending) {
1993 process_pending_handles(data->multi);
2018 struct connectdata *conn = data->conn;
2023 if(conn->bits.httpproxy)
2024 hostname = conn->http_proxy.host.name;
2027 if(conn->bits.conn_to_host)
2028 hostname = conn->conn_to_host.name;
2030 hostname = conn->host.name;
2033 dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
2037 data->state.async.dns = dns;
2038 data->state.async.done = TRUE;
2065 data->conn = NULL; /* no more connection */
2087 /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
2088 DEBUGASSERT(data->conn);
2091 if(data->conn->bits.proxy_connect_closed) {
2112 DEBUGASSERT(data->conn);
2128 if(!result && data->conn->bits.reuse) {
2157 /* protocol-specific connect phase */
2173 if(data->set.fprereq) {
2178 prereq_rc = data->set.fprereq(data->set.prereq_userp,
2179 data->info.primary.remote_ip,
2180 data->info.primary.local_ip,
2181 data->info.primary.remote_port,
2182 data->info.primary.local_port);
2185 failf(data, "operation aborted by pre-request callback");
2186 /* failure in pre-request callback - don't do any other processing */
2195 if(data->set.connect_only == 1) {
2197 connkeep(data->conn, "CONNECT_ONLY");
2206 /* When multi_do() returns failure, data->conn might be NULL! */
2212 if(data->state.wildcardmatch) {
2213 struct WildcardData *wc = data->wildcard;
2214 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
2219 multistate(data, data->conn ?
2233 else if(data->conn->bits.do_more) {
2246 data->conn->bits.reuse) {
2296 if(data->conn)
2305 DEBUGASSERT(data->conn);
2310 multistate(data, data->conn->bits.do_more?
2327 DEBUGASSERT(data->conn);
2350 DEBUGASSERT(data->conn);
2351 if(data->conn->bits.multiplex)
2357 if((data->conn->sockfd != CURL_SOCKET_BAD) ||
2358 (data->conn->writesockfd != CURL_SOCKET_BAD))
2362 if(data->state.wildcardmatch &&
2363 ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
2364 data->wildcard->state = CURLWC_DONE;
2372 case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
2373 DEBUGASSERT(data->conn);
2381 if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2383 streamclose(data->conn, "Transfer returned error");
2390 if(data->set.max_send_speed)
2392 Curl_pgrsLimitWaitTime(data->progress.uploaded,
2393 data->progress.ul_limit_size,
2394 data->set.max_send_speed,
2395 data->progress.ul_limit_start,
2399 if(data->set.max_recv_speed)
2401 Curl_pgrsLimitWaitTime(data->progress.downloaded,
2402 data->progress.dl_limit_size,
2403 data->set.max_recv_speed,
2404 data->progress.dl_limit_start,
2424 if(data->set.max_send_speed)
2425 send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
2426 data->progress.ul_limit_size,
2427 data->set.max_send_speed,
2428 data->progress.ul_limit_start,
2433 if(data->set.max_recv_speed)
2434 recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
2435 data->progress.dl_limit_size,
2436 data->set.max_recv_speed,
2437 data->progress.dl_limit_start,
2453 if(data->req.done || (result == CURLE_RECV_ERROR)) {
2468 data->req.done = TRUE;
2477 streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
2478 data->state.httpwant = CURL_HTTP_VERSION_1_1;
2480 data->state.errorbuf = FALSE;
2483 newurl = strdup(data->state.url);
2488 data->req.done = TRUE;
2503 if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2505 streamclose(data->conn, "Transfer returned error");
2510 else if(data->req.done && !Curl_cwriter_is_paused(data)) {
2517 if(data->req.newurl || retry) {
2520 /* if the URL is a follow-location and not just a retried request
2523 newurl = data->req.newurl;
2524 data->req.newurl = NULL;
2542 if(data->req.location) {
2544 newurl = data->req.location;
2545 data->req.location = NULL;
2559 else if(data->state.select_bits) {
2573 if(data->conn) {
2576 if(data->conn->bits.multiplex)
2580 /* post-transfer command */
2589 if(data->state.wildcardmatch) {
2590 if(data->wildcard->state != CURLWC_DONE) {
2591 /* if a wildcard is set and we are not ending -> lets start again
2616 if(data->mstate >= MSTATE_CONNECT &&
2617 data->mstate < MSTATE_DO &&
2620 /* We now handle stream timeouts if and only if this will be the last
2631 if(data->mstate < MSTATE_COMPLETED) {
2639 in the case blocks above - cleanup happens only here */
2644 if(data->conn) {
2648 struct connectdata *conn = data->conn;
2662 else if(data->mstate == MSTATE_CONNECT) {
2671 else if(data->conn && Curl_pgrsUpdate(data)) {
2675 streamclose(data->conn, "Aborted by callback");
2678 multistate(data, (data->mstate < MSTATE_DONE)?
2684 if(MSTATE_COMPLETED == data->mstate) {
2685 if(data->set.fmultidone) {
2687 data->set.fmultidone(data, result);
2691 msg = &data->msg;
2693 msg->extmsg.msg = CURLMSG_DONE;
2694 msg->extmsg.easy_handle = data;
2695 msg->extmsg.data.result = result;
2698 DEBUGASSERT(!data->conn);
2703 Curl_llist_append(&multi->msgsent, data, &data->connect_queue);
2710 data->result = result;
2725 if(multi->in_callback)
2728 data = multi->easyp;
2731 bool nosig = data->set.no_signal;
2739 struct Curl_easy *datanext = data->next;
2740 if(data->set.no_signal != nosig) {
2743 nosig = data->set.no_signal;
2764 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
2767 (void)add_next_timeout(now, multi, t->payload);
2770 *running_handles = multi->num_alive;
2782 struct Curl_llist_element *e = multi->msgsent.head;
2784 struct Curl_easy *data = e->ptr;
2785 DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
2786 data->multi = NULL;
2796 if(multi->in_callback)
2799 multi->magic = 0; /* not good anymore */
2804 data = multi->easyp;
2806 nextdata = data->next;
2807 if(!data->state.done && data->conn)
2810 if(data->dns.hostcachetype == HCACHE_MULTI) {
2812 Curl_hostcache_clean(data, data->dns.hostcache);
2813 data->dns.hostcache = NULL;
2814 data->dns.hostcachetype = HCACHE_NONE;
2818 data->state.conn_cache = NULL;
2819 data->multi = NULL; /* clear the association */
2822 if(data->psl == &multi->psl)
2823 data->psl = NULL;
2830 Curl_conncache_close_all_connections(&multi->conn_cache);
2832 sockhash_destroy(&multi->sockhash);
2833 Curl_conncache_destroy(&multi->conn_cache);
2834 Curl_hash_destroy(&multi->hostcache);
2835 Curl_psl_destroy(&multi->psl);
2838 WSACloseEvent(multi->wsa_event);
2841 wakeup_close(multi->wakeup_pair[0]);
2842 wakeup_close(multi->wakeup_pair[1]);
2847 Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
2875 !multi->in_callback &&
2876 Curl_llist_count(&multi->msglist)) {
2881 e = multi->msglist.head;
2883 msg = e->ptr;
2886 Curl_llist_remove(&multi->msglist, e, NULL);
2888 *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
2890 return &msg->extmsg;
2926 entry = sh_getentry(&multi->sockhash, s);
2930 for(j = 0; j< data->last_poll.num; j++) {
2931 if(s == data->last_poll.sockets[j]) {
2932 last_action = data->last_poll.actions[j];
2939 entry = sh_addentry(&multi->sockhash, s);
2947 entry->readers--;
2949 entry->writers--;
2951 entry->readers++;
2953 entry->writers++;
2957 entry->users++;
2959 entry->readers++;
2961 entry->writers++;
2964 if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
2966 Curl_hash_destroy(&entry->transfers);
2971 comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
2972 (entry->readers ? CURL_POLL_IN : 0);
2975 if(last_action && ((int)entry->action == comboaction))
2979 if(multi->socket_cb) {
2981 rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
2982 entry->socketp);
2985 if(rc == -1) {
2986 multi->dead = TRUE;
2991 entry->action = comboaction; /* store the current action state */
2995 * Need to remove the easy handle from the multi->sockhash->transfers and
2996 * remove multi->sockhash entry when this was the last transfer */
2997 for(i = 0; i< data->last_poll.num; i++) {
3000 s = data->last_poll.sockets[i];
3011 entry = sh_getentry(&multi->sockhash, s);
3015 unsigned char oldactions = data->last_poll.actions[i];
3017 entry->users--;
3019 entry->writers--;
3021 entry->readers--;
3022 if(!entry->users) {
3023 if(multi->socket_cb) {
3025 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
3026 multi->socket_userp, entry->socketp);
3028 if(rc == -1) {
3029 multi->dead = TRUE;
3033 sh_delentry(entry, &multi->sockhash, s);
3037 if(Curl_hash_delete(&entry->transfers, (char *)&data,
3046 memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll));
3052 if(singlesocket(data->multi, data))
3072 struct Curl_multi *multi = data->multi;
3076 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
3080 if(multi->socket_cb) {
3082 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
3083 multi->socket_userp, entry->socketp);
3088 sh_delentry(entry, &multi->sockhash, s);
3089 if(rc == -1)
3093 multi->dead = TRUE;
3102 * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
3115 struct curltime *tv = &d->state.expiretime;
3116 struct Curl_llist *list = &d->state.timeoutlist;
3121 timeouts that are now passed tense and store the next pending
3123 for(e = list->head; e;) {
3124 struct Curl_llist_element *n = e->next;
3126 node = (struct time_node *)e->ptr;
3127 diff = Curl_timediff_us(node->time, now);
3136 e = list->head;
3140 tv->tv_sec = 0;
3141 tv->tv_usec = 0;
3145 memcpy(tv, &node->time, sizeof(*tv));
3149 multi->timetree = Curl_splayinsert(*tv, multi->timetree,
3150 &d->state.timenode);
3176 data = multi->easyp;
3179 data = data->next;
3183 /* or should we fall-through and do the timer-based stuff? */
3187 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
3191 real-world tests it has been proved that libevent can in fact give
3201 Curl_hash_start_iterate(&entry->transfers, &iter);
3204 data = (struct Curl_easy *)he->ptr;
3206 DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
3208 if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK)) {
3210 data->state.select_bits |= (unsigned char)ev_bitmask;
3213 if (data->state.select_bits & CURL_CSELECT_IN) {
3214 data->last_pollin_time = now;
3216 data->last_os_pollin_time = now;
3219 if (data->state.select_bits & CURL_CSELECT_OUT) {
3220 data->last_pollout_time = now;
3222 data->last_os_pollout_time = now;
3230 /* Now we fall-through and do the timer-based stuff, since we don't want
3231 to force the user to have to deal with timeouts as long as at least
3241 /* Asked to run due to time-out. Clear the 'lastcall' variable to force
3246 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
3250 * The loop following here will go on as long as there are expire-times left
3251 * to process in the splay and 'data' will be re-assigned for every expired
3259 nosig = data->set.no_signal; /* initial state */
3262 else if(data->set.no_signal != nosig) {
3265 nosig = data->set.no_signal; /* remember new state */
3281 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
3283 data = t->payload; /* assign this for next loop */
3284 (void)add_next_timeout(now, multi, t->payload);
3291 *running_handles = multi->num_alive;
3306 if(multi->in_callback)
3313 multi->socket_cb = va_arg(param, curl_socket_callback);
3316 multi->socket_userp = va_arg(param, void *);
3319 multi->push_cb = va_arg(param, curl_push_callback);
3322 multi->push_userp = va_arg(param, void *);
3325 multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX ? 1 : 0;
3328 multi->timer_cb = va_arg(param, curl_multi_timer_callback);
3331 multi->timer_userp = va_arg(param, void *);
3336 multi->maxconnects = (unsigned int)uarg;
3339 multi->max_host_connections = va_arg(param, long);
3342 multi->max_total_connections = va_arg(param, long);
3360 multi->max_concurrent_streams = (unsigned int)streams;
3378 if(multi->in_callback)
3390 if(multi->in_callback)
3401 if(multi->in_callback)
3414 if(multi->dead) {
3419 if(multi->timetree) {
3424 multi->timetree = Curl_splay(tv_zero, multi->timetree);
3426 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
3428 timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now);
3430 overly long timeouts */
3438 *timeout_ms = -1;
3450 if(multi->in_callback)
3465 if(!multi->timer_cb || multi->dead)
3472 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
3473 multi->timer_lastcall = none;
3477 rc = multi->timer_cb(multi, -1, multi->timer_userp);
3479 if(rc == -1) {
3480 multi->dead = TRUE;
3488 /* When multi_timeout() is done, multi->timetree points to the node with the
3489 * timeout we got the (relative) time-out time for. We can thus easily check
3492 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
3495 multi->timer_lastcall = multi->timetree->key;
3498 rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
3500 if(rc == -1) {
3501 multi->dead = TRUE;
3510 * Remove a given timestamp from the list of timeouts.
3516 struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3518 for(e = timeoutlist->head; e; e = e->next) {
3519 struct time_node *n = (struct time_node *)e->ptr;
3520 if(n->eid == eid) {
3530 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
3543 struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3545 node = &data->state.expires[eid];
3548 memcpy(&node->time, stamp, sizeof(*stamp));
3549 node->eid = eid; /* also marks it as in use */
3554 for(e = timeoutlist->head; e; e = e->next) {
3555 struct time_node *check = (struct time_node *)e->ptr;
3556 timediff_t diff = Curl_timediff(check->time, node->time);
3566 Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
3574 * this'-time for the transfer, to be extracted by curl_multi_timeout()
3576 * The timeout will be added to a queue of timeouts if it defines a moment in
3583 struct Curl_multi *multi = data->multi;
3584 struct curltime *nowp = &data->state.expiretime;
3600 set.tv_usec -= 1000000;
3610 if(nowp->tv_sec || nowp->tv_usec) {
3612 Compare if the new time is earlier, and only remove-old/add-new if it
3624 the splay tree first and then re-add the new value */
3625 rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3626 &multi->timetree);
3634 data->state.timenode.payload = data;
3635 multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
3636 &data->state.timenode);
3658 struct Curl_multi *multi = data->multi;
3659 struct curltime *nowp = &data->state.expiretime;
3666 if(nowp->tv_sec || nowp->tv_usec) {
3669 struct Curl_llist *list = &data->state.timeoutlist;
3672 rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3673 &multi->timetree);
3678 while(list->size > 0) {
3679 Curl_llist_remove(list, list->tail, NULL);
3685 nowp->tv_sec = 0;
3686 nowp->tv_usec = 0;
3698 there = sh_getentry(&multi->sockhash, s);
3703 there->socketp = hashp;
3710 return multi ? multi->max_host_connections : 0;
3715 return multi ? multi->max_total_connections : 0;
3727 DEBUGASSERT(data->multi);
3728 conn = data->conn;
3730 DEBUGASSERT(conn->bundle);
3732 conn->bundle->multiuse = bundlestate;
3733 process_pending_handles(data->multi);
3740 struct Curl_llist_element *e = multi->pending.head;
3742 struct Curl_easy *data = e->ptr;
3744 DEBUGASSERT(data->mstate == MSTATE_PENDING);
3752 Curl_llist_remove(&multi->pending, e, NULL);
3758 data->state.previouslypending = TRUE;
3764 if(data && data->multi)
3765 data->multi->in_callback = value;
3770 return (data && data->multi && data->multi->in_callback);
3776 return multi->max_concurrent_streams;
3782 (multi->num_easy + 1));
3785 struct Curl_easy *e = multi->easyp;
3787 DEBUGASSERT(i < multi->num_easy);
3788 if(!e->state.internal)
3790 e = e->next;
3801 DEBUGASSERT(data->multi);
3804 if(!data->multi) {
3808 if(!data->set.buffer_size) {
3812 if(data->multi->xfer_buf_borrowed) {
3817 if(data->multi->xfer_buf &&
3818 data->set.buffer_size > data->multi->xfer_buf_len) {
3820 free(data->multi->xfer_buf);
3821 data->multi->xfer_buf = NULL;
3822 data->multi->xfer_buf_len = 0;
3825 if(!data->multi->xfer_buf) {
3826 data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
3827 if(!data->multi->xfer_buf) {
3829 (size_t)data->set.buffer_size);
3832 data->multi->xfer_buf_len = data->set.buffer_size;
3835 data->multi->xfer_buf_borrowed = TRUE;
3836 *pbuf = data->multi->xfer_buf;
3837 *pbuflen = data->multi->xfer_buf_len;
3845 DEBUGASSERT(data->multi);
3846 DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
3847 data->multi->xfer_buf_borrowed = FALSE;
3854 DEBUGASSERT(data->multi);
3857 if(!data->multi) {
3861 if(!data->set.upload_buffer_size) {
3865 if(data->multi->xfer_ulbuf_borrowed) {
3870 if(data->multi->xfer_ulbuf &&
3871 data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
3873 free(data->multi->xfer_ulbuf);
3874 data->multi->xfer_ulbuf = NULL;
3875 data->multi->xfer_ulbuf_len = 0;
3878 if(!data->multi->xfer_ulbuf) {
3879 data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
3880 if(!data->multi->xfer_ulbuf) {
3882 (size_t)data->set.upload_buffer_size);
3885 data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
3888 data->multi->xfer_ulbuf_borrowed = TRUE;
3889 *pbuf = data->multi->xfer_ulbuf;
3890 *pbuflen = data->multi->xfer_ulbuf_len;
3898 DEBUGASSERT(data->multi);
3899 DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
3900 data->multi->xfer_ulbuf_borrowed = FALSE;
3906 Curl_safefree(multi->xfer_buf);
3907 multi->xfer_buf_len = 0;
3908 multi->xfer_buf_borrowed = FALSE;
3909 Curl_safefree(multi->xfer_ulbuf);
3910 multi->xfer_ulbuf_len = 0;
3911 multi->xfer_ulbuf_borrowed = FALSE;