url.c: code/comment cleanup around conn creation

Several comments were outdated and parameters to create_conn() and
ConnectionExists() were not needed. Give functions better names and
consistently use terms `needle` and `conn`.

No functional change.

Closes #20464
This commit is contained in:
Stefan Eissing 2026-01-28 17:20:57 +01:00 committed by Daniel Stenberg
parent 161be30854
commit d7a9f1ab15
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2

428
lib/url.c
View file

@ -1268,25 +1268,22 @@ static bool url_match_result(bool result, void *userdata)
} }
/* /*
* Given one filled in connection struct (named needle), this function should * Given a transfer and a prototype connection (needle),
* detect if there already is one that has all the significant details * find and attach an existing connection that matches.
* exactly the same and thus should be used instead.
* *
* If there is a match, this function returns TRUE - and has marked the * Return TRUE if an existing connection was attached.
* connection as 'in-use'. It must later be called with ConnectionDone() to * `waitpipe` is TRUE if no existing connection matched, but there
* return back to 'idle' (unused) state. * might be suitable one in the near future (common cause: multiplexing
* * capability has not been determined yet, e.g. ALPN handshake).
* The force_reuse flag is set if the connection must be used.
*/ */
static bool ConnectionExists(struct Curl_easy *data, static bool url_attach_existing(struct Curl_easy *data,
struct connectdata *needle, struct connectdata *needle,
struct connectdata **usethis, bool *waitpipe)
bool *force_reuse,
bool *waitpipe)
{ {
struct url_conn_match match; struct url_conn_match match;
bool result; bool result;
DEBUGASSERT(!data->conn);
memset(&match, 0, sizeof(match)); memset(&match, 0, sizeof(match));
match.data = data; match.data = data;
match.needle = needle; match.needle = needle;
@ -1310,8 +1307,6 @@ static bool ConnectionExists(struct Curl_easy *data,
/* wait_pipe is TRUE if we encounter a bundle that is undecided. There /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
* is no matching connection then, yet. */ * is no matching connection then, yet. */
*usethis = match.found;
*force_reuse = (bool)match.force_reuse;
*waitpipe = (bool)match.wait_pipe; *waitpipe = (bool)match.wait_pipe;
return result; return result;
} }
@ -3118,42 +3113,41 @@ static void url_move_hostname(struct hostname *dest, struct hostname *src)
} }
/* /*
* Cleanup the connection `temp`, just allocated for `data`, before using the * Adjust reused connection settings to the transfer/needle.
* previously `existing` one for `data`. All relevant info is copied over
* and `temp` is freed.
*/ */
static void reuse_conn(struct Curl_easy *data, static void url_conn_reuse_adjust(struct Curl_easy *data,
struct connectdata *temp, struct connectdata *needle)
struct connectdata *existing)
{ {
/* get the user+password information from the temp struct since it may struct connectdata *conn = data->conn;
* be new for this request even when we reuse an existing connection */
if(temp->user) { /* get the user+password information from the needle since it may
* be new for this request even when we reuse conn */
if(needle->user) {
/* use the new username and password though */ /* use the new username and password though */
curlx_free(existing->user); curlx_free(conn->user);
curlx_free(existing->passwd); curlx_free(conn->passwd);
existing->user = temp->user; conn->user = needle->user;
existing->passwd = temp->passwd; conn->passwd = needle->passwd;
temp->user = NULL; needle->user = NULL;
temp->passwd = NULL; needle->passwd = NULL;
} }
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd; conn->bits.proxy_user_passwd = needle->bits.proxy_user_passwd;
if(existing->bits.proxy_user_passwd) { if(conn->bits.proxy_user_passwd) {
/* use the new proxy username and proxy password though */ /* use the new proxy username and proxy password though */
curlx_free(existing->http_proxy.user); curlx_free(conn->http_proxy.user);
curlx_free(existing->socks_proxy.user); curlx_free(conn->socks_proxy.user);
curlx_free(existing->http_proxy.passwd); curlx_free(conn->http_proxy.passwd);
curlx_free(existing->socks_proxy.passwd); curlx_free(conn->socks_proxy.passwd);
existing->http_proxy.user = temp->http_proxy.user; conn->http_proxy.user = needle->http_proxy.user;
existing->socks_proxy.user = temp->socks_proxy.user; conn->socks_proxy.user = needle->socks_proxy.user;
existing->http_proxy.passwd = temp->http_proxy.passwd; conn->http_proxy.passwd = needle->http_proxy.passwd;
existing->socks_proxy.passwd = temp->socks_proxy.passwd; conn->socks_proxy.passwd = needle->socks_proxy.passwd;
temp->http_proxy.user = NULL; needle->http_proxy.user = NULL;
temp->socks_proxy.user = NULL; needle->socks_proxy.user = NULL;
temp->http_proxy.passwd = NULL; needle->http_proxy.passwd = NULL;
temp->socks_proxy.passwd = NULL; needle->socks_proxy.passwd = NULL;
} }
#endif #endif
@ -3163,27 +3157,19 @@ static void reuse_conn(struct Curl_easy *data,
* - we use a proxy (not tunneling). we want to send all requests * - we use a proxy (not tunneling). we want to send all requests
* that use the same proxy on this connection. * that use the same proxy on this connection.
* - we have a "connect-to" setting that may redirect the hostname of * - we have a "connect-to" setting that may redirect the hostname of
* a new request to the same remote endpoint of an existing conn. * a new request to the same remote endpoint of an conn conn.
* We want to reuse an existing conn to the remote endpoint. * We want to reuse an conn conn to the remote endpoint.
* Since connection reuse does not match on conn->host necessarily, we * Since connection reuse does not match on conn->host necessarily, we
* switch `existing` conn to `temp` conn's host settings. * switch conn to needle's host settings.
* Is this correct in the case of TLS connections that have
* used the original hostname in SNI to negotiate? Do we send
* requests for another host through the different SNI?
*/ */
url_move_hostname(&existing->host, &temp->host); url_move_hostname(&conn->host, &needle->host);
url_move_hostname(&existing->conn_to_host, &temp->conn_to_host); url_move_hostname(&conn->conn_to_host, &needle->conn_to_host);
existing->conn_to_port = temp->conn_to_port; conn->conn_to_port = needle->conn_to_port;
existing->remote_port = temp->remote_port; conn->remote_port = needle->remote_port;
curlx_free(existing->hostname_resolve); curlx_free(conn->hostname_resolve);
existing->hostname_resolve = temp->hostname_resolve; conn->hostname_resolve = needle->hostname_resolve;
temp->hostname_resolve = NULL; needle->hostname_resolve = NULL;
/* reuse init */
existing->bits.reuse = TRUE; /* yes, we are reusing here */
Curl_conn_free(data, temp);
} }
static void conn_meta_freeentry(void *p) static void conn_meta_freeentry(void *p)
@ -3195,35 +3181,11 @@ static void conn_meta_freeentry(void *p)
DEBUGASSERT(p == NULL); DEBUGASSERT(p == NULL);
} }
/** static CURLcode url_create_needle(struct Curl_easy *data,
* create_conn() sets up a new connectdata struct, or reuses an already struct connectdata **pneedle)
* existing one, and resolves hostname.
*
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
* response will be coming asynchronously. If *async is FALSE, the name is
* already resolved.
*
* @param data The sessionhandle pointer
* @param in_connect is set to the next connection data pointer
* @param reusedp is set to to TRUE if connection was reused
* @see Curl_setup_conn()
*
*/
static CURLcode create_conn(struct Curl_easy *data,
struct connectdata **in_connect,
bool *reusedp)
{ {
struct connectdata *needle = NULL;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct connectdata *conn;
struct connectdata *existing = NULL;
bool reuse;
bool connections_available = TRUE;
bool force_reuse = FALSE;
bool waitpipe = FALSE;
*reusedp = FALSE;
*in_connect = NULL;
/************************************************************* /*************************************************************
* Check input data * Check input data
@ -3237,37 +3199,31 @@ static CURLcode create_conn(struct Curl_easy *data,
parts for checking against the already present connections. In order parts for checking against the already present connections. In order
to not have to modify everything at once, we allocate a temporary to not have to modify everything at once, we allocate a temporary
connection data struct and fill in for comparison purposes. */ connection data struct and fill in for comparison purposes. */
conn = allocate_conn(data); needle = allocate_conn(data);
if(!needle) {
if(!conn) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
goto out; goto out;
} }
/* We must set the return variable as soon as possible, so that our
parent can cleanup any possible allocs we may have done before
any failure */
*in_connect = conn;
/* Do the unfailable inits first, before checks that may early return */ /* Do the unfailable inits first, before checks that may early return */
Curl_hash_init(&conn->meta_hash, 23, Curl_hash_init(&needle->meta_hash, 23,
Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry); Curl_hash_str, curlx_str_key_compare, conn_meta_freeentry);
result = parseurlandfillconn(data, conn); result = parseurlandfillconn(data, needle);
if(result) if(result)
goto out; goto out;
if(data->set.str[STRING_SASL_AUTHZID]) { if(data->set.str[STRING_SASL_AUTHZID]) {
conn->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]); needle->sasl_authzid = curlx_strdup(data->set.str[STRING_SASL_AUTHZID]);
if(!conn->sasl_authzid) { if(!needle->sasl_authzid) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
goto out; goto out;
} }
} }
if(data->set.str[STRING_BEARER]) { if(data->set.str[STRING_BEARER]) {
conn->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]); needle->oauth_bearer = curlx_strdup(data->set.str[STRING_BEARER]);
if(!conn->oauth_bearer) { if(!needle->oauth_bearer) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
goto out; goto out;
} }
@ -3275,20 +3231,20 @@ static CURLcode create_conn(struct Curl_easy *data,
#ifdef USE_UNIX_SOCKETS #ifdef USE_UNIX_SOCKETS
if(data->set.str[STRING_UNIX_SOCKET_PATH]) { if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
conn->unix_domain_socket = needle->unix_domain_socket =
curlx_strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); curlx_strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
if(!conn->unix_domain_socket) { if(!needle->unix_domain_socket) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
goto out; goto out;
} }
conn->bits.abstract_unix_socket = data->set.abstract_unix_socket; needle->bits.abstract_unix_socket = data->set.abstract_unix_socket;
} }
#endif #endif
/* After the Unix socket init but before the proxy vars are used, parse and /* After the Unix socket init but before the proxy vars are used, parse and
initialize the proxy vars */ initialize the proxy vars */
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
result = create_conn_helper_init_proxy(data, conn); result = create_conn_helper_init_proxy(data, needle);
if(result) if(result)
goto out; goto out;
@ -3296,24 +3252,24 @@ static CURLcode create_conn(struct Curl_easy *data,
* If the protocol is using SSL and HTTP proxy is used, we set * If the protocol is using SSL and HTTP proxy is used, we set
* the tunnel_proxy bit. * the tunnel_proxy bit.
*************************************************************/ *************************************************************/
if((conn->given->flags & PROTOPT_SSL) && conn->bits.httpproxy) if((needle->given->flags & PROTOPT_SSL) && needle->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE; needle->bits.tunnel_proxy = TRUE;
#endif #endif
/************************************************************* /*************************************************************
* Figure out the remote port number and fix it in the URL * Figure out the remote port number and fix it in the URL
*************************************************************/ *************************************************************/
result = parse_remote_port(data, conn); result = parse_remote_port(data, needle);
if(result) if(result)
goto out; goto out;
/* Check for overridden login details and set them accordingly so that /* Check for overridden login details and set them accordingly so that
they are known when protocol->setup_connection is called! */ they are known when protocol->setup_connection is called! */
result = override_login(data, conn); result = override_login(data, needle);
if(result) if(result)
goto out; goto out;
result = set_login(data, conn); /* default credentials */ result = set_login(data, needle); /* default credentials */
if(result) if(result)
goto out; goto out;
@ -3321,7 +3277,7 @@ static CURLcode create_conn(struct Curl_easy *data,
* Process the "connect to" linked list of hostname/port mappings. * Process the "connect to" linked list of hostname/port mappings.
* Do this after the remote port number has been fixed in the URL. * Do this after the remote port number has been fixed in the URL.
*************************************************************/ *************************************************************/
result = parse_connect_to_slist(data, conn, data->set.connect_to); result = parse_connect_to_slist(data, needle, data->set.connect_to);
if(result) if(result)
goto out; goto out;
@ -3329,38 +3285,39 @@ static CURLcode create_conn(struct Curl_easy *data,
* IDN-convert the proxy hostnames * IDN-convert the proxy hostnames
*************************************************************/ *************************************************************/
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy) { if(needle->bits.httpproxy) {
result = Curl_idnconvert_hostname(&conn->http_proxy.host); result = Curl_idnconvert_hostname(&needle->http_proxy.host);
if(result) if(result)
return result; goto out;
} }
if(conn->bits.socksproxy) { if(needle->bits.socksproxy) {
result = Curl_idnconvert_hostname(&conn->socks_proxy.host); result = Curl_idnconvert_hostname(&needle->socks_proxy.host);
if(result) if(result)
return result; goto out;
} }
#endif #endif
if(conn->bits.conn_to_host) { if(needle->bits.conn_to_host) {
result = Curl_idnconvert_hostname(&conn->conn_to_host); result = Curl_idnconvert_hostname(&needle->conn_to_host);
if(result) if(result)
return result; goto out;
} }
/************************************************************* /*************************************************************
* Check whether the host and the "connect to host" are equal. * Check whether the host and the "connect to host" are equal.
* Do this after the hostnames have been IDN-converted. * Do this after the hostnames have been IDN-converted.
*************************************************************/ *************************************************************/
if(conn->bits.conn_to_host && if(needle->bits.conn_to_host &&
curl_strequal(conn->conn_to_host.name, conn->host.name)) { curl_strequal(needle->conn_to_host.name, needle->host.name)) {
conn->bits.conn_to_host = FALSE; needle->bits.conn_to_host = FALSE;
} }
/************************************************************* /*************************************************************
* Check whether the port and the "connect to port" are equal. * Check whether the port and the "connect to port" are equal.
* Do this after the remote port number has been fixed in the URL. * Do this after the remote port number has been fixed in the URL.
*************************************************************/ *************************************************************/
if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { if(needle->bits.conn_to_port &&
conn->bits.conn_to_port = FALSE; needle->conn_to_port == needle->remote_port) {
needle->bits.conn_to_port = FALSE;
} }
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
@ -3368,101 +3325,137 @@ static CURLcode create_conn(struct Curl_easy *data,
* If the "connect to" feature is used with an HTTP proxy, * If the "connect to" feature is used with an HTTP proxy,
* we set the tunnel_proxy bit. * we set the tunnel_proxy bit.
*************************************************************/ *************************************************************/
if((conn->bits.conn_to_host || conn->bits.conn_to_port) && if((needle->bits.conn_to_host || needle->bits.conn_to_port) &&
conn->bits.httpproxy) needle->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE; needle->bits.tunnel_proxy = TRUE;
#endif #endif
/************************************************************* /*************************************************************
* Setup internals depending on protocol. Needs to be done after * Setup internals depending on protocol. Needs to be done after
* we figured out what/if proxy to use. * we figured out what/if proxy to use.
*************************************************************/ *************************************************************/
result = setup_connection_internals(data, conn); result = setup_connection_internals(data, needle);
if(result) if(result)
goto out; goto out;
if(needle->scheme->flags & PROTOPT_ALPN) {
/* The protocol wants it, so set the bits if enabled in the easy handle
(default) */
if(data->set.ssl_enable_alpn)
needle->bits.tls_enable_alpn = TRUE;
}
if(!(needle->scheme->flags & PROTOPT_NONETWORK)) {
/* Setup callbacks for network connections */
needle->recv[FIRSTSOCKET] = Curl_cf_recv;
needle->send[FIRSTSOCKET] = Curl_cf_send;
needle->recv[SECONDARYSOCKET] = Curl_cf_recv;
needle->send[SECONDARYSOCKET] = Curl_cf_send;
needle->bits.tcp_fastopen = data->set.tcp_fastopen;
}
out:
if(!result) {
DEBUGASSERT(needle);
*pneedle = needle;
}
else {
*pneedle = NULL;
if(needle)
Curl_conn_free(data, needle);
}
return result;
}
/**
* Find an existing connection for the transfer or create a new one.
* Returns
* - CURLE_OK on success with a connection attached to data
* - CURLE_NO_CONNECTION_AVAILABLE when connection limits apply or when
* a suitable connection has not determined its multiplex capability.
* - a fatal error
*/
static CURLcode url_find_or_create_conn(struct Curl_easy *data)
{
struct connectdata *needle = NULL;
bool waitpipe = FALSE;
CURLcode result;
/* create the template connection for transfer data. Use this needle to
* find an existing connection or, if none exists, convert needle
* to a full connection and attach it to data. */
result = url_create_needle(data, &needle);
if(result)
goto out;
DEBUGASSERT(needle);
/*********************************************************************** /***********************************************************************
* file: is a special case in that it does not need a network connection * file: is a special case in that it does not need a network connection
***********************************************************************/ ***********************************************************************/
#ifndef CURL_DISABLE_FILE #ifndef CURL_DISABLE_FILE
if(conn->scheme->flags & PROTOPT_NONETWORK) { if(needle->scheme->flags & PROTOPT_NONETWORK) {
bool done; bool done;
/* this is supposed to be the connect function so we better at least check /* this is supposed to be the connect function so we better at least check
that the file is present here! */ that the file is present here! */
DEBUGASSERT(conn->scheme->run->connect_it); DEBUGASSERT(needle->scheme->run->connect_it);
data->info.conn_scheme = conn->scheme->name; data->info.conn_scheme = needle->scheme->name;
/* conn_protocol can only provide "old" protocols */ /* conn_protocol can only provide "old" protocols */
data->info.conn_protocol = (conn->scheme->protocol) & CURLPROTO_MASK; data->info.conn_protocol = (needle->scheme->protocol) & CURLPROTO_MASK;
result = conn->scheme->run->connect_it(data, &done); result = needle->scheme->run->connect_it(data, &done);
if(result) if(result)
goto out; goto out;
/* Setup a "faked" transfer that will do nothing */ /* Setup a "faked" transfer that will do nothing */
Curl_attach_connection(data, conn); Curl_attach_connection(data, needle);
result = Curl_cpool_add(data, conn); needle = NULL;
result = Curl_cpool_add(data, data->conn);
if(!result) { if(!result) {
/* Setup whatever necessary for a resumed transfer */ /* Setup whatever necessary for a resumed transfer */
result = setup_range(data); result = setup_range(data);
if(!result) { if(!result) {
Curl_xfer_setup_nop(data); Curl_xfer_setup_nop(data);
result = Curl_init_do(data, conn); result = Curl_init_do(data, data->conn);
} }
} }
if(result) { if(result) {
DEBUGASSERT(conn->scheme->run->done); DEBUGASSERT(data->conn->scheme->run->done);
/* we ignore the return code for the protocol-specific DONE */ /* we ignore the return code for the protocol-specific DONE */
(void)conn->scheme->run->done(data, result, FALSE); (void)data->conn->scheme->run->done(data, result, FALSE);
} }
goto out; goto out;
} }
#endif #endif
/* Setup filter for network connections */
conn->recv[FIRSTSOCKET] = Curl_cf_recv;
conn->send[FIRSTSOCKET] = Curl_cf_send;
conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
conn->send[SECONDARYSOCKET] = Curl_cf_send;
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
/* Complete the easy's SSL configuration for connection cache matching */ /* Complete the easy's SSL configuration for connection cache matching */
result = Curl_ssl_easy_config_complete(data); result = Curl_ssl_easy_config_complete(data);
if(result) if(result)
goto out; goto out;
/* Get rid of any dead connections so limit are easier kept. */
Curl_cpool_prune_dead(data); Curl_cpool_prune_dead(data);
/************************************************************* /*************************************************************
* Check the current list of connections to see if we can * Reuse of existing connection is not allowed when
* reuse an already existing one or if we have to create a * - connect_only is set or
* new one. * - reuse_fresh is set and this is not a follow-up request
* (like with HTTP followlocation)
*************************************************************/ *************************************************************/
if((!data->set.reuse_fresh || data->state.followlocation) &&
!data->set.connect_only) {
/* Ok, try to find and attach an existing one */
url_attach_existing(data, needle, &waitpipe);
}
DEBUGASSERT(conn->user); if(data->conn) {
DEBUGASSERT(conn->passwd); /* We attached an existing connection for this transfer. Copy
* over transfer specific properties over from needle. */
/* reuse_fresh is TRUE if we are told to use a new connection by force, but struct connectdata *conn = data->conn;
we only acknowledge this option if this is not a reused connection VERBOSE(bool tls_upgraded = (!(needle->given->flags & PROTOPT_SSL) &&
already (which happens due to follow-location or during an HTTP
authentication phase). CONNECT_ONLY transfers also refuse reuse. */
if((data->set.reuse_fresh && !data->state.followlocation) ||
data->set.connect_only)
reuse = FALSE;
else
reuse = ConnectionExists(data, conn, &existing, &force_reuse, &waitpipe);
if(reuse) {
/*
* We already have a connection for this, we got the former connection in
* `existing` and thus we need to cleanup the one we just
* allocated before we can move along and use `existing`.
*/
VERBOSE(bool tls_upgraded = (!(conn->given->flags & PROTOPT_SSL) &&
Curl_conn_is_ssl(conn, FIRSTSOCKET))); Curl_conn_is_ssl(conn, FIRSTSOCKET)));
reuse_conn(data, conn, existing); conn->bits.reuse = TRUE;
conn = existing; url_conn_reuse_adjust(data, needle);
*in_connect = conn;
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
infof(data, "Reusing existing %s: connection%s with %s %s", infof(data, "Reusing existing %s: connection%s with %s %s",
@ -3483,27 +3476,21 @@ static CURLcode create_conn(struct Curl_easy *data,
/* We have decided that we want a new connection. However, we may not /* We have decided that we want a new connection. However, we may not
be able to do that if we have reached the limit of how many be able to do that if we have reached the limit of how many
connections we are allowed to open. */ connections we are allowed to open. */
DEBUGF(infof(data, "new connection, bits.close=%d", conn->bits.close)); DEBUGF(infof(data, "new connection, bits.close=%d", needle->bits.close));
if(conn->scheme->flags & PROTOPT_ALPN) {
/* The protocol wants it, so set the bits if enabled in the easy handle
(default) */
if(data->set.ssl_enable_alpn)
conn->bits.tls_enable_alpn = TRUE;
}
if(waitpipe) { if(waitpipe) {
/* There is a connection that *might* become usable for multiplexing /* There is a connection that *might* become usable for multiplexing
"soon", and we wait for that */ "soon", and we wait for that */
infof(data, "Waiting on connection to negotiate possible multiplexing."); infof(data, "Waiting on connection to negotiate possible multiplexing.");
connections_available = FALSE; result = CURLE_NO_CONNECTION_AVAILABLE;
goto out;
} }
else { else {
switch(Curl_cpool_check_limits(data, conn)) { switch(Curl_cpool_check_limits(data, needle)) {
case CPOOL_LIMIT_DEST: case CPOOL_LIMIT_DEST:
infof(data, "No more connections allowed to host"); infof(data, "No more connections allowed to host");
connections_available = FALSE; result = CURLE_NO_CONNECTION_AVAILABLE;
break; goto out;
case CPOOL_LIMIT_TOTAL: case CPOOL_LIMIT_TOTAL:
if(data->master_mid != UINT32_MAX) if(data->master_mid != UINT32_MAX)
CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override " CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
@ -3511,7 +3498,8 @@ static CURLcode create_conn(struct Curl_easy *data,
else { else {
infof(data, "No connections available, total of %zu reached.", infof(data, "No connections available, total of %zu reached.",
data->multi->max_total_connections); data->multi->max_total_connections);
connections_available = FALSE; result = CURLE_NO_CONNECTION_AVAILABLE;
goto out;
} }
break; break;
default: default:
@ -3519,29 +3507,20 @@ static CURLcode create_conn(struct Curl_easy *data,
} }
} }
if(!connections_available) { /* Convert needle into a full connection by filling in all the
Curl_conn_free(data, conn); * remaining parts like the cloned SSL configuration. */
*in_connect = NULL; result = Curl_ssl_conn_config_init(data, needle);
if(result) {
result = CURLE_NO_CONNECTION_AVAILABLE; DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
goto out; goto out;
} }
else { /* attach it and no longer own it */
/* Curl_attach_connection(data, needle);
* This is a brand new connection, so let's store it in the connection needle = NULL;
* cache of ours!
*/
result = Curl_ssl_conn_config_init(data, conn);
if(result) {
DEBUGF(curl_mfprintf(stderr, "Error: init connection ssl config\n"));
goto out;
}
Curl_attach_connection(data, conn); result = Curl_cpool_add(data, data->conn);
result = Curl_cpool_add(data, conn); if(result)
if(result) goto out;
goto out;
}
#ifdef USE_NTLM #ifdef USE_NTLM
/* If NTLM is requested in a part of this connection, make sure we do not /* If NTLM is requested in a part of this connection, make sure we do not
@ -3564,43 +3543,34 @@ static CURLcode create_conn(struct Curl_easy *data,
} }
/* Setup and init stuff before DO starts, in preparing for the transfer. */ /* Setup and init stuff before DO starts, in preparing for the transfer. */
result = Curl_init_do(data, conn); result = Curl_init_do(data, data->conn);
if(result) if(result)
goto out; goto out;
/* /* Setup whatever necessary for a resumed transfer */
* Setup whatever necessary for a resumed transfer
*/
result = setup_range(data); result = setup_range(data);
if(result) if(result)
goto out; goto out;
/* Continue connectdata initialization here. */
if(conn->bits.reuse) {
/* We are reusing the connection - no need to resolve anything, and
idnconvert_hostname() was called already in create_conn() for the reuse
case. */
*reusedp = TRUE;
}
/* persist the scheme and handler the transfer is using */ /* persist the scheme and handler the transfer is using */
data->info.conn_scheme = conn->scheme->name; data->info.conn_scheme = data->conn->scheme->name;
/* conn_protocol can only provide "old" protocols */ /* conn_protocol can only provide "old" protocols */
data->info.conn_protocol = (conn->scheme->protocol) & CURLPROTO_MASK; data->info.conn_protocol = (data->conn->scheme->protocol) & CURLPROTO_MASK;
data->info.used_proxy = data->info.used_proxy =
#ifdef CURL_DISABLE_PROXY #ifdef CURL_DISABLE_PROXY
0 0
#else #else
conn->bits.proxy data->conn->bits.proxy
#endif #endif
; ;
/* Everything general done, inform filters that they need /* Lastly, inform connection filters that a new transfer is attached */
* to prepare for a data transfer. */
result = Curl_conn_ev_data_setup(data); result = Curl_conn_ev_data_setup(data);
out: out:
if(needle)
Curl_conn_free(data, needle);
DEBUGASSERT(result || data->conn);
return result; return result;
} }
@ -3636,7 +3606,6 @@ CURLcode Curl_connect(struct Curl_easy *data,
{ {
CURLcode result; CURLcode result;
struct connectdata *conn; struct connectdata *conn;
bool reused = FALSE;
*asyncp = FALSE; /* assume synchronous resolves by default */ *asyncp = FALSE; /* assume synchronous resolves by default */
*protocol_done = FALSE; *protocol_done = FALSE;
@ -3644,8 +3613,9 @@ CURLcode Curl_connect(struct Curl_easy *data,
/* Set the request to virgin state based on transfer settings */ /* Set the request to virgin state based on transfer settings */
Curl_req_hard_reset(&data->req, data); Curl_req_hard_reset(&data->req, data);
/* call the stuff that needs to be called */ /* Get or create a connection for the transfer. */
result = create_conn(data, &conn, &reused); result = url_find_or_create_conn(data);
conn = data->conn;
if(result == CURLE_NO_CONNECTION_AVAILABLE) { if(result == CURLE_NO_CONNECTION_AVAILABLE) {
DEBUGASSERT(!conn); DEBUGASSERT(!conn);
@ -3655,7 +3625,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
if(!result) { if(!result) {
DEBUGASSERT(conn); DEBUGASSERT(conn);
Curl_pgrsTime(data, TIMER_POSTQUEUE); Curl_pgrsTime(data, TIMER_POSTQUEUE);
if(reused) { if(conn->bits.reuse) {
if(conn->attached_xfers > 1) if(conn->attached_xfers > 1)
/* multiplexed */ /* multiplexed */
*protocol_done = TRUE; *protocol_done = TRUE;