aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/curl/lib/connect.c
diff options
context:
space:
mode:
authorAlexander Smirnov <alex@ydb.tech>2024-10-16 12:11:24 +0000
committerAlexander Smirnov <alex@ydb.tech>2024-10-16 12:11:24 +0000
commit40811e93f3fdf9342a9295369994012420fac548 (patch)
treea8d85e094a9c21e10aa250f537c101fc2016a049 /contrib/libs/curl/lib/connect.c
parent30ebe5357bb143648c6be4d151ecd4944af81ada (diff)
parent28a0c4a9f297064538a018c512cd9bbd00a1a35d (diff)
downloadydb-40811e93f3fdf9342a9295369994012420fac548.tar.gz
Merge branch 'rightlib' into mergelibs-241016-1210
Diffstat (limited to 'contrib/libs/curl/lib/connect.c')
-rw-r--r--contrib/libs/curl/lib/connect.c326
1 files changed, 136 insertions, 190 deletions
diff --git a/contrib/libs/curl/lib/connect.c b/contrib/libs/curl/lib/connect.c
index 923f37ac3b..ec5ab71d49 100644
--- a/contrib/libs/curl/lib/connect.c
+++ b/contrib/libs/curl/lib/connect.c
@@ -90,20 +90,28 @@
/*
* Curl_timeleft() returns the amount of milliseconds left allowed for the
- * transfer/connection. If the value is 0, there is no timeout (ie there is
+ * transfer/connection. If the value is 0, there's no timeout (ie there's
* infinite time left). If the value is negative, the timeout time has already
* elapsed.
- * @param data the transfer to check on
- * @param nowp timestamp to use for calculation, NULL to use Curl_now()
- * @param duringconnect TRUE iff connect timeout is also taken into account.
+ *
+ * If 'nowp' is non-NULL, it points to the current time.
+ * 'duringconnect' is FALSE if not during a connect, as then of course the
+ * connect timeout is not taken into account!
+ *
* @unittest: 1303
*/
+
+#define TIMEOUT_CONNECT 1
+#define TIMEOUT_MAXTIME 2
+
timediff_t Curl_timeleft(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect)
{
- timediff_t timeleft_ms = 0;
- timediff_t ctimeleft_ms = 0;
+ unsigned int timeout_set = 0;
+ timediff_t connect_timeout_ms = 0;
+ timediff_t maxtime_timeout_ms = 0;
+ timediff_t timeout_ms = 0;
struct curltime now;
/* The duration of a connect and the total transfer are calculated from two
@@ -111,101 +119,61 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
before the connect timeout expires and we must acknowledge whichever
timeout that is reached first. The total timeout is set per entire
operation, while the connect timeout is set per connect. */
- if(data->set.timeout <= 0 && !duringconnect)
- return 0; /* no timeout in place or checked, return "no limit" */
-
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
if(data->set.timeout > 0) {
- timeleft_ms = data->set.timeout -
- Curl_timediff(*nowp, data->progress.t_startop);
- if(!timeleft_ms)
- timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
- if(!duringconnect)
- return timeleft_ms; /* no connect check, this is it */
+ timeout_set = TIMEOUT_MAXTIME;
+ maxtime_timeout_ms = data->set.timeout;
}
-
if(duringconnect) {
- timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
+ timeout_set |= TIMEOUT_CONNECT;
+ connect_timeout_ms = (data->set.connecttimeout > 0) ?
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
- ctimeleft_ms = ctimeout_ms -
- Curl_timediff(*nowp, data->progress.t_startsingle);
- if(!ctimeleft_ms)
- ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
- if(!timeleft_ms)
- return ctimeleft_ms; /* no general timeout, this is it */
}
- /* return minimal time left or max amount already expired */
- return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
-}
-
-void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
- struct curltime *nowp)
-{
- struct curltime now;
+ if(!timeout_set)
+ /* no timeout */
+ return 0;
- DEBUGASSERT(data->conn);
if(!nowp) {
now = Curl_now();
nowp = &now;
}
- data->conn->shutdown.start[sockindex] = *nowp;
- data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
- data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
-}
-
-timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
- struct curltime *nowp)
-{
- struct curltime now;
- timediff_t left_ms;
- if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
- return 0; /* not started or no limits */
-
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
+ if(timeout_set & TIMEOUT_MAXTIME) {
+ maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ timeout_ms = maxtime_timeout_ms;
}
- left_ms = conn->shutdown.timeout_ms -
- Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
- return left_ms? left_ms : -1;
-}
-timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
- struct curltime *nowp)
-{
- timediff_t left_ms = 0, ms;
- struct curltime now;
- int i;
+ if(timeout_set & TIMEOUT_CONNECT) {
+ connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
- for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
- if(!conn->shutdown.start[i].tv_sec)
- continue;
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
- ms = Curl_shutdown_timeleft(conn, i, nowp);
- if(ms && (!left_ms || ms < left_ms))
- left_ms = ms;
+ if(!(timeout_set & TIMEOUT_MAXTIME) ||
+ (connect_timeout_ms < maxtime_timeout_ms))
+ timeout_ms = connect_timeout_ms;
}
- return left_ms;
-}
-void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
-{
- struct curltime *pt = &data->conn->shutdown.start[sockindex];
- memset(pt, 0, sizeof(*pt));
+ if(!timeout_ms)
+ /* avoid returning 0 as that means no timeout! */
+ return -1;
+
+ return timeout_ms;
}
-bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
+/* Copies connection info into the transfer handle to make it available when
+ the transfer handle is no longer associated with the connection. */
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+ char *local_ip, int local_port)
{
- struct curltime *pt = &data->conn->shutdown.start[sockindex];
- return (pt->tv_sec > 0) || (pt->tv_usec > 0);
+ memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
+ if(local_ip && local_ip[0])
+ memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN);
+ else
+ data->info.conn_local_ip[0] = 0;
+ data->info.conn_scheme = conn->handler->scheme;
+ /* conn_protocol can only provide "old" protocols */
+ data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
+ data->info.conn_primary_port = conn->port;
+ data->info.conn_remote_port = conn->remote_port;
+ data->info.conn_local_port = local_port;
}
static const struct Curl_addrinfo *
@@ -236,7 +204,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port)
{
struct sockaddr_in *si = NULL;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
@@ -255,7 +223,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return TRUE;
}
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
@@ -287,6 +255,23 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return FALSE;
}
+struct connfind {
+ curl_off_t id_tofind;
+ struct connectdata *found;
+};
+
+static int conn_is_conn(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
+{
+ struct connfind *f = (struct connfind *)param;
+ (void)data;
+ if(conn->connection_id == f->id_tofind) {
+ f->found = conn;
+ return 1;
+ }
+ return 0;
+}
+
/*
* Used to extract socket and connectdata struct for the most recent
* transfer on the given Curl_easy.
@@ -303,19 +288,30 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
* - that is associated with a multi handle, and whose connection
* was detached with CURLOPT_CONNECT_ONLY
*/
- if(data->state.lastconnect_id != -1) {
- struct connectdata *conn;
-
- conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
- if(!conn) {
+ if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
+ struct connectdata *c;
+ struct connfind find;
+ find.id_tofind = data->state.lastconnect_id;
+ find.found = NULL;
+
+ Curl_conncache_foreach(data,
+ data->share && (data->share->specifier
+ & (1<< CURL_LOCK_DATA_CONNECT))?
+ &data->share->conn_cache:
+ data->multi_easy?
+ &data->multi_easy->conn_cache:
+ &data->multi->conn_cache, &find, conn_is_conn);
+
+ if(!find.found) {
data->state.lastconnect_id = -1;
return CURL_SOCKET_BAD;
}
+ c = find.found;
if(connp)
/* only store this if the caller cares for it */
- *connp = conn;
- return conn->sock[FIRSTSOCKET];
+ *connp = c;
+ return c->sock[FIRSTSOCKET];
}
return CURL_SOCKET_BAD;
}
@@ -330,7 +326,7 @@ void Curl_conncontrol(struct connectdata *conn,
#endif
)
{
- /* close if a connection, or a stream that is not multiplexed. */
+ /* close if a connection, or a stream that isn't multiplexed. */
/* This function will be called both before and after this connection is
associated with a transfer. */
bool closeit, is_multiplex;
@@ -371,7 +367,6 @@ struct eyeballer {
BIT(has_started); /* attempts have started */
BIT(is_done); /* out of addresses/time */
BIT(connected); /* cf has connected */
- BIT(shutdown); /* cf has shutdown */
BIT(inconclusive); /* connect was not a hard failure, we
* might talk to a restarting server */
};
@@ -410,12 +405,12 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
struct eyeballer *baller;
*pballer = NULL;
- baller = calloc(1, sizeof(*baller));
+ baller = calloc(1, sizeof(*baller) + 1000);
if(!baller)
return CURLE_OUT_OF_MEMORY;
baller->name = ((ai_family == AF_INET)? "ipv4" : (
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
(ai_family == AF_INET6)? "ipv6" :
#endif
"ip"));
@@ -478,7 +473,7 @@ static void baller_initiate(struct Curl_cfilter *cf,
CURLcode result;
- /* Do not close a previous cfilter yet to ensure that the next IP's
+ /* Don't close a previous cfilter yet to ensure that the next IP's
socket gets a different file descriptor, which can prevent bugs when
the curl_multi_socket_action interface is used with certain select()
replacements such as kqueue. */
@@ -547,11 +542,9 @@ static CURLcode baller_start_next(struct Curl_cfilter *cf,
{
if(cf->sockindex == FIRSTSOCKET) {
baller_next_addr(baller);
- /* If we get inconclusive answers from the server(s), we start
- * again until this whole thing times out. This allows us to
- * connect to servers that are gracefully restarting and the
- * packet routing to the new instance has not happened yet (e.g. QUIC). */
- if(!baller->addr && baller->inconclusive)
+ /* If we get inconclusive answers from the server(s), we make
+ * a second iteration over the address list */
+ if(!baller->addr && baller->inconclusive && !baller->rewinded)
baller_rewind(baller);
baller_start(cf, data, baller, timeoutms);
}
@@ -583,7 +576,7 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
baller->is_done = TRUE;
}
else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
- infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T
+ infof(data, "%s connect timeout after %" CURL_FORMAT_TIMEDIFF_T
"ms, move on!", baller->name, baller->timeoutms);
#if defined(ETIMEDOUT)
baller->error = ETIMEDOUT;
@@ -674,7 +667,7 @@ evaluate:
/* Nothing connected, check the time before we might
* start new ballers or return ok. */
if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) {
- failf(data, "Connection timeout after %" FMT_OFF_T " ms",
+ failf(data, "Connection timeout after %" CURL_FORMAT_CURL_OFF_T " ms",
Curl_timediff(now, data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
@@ -697,7 +690,8 @@ evaluate:
CURL_TRC_CF(data, cf, "%s done", baller->name);
}
else {
- CURL_TRC_CF(data, cf, "%s starting (timeout=%" FMT_TIMEDIFF_T "ms)",
+ CURL_TRC_CF(data, cf, "%s starting (timeout=%"
+ CURL_FORMAT_TIMEDIFF_T "ms)",
baller->name, baller->timeoutms);
++ongoing;
++added;
@@ -742,8 +736,8 @@ evaluate:
hostname = conn->host.name;
failf(data, "Failed to connect to %s port %u after "
- "%" FMT_TIMEDIFF_T " ms: %s",
- hostname, conn->primary.remote_port,
+ "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+ hostname, conn->port,
Curl_timediff(now, data->progress.t_startsingle),
curl_easy_strerror(result));
@@ -759,7 +753,7 @@ evaluate:
}
/*
- * Connect to the given host with timeout, proxy or remote does not matter.
+ * Connect to the given host with timeout, proxy or remote doesn't matter.
* There might be more than one IP address to try out.
*/
static CURLcode start_connect(struct Curl_cfilter *cf,
@@ -769,9 +763,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
struct cf_he_ctx *ctx = cf->ctx;
struct connectdata *conn = cf->conn;
CURLcode result = CURLE_COULDNT_CONNECT;
- int ai_family0 = 0, ai_family1 = 0;
+ int ai_family0, ai_family1;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
- const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
+ const struct Curl_addrinfo *addr0, *addr1;
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
@@ -790,33 +784,33 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
* the 2 connect attempt ballers to try different families, if possible.
*
*/
- if(conn->ip_version == CURL_IPRESOLVE_V6) {
-#ifdef USE_IPV6
- ai_family0 = AF_INET6;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
+ /* any IP version is allowed */
+ ai_family0 = remotehost->addr?
+ remotehost->addr->ai_family : 0;
+#ifdef ENABLE_IPV6
+ ai_family1 = ai_family0 == AF_INET6 ?
+ AF_INET : AF_INET6;
+#else
+ ai_family1 = AF_UNSPEC;
#endif
}
- else if(conn->ip_version == CURL_IPRESOLVE_V4) {
- ai_family0 = AF_INET;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
- }
else {
- /* no user preference, we try ipv6 always first when available */
-#ifdef USE_IPV6
- ai_family0 = AF_INET6;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ /* only one IP version is allowed */
+ ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
+ AF_INET :
+#ifdef ENABLE_IPV6
+ AF_INET6;
+#else
+ AF_UNSPEC;
#endif
- /* next candidate is ipv4 */
- ai_family1 = AF_INET;
- addr1 = addr_first_match(remotehost->addr, ai_family1);
- /* no ip address families, probably AF_UNIX or something, use the
- * address family given to us */
- if(!addr1 && !addr0 && remotehost->addr) {
- ai_family0 = remotehost->addr->ai_family;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
- }
+ ai_family1 = AF_UNSPEC;
}
+ /* Get the first address in the list that matches the family,
+ * this might give NULL, if we do not have any matches. */
+ addr0 = addr_first_match(remotehost->addr, ai_family0);
+ addr1 = addr_first_match(remotehost->addr, ai_family1);
if(!addr0 && addr1) {
/* switch around, so a single baller always uses addr0 */
addr0 = addr1;
@@ -835,7 +829,8 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
timeout_ms, EXPIRE_DNS_PER_NAME);
if(result)
return result;
- CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)",
+ CURL_TRC_CF(data, cf, "created %s (timeout %"
+ CURL_FORMAT_TIMEDIFF_T "ms)",
ctx->baller[0]->name, ctx->baller[0]->timeoutms);
if(addr1) {
/* second one gets a delayed start */
@@ -846,7 +841,8 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
timeout_ms, EXPIRE_DNS_PER_NAME2);
if(result)
return result;
- CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)",
+ CURL_TRC_CF(data, cf, "created %s (timeout %"
+ CURL_FORMAT_TIMEDIFF_T "ms)",
ctx->baller[1]->name, ctx->baller[1]->timeoutms);
Curl_expire(data, data->set.happy_eyeballs_timeout,
EXPIRE_HAPPY_EYEBALLS);
@@ -870,46 +866,6 @@ static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
ctx->winner = NULL;
}
-static CURLcode cf_he_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- struct cf_he_ctx *ctx = cf->ctx;
- size_t i;
- CURLcode result = CURLE_OK;
-
- DEBUGASSERT(data);
- if(cf->connected) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- /* shutdown all ballers that have not done so already. If one fails,
- * continue shutting down others until all are shutdown. */
- for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
- struct eyeballer *baller = ctx->baller[i];
- bool bdone = FALSE;
- if(!baller || !baller->cf || baller->shutdown)
- continue;
- baller->result = baller->cf->cft->do_shutdown(baller->cf, data, &bdone);
- if(baller->result || bdone)
- baller->shutdown = TRUE; /* treat a failed shutdown as done */
- }
-
- *done = TRUE;
- for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
- if(ctx->baller[i] && !ctx->baller[i]->shutdown)
- *done = FALSE;
- }
- if(*done) {
- for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
- if(ctx->baller[i] && ctx->baller[i]->result)
- result = ctx->baller[i]->result;
- }
- }
- CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
- return result;
-}
-
static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@@ -952,7 +908,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
if(result)
return result;
ctx->state = SCFST_WAITING;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SCFST_WAITING:
result = is_connected(cf, data, done);
if(!result && *done) {
@@ -966,20 +922,12 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
cf->next = ctx->winner->cf;
ctx->winner->cf = NULL;
cf_he_ctx_clear(cf, data);
+ Curl_conn_cf_cntrl(cf->next, data, TRUE,
+ CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
- if(Curl_trc_cf_is_verbose(cf, data)) {
- struct ip_quadruple ipquad;
- int is_ipv6;
- if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
- const char *host, *disphost;
- int port;
- cf->next->cft->get_host(cf->next, data, &host, &disphost, &port);
- CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
- disphost, ipquad.remote_ip, ipquad.remote_port);
- }
- }
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ Curl_verboseconnect(data, cf->conn);
data->info.numconnects++; /* to track the # of connections made */
}
break;
@@ -1113,7 +1061,6 @@ struct Curl_cftype Curl_cft_happy_eyeballs = {
cf_he_destroy,
cf_he_connect,
cf_he_close,
- cf_he_shutdown,
Curl_cf_def_get_host,
cf_he_adjust_pollset,
cf_he_data_pending,
@@ -1174,12 +1121,12 @@ struct transport_provider {
};
static
-#ifndef UNITTESTS
+#ifndef DEBUGBUILD
const
#endif
struct transport_provider transport_providers[] = {
{ TRNSPRT_TCP, Curl_cf_tcp_create },
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
{ TRNSPRT_QUIC, Curl_cf_quic_create },
#endif
#ifndef CURL_DISABLE_TFTP
@@ -1378,7 +1325,6 @@ struct Curl_cftype Curl_cft_setup = {
cf_setup_destroy,
cf_setup_connect,
cf_setup_close,
- Curl_cf_def_shutdown,
Curl_cf_def_get_host,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
@@ -1441,7 +1387,7 @@ out:
return result;
}
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
/* used by unit2600.c */
void Curl_debug_set_transport_provider(int transport,
cf_ip_connect_create *cf_create)
@@ -1454,7 +1400,7 @@ void Curl_debug_set_transport_provider(int transport,
}
}
}
-#endif /* UNITTESTS */
+#endif /* DEBUGBUILD */
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,