mirror of
https://github.com/curl/curl.git
synced 2026-04-14 22:41:40 +03:00
cf-dns: connection filter for DNS queries
New connection filter `cf-dns` that manages DNS queries. If hands out addresses and HTTPS-RR records to anyone interested. Used by HTTPS and IP happy eyeballing. Information may become available *before* the libcurl "dns entry" is complete, e.g. all queries have been answered. The cf-ip-happy filter uses this information to start connection attempts as soon as the first address is available. The multi MSTATE_RESOLVING was removed. A new connection always goes to MSTATE_CONNECTING. The connectdata bit `dns_resolved` indicates when DNS information is complete. This is used for error reporting and starting the progress meter. Removed dns entries `data->state.dns[i]`, as the `cf-dns` filter now keeps the reference now. Many minor tweaks for making this work and pass address information around safely. Closes #21027
This commit is contained in:
parent
89741958e8
commit
335dc0e3c5
44 changed files with 1785 additions and 1017 deletions
190
lib/url.c
190
lib/url.c
|
|
@ -132,10 +132,6 @@ static void data_priority_cleanup(struct Curl_easy *data);
|
|||
# error READBUFFER_SIZE is too small
|
||||
#endif
|
||||
|
||||
#if !defined(CURL_DISABLE_PROXY) && defined(USE_UNIX_SOCKETS)
|
||||
#define UNIX_SOCKET_PREFIX "localhost"
|
||||
#endif
|
||||
|
||||
/* Reject URLs exceeding this length */
|
||||
#define MAX_URL_LEN 0xffff
|
||||
|
||||
|
|
@ -244,8 +240,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
|
|||
|
||||
/* release any resolve information this transfer kept */
|
||||
Curl_async_destroy(data);
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[0]); /* done with this */
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[1]);
|
||||
|
||||
data->set.verbose = FALSE; /* no more calls to DEBUGFUNCTION */
|
||||
data->magic = 0; /* force a clear AFTER the possibly enforced removal from
|
||||
|
|
@ -2951,118 +2945,6 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
static CURLcode resolve_unix(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const char *unix_path,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct Curl_dns_entry *hostaddr;
|
||||
bool longpath = FALSE;
|
||||
|
||||
DEBUGASSERT(unix_path);
|
||||
*pdns = NULL;
|
||||
|
||||
/* Unix domain sockets are local. The host gets ignored, use the specified
|
||||
* domain socket address. Do not cache "DNS entries". There is no DNS
|
||||
* involved and we already have the file system path available. */
|
||||
hostaddr = curlx_calloc(1, sizeof(struct Curl_dns_entry));
|
||||
if(!hostaddr)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
hostaddr->addr = Curl_unix2addr(unix_path, &longpath,
|
||||
(bool)conn->bits.abstract_unix_socket);
|
||||
if(!hostaddr->addr) {
|
||||
if(longpath)
|
||||
/* Long paths are not supported for now */
|
||||
failf(data, "Unix socket path too long: '%s'", unix_path);
|
||||
curlx_free(hostaddr);
|
||||
return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
hostaddr->refcount = 1; /* connection is the only one holding this */
|
||||
*pdns = hostaddr;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*************************************************************
|
||||
* Resolve the address of the server or proxy
|
||||
*************************************************************/
|
||||
static CURLcode resolve_server(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct hostname *ehost;
|
||||
uint16_t eport;
|
||||
timediff_t timeout_ms = Curl_timeleft_ms(data);
|
||||
const char *peertype = "host";
|
||||
CURLcode result;
|
||||
|
||||
*pdns = NULL;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
{
|
||||
const char *unix_path = conn->unix_domain_socket;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
|
||||
!strncmp(UNIX_SOCKET_PREFIX "/",
|
||||
conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
|
||||
unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
|
||||
#endif
|
||||
|
||||
if(unix_path) {
|
||||
/* This only works if previous transport is TRNSPRT_TCP. Check it? */
|
||||
conn->transport_wanted = TRNSPRT_UNIX;
|
||||
return resolve_unix(data, conn, unix_path, pdns);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(CONN_IS_PROXIED(conn)) {
|
||||
ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
|
||||
&conn->http_proxy.host;
|
||||
eport = conn->bits.socksproxy ? conn->socks_proxy.port :
|
||||
conn->http_proxy.port;
|
||||
peertype = "proxy";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
|
||||
/* If not connecting via a proxy, extract the port from the URL, if it is
|
||||
* there, thus overriding any defaults that might have been set above. */
|
||||
eport = conn->bits.conn_to_port ?
|
||||
conn->conn_to_port : (uint16_t)conn->remote_port;
|
||||
}
|
||||
|
||||
result = Curl_resolv(data, ehost->name, eport,
|
||||
conn->ip_version, conn->transport_wanted,
|
||||
timeout_ms, pdns);
|
||||
DEBUGASSERT(!result || !*pdns);
|
||||
if(!result) { /* resolved right away, either sync or from dnscache */
|
||||
DEBUGASSERT(*pdns);
|
||||
return CURLE_OK;
|
||||
}
|
||||
else if(result == CURLE_AGAIN) { /* async resolv in progress */
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
else if(result == CURLE_OPERATION_TIMEDOUT) { /* took too long */
|
||||
failf(data, "Failed to resolve %s '%s' with timeout after %"
|
||||
FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
|
||||
curlx_ptimediff_ms(Curl_pgrs_now(data),
|
||||
&data->progress.t_startsingle));
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(result);
|
||||
failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static void url_move_hostname(struct hostname *dest, struct hostname *src)
|
||||
{
|
||||
Curl_safefree(dest->rawalloc);
|
||||
|
|
@ -3308,6 +3190,10 @@ static CURLcode url_create_needle(struct Curl_easy *data,
|
|||
needle->recv[SECONDARYSOCKET] = Curl_cf_recv;
|
||||
needle->send[SECONDARYSOCKET] = Curl_cf_send;
|
||||
needle->bits.tcp_fastopen = data->set.tcp_fastopen;
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(Curl_conn_get_unix_path(needle))
|
||||
needle->transport_wanted = TRNSPRT_UNIX;
|
||||
#endif
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -3542,9 +3428,6 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
|
|||
CURLcode result = CURLE_OK;
|
||||
struct connectdata *conn = data->conn;
|
||||
|
||||
DEBUGASSERT(dns);
|
||||
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
||||
|
||||
if(!conn->bits.reuse)
|
||||
result = Curl_conn_setup(data, conn, FIRSTSOCKET, dns,
|
||||
CURL_CF_SSL_DEFAULT);
|
||||
|
|
@ -3556,15 +3439,12 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
|
|||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_connect(struct Curl_easy *data,
|
||||
bool *asyncp,
|
||||
bool *protocol_done)
|
||||
CURLcode Curl_connect(struct Curl_easy *data, bool *pconnected)
|
||||
{
|
||||
CURLcode result;
|
||||
struct connectdata *conn;
|
||||
|
||||
*asyncp = FALSE; /* assume synchronous resolves by default */
|
||||
*protocol_done = FALSE;
|
||||
*pconnected = FALSE;
|
||||
|
||||
/* Set the request to virgin state based on transfer settings */
|
||||
Curl_req_hard_reset(&data->req, data);
|
||||
|
|
@ -3573,43 +3453,31 @@ CURLcode Curl_connect(struct Curl_easy *data,
|
|||
result = url_find_or_create_conn(data);
|
||||
conn = data->conn;
|
||||
|
||||
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
|
||||
DEBUGASSERT(!conn);
|
||||
return result;
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
DEBUGASSERT(conn);
|
||||
Curl_pgrsTime(data, TIMER_POSTQUEUE);
|
||||
if(conn->bits.reuse) {
|
||||
if(conn->attached_xfers > 1)
|
||||
/* multiplexed */
|
||||
*pconnected = TRUE;
|
||||
}
|
||||
else if(conn->scheme->flags & PROTOPT_NONETWORK) {
|
||||
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
||||
*pconnected = TRUE;
|
||||
}
|
||||
else {
|
||||
result = Curl_conn_setup(data, conn, FIRSTSOCKET, NULL,
|
||||
CURL_CF_SSL_DEFAULT);
|
||||
if(!result)
|
||||
result = Curl_headers_init(data);
|
||||
CURL_TRC_M(data, "Curl_setup_conn() -> %d", result);
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
DEBUGASSERT(conn);
|
||||
Curl_pgrsTime(data, TIMER_POSTQUEUE);
|
||||
if(conn->bits.reuse) {
|
||||
if(conn->attached_xfers > 1)
|
||||
/* multiplexed */
|
||||
*protocol_done = TRUE;
|
||||
}
|
||||
else if(conn->scheme->flags & PROTOPT_NONETWORK) {
|
||||
*asyncp = FALSE;
|
||||
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
||||
*protocol_done = TRUE;
|
||||
}
|
||||
else {
|
||||
/*************************************************************
|
||||
* Resolve the address of the server or proxy
|
||||
*************************************************************/
|
||||
struct Curl_dns_entry *dns;
|
||||
result = resolve_server(data, conn, &dns);
|
||||
if(!result) {
|
||||
DEBUGASSERT(dns);
|
||||
/* DNS resolution is done: that is either because this is a reused
|
||||
connection, in which case DNS was unnecessary, or because DNS
|
||||
really did finish already (synch resolver/fast async resolve) */
|
||||
result = Curl_setup_conn(data, dns, protocol_done);
|
||||
}
|
||||
else if(result == CURLE_AGAIN) {
|
||||
*asyncp = TRUE;
|
||||
result = CURLE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if(result == CURLE_NO_CONNECTION_AVAILABLE)
|
||||
DEBUGASSERT(!conn);
|
||||
|
||||
if(result && conn) {
|
||||
/* We are not allowed to return failure with memory left allocated in the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue