• Home
  • Raw
  • Download

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)
125 data->req.chunk = FALSE; in before_perform()
146 CURLMstate oldstate = data->mstate; in mstate()
175 data->mstate = state; in mstate()
178 if(data->mstate >= MSTATE_PENDING && in mstate()
179 data->mstate < MSTATE_COMPLETED) { in mstate()
182 multi_statename[oldstate], multi_statename[data->mstate], in mstate()
194 multi_statename[data->mstate], in mstate()
195 address + strlen(address) - reserve_digits); in mstate()
200 DEBUGASSERT(data->multi->num_alive > 0); in mstate()
201 data->multi->num_alive--; in mstate()
202 if(!data->multi->num_alive) { in mstate()
204 multi_xfer_bufs_free(data->multi); in mstate()
208 /* if this state has an init-function, run it */ in mstate()
279 struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr; in sockhash_destroy()
280 Curl_hash_destroy(&sh->transfers); in sockhash_destroy()
304 Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare, in sh_addentry()
309 Curl_hash_destroy(&check->transfers); in sh_addentry()
322 Curl_hash_destroy(&entry->transfers); in sh_delentry()
361 * limiting. It simply has a fixed-size array, and on each entry in the array
386 Curl_llist_append(&multi->msglist, msg, &msg->list); in multi_addmsg()
398 multi->magic = CURL_MULTI_HANDLE; in Curl_multi_handle()
400 Curl_init_dnscache(&multi->hostcache, dnssize); in Curl_multi_handle()
402 sh_init(&multi->sockhash, hashsize); in Curl_multi_handle()
404 if(Curl_conncache_init(&multi->conn_cache, chashsize)) in Curl_multi_handle()
407 Curl_llist_init(&multi->msglist, NULL); in Curl_multi_handle()
408 Curl_llist_init(&multi->pending, NULL); in Curl_multi_handle()
409 Curl_llist_init(&multi->msgsent, NULL); in Curl_multi_handle()
411 multi->multiplexing = TRUE; in Curl_multi_handle()
412 multi->max_concurrent_streams = 100; in Curl_multi_handle()
415 multi->wsa_event = WSACreateEvent(); in Curl_multi_handle()
416 if(multi->wsa_event == WSA_INVALID_EVENT) in Curl_multi_handle()
420 if(wakeup_create(multi->wakeup_pair) < 0) { in Curl_multi_handle()
421 multi->wakeup_pair[0] = CURL_SOCKET_BAD; in Curl_multi_handle()
422 multi->wakeup_pair[1] = CURL_SOCKET_BAD; in Curl_multi_handle()
424 else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 || in Curl_multi_handle()
425 curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) { in Curl_multi_handle()
426 wakeup_close(multi->wakeup_pair[0]); in Curl_multi_handle()
427 wakeup_close(multi->wakeup_pair[1]); in Curl_multi_handle()
428 multi->wakeup_pair[0] = CURL_SOCKET_BAD; in Curl_multi_handle()
429 multi->wakeup_pair[1] = CURL_SOCKET_BAD; in Curl_multi_handle()
438 sockhash_destroy(&multi->sockhash); in Curl_multi_handle()
439 Curl_hash_destroy(&multi->hostcache); in Curl_multi_handle()
440 Curl_conncache_destroy(&multi->conn_cache); in Curl_multi_handle()
455 if(!multi->warned) { in multi_warn_debug()
459 multi->warned = true; in multi_warn_debug()
470 return ((data->mstate != MSTATE_PENDING) && in in_main_list()
471 (data->mstate != MSTATE_MSGSENT)); in in_main_list()
478 data->next = NULL; /* end of the line */ in link_easy()
479 if(multi->easyp) { in link_easy()
480 struct Curl_easy *last = multi->easylp; in link_easy()
481 last->next = data; in link_easy()
482 data->prev = last; in link_easy()
483 multi->easylp = data; /* the new last node */ in link_easy()
487 data->prev = NULL; in link_easy()
488 multi->easylp = multi->easyp = data; /* both first and last */ in link_easy()
497 if(data->prev) in unlink_easy()
498 data->prev->next = data->next; in unlink_easy()
500 multi->easyp = data->next; /* point to first node */ in unlink_easy()
503 if(data->next) in unlink_easy()
504 data->next->prev = data->prev; in unlink_easy()
506 multi->easylp = data->prev; /* point to last node */ in unlink_easy()
508 data->prev = data->next = NULL; in unlink_easy()
526 if(data->multi) in curl_multi_add_handle()
529 if(multi->in_callback) in curl_multi_add_handle()
532 if(multi->dead) { in curl_multi_add_handle()
534 handles are still alive - but if there are none alive anymore, it is in curl_multi_add_handle()
536 if(multi->num_alive) in curl_multi_add_handle()
538 multi->dead = FALSE; in curl_multi_add_handle()
541 if(data->multi_easy) { in curl_multi_add_handle()
544 curl_multi_cleanup(data->multi_easy); in curl_multi_add_handle()
545 data->multi_easy = NULL; in curl_multi_add_handle()
549 Curl_llist_init(&data->state.timeoutlist, NULL); in curl_multi_add_handle()
557 if(data->set.errorbuffer) in curl_multi_add_handle()
558 data->set.errorbuffer[0] = 0; in curl_multi_add_handle()
560 data->state.os_errno = 0; in curl_multi_add_handle()
562 /* make the Curl_easy refer back to this multi handle - before Curl_expire() in curl_multi_add_handle()
564 data->multi = multi; in curl_multi_add_handle()
569 sockets that time-out or have actions will be dealt with. Since this in curl_multi_add_handle()
574 /* A somewhat crude work-around for a little glitch in Curl_update_timer() in curl_multi_add_handle()
581 The work-around is thus simply to clear the 'lastcall' variable to force in curl_multi_add_handle()
584 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); in curl_multi_add_handle()
595 if(!data->dns.hostcache || in curl_multi_add_handle()
596 (data->dns.hostcachetype == HCACHE_NONE)) { in curl_multi_add_handle()
597 data->dns.hostcache = &multi->hostcache; in curl_multi_add_handle()
598 data->dns.hostcachetype = HCACHE_MULTI; in curl_multi_add_handle()
602 if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT))) in curl_multi_add_handle()
603 data->state.conn_cache = &data->share->conn_cache; in curl_multi_add_handle()
605 data->state.conn_cache = &multi->conn_cache; in curl_multi_add_handle()
606 data->state.lastconnect_id = -1; in curl_multi_add_handle()
610 if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL))) in curl_multi_add_handle()
611 data->psl = &data->share->psl; in curl_multi_add_handle()
613 data->psl = &multi->psl; in curl_multi_add_handle()
618 /* increase the node-counter */ in curl_multi_add_handle()
619 multi->num_easy++; in curl_multi_add_handle()
621 /* increase the alive-counter */ in curl_multi_add_handle()
622 multi->num_alive++; in curl_multi_add_handle()
625 /* The closure handle only ever has default timeouts set. To improve the in curl_multi_add_handle()
626 state somewhat we clone the timeouts from each added handle so that the in curl_multi_add_handle()
627 closure handle always has the same timeouts as the most recently added in curl_multi_add_handle()
629 data->state.conn_cache->closure_handle->set.timeout = data->set.timeout; in curl_multi_add_handle()
630 data->state.conn_cache->closure_handle->set.server_response_timeout = in curl_multi_add_handle()
631 data->set.server_response_timeout; in curl_multi_add_handle()
632 data->state.conn_cache->closure_handle->set.no_signal = in curl_multi_add_handle()
633 data->set.no_signal; in curl_multi_add_handle()
634 data->id = data->state.conn_cache->next_easy_id++; in curl_multi_add_handle()
635 if(data->state.conn_cache->next_easy_id <= 0) in curl_multi_add_handle()
636 data->state.conn_cache->next_easy_id = 0; in curl_multi_add_handle()
645 /* Debug-function, used like this:
647 * Curl_hash_print(&multi->sockhash, debug_print_sock_hash);
656 sh->readers, sh->writers);
666 struct connectdata *conn = data->conn; in multi_done()
670 multi_statename[data->mstate], in multi_done()
671 (int)status, (int)premature, data->state.done)); in multi_done()
674 (int)status, (int)premature, data->state.done)); in multi_done()
677 if(data->state.done) in multi_done()
685 Curl_safefree(data->req.newurl); in multi_done()
686 Curl_safefree(data->req.location); in multi_done()
695 this more fine-grained in the future. */ in multi_done()
702 /* this calls the protocol-specific function pointer previously set */ in multi_done()
703 if(conn->handler->done) in multi_done()
704 result = conn->handler->done(data, status, premature); in multi_done()
724 process_pending_handles(data->multi); /* connection / multiplex */ in multi_done()
727 result = Curl_req_done(&data->req, data, premature); in multi_done()
736 conn->easyq.size)); in multi_done()
740 data->state.done = TRUE; /* called just now! */ in multi_done()
742 if(conn->dns_entry) { in multi_done()
743 Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ in multi_done()
744 conn->dns_entry = NULL; in multi_done()
748 /* if data->set.reuse_forbid is TRUE, it means the libcurl client has in multi_done()
752 if conn->bits.close is TRUE, it means that the connection should be in multi_done()
763 data->state.recent_conn_id = conn->connection_id; in multi_done()
764 if((data->set.reuse_forbid in multi_done()
766 && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 || in multi_done()
767 conn->proxy_ntlm_state == NTLMSTATE_TYPE2) in multi_done()
770 && !(conn->http_negotiate_state == GSS_AUTHRECV || in multi_done()
771 conn->proxy_negotiate_state == GSS_AUTHRECV) in multi_done()
773 ) || conn->bits.close in multi_done()
778 conn->connection_id, in multi_done()
779 data->set.reuse_forbid, conn->bits.close, premature, in multi_done()
790 conn->bits.socksproxy ? in multi_done()
791 conn->socks_proxy.host.dispname : in multi_done()
792 conn->bits.httpproxy ? conn->http_proxy.host.dispname : in multi_done()
794 conn->bits.conn_to_host ? conn->conn_to_host.dispname : in multi_done()
795 conn->host.dispname; in multi_done()
797 curl_off_t connection_id = conn->connection_id; in multi_done()
805 data->state.lastconnect_id = connection_id; in multi_done()
806 data->state.recent_conn_id = connection_id; in multi_done()
810 data->state.lastconnect_id = -1; in multi_done()
820 if(data->state.lastconnect_id != conn->connection_id) in close_connect_only()
823 if(!conn->connect_only) in close_connect_only()
826 connclose(conn, "Removing connect-only easy handle"); in close_connect_only()
848 if(!data->multi) in curl_multi_remove_handle()
852 if(data->multi != multi) in curl_multi_remove_handle()
855 if(multi->in_callback) in curl_multi_remove_handle()
858 premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE; in curl_multi_remove_handle()
865 multi->num_alive--; in curl_multi_remove_handle()
868 if(data->conn && in curl_multi_remove_handle()
869 data->mstate > MSTATE_DO && in curl_multi_remove_handle()
870 data->mstate < MSTATE_COMPLETED) { in curl_multi_remove_handle()
873 streamclose(data->conn, "Removed with partial response"); in curl_multi_remove_handle()
876 if(data->conn) { in curl_multi_remove_handle()
882 (void)multi_done(data, data->result, premature); in curl_multi_remove_handle()
885 /* The timer must be shut down before data->multi is set to NULL, else the in curl_multi_remove_handle()
890 if(data->connect_queue.ptr) { in curl_multi_remove_handle()
893 if(data->mstate == MSTATE_PENDING) in curl_multi_remove_handle()
894 Curl_llist_remove(&multi->pending, &data->connect_queue, NULL); in curl_multi_remove_handle()
896 Curl_llist_remove(&multi->msgsent, &data->connect_queue, NULL); in curl_multi_remove_handle()
901 if(data->dns.hostcachetype == HCACHE_MULTI) { in curl_multi_remove_handle()
904 data->dns.hostcache = NULL; in curl_multi_remove_handle()
905 data->dns.hostcachetype = HCACHE_NONE; in curl_multi_remove_handle()
908 Curl_wildcard_dtor(&data->wildcard); in curl_multi_remove_handle()
912 data->mstate = MSTATE_COMPLETED; in curl_multi_remove_handle()
922 if(data->set.connect_only && !data->multi_easy) { in curl_multi_remove_handle()
940 if(data->state.lastconnect_id != -1) { in curl_multi_remove_handle()
941 /* Mark any connect-only connection for closure */ in curl_multi_remove_handle()
942 Curl_conncache_foreach(data, data->state.conn_cache, in curl_multi_remove_handle()
948 if(data->psl == &multi->psl) in curl_multi_remove_handle()
949 data->psl = NULL; in curl_multi_remove_handle()
954 data->state.conn_cache = NULL; in curl_multi_remove_handle()
956 data->multi = NULL; /* clear the association to this multi handle */ in curl_multi_remove_handle()
960 for(e = multi->msglist.head; e; e = e->next) { in curl_multi_remove_handle()
961 struct Curl_message *msg = e->ptr; in curl_multi_remove_handle()
963 if(msg->extmsg.easy_handle == easy) { in curl_multi_remove_handle()
964 Curl_llist_remove(&multi->msglist, e, NULL); in curl_multi_remove_handle()
972 multi->num_easy--; /* one less to care about now */ in curl_multi_remove_handle()
985 return (multi && (multi->multiplexing)); in Curl_multiplex_wanted()
991 * This is the only function that should clear data->conn. This will
992 * occasionally be called with the data->conn pointer already cleared.
996 struct connectdata *conn = data->conn; in Curl_detach_connection()
999 Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); in Curl_detach_connection()
1001 data->conn = NULL; in Curl_detach_connection()
1007 * This is the only function that should assign data->conn
1012 DEBUGASSERT(!data->conn); in Curl_attach_connection()
1014 data->conn = conn; in Curl_attach_connection()
1015 Curl_llist_append(&conn->easyq, data, &data->conn_queue); in Curl_attach_connection()
1016 if(conn->handler && conn->handler->attach) in Curl_attach_connection()
1017 conn->handler->attach(data, conn); in Curl_attach_connection()
1023 struct connectdata *conn = data->conn; in connecting_getsock()
1025 /* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes in connecting_getsock()
1027 if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) { in connecting_getsock()
1029 socks[0] = conn->sock[FIRSTSOCKET]; in connecting_getsock()
1037 struct connectdata *conn = data->conn; in protocol_getsock()
1038 if(conn && conn->handler->proto_getsock) in protocol_getsock()
1039 return conn->handler->proto_getsock(data, conn, socks); in protocol_getsock()
1040 else if(conn && conn->sockfd != CURL_SOCKET_BAD) { in protocol_getsock()
1042 socks[0] = conn->sockfd; in protocol_getsock()
1050 struct connectdata *conn = data->conn; in domore_getsock()
1051 if(conn && conn->handler->domore_getsock) in domore_getsock()
1052 return conn->handler->domore_getsock(data, conn, socks); in domore_getsock()
1053 else if(conn && conn->sockfd != CURL_SOCKET_BAD) { in domore_getsock()
1055 socks[0] = conn->sockfd; in domore_getsock()
1063 struct connectdata *conn = data->conn; in doing_getsock()
1064 if(conn && conn->handler->doing_getsock) in doing_getsock()
1065 return conn->handler->doing_getsock(data, conn, socks); in doing_getsock()
1066 else if(conn && conn->sockfd != CURL_SOCKET_BAD) { in doing_getsock()
1068 socks[0] = conn->sockfd; in doing_getsock()
1076 struct connectdata *conn = data->conn; in perform_getsock()
1080 else if(conn->handler->perform_getsock) in perform_getsock()
1081 return conn->handler->perform_getsock(data, conn, sock); in perform_getsock()
1083 /* Default is to obey the data->req.keepon flags for send/recv */ in perform_getsock()
1087 DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); in perform_getsock()
1089 sock[sockindex] = conn->sockfd; in perform_getsock()
1093 if((conn->sockfd != conn->writesockfd) || in perform_getsock()
1100 DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); in perform_getsock()
1101 sock[sockindex] = conn->writesockfd; in perform_getsock()
1118 if(!data->conn) in multi_getsock()
1121 switch(data->mstate) { in multi_getsock()
1173 failf(data, "multi_getsock: unexpected multi state %d", data->mstate); in multi_getsock()
1187 int this_max_fd = -1; in curl_multi_fdset()
1195 if(multi->in_callback) in curl_multi_fdset()
1199 for(data = multi->easyp; data; data = data->next) { in curl_multi_fdset()
1239 if(multi->in_callback) in curl_multi_waitfds()
1243 for(data = multi->easyp; data; data = data->next) { in curl_multi_waitfds()
1249 int fd_idx = -1; in curl_multi_waitfds()
1261 ufd->fd = ps.sockets[i]; in curl_multi_waitfds()
1262 ufd->events = 0; in curl_multi_waitfds()
1268 ufd->events |= CURL_WAIT_POLLIN; in curl_multi_waitfds()
1270 ufd->events |= CURL_WAIT_POLLOUT; in curl_multi_waitfds()
1293 if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM) in reset_socket_fdwrite()
1343 DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
1352 if(multi->in_callback)
1360 is actually larger than -1! */
1369 for(data = multi->easyp; data; data = data->next) {
1391 if(nfds && ps.sockets[i] == ufds[nfds-1].fd) {
1392 ufds[nfds-1].events |= events;
1407 if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
1419 /* Add external file descriptions from poll-like struct curl_waitfd */
1431 if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
1455 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1461 ufds[nfds].fd = multi->wakeup_pair[0];
1476 pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
1489 else { /* now wait... if not ready during the pre-check (pollrc == 0) */
1490 WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
1515 WSAEventSelect(s, multi->wsa_event, 0);
1535 for(data = multi->easyp; data; data = data->next) {
1545 WSAEventSelect(ps.sockets[i], multi->wsa_event, 0);
1550 WSAResetEvent(multi->wsa_event);
1553 if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
1558 /* the reading socket is non-blocking, try to read
1562 nread = wakeup_read(multi->wakeup_pair[0], buf, sizeof(buf));
1570 retcode--;
1589 /* Avoid busy-looping when there's nothing particular to wait for */
1593 /* when there are no easy handles in the multi, this holds a -1
1636 if(WSASetEvent(multi->wsa_event))
1642 if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
1646 /* swrite() is not thread-safe in general, because concurrent calls
1650 The write socket is set to non-blocking, this way this function
1655 if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
1686 bool retval = multi->recheckstate;
1688 multi->recheckstate = FALSE;
1701 multi->recheckstate = TRUE;
1710 if(multi->in_callback)
1715 struct SingleRequest *k = &data->req;
1724 k->keepon |= KEEP_RECV; /* setup to receive! */
1732 struct connectdata *conn = data->conn;
1735 DEBUGASSERT(conn->handler);
1737 if(conn->handler->do_it)
1738 result = conn->handler->do_it(data, done);
1748 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
1755 struct connectdata *conn = data->conn;
1759 if(conn->handler->do_more)
1760 result = conn->handler->do_more(data, complete);
1779 since = data->progress.t_startsingle;
1781 since = data->progress.t_startop;
1782 if(data->mstate == MSTATE_RESOLVING)
1785 else if(data->mstate == MSTATE_CONNECTING)
1789 struct SingleRequest *k = &data->req;
1790 if(k->size != -1) {
1794 Curl_timediff(*now, since), k->bytecount, k->size);
1799 " bytes received", Curl_timediff(*now, since), k->bytecount);
1803 if(data->conn) {
1805 if(data->mstate > MSTATE_DO) {
1806 streamclose(data->conn, "Disconnect due to timeout");
1818 * We are doing protocol-specific connecting and this is being called over and
1826 struct connectdata *conn = data->conn;
1828 if(conn && conn->handler->connecting) {
1830 result = conn->handler->connecting(data, done);
1846 struct connectdata *conn = data->conn;
1848 if(conn && conn->handler->doing) {
1850 result = conn->handler->doing(data, done);
1867 struct connectdata *conn = data->conn;
1874 && conn->bits.protoconnstart) {
1879 Unless this protocol doesn't have any protocol-connect callback, as
1881 if(!conn->handler->connecting)
1887 if(!conn->bits.protoconnstart) {
1888 if(conn->handler->connect_it) {
1889 /* is there a protocol-specific connect() procedure? */
1891 /* Call the protocol-specific connect function */
1892 result = conn->handler->connect_it(data, protocol_done);
1900 conn->bits.protoconnstart = TRUE;
1908 multi->in_callback = value;
1929 if(multi->dead) {
1930 /* a multi-level callback returned error before, meaning every individual
1951 if(data->mstate > MSTATE_CONNECT &&
1952 data->mstate < MSTATE_COMPLETED) {
1954 DEBUGASSERT(data->conn);
1955 if(!data->conn)
1961 if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
1966 switch(data->mstate) {
1982 if(data->set.timeout)
1983 Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
1985 if(data->set.connecttimeout)
1986 Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
1992 /* add this handle to the list of connect-pending handles */
1993 Curl_llist_append(&multi->pending, data, &data->connect_queue);
1999 else if(data->state.previouslypending) {
2002 process_pending_handles(data->multi);
2027 struct connectdata *conn = data->conn;
2032 if(conn->bits.httpproxy)
2033 hostname = conn->http_proxy.host.name;
2036 if(conn->bits.conn_to_host)
2037 hostname = conn->conn_to_host.name;
2039 hostname = conn->host.name;
2042 dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
2046 data->state.async.dns = dns;
2047 data->state.async.done = TRUE;
2074 data->conn = NULL; /* no more connection */
2096 /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
2097 DEBUGASSERT(data->conn);
2100 if(data->conn->bits.proxy_connect_closed) {
2121 DEBUGASSERT(data->conn);
2137 if(!result && data->conn->bits.reuse) {
2166 /* protocol-specific connect phase */
2182 if(data->set.fprereq) {
2187 prereq_rc = data->set.fprereq(data->set.prereq_userp,
2188 data->info.primary.remote_ip,
2189 data->info.primary.local_ip,
2190 data->info.primary.remote_port,
2191 data->info.primary.local_port);
2194 failf(data, "operation aborted by pre-request callback");
2195 /* failure in pre-request callback - don't do any other processing */
2204 if(data->set.connect_only == 1) {
2206 connkeep(data->conn, "CONNECT_ONLY");
2215 /* When multi_do() returns failure, data->conn might be NULL! */
2221 if(data->state.wildcardmatch) {
2222 struct WildcardData *wc = data->wildcard;
2223 if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
2228 multistate(data, data->conn ?
2242 else if(data->conn->bits.do_more) {
2255 data->conn->bits.reuse) {
2305 if(data->conn)
2314 DEBUGASSERT(data->conn);
2319 multistate(data, data->conn->bits.do_more?
2336 DEBUGASSERT(data->conn);
2359 DEBUGASSERT(data->conn);
2360 if(data->conn->bits.multiplex)
2366 if((data->conn->sockfd != CURL_SOCKET_BAD) ||
2367 (data->conn->writesockfd != CURL_SOCKET_BAD))
2371 if(data->state.wildcardmatch &&
2372 ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
2373 data->wildcard->state = CURLWC_DONE;
2381 case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
2382 DEBUGASSERT(data->conn);
2390 if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2392 streamclose(data->conn, "Transfer returned error");
2399 if(data->set.max_send_speed)
2401 Curl_pgrsLimitWaitTime(data->progress.uploaded,
2402 data->progress.ul_limit_size,
2403 data->set.max_send_speed,
2404 data->progress.ul_limit_start,
2408 if(data->set.max_recv_speed)
2410 Curl_pgrsLimitWaitTime(data->progress.downloaded,
2411 data->progress.dl_limit_size,
2412 data->set.max_recv_speed,
2413 data->progress.dl_limit_start,
2433 if(data->set.max_send_speed)
2434 send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
2435 data->progress.ul_limit_size,
2436 data->set.max_send_speed,
2437 data->progress.ul_limit_start,
2442 if(data->set.max_recv_speed)
2443 recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
2444 data->progress.dl_limit_size,
2445 data->set.max_recv_speed,
2446 data->progress.dl_limit_start,
2462 if(data->req.done || (result == CURLE_RECV_ERROR)) {
2477 data->req.done = TRUE;
2486 streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
2487 data->state.httpwant = CURL_HTTP_VERSION_1_1;
2489 data->state.errorbuf = FALSE;
2492 newurl = strdup(data->state.url);
2497 data->req.done = TRUE;
2512 if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
2514 streamclose(data->conn, "Transfer returned error");
2519 else if(data->req.done && !Curl_cwriter_is_paused(data)) {
2526 if(data->req.newurl || retry) {
2529 /* if the URL is a follow-location and not just a retried request
2532 newurl = data->req.newurl;
2533 data->req.newurl = NULL;
2551 if(data->req.location) {
2553 newurl = data->req.location;
2554 data->req.location = NULL;
2568 else if(data->state.select_bits) {
2582 if(data->conn) {
2585 if(data->conn->bits.multiplex)
2589 /* post-transfer command */
2598 if(data->state.wildcardmatch) {
2599 if(data->wildcard->state != CURLWC_DONE) {
2600 /* if a wildcard is set and we are not ending -> lets start again
2625 if(data->mstate >= MSTATE_CONNECT &&
2626 data->mstate < MSTATE_DO &&
2629 /* We now handle stream timeouts if and only if this will be the last
2640 if(data->mstate < MSTATE_COMPLETED) {
2648 in the case blocks above - cleanup happens only here */
2653 if(data->conn) {
2657 struct connectdata *conn = data->conn;
2671 else if(data->mstate == MSTATE_CONNECT) {
2680 else if(data->conn && Curl_pgrsUpdate(data)) {
2684 streamclose(data->conn, "Aborted by callback");
2687 multistate(data, (data->mstate < MSTATE_DONE)?
2693 if(MSTATE_COMPLETED == data->mstate) {
2694 if(data->set.fmultidone) {
2696 data->set.fmultidone(data, result);
2700 msg = &data->msg;
2702 msg->extmsg.msg = CURLMSG_DONE;
2703 msg->extmsg.easy_handle = data;
2704 msg->extmsg.data.result = result;
2707 DEBUGASSERT(!data->conn);
2712 Curl_llist_append(&multi->msgsent, data, &data->connect_queue);
2719 data->result = result;
2734 if(multi->in_callback)
2737 data = multi->easyp;
2740 bool nosig = data->set.no_signal;
2748 struct Curl_easy *datanext = data->next;
2749 if(data->set.no_signal != nosig) {
2752 nosig = data->set.no_signal;
2773 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
2776 (void)add_next_timeout(now, multi, t->payload);
2779 *running_handles = multi->num_alive;
2791 struct Curl_llist_element *e = multi->msgsent.head;
2793 struct Curl_easy *data = e->ptr;
2794 DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
2795 data->multi = NULL;
2805 if(multi->in_callback)
2808 multi->magic = 0; /* not good anymore */
2813 data = multi->easyp;
2815 nextdata = data->next;
2816 if(!data->state.done && data->conn)
2819 if(data->dns.hostcachetype == HCACHE_MULTI) {
2821 Curl_hostcache_clean(data, data->dns.hostcache);
2822 data->dns.hostcache = NULL;
2823 data->dns.hostcachetype = HCACHE_NONE;
2827 data->state.conn_cache = NULL;
2828 data->multi = NULL; /* clear the association */
2831 if(data->psl == &multi->psl)
2832 data->psl = NULL;
2839 Curl_conncache_close_all_connections(&multi->conn_cache);
2841 sockhash_destroy(&multi->sockhash);
2842 Curl_conncache_destroy(&multi->conn_cache);
2843 Curl_hash_destroy(&multi->hostcache);
2844 Curl_psl_destroy(&multi->psl);
2847 WSACloseEvent(multi->wsa_event);
2850 wakeup_close(multi->wakeup_pair[0]);
2851 wakeup_close(multi->wakeup_pair[1]);
2856 Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
2884 !multi->in_callback &&
2885 Curl_llist_count(&multi->msglist)) {
2890 e = multi->msglist.head;
2892 msg = e->ptr;
2895 Curl_llist_remove(&multi->msglist, e, NULL);
2897 *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
2899 return &msg->extmsg;
2935 entry = sh_getentry(&multi->sockhash, s);
2939 for(j = 0; j< data->last_poll.num; j++) {
2940 if(s == data->last_poll.sockets[j]) {
2941 last_action = data->last_poll.actions[j];
2948 entry = sh_addentry(&multi->sockhash, s);
2956 entry->readers--;
2958 entry->writers--;
2960 entry->readers++;
2962 entry->writers++;
2966 entry->users++;
2968 entry->readers++;
2970 entry->writers++;
2973 if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
2975 Curl_hash_destroy(&entry->transfers);
2980 comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
2981 (entry->readers ? CURL_POLL_IN : 0);
2984 if(last_action && ((int)entry->action == comboaction))
2988 if(multi->socket_cb) {
2990 rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
2991 entry->socketp);
2994 if(rc == -1) {
2995 multi->dead = TRUE;
3000 entry->action = comboaction; /* store the current action state */
3004 * Need to remove the easy handle from the multi->sockhash->transfers and
3005 * remove multi->sockhash entry when this was the last transfer */
3006 for(i = 0; i< data->last_poll.num; i++) {
3009 s = data->last_poll.sockets[i];
3020 entry = sh_getentry(&multi->sockhash, s);
3024 unsigned char oldactions = data->last_poll.actions[i];
3026 entry->users--;
3028 entry->writers--;
3030 entry->readers--;
3031 if(!entry->users) {
3032 if(multi->socket_cb) {
3034 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
3035 multi->socket_userp, entry->socketp);
3037 if(rc == -1) {
3038 multi->dead = TRUE;
3042 sh_delentry(entry, &multi->sockhash, s);
3046 if(Curl_hash_delete(&entry->transfers, (char *)&data,
3055 memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll));
3061 if(singlesocket(data->multi, data))
3081 struct Curl_multi *multi = data->multi;
3085 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
3089 if(multi->socket_cb) {
3091 rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
3092 multi->socket_userp, entry->socketp);
3097 sh_delentry(entry, &multi->sockhash, s);
3098 if(rc == -1)
3102 multi->dead = TRUE;
3111 * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
3124 struct curltime *tv = &d->state.expiretime;
3125 struct Curl_llist *list = &d->state.timeoutlist;
3130 timeouts that are now passed tense and store the next pending
3132 for(e = list->head; e;) {
3133 struct Curl_llist_element *n = e->next;
3135 node = (struct time_node *)e->ptr;
3136 diff = Curl_timediff_us(node->time, now);
3145 e = list->head;
3149 tv->tv_sec = 0;
3150 tv->tv_usec = 0;
3154 memcpy(tv, &node->time, sizeof(*tv));
3158 multi->timetree = Curl_splayinsert(*tv, multi->timetree,
3159 &d->state.timenode);
3185 data = multi->easyp;
3188 data = data->next;
3192 /* or should we fall-through and do the timer-based stuff? */
3196 struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
3200 real-world tests it has been proved that libevent can in fact give
3210 Curl_hash_start_iterate(&entry->transfers, &iter);
3213 data = (struct Curl_easy *)he->ptr;
3215 DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
3217 if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK)) {
3219 data->state.select_bits |= (unsigned char)ev_bitmask;
3222 if (data->state.select_bits & CURL_CSELECT_IN) {
3223 data->last_pollin_time = now;
3225 data->last_os_pollin_time = now;
3228 if (data->state.select_bits & CURL_CSELECT_OUT) {
3229 data->last_pollout_time = now;
3231 data->last_os_pollout_time = now;
3239 /* Now we fall-through and do the timer-based stuff, since we don't want
3240 to force the user to have to deal with timeouts as long as at least
3250 /* Asked to run due to time-out. Clear the 'lastcall' variable to force
3255 memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
3259 * The loop following here will go on as long as there are expire-times left
3260 * to process in the splay and 'data' will be re-assigned for every expired
3268 nosig = data->set.no_signal; /* initial state */
3271 else if(data->set.no_signal != nosig) {
3274 nosig = data->set.no_signal; /* remember new state */
3290 multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
3292 data = t->payload; /* assign this for next loop */
3293 (void)add_next_timeout(now, multi, t->payload);
3300 *running_handles = multi->num_alive;
3315 if(multi->in_callback)
3322 multi->socket_cb = va_arg(param, curl_socket_callback);
3325 multi->socket_userp = va_arg(param, void *);
3328 multi->push_cb = va_arg(param, curl_push_callback);
3331 multi->push_userp = va_arg(param, void *);
3334 multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX ? 1 : 0;
3337 multi->timer_cb = va_arg(param, curl_multi_timer_callback);
3340 multi->timer_userp = va_arg(param, void *);
3345 multi->maxconnects = (unsigned int)uarg;
3348 multi->max_host_connections = va_arg(param, long);
3351 multi->max_total_connections = va_arg(param, long);
3369 multi->max_concurrent_streams = (unsigned int)streams;
3387 if(multi->in_callback)
3399 if(multi->in_callback)
3410 if(multi->in_callback)
3423 if(multi->dead) {
3428 if(multi->timetree) {
3433 multi->timetree = Curl_splay(tv_zero, multi->timetree);
3435 if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
3437 timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now);
3439 overly long timeouts */
3447 *timeout_ms = -1;
3459 if(multi->in_callback)
3474 if(!multi->timer_cb || multi->dead)
3481 if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
3482 multi->timer_lastcall = none;
3486 rc = multi->timer_cb(multi, -1, multi->timer_userp);
3488 if(rc == -1) {
3489 multi->dead = TRUE;
3497 /* When multi_timeout() is done, multi->timetree points to the node with the
3498 * timeout we got the (relative) time-out time for. We can thus easily check
3501 if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
3504 multi->timer_lastcall = multi->timetree->key;
3507 rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
3509 if(rc == -1) {
3510 multi->dead = TRUE;
3519 * Remove a given timestamp from the list of timeouts.
3525 struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3527 for(e = timeoutlist->head; e; e = e->next) {
3528 struct time_node *n = (struct time_node *)e->ptr;
3529 if(n->eid == eid) {
3539 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
3552 struct Curl_llist *timeoutlist = &data->state.timeoutlist;
3554 node = &data->state.expires[eid];
3557 memcpy(&node->time, stamp, sizeof(*stamp));
3558 node->eid = eid; /* also marks it as in use */
3563 for(e = timeoutlist->head; e; e = e->next) {
3564 struct time_node *check = (struct time_node *)e->ptr;
3565 timediff_t diff = Curl_timediff(check->time, node->time);
3575 Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
3583 * this'-time for the transfer, to be extracted by curl_multi_timeout()
3585 * The timeout will be added to a queue of timeouts if it defines a moment in
3592 struct Curl_multi *multi = data->multi;
3593 struct curltime *nowp = &data->state.expiretime;
3609 set.tv_usec -= 1000000;
3619 if(nowp->tv_sec || nowp->tv_usec) {
3621 Compare if the new time is earlier, and only remove-old/add-new if it
3633 the splay tree first and then re-add the new value */
3634 rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3635 &multi->timetree);
3643 data->state.timenode.payload = data;
3644 multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
3645 &data->state.timenode);
3667 struct Curl_multi *multi = data->multi;
3668 struct curltime *nowp = &data->state.expiretime;
3675 if(nowp->tv_sec || nowp->tv_usec) {
3678 struct Curl_llist *list = &data->state.timeoutlist;
3681 rc = Curl_splayremove(multi->timetree, &data->state.timenode,
3682 &multi->timetree);
3687 while(list->size > 0) {
3688 Curl_llist_remove(list, list->tail, NULL);
3694 nowp->tv_sec = 0;
3695 nowp->tv_usec = 0;
3707 there = sh_getentry(&multi->sockhash, s);
3712 there->socketp = hashp;
3719 return multi ? multi->max_host_connections : 0;
3724 return multi ? multi->max_total_connections : 0;
3736 DEBUGASSERT(data->multi);
3737 conn = data->conn;
3739 DEBUGASSERT(conn->bundle);
3741 conn->bundle->multiuse = bundlestate;
3742 process_pending_handles(data->multi);
3749 struct Curl_llist_element *e = multi->pending.head;
3751 struct Curl_easy *data = e->ptr;
3753 DEBUGASSERT(data->mstate == MSTATE_PENDING);
3761 Curl_llist_remove(&multi->pending, e, NULL);
3767 data->state.previouslypending = TRUE;
3773 if(data && data->multi)
3774 data->multi->in_callback = value;
3779 return (data && data->multi && data->multi->in_callback);
3785 return multi->max_concurrent_streams;
3791 (multi->num_easy + 1));
3794 struct Curl_easy *e = multi->easyp;
3796 DEBUGASSERT(i < multi->num_easy);
3797 if(!e->state.internal)
3799 e = e->next;
3810 DEBUGASSERT(data->multi);
3813 if(!data->multi) {
3817 if(!data->set.buffer_size) {
3821 if(data->multi->xfer_buf_borrowed) {
3826 if(data->multi->xfer_buf &&
3827 data->set.buffer_size > data->multi->xfer_buf_len) {
3829 free(data->multi->xfer_buf);
3830 data->multi->xfer_buf = NULL;
3831 data->multi->xfer_buf_len = 0;
3834 if(!data->multi->xfer_buf) {
3835 data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
3836 if(!data->multi->xfer_buf) {
3838 (size_t)data->set.buffer_size);
3841 data->multi->xfer_buf_len = data->set.buffer_size;
3844 data->multi->xfer_buf_borrowed = TRUE;
3845 *pbuf = data->multi->xfer_buf;
3846 *pbuflen = data->multi->xfer_buf_len;
3854 DEBUGASSERT(data->multi);
3855 DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
3856 data->multi->xfer_buf_borrowed = FALSE;
3863 DEBUGASSERT(data->multi);
3866 if(!data->multi) {
3870 if(!data->set.upload_buffer_size) {
3874 if(data->multi->xfer_ulbuf_borrowed) {
3879 if(data->multi->xfer_ulbuf &&
3880 data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
3882 free(data->multi->xfer_ulbuf);
3883 data->multi->xfer_ulbuf = NULL;
3884 data->multi->xfer_ulbuf_len = 0;
3887 if(!data->multi->xfer_ulbuf) {
3888 data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
3889 if(!data->multi->xfer_ulbuf) {
3891 (size_t)data->set.upload_buffer_size);
3894 data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
3897 data->multi->xfer_ulbuf_borrowed = TRUE;
3898 *pbuf = data->multi->xfer_ulbuf;
3899 *pbuflen = data->multi->xfer_ulbuf_len;
3907 DEBUGASSERT(data->multi);
3908 DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
3909 data->multi->xfer_ulbuf_borrowed = FALSE;
3915 Curl_safefree(multi->xfer_buf);
3916 multi->xfer_buf_len = 0;
3917 multi->xfer_buf_borrowed = FALSE;
3918 Curl_safefree(multi->xfer_ulbuf);
3919 multi->xfer_ulbuf_len = 0;
3920 multi->xfer_ulbuf_borrowed = FALSE;