mirror of
https://github.com/curl/curl.git
synced 2026-04-14 18:31:42 +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
|
|
@ -149,6 +149,7 @@ LIB_CFILES = \
|
|||
asyn-thrdd.c \
|
||||
bufq.c \
|
||||
bufref.c \
|
||||
cf-dns.c \
|
||||
cf-h1-proxy.c \
|
||||
cf-h2-proxy.c \
|
||||
cf-haproxy.c \
|
||||
|
|
@ -278,6 +279,7 @@ LIB_HFILES = \
|
|||
asyn.h \
|
||||
bufq.h \
|
||||
bufref.h \
|
||||
cf-dns.h \
|
||||
cf-h1-proxy.h \
|
||||
cf-h2-proxy.h \
|
||||
cf-haproxy.h \
|
||||
|
|
|
|||
|
|
@ -349,6 +349,19 @@ static timediff_t async_ares_poll_timeout(struct async_ares_ctx *ares,
|
|||
return 1000;
|
||||
}
|
||||
|
||||
const struct Curl_addrinfo *
|
||||
Curl_async_get_ai(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async,
|
||||
int ai_family, unsigned int index)
|
||||
{
|
||||
/* Not supported by our implementation yet. */
|
||||
(void)data;
|
||||
(void)async;
|
||||
(void)ai_family;
|
||||
(void)index;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_async_await()
|
||||
*
|
||||
|
|
|
|||
250
lib/asyn-thrdd.c
250
lib/asyn-thrdd.c
|
|
@ -118,9 +118,6 @@ CURLcode Curl_async_get_impl(struct Curl_easy *data,
|
|||
|
||||
struct async_thrdd_item {
|
||||
struct Curl_addrinfo *res;
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo hints;
|
||||
#endif
|
||||
#ifdef CURLVERBOSE
|
||||
char description[CURL_ASYN_ITEM_DESC_LEN];
|
||||
#endif
|
||||
|
|
@ -156,7 +153,7 @@ async_thrdd_item_create(struct Curl_easy *data,
|
|||
{
|
||||
size_t hostlen = strlen(hostname);
|
||||
struct async_thrdd_item *item;
|
||||
VERBOSE(const char *qtype = "A");
|
||||
VERBOSE(const char *qtype);
|
||||
|
||||
item = curlx_calloc(1, sizeof(*item) + hostlen);
|
||||
if(!item)
|
||||
|
|
@ -170,27 +167,9 @@ async_thrdd_item_create(struct Curl_easy *data,
|
|||
item->mid = data->mid;
|
||||
item->async_id = async_id;
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
{
|
||||
int pf = PF_INET;
|
||||
#ifdef CURLRES_IPV6
|
||||
if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
|
||||
/* The stack seems to be IPv6-enabled */
|
||||
if(ip_version == CURL_IPRESOLVE_V6)
|
||||
pf = PF_INET6;
|
||||
else
|
||||
pf = PF_UNSPEC;
|
||||
}
|
||||
#endif /* CURLRES_IPV6 */
|
||||
item->hints.ai_family = pf;
|
||||
item->hints.ai_socktype = Curl_socktype_for_transport(transport);
|
||||
#ifdef CURLVERBOSE
|
||||
qtype = (pf == PF_INET6) ? "AAAA" : "A+AAAA";
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_GETADDRINFO */
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
qtype = (ip_version == CURL_IPRESOLVE_WHATEVER) ? "A+AAAA":
|
||||
((ip_version == CURL_IPRESOLVE_V6) ? "AAAA" : "A");
|
||||
curl_msnprintf(item->description, sizeof(item->description),
|
||||
"[%" FMT_OFF_T "/%d] %s %s:%u",
|
||||
data->id, item->async_id, qtype, item->hostname, item->port);
|
||||
|
|
@ -245,8 +224,7 @@ static CURLcode async_rr_start(struct Curl_easy *data,
|
|||
|
||||
DEBUGASSERT(!thrdd->rr.channel);
|
||||
if(async->port != 443) {
|
||||
rrname = curl_maprintf("_%d_.https.%s",
|
||||
async->port, data->conn->host.name);
|
||||
rrname = curl_maprintf("_%d_.https.%s", async->port, async->hostname);
|
||||
if(!rrname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
|
@ -271,10 +249,11 @@ static CURLcode async_rr_start(struct Curl_easy *data,
|
|||
thrdd->rr.hinfo.port = -1;
|
||||
thrdd->rr.hinfo.rrname = rrname;
|
||||
ares_query_dnsrec(thrdd->rr.channel,
|
||||
rrname ? rrname : data->conn->host.name, ARES_CLASS_IN,
|
||||
rrname ? rrname : async->hostname, ARES_CLASS_IN,
|
||||
ARES_REC_TYPE_HTTPS,
|
||||
async_thrdd_rr_done, data, NULL);
|
||||
CURL_TRC_DNS(data, "Issued HTTPS-RR request for %s", data->conn->host.name);
|
||||
CURL_TRC_DNS(data, "Issued HTTPS-RR request for %s",
|
||||
rrname ? rrname : async->hostname);
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -309,8 +288,10 @@ void Curl_async_thrdd_destroy(struct Curl_easy *data,
|
|||
}
|
||||
Curl_httpsrr_cleanup(&async->thrdd.rr.hinfo);
|
||||
#endif
|
||||
async_thrdd_item_destroy(async->thrdd.resolved);
|
||||
async->thrdd.resolved = NULL;
|
||||
async_thrdd_item_destroy(async->thrdd.res_A);
|
||||
async->thrdd.res_A = NULL;
|
||||
async_thrdd_item_destroy(async->thrdd.res_AAAA);
|
||||
async->thrdd.res_AAAA = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -352,22 +333,38 @@ CURLcode Curl_async_await(struct Curl_easy *data,
|
|||
static void async_thrdd_item_process(void *arg)
|
||||
{
|
||||
struct async_thrdd_item *item = arg;
|
||||
struct addrinfo hints;
|
||||
char service[12];
|
||||
int pf = PF_INET;
|
||||
int rc;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
if(item->delay_ms) {
|
||||
curlx_wait_ms(item->delay_ms);
|
||||
}
|
||||
if(item->delay_fail_ms) {
|
||||
curlx_wait_ms(item->delay_fail_ms);
|
||||
return;
|
||||
}
|
||||
if(item->delay_ms) {
|
||||
curlx_wait_ms(item->delay_ms);
|
||||
}
|
||||
if(item->delay_fail_ms) {
|
||||
curlx_wait_ms(item->delay_fail_ms);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
curl_msnprintf(service, sizeof(service), "%d", item->port);
|
||||
|
||||
rc = Curl_getaddrinfo_ex(item->hostname, service,
|
||||
&item->hints, &item->res);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
#ifdef CURLRES_IPV6
|
||||
if(item->ip_version != CURL_IPRESOLVE_V4) {
|
||||
pf = (item->ip_version == CURL_IPRESOLVE_V6) ? PF_INET6 : PF_UNSPEC;
|
||||
}
|
||||
#endif
|
||||
hints.ai_family = pf;
|
||||
hints.ai_socktype = Curl_socktype_for_transport(item->transport);
|
||||
hints.ai_protocol = Curl_protocol_for_transport(item->transport);
|
||||
#ifdef AI_NUMERICSERV
|
||||
/* Without service and flags, resolvers might lookup up in more
|
||||
* places than we want them to, causing a delay. */
|
||||
hints.ai_flags |= AI_NUMERICSERV;
|
||||
#endif
|
||||
curl_msnprintf(service, sizeof(service), "%u", item->port);
|
||||
|
||||
rc = Curl_getaddrinfo_ex(item->hostname, service, &hints, &item->res);
|
||||
if(rc) {
|
||||
item->sock_error = SOCKERRNO ? SOCKERRNO : rc;
|
||||
if(item->sock_error == 0)
|
||||
|
|
@ -466,6 +463,39 @@ void Curl_async_thrdd_multi_destroy(struct Curl_multi *multi, bool join)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
static void async_thrdd_report_item(struct Curl_easy *data,
|
||||
struct async_thrdd_item *item)
|
||||
{
|
||||
char buf[MAX_IPADR_LEN];
|
||||
struct dynbuf tmp;
|
||||
const char *sep = "";
|
||||
const struct Curl_addrinfo *ai = item->res;
|
||||
int ai_family = (item->ip_version == CURL_IPRESOLVE_V6) ? AF_INET6 : AF_INET;
|
||||
CURLcode result;
|
||||
|
||||
curlx_dyn_init(&tmp, 1024);
|
||||
for(; ai; ai = ai->ai_next) {
|
||||
if(ai->ai_family == ai_family) {
|
||||
Curl_printable_address(ai, buf, sizeof(buf));
|
||||
result = curlx_dyn_addf(&tmp, "%s%s", sep, buf);
|
||||
if(result) {
|
||||
CURL_TRC_DNS(data, "too many IP, cannot show");
|
||||
goto out;
|
||||
}
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
infof(data, "Host %s:%u resolved IPv%c: %s",
|
||||
item->hostname, item->port,
|
||||
(item->ip_version == CURL_IPRESOLVE_V6) ? '6' : '4',
|
||||
(curlx_dyn_len(&tmp) ? curlx_dyn_ptr(&tmp) : "(none)"));
|
||||
out:
|
||||
curlx_dyn_free(&tmp);
|
||||
}
|
||||
#endif /* CURLVERBOSE */
|
||||
|
||||
/* Process the receiving end of the thread queue, dispatching
|
||||
* processed items to their transfer when it can still be found
|
||||
* and has an `async` state present. Otherwise, destroy the item. */
|
||||
|
|
@ -478,19 +508,28 @@ void Curl_async_thrdd_multi_process(struct Curl_multi *multi)
|
|||
/* dispatch resolve result */
|
||||
struct async_thrdd_item *item = qitem;
|
||||
|
||||
CURL_TRC_DNS(multi->admin, "[async] got %s'%s'",
|
||||
item->res ? "" : "negative for ", item->description);
|
||||
|
||||
data = Curl_multi_get_easy(multi, item->mid);
|
||||
/* there is a chance that the original resolve was discarded and
|
||||
* either no new, or a new resolve with a different id is ongoing. */
|
||||
if(data && data->conn && data->state.async &&
|
||||
(data->state.async->id == item->async_id)) {
|
||||
struct Curl_resolv_async *async = data->state.async;
|
||||
struct async_thrdd_item **pdest = &async->thrdd.res_A;
|
||||
|
||||
async->thrdd.resolved = item;
|
||||
async->thrdd.done = TRUE;
|
||||
item = NULL;
|
||||
--async->thrdd.queued;
|
||||
async->thrdd.done = !async->thrdd.queued;
|
||||
|
||||
#ifdef CURLRES_IPV6
|
||||
if(item->ip_version == CURL_IPRESOLVE_V6)
|
||||
pdest = &async->thrdd.res_AAAA;
|
||||
#endif
|
||||
if(!*pdest) {
|
||||
VERBOSE(async_thrdd_report_item(data, item));
|
||||
*pdest = item;
|
||||
item = NULL;
|
||||
}
|
||||
else
|
||||
DEBUGASSERT(0); /* should not receive duplicates here */
|
||||
Curl_multi_mark_dirty(data);
|
||||
}
|
||||
async_thrdd_item_free(item);
|
||||
|
|
@ -509,31 +548,69 @@ CURLcode Curl_async_thrdd_multi_set_props(struct Curl_multi *multi,
|
|||
min_threads, max_threads, idle_time_ms);
|
||||
}
|
||||
|
||||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
static CURLcode async_thrdd_query(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async,
|
||||
uint8_t query_version)
|
||||
{
|
||||
struct async_thrdd_item *item;
|
||||
CURLcode result;
|
||||
|
||||
if(async->thrdd.queued || async->thrdd.done || async->thrdd.resolved)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
item = async_thrdd_item_create(data, async->hostname, async->port,
|
||||
async->ip_version, async->transport,
|
||||
query_version, async->transport,
|
||||
async->id);
|
||||
if(!item) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
CURL_TRC_DNS(data, "[async] queueing %s", item->description);
|
||||
/* queue takes ownership of `item` on success */
|
||||
result = Curl_thrdq_send(data->multi->resolv_thrdq, item,
|
||||
async_item_description(item), async->timeout_ms);
|
||||
if(!result)
|
||||
async->thrdd.queued = TRUE;
|
||||
else
|
||||
async_thrdd_item_destroy(item);
|
||||
if(result)
|
||||
goto out;
|
||||
item = NULL;
|
||||
async->thrdd.queued++;
|
||||
|
||||
out:
|
||||
if(item)
|
||||
async_thrdd_item_free(item);
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
CURLcode result = CURLE_FAILED_INIT;
|
||||
|
||||
if(async->thrdd.queued || async->thrdd.done)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
switch(async->ip_version) {
|
||||
#ifdef CURL_IPRESOLVE_V6
|
||||
case CURL_IPRESOLVE_V6:
|
||||
result = async_thrdd_query(data, async, CURL_IPRESOLVE_V6);
|
||||
break;
|
||||
#endif
|
||||
case CURL_IPRESOLVE_V4:
|
||||
result = async_thrdd_query(data, async, CURL_IPRESOLVE_V4);
|
||||
break;
|
||||
default:
|
||||
#ifdef CURL_IPRESOLVE_V6
|
||||
/* When resolving IP addresses, some resolvers (e.g. macOS) will
|
||||
* happily "embed" an IPv4 address into the IPv6 equivalent.
|
||||
* This will then confuse FTP that has been told an IPv4 for
|
||||
* DATA, but suddenly sees IPv6. */
|
||||
if(Curl_ipv6works(data) && !Curl_is_ipv4addr(async->hostname)) {
|
||||
result = async_thrdd_query(data, async, CURL_IPRESOLVE_V6);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
result = async_thrdd_query(data, async, CURL_IPRESOLVE_V4);
|
||||
break;
|
||||
}
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
Curl_thrdq_trace(data->multi->resolv_thrdq, data, &Curl_trc_feat_dns);
|
||||
#endif
|
||||
|
|
@ -604,7 +681,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
|
|||
|
||||
DEBUGASSERT(pdns);
|
||||
*pdns = NULL;
|
||||
if(!thrdd->queued) {
|
||||
if(!thrdd->queued && !thrdd->done) {
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
|
@ -615,17 +692,17 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
|
|||
(void)Curl_ares_perform(thrdd->rr.channel, 0);
|
||||
#endif
|
||||
|
||||
if(!thrdd->done) {
|
||||
CURL_TRC_DNS(data, "[async] take %s:%d -> EAGAIN",
|
||||
async->hostname, async->port);
|
||||
if(!thrdd->done)
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
|
||||
Curl_expire_done(data, EXPIRE_ASYNC_NAME);
|
||||
if(thrdd->resolved && thrdd->resolved->res) {
|
||||
if((thrdd->res_A && thrdd->res_A->res) ||
|
||||
(thrdd->res_AAAA && thrdd->res_AAAA->res)) {
|
||||
struct Curl_dns_entry *dns =
|
||||
Curl_dnscache_mk_entry(data, &thrdd->resolved->res,
|
||||
async->hostname, async->port, async->ip_version);
|
||||
Curl_dnscache_mk_entry2(data,
|
||||
thrdd->res_A ? &thrdd->res_A->res : NULL,
|
||||
thrdd->res_AAAA ? &thrdd->res_AAAA->res : NULL,
|
||||
async->hostname, async->port, async->ip_version);
|
||||
if(!dns)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
|
|
@ -643,8 +720,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
|
|||
}
|
||||
#endif
|
||||
if(!result && dns) {
|
||||
CURL_TRC_DNS(data, "[async] resolved: %s",
|
||||
thrdd->resolved->description);
|
||||
CURL_TRC_DNS(data, "[async] resolving complete");
|
||||
*pdns = dns;
|
||||
dns = NULL;
|
||||
}
|
||||
|
|
@ -666,4 +742,42 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
|
|||
return result;
|
||||
}
|
||||
|
||||
static const struct Curl_addrinfo *
|
||||
async_thrdd_get_ai(const struct Curl_addrinfo *ai,
|
||||
int ai_family, unsigned int index)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for(i = 0; ai; ai = ai->ai_next) {
|
||||
if(ai->ai_family == ai_family) {
|
||||
if(i == index)
|
||||
return ai;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct Curl_addrinfo *
|
||||
Curl_async_get_ai(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async,
|
||||
int ai_family, unsigned int index)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &async->thrdd;
|
||||
|
||||
(void)data;
|
||||
switch(ai_family) {
|
||||
case AF_INET:
|
||||
if(thrdd->res_A)
|
||||
return async_thrdd_get_ai(thrdd->res_A->res, ai_family, index);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if(thrdd->res_AAAA)
|
||||
return async_thrdd_get_ai(thrdd->res_AAAA->res, ai_family, index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* USE_RESOLV_THREADED */
|
||||
|
|
|
|||
12
lib/asyn.h
12
lib/asyn.h
|
|
@ -124,6 +124,11 @@ CURLcode Curl_async_await(struct Curl_easy *data,
|
|||
CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async);
|
||||
|
||||
const struct Curl_addrinfo *
|
||||
Curl_async_get_ai(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async,
|
||||
int ai_family, unsigned int index);
|
||||
|
||||
#ifdef USE_ARES
|
||||
/* common functions for c-ares and threaded resolver with HTTPSRR */
|
||||
#include <ares.h>
|
||||
|
|
@ -175,7 +180,8 @@ struct async_thrdd_item;
|
|||
|
||||
/* Context for threaded resolver */
|
||||
struct async_thrdd_ctx {
|
||||
struct async_thrdd_item *resolved;
|
||||
struct async_thrdd_item *res_A; /* ipv4 result */
|
||||
struct async_thrdd_item *res_AAAA; /* ipv6 result */
|
||||
#if defined(USE_HTTPSRR) && defined(USE_ARES)
|
||||
struct {
|
||||
ares_channel channel;
|
||||
|
|
@ -184,7 +190,7 @@ struct async_thrdd_ctx {
|
|||
BIT(done);
|
||||
} rr;
|
||||
#endif
|
||||
BIT(queued);
|
||||
uint32_t queued;
|
||||
BIT(done);
|
||||
};
|
||||
|
||||
|
|
@ -219,7 +225,7 @@ struct doh_probes;
|
|||
#define Curl_async_await(x, y, z) CURLE_COULDNT_RESOLVE_HOST
|
||||
#define Curl_async_global_init() CURLE_OK
|
||||
#define Curl_async_global_cleanup() Curl_nop_stmt
|
||||
|
||||
#define Curl_async_get_ai(a,b,c,d) NULL
|
||||
#endif /* !CURLRES_ASYNCH */
|
||||
|
||||
#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
|
||||
|
|
|
|||
556
lib/cf-dns.c
Normal file
556
lib/cf-dns.c
Normal file
|
|
@ -0,0 +1,556 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#include "urldata.h"
|
||||
#include "curl_addrinfo.h"
|
||||
#include "cfilters.h"
|
||||
#include "connect.h"
|
||||
#include "dnscache.h"
|
||||
#include "curl_trc.h"
|
||||
#include "progress.h"
|
||||
#include "url.h"
|
||||
#include "cf-dns.h"
|
||||
|
||||
|
||||
struct cf_dns_ctx {
|
||||
struct Curl_dns_entry *dns;
|
||||
CURLcode resolv_result;
|
||||
uint16_t port;
|
||||
uint8_t ip_version;
|
||||
uint8_t transport;
|
||||
BIT(started);
|
||||
BIT(announced);
|
||||
BIT(abstract_unix_socket);
|
||||
char hostname[1];
|
||||
};
|
||||
|
||||
static struct cf_dns_ctx *
|
||||
cf_dns_ctx_create(struct Curl_easy *data,
|
||||
const char *hostname, uint16_t port,
|
||||
uint8_t ip_version, uint8_t transport,
|
||||
bool abstract_unix_socket,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct cf_dns_ctx *ctx;
|
||||
size_t hlen = strlen(hostname);
|
||||
|
||||
ctx = curlx_calloc(1, sizeof(*ctx) + hlen);
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->port = port;
|
||||
ctx->ip_version = ip_version;
|
||||
ctx->transport = transport;
|
||||
ctx->abstract_unix_socket = abstract_unix_socket;
|
||||
ctx->dns = Curl_dns_entry_link(data, dns);
|
||||
ctx->started = !!ctx->dns;
|
||||
if(hlen)
|
||||
memcpy(ctx->hostname, hostname, hlen);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void cf_dns_ctx_destroy(struct Curl_easy *data,
|
||||
struct cf_dns_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_dns_entry_unlink(data, &ctx->dns);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
static void cf_dns_report_addr(struct Curl_easy *data,
|
||||
struct dynbuf *tmp,
|
||||
const char *label,
|
||||
int ai_family,
|
||||
const struct Curl_addrinfo *ai)
|
||||
{
|
||||
char buf[MAX_IPADR_LEN];
|
||||
const char *sep = "";
|
||||
CURLcode result;
|
||||
|
||||
curlx_dyn_reset(tmp);
|
||||
for(; ai; ai = ai->ai_next) {
|
||||
if(ai->ai_family == ai_family) {
|
||||
Curl_printable_address(ai, buf, sizeof(buf));
|
||||
result = curlx_dyn_addf(tmp, "%s%s", sep, buf);
|
||||
if(result) {
|
||||
infof(data, "too many IP, cannot show");
|
||||
return;
|
||||
}
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
infof(data, "%s%s", label,
|
||||
(curlx_dyn_len(tmp) ? curlx_dyn_ptr(tmp) : "(none)"));
|
||||
}
|
||||
|
||||
static void cf_dns_report(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
struct dynbuf tmp;
|
||||
|
||||
if(!Curl_trc_is_verbose(data) ||
|
||||
/* ignore no name or numerical IP addresses */
|
||||
!dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
|
||||
return;
|
||||
|
||||
switch(ctx->transport) {
|
||||
case TRNSPRT_UNIX:
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
CURL_TRC_CF(data, cf, "resolved unix domain %s",
|
||||
Curl_conn_get_unix_path(data->conn));
|
||||
#else
|
||||
DEBUGASSERT(0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
curlx_dyn_init(&tmp, 1024);
|
||||
infof(data, "Host %s:%d was resolved.", dns->hostname, dns->port);
|
||||
#ifdef CURLRES_IPV6
|
||||
cf_dns_report_addr(data, &tmp, "IPv6: ", AF_INET6, dns->addr);
|
||||
#endif
|
||||
cf_dns_report_addr(data, &tmp, "IPv4: ", AF_INET, dns->addr);
|
||||
curlx_dyn_free(&tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define cf_dns_report(x, y, z) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/*************************************************************
|
||||
* Resolve the address of the server or proxy
|
||||
*************************************************************/
|
||||
static CURLcode cf_dns_start(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
timediff_t timeout_ms = Curl_timeleft_ms(data);
|
||||
CURLcode result;
|
||||
|
||||
*pdns = NULL;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(ctx->transport == TRNSPRT_UNIX) {
|
||||
CURL_TRC_CF(data, cf, "resolve unix socket %s", ctx->hostname);
|
||||
return Curl_resolv_unix(data, ctx->hostname,
|
||||
(bool)cf->conn->bits.abstract_unix_socket, pdns);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve target host right on */
|
||||
CURL_TRC_CF(data, cf, "resolve host %s:%u", ctx->hostname, ctx->port);
|
||||
result = Curl_resolv(data, ctx->hostname, ctx->port, ctx->ip_version,
|
||||
ctx->transport, 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_OK;
|
||||
}
|
||||
else if(result == CURLE_OPERATION_TIMEDOUT) { /* took too long */
|
||||
failf(data, "Failed to resolve '%s' with timeout after %"
|
||||
FMT_TIMEDIFF_T " ms", ctx->hostname,
|
||||
curlx_ptimediff_ms(Curl_pgrs_now(data),
|
||||
&data->progress.t_startsingle));
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(result);
|
||||
failf(data, "Could not resolve: %s", ctx->hostname);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
{
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
*done = FALSE;
|
||||
if(!ctx->started) {
|
||||
ctx->started = TRUE;
|
||||
ctx->resolv_result = cf_dns_start(cf, data, &ctx->dns);
|
||||
}
|
||||
|
||||
if(!ctx->dns && !ctx->resolv_result) {
|
||||
ctx->resolv_result = Curl_resolv_take_result(data, &ctx->dns);
|
||||
if(!ctx->dns && !ctx->resolv_result)
|
||||
CURL_TRC_CF(data, cf, "DNS resolution not complete yet");
|
||||
}
|
||||
|
||||
if(ctx->resolv_result) {
|
||||
CURL_TRC_CF(data, cf, "error resolving: %d", ctx->resolv_result);
|
||||
return ctx->resolv_result;
|
||||
}
|
||||
|
||||
if(ctx->dns && !ctx->announced) {
|
||||
ctx->announced = TRUE;
|
||||
if(cf->sockindex == FIRSTSOCKET) {
|
||||
cf->conn->bits.dns_resolved = TRUE;
|
||||
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
||||
}
|
||||
cf_dns_report(cf, data, ctx->dns);
|
||||
}
|
||||
|
||||
if(cf->next && !cf->next->connected) {
|
||||
CURLcode result = Curl_conn_cf_connect(cf->next, data, done);
|
||||
CURL_TRC_CF(data, cf, "connect subfilters -> %d, done=%d", result, *done);
|
||||
if(result || !*done)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* sub filter chain is connected, so are we now.
|
||||
* Unlink the DNS entry, it is no longer needed and if it
|
||||
* came from a SHARE in `data`, we need to release it under
|
||||
* that one's lock. */
|
||||
DEBUGASSERT(*done);
|
||||
cf->connected = TRUE;
|
||||
Curl_async_shutdown(data);
|
||||
Curl_dns_entry_unlink(data, &ctx->dns);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void cf_dns_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
cf_dns_ctx_destroy(data, ctx);
|
||||
}
|
||||
|
||||
static void cf_dns_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
cf->connected = FALSE;
|
||||
if(cf->next)
|
||||
cf->next->cft->do_close(cf->next, data);
|
||||
}
|
||||
|
||||
static CURLcode cf_dns_adjust_pollset(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
if(!cf->connected)
|
||||
return Curl_resolv_pollset(data, ps);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode cf_dns_cntrl(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int event, int arg1, void *arg2)
|
||||
{
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
(void)arg1;
|
||||
(void)arg2;
|
||||
switch(event) {
|
||||
case CF_CTRL_DATA_DONE:
|
||||
if(ctx->dns) {
|
||||
/* Should only come here when the connect attempt failed and
|
||||
* `data` is giving up on it. On a successful connect, we already
|
||||
* unlinked the DNS entry. */
|
||||
Curl_dns_entry_unlink(data, &ctx->dns);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_dns = {
|
||||
"DNS",
|
||||
0,
|
||||
CURL_LOG_LVL_NONE,
|
||||
cf_dns_destroy,
|
||||
cf_dns_connect,
|
||||
cf_dns_close,
|
||||
Curl_cf_def_shutdown,
|
||||
cf_dns_adjust_pollset,
|
||||
Curl_cf_def_data_pending,
|
||||
Curl_cf_def_send,
|
||||
Curl_cf_def_recv,
|
||||
cf_dns_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_def_query,
|
||||
};
|
||||
|
||||
static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
uint8_t transport,
|
||||
bool abstract_unix_socket,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
struct cf_dns_ctx *ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
(void)data;
|
||||
ctx = cf_dns_ctx_create(data, hostname, port, ip_version, transport,
|
||||
abstract_unix_socket, dns);
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_dns, ctx);
|
||||
|
||||
out:
|
||||
*pcf = result ? NULL : cf;
|
||||
if(result)
|
||||
cf_dns_ctx_destroy(data, ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Create a "resolv" filter for the transfer's connection. Figures
|
||||
* out the hostname/path and port where to connect to. */
|
||||
static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
uint8_t transport,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
const char *hostname = NULL;
|
||||
uint16_t port = 0;
|
||||
uint8_t ip_version = conn->ip_version;
|
||||
bool abstract_unix_socket = FALSE;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
{
|
||||
const char *unix_path = Curl_conn_get_unix_path(conn);
|
||||
if(unix_path) {
|
||||
DEBUGASSERT(transport == TRNSPRT_UNIX);
|
||||
hostname = unix_path;
|
||||
abstract_unix_socket = (bool)conn->bits.abstract_unix_socket;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(!hostname && CONN_IS_PROXIED(conn)) {
|
||||
struct hostname *ehost;
|
||||
ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
|
||||
&conn->http_proxy.host;
|
||||
hostname = ehost->name;
|
||||
port = conn->bits.socksproxy ? conn->socks_proxy.port :
|
||||
conn->http_proxy.port;
|
||||
}
|
||||
#endif
|
||||
if(!hostname) {
|
||||
struct hostname *ehost;
|
||||
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. */
|
||||
hostname = ehost->name;
|
||||
port = conn->bits.conn_to_port ?
|
||||
conn->conn_to_port : (uint16_t)conn->remote_port;
|
||||
}
|
||||
|
||||
if(!hostname) {
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
return cf_dns_create(pcf, data, hostname, port, ip_version,
|
||||
transport, abstract_unix_socket, dns);
|
||||
}
|
||||
|
||||
/* Adds a "resolv" filter at the top of the connection's filter chain.
|
||||
* For FIRSTSOCKET, the `dns` parameter may be NULL. The filter will
|
||||
* figure out hostname and port to connect to and start the DNS resolve
|
||||
* on the first connect attempt.
|
||||
* For SECONDARYSOCKET, the `dns` parameter must be given.
|
||||
*/
|
||||
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
uint8_t transport,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
if(sockindex == FIRSTSOCKET)
|
||||
result = cf_dns_conn_create(&cf, data, transport, dns);
|
||||
else if(dns) {
|
||||
result = cf_dns_create(&cf, data, dns->hostname, dns->port,
|
||||
dns->ip_version, transport, FALSE, dns);
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(0);
|
||||
result = CURLE_FAILED_INIT;
|
||||
}
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Insert a new "resolv" filter directly after `cf`. It will
|
||||
* start a DNS resolve for the given hostnmae and port on the
|
||||
* first connect attempt.
|
||||
* See socks.c on how this is used to make a non-blocking DNS
|
||||
* resolve during connect.
|
||||
*/
|
||||
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
uint8_t transport)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_dns_create(&cf, data, hostname, port, ip_version,
|
||||
transport, FALSE, NULL);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Return the resolv result from the first "resolv" filter, starting
|
||||
* the given filter `cf` downwards.
|
||||
*/
|
||||
CURLcode Curl_cf_dns_result(struct Curl_cfilter *cf)
|
||||
{
|
||||
for(; cf; cf = cf->next) {
|
||||
if(cf->cft == &Curl_cft_dns) {
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
if(ctx->dns || ctx->resolv_result)
|
||||
return ctx->resolv_result;
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
}
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
/* Return the result of the DNS resolution. Searches for a "resolv"
|
||||
* filter from the top of the filter chain down. Returns
|
||||
* - CURLE_AGAIN when not done yet
|
||||
* - CURLE_OK when DNS was successfully resolved
|
||||
* - CURLR_FAILED_INIT when no resolv filter was found
|
||||
* - error returned by the DNS resolv
|
||||
*/
|
||||
CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex)
|
||||
{
|
||||
return Curl_cf_dns_result(conn->cfilter[sockindex]);
|
||||
}
|
||||
|
||||
static const struct Curl_addrinfo *
|
||||
cf_dns_get_nth_ai(const struct Curl_addrinfo *ai,
|
||||
int ai_family, unsigned int index)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for(i = 0; ai; ai = ai->ai_next) {
|
||||
if(ai->ai_family == ai_family) {
|
||||
if(i == index)
|
||||
return ai;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the addrinfo at `index` for the given `family` from the
|
||||
* first "resolve" filter underneath `cf`. If the DNS resolving is
|
||||
* not done yet or if no address for the family exists, returns NULL.
|
||||
*/
|
||||
const struct Curl_addrinfo *
|
||||
Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int ai_family,
|
||||
unsigned int index)
|
||||
{
|
||||
(void)data;
|
||||
for(; cf; cf = cf->next) {
|
||||
if(cf->cft == &Curl_cft_dns) {
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
if(ctx->resolv_result)
|
||||
return NULL;
|
||||
else if(ctx->dns)
|
||||
return cf_dns_get_nth_ai(ctx->dns->addr, ai_family, index);
|
||||
else
|
||||
return Curl_resolv_get_ai(data, ai_family, index);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the addrinfo at `index` for the given `family` from the
|
||||
* first "resolve" filter at the connection. If the DNS resolving is
|
||||
* not done yet or if no address for the family exists, returns NULL.
|
||||
*/
|
||||
const struct Curl_addrinfo *
|
||||
Curl_conn_dns_get_ai(struct Curl_easy *data,
|
||||
int sockindex,
|
||||
int ai_family,
|
||||
unsigned int index)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data,
|
||||
ai_family, index);
|
||||
}
|
||||
|
||||
#ifdef USE_HTTPSRR
|
||||
/* Return the HTTPS-RR info from the first "resolve" filter at the
|
||||
* connection. If the DNS resolving is not done yet or if there
|
||||
* is no HTTPS-RR info, returns NULL.
|
||||
*/
|
||||
const struct Curl_https_rrinfo *
|
||||
Curl_conn_dns_get_https(struct Curl_easy *data, int sockindex)
|
||||
{
|
||||
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
|
||||
for(; cf; cf = cf->next) {
|
||||
if(cf->cft == &Curl_cft_dns) {
|
||||
struct cf_dns_ctx *ctx = cf->ctx;
|
||||
return ctx->dns ? ctx->dns->hinfo : NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* USE_HTTPSRR */
|
||||
70
lib/cf-dns.h
Normal file
70
lib/cf-dns.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef HEADER_CURL_CF_DNS_H
|
||||
#define HEADER_CURL_CF_DNS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
struct Curl_dns_entry;
|
||||
struct Curl_addrinfo;
|
||||
|
||||
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
uint8_t transport,
|
||||
struct Curl_dns_entry *dns);
|
||||
|
||||
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
uint8_t transport);
|
||||
|
||||
CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex);
|
||||
CURLcode Curl_cf_dns_result(struct Curl_cfilter *cf);
|
||||
|
||||
|
||||
const struct Curl_addrinfo *
|
||||
Curl_conn_dns_get_ai(struct Curl_easy *data,
|
||||
int sockindex,
|
||||
int ai_family,
|
||||
unsigned int index);
|
||||
|
||||
const struct Curl_addrinfo *
|
||||
Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int ai_family,
|
||||
unsigned int index);
|
||||
|
||||
#ifdef USE_HTTPSRR
|
||||
const struct Curl_https_rrinfo *
|
||||
Curl_conn_dns_get_https(struct Curl_easy *data, int sockindex);
|
||||
#endif
|
||||
|
||||
|
||||
extern struct Curl_cftype Curl_cft_dns;
|
||||
|
||||
#endif /* HEADER_CURL_CF_DNS_H */
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include "urldata.h"
|
||||
#include "curl_trc.h"
|
||||
#include "cfilters.h"
|
||||
#include "cf-dns.h"
|
||||
#include "connect.h"
|
||||
#include "hostip.h"
|
||||
#include "httpsrr.h"
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#include "vquic/vquic.h"
|
||||
|
||||
typedef enum {
|
||||
CF_HC_RESOLV,
|
||||
CF_HC_INIT,
|
||||
CF_HC_CONNECT,
|
||||
CF_HC_SUCCESS,
|
||||
|
|
@ -116,8 +118,32 @@ struct cf_hc_ctx {
|
|||
size_t baller_count;
|
||||
timediff_t soft_eyeballs_timeout_ms;
|
||||
timediff_t hard_eyeballs_timeout_ms;
|
||||
uint8_t def_transport;
|
||||
};
|
||||
|
||||
static void cf_hc_ctx_reset(struct Curl_easy *data,
|
||||
struct cf_hc_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
size_t i;
|
||||
for(i = 0; i < ctx->baller_count; ++i)
|
||||
cf_hc_baller_reset(&ctx->ballers[i], data);
|
||||
ctx->state = CF_HC_RESOLV;
|
||||
ctx->result = CURLE_OK;
|
||||
ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
|
||||
ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_hc_ctx_destroy(struct Curl_easy *data,
|
||||
struct cf_hc_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
cf_hc_ctx_reset(data, ctx);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_hc_baller_assign(struct cf_hc_baller *b,
|
||||
enum alpnid alpn_id,
|
||||
uint8_t def_transport)
|
||||
|
|
@ -135,6 +161,9 @@ static void cf_hc_baller_assign(struct cf_hc_baller *b,
|
|||
case ALPN_h1:
|
||||
b->name = "h1";
|
||||
break;
|
||||
case ALPN_none:
|
||||
b->name = "no-alpn";
|
||||
break;
|
||||
default:
|
||||
b->result = CURLE_FAILED_INIT;
|
||||
break;
|
||||
|
|
@ -179,21 +208,6 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
|
|||
return b->result;
|
||||
}
|
||||
|
||||
static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
size_t i;
|
||||
|
||||
if(ctx) {
|
||||
for(i = 0; i < ctx->baller_count; ++i)
|
||||
cf_hc_baller_reset(&ctx->ballers[i], data);
|
||||
ctx->state = CF_HC_INIT;
|
||||
ctx->result = CURLE_OK;
|
||||
ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
|
||||
ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 4;
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode baller_connected(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_hc_baller *winner)
|
||||
|
|
@ -290,6 +304,157 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static bool cf_https_alpns_contain(enum alpnid id,
|
||||
enum alpnid *list, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < len; ++i) {
|
||||
if(id == list[i])
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_resolv(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
enum alpnid alpn_ids[2];
|
||||
size_t alpn_count = 0, i;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(cf->conn->bits.tls_enable_alpn) {
|
||||
#ifdef USE_HTTPSRR
|
||||
/* Is there an HTTPSRR use its ALPNs here.
|
||||
* We are here after having selected a connection to a host+port and
|
||||
* can no longer change that. Any HTTPSRR advice for other hosts and ports
|
||||
* we need to ignore. */
|
||||
const struct Curl_https_rrinfo *rr;
|
||||
bool need_https_rr = FALSE;
|
||||
|
||||
if(need_https_rr) {
|
||||
result = Curl_conn_dns_result(cf->conn, cf->sockindex);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Do we have HTTPS-RR information? */
|
||||
rr = Curl_conn_dns_get_https(data, cf->sockindex);
|
||||
|
||||
if(rr && !rr->no_def_alpn && /* ALPNs are defaults */
|
||||
(!rr->target || /* for same host */
|
||||
!rr->target[0] ||
|
||||
(rr->target[0] == '.' &&
|
||||
!rr->target[1])) &&
|
||||
(rr->port < 0 || /* for same port */
|
||||
rr->port == cf->conn->remote_port)) {
|
||||
for(i = 0; i < CURL_ARRAYSIZE(rr->alpns) &&
|
||||
alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
|
||||
enum alpnid alpn = rr->alpns[i];
|
||||
if(cf_https_alpns_contain(alpn, alpn_ids, alpn_count))
|
||||
continue;
|
||||
switch(alpn) {
|
||||
case ALPN_h3:
|
||||
if(Curl_conn_may_http3(data, cf->conn, ctx->def_transport))
|
||||
break; /* not possible */
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
|
||||
CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
|
||||
alpn_ids[alpn_count++] = alpn;
|
||||
}
|
||||
break;
|
||||
case ALPN_h2:
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
|
||||
CURL_TRC_CF(data, cf, "adding h2 via HTTPS-RR");
|
||||
alpn_ids[alpn_count++] = alpn;
|
||||
}
|
||||
break;
|
||||
case ALPN_h1:
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
|
||||
CURL_TRC_CF(data, cf, "adding h1 via HTTPS-RR");
|
||||
alpn_ids[alpn_count++] = alpn;
|
||||
}
|
||||
break;
|
||||
default: /* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Add preferred HTTP version ALPN first */
|
||||
if(data->state.http_neg.preferred &&
|
||||
(alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.preferred & data->state.http_neg.allowed)) {
|
||||
enum alpnid alpn_pref = ALPN_none;
|
||||
switch(data->state.http_neg.preferred) {
|
||||
case CURL_HTTP_V3x:
|
||||
if(!Curl_conn_may_http3(data, cf->conn, ctx->def_transport))
|
||||
alpn_pref = ALPN_h3;
|
||||
break;
|
||||
case CURL_HTTP_V2x:
|
||||
alpn_pref = ALPN_h2;
|
||||
break;
|
||||
case CURL_HTTP_V1x:
|
||||
alpn_pref = ALPN_h1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(alpn_pref &&
|
||||
!cf_https_alpns_contain(alpn_pref, alpn_ids, alpn_count)) {
|
||||
alpn_ids[alpn_count++] = alpn_pref;
|
||||
}
|
||||
}
|
||||
|
||||
if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.wanted & CURL_HTTP_V3x) &&
|
||||
!cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
|
||||
result = Curl_conn_may_http3(data, cf->conn, ctx->def_transport);
|
||||
if(!result) {
|
||||
CURL_TRC_CF(data, cf, "adding wanted h3");
|
||||
alpn_ids[alpn_count++] = ALPN_h3;
|
||||
}
|
||||
else if(data->state.http_neg.wanted == CURL_HTTP_V3x)
|
||||
goto out; /* only h3 allowed, not possible, error out */
|
||||
}
|
||||
if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.wanted & CURL_HTTP_V2x) &&
|
||||
!cf_https_alpns_contain(ALPN_h2, alpn_ids, alpn_count)) {
|
||||
CURL_TRC_CF(data, cf, "adding wanted h2");
|
||||
alpn_ids[alpn_count++] = ALPN_h2;
|
||||
}
|
||||
else if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.wanted & CURL_HTTP_V1x) &&
|
||||
!cf_https_alpns_contain(ALPN_h1, alpn_ids, alpn_count)) {
|
||||
CURL_TRC_CF(data, cf, "adding wanted h1");
|
||||
alpn_ids[alpn_count++] = ALPN_h1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!alpn_count) {
|
||||
alpn_ids[0] = ALPN_none;
|
||||
alpn_count = 1;
|
||||
}
|
||||
|
||||
/* Install ballers for the ALPNs we selected. */
|
||||
DEBUGASSERT(alpn_count <= CURL_ARRAYSIZE(ctx->ballers));
|
||||
if(!alpn_count || (alpn_count > CURL_ARRAYSIZE(ctx->ballers))) {
|
||||
failf(data, "https-connect filter create with unsupported %zu ALPN ids",
|
||||
alpn_count);
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for(i = 0; i < alpn_count; ++i)
|
||||
cf_hc_baller_assign(&ctx->ballers[i], alpn_ids[i], ctx->def_transport);
|
||||
for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
|
||||
ctx->ballers[i].alpn_id = ALPN_none;
|
||||
ctx->baller_count = alpn_count;
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
|
|
@ -305,6 +470,17 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
|
|||
|
||||
*done = FALSE;
|
||||
switch(ctx->state) {
|
||||
case CF_HC_RESOLV:
|
||||
result = cf_hc_resolv(cf, data);
|
||||
if(result) {
|
||||
if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
DEBUGASSERT(ctx->baller_count);
|
||||
ctx->state = CF_HC_INIT;
|
||||
FALLTHROUGH();
|
||||
|
||||
case CF_HC_INIT:
|
||||
DEBUGASSERT(!cf->next);
|
||||
for(i = 0; i < ctx->baller_count; i++)
|
||||
|
|
@ -536,7 +712,7 @@ out:
|
|||
static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
CURL_TRC_CF(data, cf, "close");
|
||||
cf_hc_reset(cf, data);
|
||||
cf_hc_ctx_reset(data, cf->ctx);
|
||||
cf->connected = FALSE;
|
||||
|
||||
if(cf->next) {
|
||||
|
|
@ -550,8 +726,7 @@ static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
struct cf_hc_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
cf_hc_reset(cf, data);
|
||||
Curl_safefree(ctx);
|
||||
cf_hc_ctx_destroy(data, ctx);
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_http_connect = {
|
||||
|
|
@ -574,59 +749,40 @@ struct Curl_cftype Curl_cft_http_connect = {
|
|||
|
||||
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
enum alpnid *alpnids, size_t alpn_count,
|
||||
uint8_t def_transport)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
struct cf_hc_ctx *ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t i;
|
||||
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGASSERT(alpnids);
|
||||
DEBUGASSERT(alpn_count);
|
||||
DEBUGASSERT(alpn_count <= CURL_ARRAYSIZE(ctx->ballers));
|
||||
if(!alpn_count || (alpn_count > CURL_ARRAYSIZE(ctx->ballers))) {
|
||||
failf(data, "https-connect filter create with unsupported %zu ALPN ids",
|
||||
alpn_count);
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for(i = 0; i < alpn_count; ++i)
|
||||
cf_hc_baller_assign(&ctx->ballers[i], alpnids[i], def_transport);
|
||||
for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
|
||||
ctx->ballers[i].alpn_id = ALPN_none;
|
||||
ctx->baller_count = alpn_count;
|
||||
ctx->def_transport = def_transport;
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
ctx = NULL;
|
||||
cf_hc_reset(cf, data);
|
||||
|
||||
out:
|
||||
*pcf = result ? NULL : cf;
|
||||
curlx_free(ctx);
|
||||
cf_hc_ctx_destroy(data, ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_http_connect_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
enum alpnid *alpn_ids, size_t alpn_count,
|
||||
uint8_t def_transport)
|
||||
static CURLcode cf_hc_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
uint8_t def_transport)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
result = cf_hc_create(&cf, data, alpn_ids, alpn_count, def_transport);
|
||||
result = cf_hc_create(&cf, data, def_transport);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
|
|
@ -634,138 +790,19 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool cf_https_alpns_contain(enum alpnid id,
|
||||
enum alpnid *list, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < len; ++i) {
|
||||
if(id == list[i])
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
enum alpnid alpn_ids[2];
|
||||
size_t alpn_count = 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct Curl_cfilter cf_fake, *cf = NULL;
|
||||
|
||||
(void)sockindex;
|
||||
/* we want to log for the filter before we create it, fake it. */
|
||||
memset(&cf_fake, 0, sizeof(cf_fake));
|
||||
cf_fake.cft = &Curl_cft_http_connect;
|
||||
cf = &cf_fake;
|
||||
DEBUGASSERT(conn->scheme->protocol == CURLPROTO_HTTPS);
|
||||
|
||||
if(conn->bits.tls_enable_alpn) {
|
||||
#ifdef USE_HTTPSRR
|
||||
/* Is there an HTTPSRR use its ALPNs here.
|
||||
* We are here after having selected a connection to a host+port and
|
||||
* can no longer change that. Any HTTPSRR advice for other hosts and ports
|
||||
* we need to ignore. */
|
||||
struct Curl_dns_entry *dns = data->state.dns[sockindex];
|
||||
struct Curl_https_rrinfo *rr = dns ? dns->hinfo : NULL;
|
||||
if(rr && !rr->no_def_alpn && /* ALPNs are defaults */
|
||||
(!rr->target || /* for same host */
|
||||
!rr->target[0] ||
|
||||
(rr->target[0] == '.' &&
|
||||
!rr->target[1])) &&
|
||||
(rr->port < 0 || /* for same port */
|
||||
rr->port == conn->remote_port)) {
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(rr->alpns) &&
|
||||
alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
|
||||
enum alpnid alpn = (enum alpnid)rr->alpns[i];
|
||||
if(cf_https_alpns_contain(alpn, alpn_ids, alpn_count))
|
||||
continue;
|
||||
switch(alpn) {
|
||||
case ALPN_h3:
|
||||
if(Curl_conn_may_http3(data, conn, conn->transport_wanted))
|
||||
break; /* not possible */
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
|
||||
CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
|
||||
alpn_ids[alpn_count++] = alpn;
|
||||
}
|
||||
break;
|
||||
case ALPN_h2:
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
|
||||
CURL_TRC_CF(data, cf, "adding h2 via HTTPS-RR");
|
||||
alpn_ids[alpn_count++] = alpn;
|
||||
}
|
||||
break;
|
||||
case ALPN_h1:
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
|
||||
CURL_TRC_CF(data, cf, "adding h1 via HTTPS-RR");
|
||||
alpn_ids[alpn_count++] = alpn;
|
||||
}
|
||||
break;
|
||||
default: /* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if((conn->scheme->protocol != CURLPROTO_HTTPS) ||
|
||||
!conn->bits.tls_enable_alpn)
|
||||
goto out;
|
||||
|
||||
/* Add preferred HTTP version ALPN first */
|
||||
if(data->state.http_neg.preferred &&
|
||||
(alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.preferred & data->state.http_neg.allowed)) {
|
||||
enum alpnid alpn_pref = ALPN_none;
|
||||
switch(data->state.http_neg.preferred) {
|
||||
case CURL_HTTP_V3x:
|
||||
if(!Curl_conn_may_http3(data, conn, conn->transport_wanted))
|
||||
alpn_pref = ALPN_h3;
|
||||
break;
|
||||
case CURL_HTTP_V2x:
|
||||
alpn_pref = ALPN_h2;
|
||||
break;
|
||||
case CURL_HTTP_V1x:
|
||||
alpn_pref = ALPN_h1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(alpn_pref &&
|
||||
!cf_https_alpns_contain(alpn_pref, alpn_ids, alpn_count)) {
|
||||
alpn_ids[alpn_count++] = alpn_pref;
|
||||
}
|
||||
}
|
||||
|
||||
if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.wanted & CURL_HTTP_V3x) &&
|
||||
!cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
|
||||
result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
|
||||
if(!result) {
|
||||
CURL_TRC_CF(data, cf, "adding wanted h3");
|
||||
alpn_ids[alpn_count++] = ALPN_h3;
|
||||
}
|
||||
else if(data->state.http_neg.wanted == CURL_HTTP_V3x)
|
||||
goto out; /* only h3 allowed, not possible, error out */
|
||||
}
|
||||
if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.wanted & CURL_HTTP_V2x) &&
|
||||
!cf_https_alpns_contain(ALPN_h2, alpn_ids, alpn_count)) {
|
||||
CURL_TRC_CF(data, cf, "adding wanted h2");
|
||||
alpn_ids[alpn_count++] = ALPN_h2;
|
||||
}
|
||||
else if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
|
||||
(data->state.http_neg.wanted & CURL_HTTP_V1x) &&
|
||||
!cf_https_alpns_contain(ALPN_h1, alpn_ids, alpn_count)) {
|
||||
CURL_TRC_CF(data, cf, "adding wanted h1");
|
||||
alpn_ids[alpn_count++] = ALPN_h1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we identified ALPNs to use, install our filter. Otherwise,
|
||||
* install nothing, so our call will use a default connect setup. */
|
||||
if(alpn_count) {
|
||||
result = cf_http_connect_add(data, conn, sockindex,
|
||||
alpn_ids, alpn_count,
|
||||
conn->transport_wanted);
|
||||
}
|
||||
result = cf_hc_add(data, conn, sockindex, conn->transport_wanted);
|
||||
|
||||
out:
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -31,15 +31,9 @@ struct Curl_cfilter;
|
|||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
struct Curl_cftype;
|
||||
struct Curl_dns_entry;
|
||||
|
||||
extern struct Curl_cftype Curl_cft_http_connect;
|
||||
|
||||
CURLcode Curl_cf_http_connect_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
bool try_h3, bool try_h21);
|
||||
|
||||
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "urldata.h"
|
||||
#include "connect.h"
|
||||
#include "cfilters.h"
|
||||
#include "cf-dns.h"
|
||||
#include "cf-ip-happy.h"
|
||||
#include "curl_addrinfo.h"
|
||||
#include "curl_trc.h"
|
||||
|
|
@ -108,59 +109,47 @@ UNITTEST void Curl_debug_set_transport_provider(
|
|||
#endif /* UNITTESTS */
|
||||
|
||||
struct cf_ai_iter {
|
||||
const struct Curl_addrinfo *head;
|
||||
const struct Curl_addrinfo *last;
|
||||
struct Curl_cfilter *cf;
|
||||
int ai_family;
|
||||
int n;
|
||||
unsigned int n;
|
||||
};
|
||||
|
||||
static void cf_ai_iter_init(struct cf_ai_iter *iter,
|
||||
const struct Curl_addrinfo *list,
|
||||
struct Curl_cfilter *cf,
|
||||
int ai_family)
|
||||
{
|
||||
iter->head = list;
|
||||
iter->cf = cf;
|
||||
iter->ai_family = ai_family;
|
||||
iter->last = NULL;
|
||||
iter->n = -1;
|
||||
iter->n = 0;
|
||||
}
|
||||
|
||||
static const struct Curl_addrinfo *cf_ai_iter_next(struct cf_ai_iter *iter)
|
||||
static const struct Curl_addrinfo *
|
||||
cf_ai_iter_next(struct cf_ai_iter *iter,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
const struct Curl_addrinfo *addr;
|
||||
if(iter->n < 0) {
|
||||
|
||||
if(!iter->cf)
|
||||
return NULL;
|
||||
|
||||
addr = Curl_conn_dns_get_ai(data, iter->cf->sockindex,
|
||||
iter->ai_family, iter->n);
|
||||
if(addr)
|
||||
iter->n++;
|
||||
for(addr = iter->head; addr; addr = addr->ai_next) {
|
||||
if(addr->ai_family == iter->ai_family)
|
||||
break;
|
||||
}
|
||||
iter->last = addr;
|
||||
}
|
||||
else if(iter->last) {
|
||||
iter->n++;
|
||||
for(addr = iter->last->ai_next; addr; addr = addr->ai_next) {
|
||||
if(addr->ai_family == iter->ai_family)
|
||||
break;
|
||||
}
|
||||
iter->last = addr;
|
||||
}
|
||||
return iter->last;
|
||||
return addr;
|
||||
}
|
||||
|
||||
static bool cf_ai_iter_has_more(struct cf_ai_iter *iter)
|
||||
static bool cf_ai_iter_has_more(struct cf_ai_iter *iter,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
const struct Curl_addrinfo *addr = iter->last ? iter->last->ai_next :
|
||||
((iter->n < 0) ? iter->head : NULL);
|
||||
while(addr) {
|
||||
if(addr->ai_family == iter->ai_family)
|
||||
return TRUE;
|
||||
addr = addr->ai_next;
|
||||
}
|
||||
return FALSE;
|
||||
return (iter->cf &&
|
||||
!!Curl_conn_dns_get_ai(data, iter->cf->sockindex,
|
||||
iter->ai_family, iter->n));
|
||||
}
|
||||
|
||||
struct cf_ip_attempt {
|
||||
struct cf_ip_attempt *next;
|
||||
const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */
|
||||
struct Curl_sockaddr_ex addr;
|
||||
struct Curl_cfilter *cf; /* current sub-cfilter connecting */
|
||||
cf_ip_connect_create *cf_create;
|
||||
struct curltime started; /* start of current attempt */
|
||||
|
|
@ -187,7 +176,7 @@ static void cf_ip_attempt_free(struct cf_ip_attempt *a,
|
|||
static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
const struct Curl_addrinfo *addr,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
int ai_family,
|
||||
uint8_t transport,
|
||||
cf_ip_connect_create *cf_create)
|
||||
|
|
@ -201,14 +190,14 @@ static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
|
|||
if(!a)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
a->addr = addr;
|
||||
a->addr = *addr;
|
||||
a->ai_family = ai_family;
|
||||
a->transport = transport;
|
||||
a->result = CURLE_OK;
|
||||
a->cf_create = cf_create;
|
||||
*pa = a;
|
||||
|
||||
result = a->cf_create(&a->cf, data, cf->conn, a->addr, transport);
|
||||
result = a->cf_create(&a->cf, data, cf->conn, &a->addr, a->transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -277,7 +266,7 @@ static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
|
|||
a->inconclusive = FALSE;
|
||||
a->cf = NULL;
|
||||
|
||||
result = a->cf_create(&a->cf, data, cf->conn, a->addr, a->transport);
|
||||
result = a->cf_create(&a->cf, data, cf->conn, &a->addr, a->transport);
|
||||
if(!result) {
|
||||
bool dummy;
|
||||
/* the new filter might have sub-filters */
|
||||
|
|
@ -307,7 +296,7 @@ static void cf_ip_ballers_clear(struct Curl_cfilter *cf,
|
|||
}
|
||||
|
||||
static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version,
|
||||
const struct Curl_addrinfo *addr_list,
|
||||
struct Curl_cfilter *cf,
|
||||
cf_ip_connect_create *cf_create,
|
||||
uint8_t transport,
|
||||
timediff_t attempt_delay_ms)
|
||||
|
|
@ -320,7 +309,7 @@ static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version,
|
|||
|
||||
if(transport == TRNSPRT_UNIX) {
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
cf_ai_iter_init(&bs->addr_iter, addr_list, AF_UNIX);
|
||||
cf_ai_iter_init(&bs->addr_iter, cf, AF_UNIX);
|
||||
#else
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
|
|
@ -330,15 +319,15 @@ static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version,
|
|||
if(ip_version == CURL_IPRESOLVE_V6)
|
||||
cf_ai_iter_init(&bs->addr_iter, NULL, AF_INET);
|
||||
else
|
||||
cf_ai_iter_init(&bs->addr_iter, addr_list, AF_INET);
|
||||
cf_ai_iter_init(&bs->addr_iter, cf, AF_INET);
|
||||
|
||||
if(ip_version == CURL_IPRESOLVE_V4)
|
||||
cf_ai_iter_init(&bs->ipv6_iter, NULL, AF_INET6);
|
||||
else
|
||||
cf_ai_iter_init(&bs->ipv6_iter, addr_list, AF_INET6);
|
||||
cf_ai_iter_init(&bs->ipv6_iter, cf, AF_INET6);
|
||||
#else
|
||||
(void)ip_version;
|
||||
cf_ai_iter_init(&bs->addr_iter, addr_list, AF_INET);
|
||||
cf_ai_iter_init(&bs->addr_iter, cf, AF_INET);
|
||||
#endif
|
||||
}
|
||||
return CURLE_OK;
|
||||
|
|
@ -347,6 +336,7 @@ static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version,
|
|||
static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool dns_resolved,
|
||||
bool *connected)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
|
@ -400,10 +390,10 @@ evaluate:
|
|||
do_more = TRUE;
|
||||
}
|
||||
else {
|
||||
bool more_possible = cf_ai_iter_has_more(&bs->addr_iter);
|
||||
bool more_possible = cf_ai_iter_has_more(&bs->addr_iter, data);
|
||||
#ifdef USE_IPV6
|
||||
if(!more_possible)
|
||||
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter);
|
||||
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter, data);
|
||||
#endif
|
||||
do_more = more_possible &&
|
||||
(curlx_ptimediff_ms(Curl_pgrs_now(data), &bs->last_attempt_started) >=
|
||||
|
|
@ -416,27 +406,37 @@ evaluate:
|
|||
if(do_more) {
|
||||
/* start the next attempt if there is another ip address to try.
|
||||
* Alternate between address families when possible. */
|
||||
const struct Curl_addrinfo *addr = NULL;
|
||||
const struct Curl_addrinfo *ai = NULL;
|
||||
int ai_family = 0;
|
||||
CURL_TRC_CF(data, cf, "want to do more");
|
||||
#ifdef USE_IPV6
|
||||
if((bs->last_attempt_ai_family == AF_INET) ||
|
||||
!cf_ai_iter_has_more(&bs->addr_iter)) {
|
||||
addr = cf_ai_iter_next(&bs->ipv6_iter);
|
||||
!cf_ai_iter_has_more(&bs->addr_iter, data)) {
|
||||
ai = cf_ai_iter_next(&bs->ipv6_iter, data);
|
||||
ai_family = bs->ipv6_iter.ai_family;
|
||||
CURL_TRC_CF(data, cf, "check for next AAAA address: %s",
|
||||
ai ? "found" : "none");
|
||||
}
|
||||
#endif
|
||||
if(!addr) {
|
||||
addr = cf_ai_iter_next(&bs->addr_iter);
|
||||
if(!ai) {
|
||||
ai = cf_ai_iter_next(&bs->addr_iter, data);
|
||||
ai_family = bs->addr_iter.ai_family;
|
||||
CURL_TRC_CF(data, cf, "check for next A address: %s",
|
||||
ai ? "found" : "none");
|
||||
}
|
||||
/* We are (re-)starting attempts. We are not interested in
|
||||
* keeping old failure information. The new attempt will either
|
||||
* succeed or persist new failure. */
|
||||
Curl_reset_fail(data);
|
||||
|
||||
if(addr) { /* try another address */
|
||||
result = cf_ip_attempt_new(&a, cf, data, addr, ai_family,
|
||||
bs->transport, bs->cf_create);
|
||||
if(ai) { /* try another address */
|
||||
struct Curl_sockaddr_ex addr;
|
||||
result = Curl_socket_addr_from_ai(&addr, ai, bs->transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = cf_ip_attempt_new(&a, cf, data, &addr, ai_family,
|
||||
bs->transport, bs->cf_create);
|
||||
CURL_TRC_CF(data, cf, "starting %s attempt for ipv%s -> %d",
|
||||
bs->running ? "next" : "first",
|
||||
(ai_family == AF_INET) ? "4" : "6", result);
|
||||
|
|
@ -485,7 +485,7 @@ evaluate:
|
|||
/* attempt timeout for restart has not expired yet */
|
||||
goto out;
|
||||
}
|
||||
else if(!ongoing) {
|
||||
else if(!ongoing && dns_resolved) {
|
||||
/* no more addresses, no inconclusive attempts */
|
||||
CURL_TRC_CF(data, cf, "no more attempts to try");
|
||||
result = CURLE_COULDNT_CONNECT;
|
||||
|
|
@ -511,10 +511,10 @@ out:
|
|||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
more_possible = cf_ai_iter_has_more(&bs->addr_iter);
|
||||
more_possible = cf_ai_iter_has_more(&bs->addr_iter, data);
|
||||
#ifdef USE_IPV6
|
||||
if(!more_possible)
|
||||
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter);
|
||||
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter, data);
|
||||
#endif
|
||||
if(more_possible) {
|
||||
timediff_t expire_ms, elapsed_ms;
|
||||
|
|
@ -630,6 +630,7 @@ struct cf_ip_happy_ctx {
|
|||
cf_connect_state state;
|
||||
struct cf_ip_ballers ballers;
|
||||
struct curltime started;
|
||||
BIT(dns_resolved);
|
||||
};
|
||||
|
||||
static CURLcode is_connected(struct Curl_cfilter *cf,
|
||||
|
|
@ -640,7 +641,8 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
|
|||
struct connectdata *conn = cf->conn;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_ip_ballers_run(&ctx->ballers, cf, data, connected);
|
||||
result = cf_ip_ballers_run(&ctx->ballers, cf, data,
|
||||
(bool)ctx->dns_resolved, connected);
|
||||
|
||||
if(!result)
|
||||
return CURLE_OK;
|
||||
|
|
@ -693,18 +695,10 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to the given host with timeout, proxy or remote does not matter.
|
||||
* There might be more than one IP address to try out.
|
||||
*/
|
||||
static CURLcode start_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
static CURLcode cf_ip_happy_init(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
|
||||
|
||||
if(!dns)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(Curl_timeleft_ms(data) < 0) {
|
||||
/* a precaution, no need to continue if time already is up */
|
||||
|
|
@ -714,8 +708,8 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
|
|||
|
||||
CURL_TRC_CF(data, cf, "init ip ballers for transport %u", ctx->transport);
|
||||
ctx->started = *Curl_pgrs_now(data);
|
||||
return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version,
|
||||
dns->addr, ctx->cf_create, ctx->transport,
|
||||
return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version, cf,
|
||||
ctx->cf_create, ctx->transport,
|
||||
data->set.happy_eyeballs_timeout);
|
||||
}
|
||||
|
||||
|
|
@ -729,6 +723,12 @@ static void cf_ip_happy_ctx_clear(struct Curl_cfilter *cf,
|
|||
cf_ip_ballers_clear(cf, data, &ctx->ballers);
|
||||
}
|
||||
|
||||
static void cf_ip_happy_ctx_destroy(struct cf_ip_happy_ctx *ctx)
|
||||
{
|
||||
if(ctx)
|
||||
curlx_free(ctx);
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_happy_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
|
|
@ -768,6 +768,10 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
|
|||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
/* -Werror=null-dereference finds false positives suddenly. */
|
||||
if(!data)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
|
|
@ -776,13 +780,23 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
|
|||
DEBUGASSERT(ctx);
|
||||
*done = FALSE;
|
||||
|
||||
if(!ctx->dns_resolved) {
|
||||
result = Curl_conn_dns_result(cf->conn, cf->sockindex);
|
||||
if(!result)
|
||||
ctx->dns_resolved = TRUE;
|
||||
else if(result == CURLE_AGAIN) /* not complete yet */
|
||||
result = CURLE_OK;
|
||||
else /* real error */
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch(ctx->state) {
|
||||
case SCFST_INIT:
|
||||
DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
|
||||
DEBUGASSERT(!cf->connected);
|
||||
result = start_connect(cf, data);
|
||||
result = cf_ip_happy_init(cf, data);
|
||||
if(result)
|
||||
return result;
|
||||
goto out;
|
||||
ctx->state = SCFST_WAITING;
|
||||
FALLTHROUGH();
|
||||
case SCFST_WAITING:
|
||||
|
|
@ -823,6 +837,7 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
|
|||
*done = TRUE;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -896,9 +911,8 @@ static void cf_ip_happy_destroy(struct Curl_cfilter *cf,
|
|||
CURL_TRC_CF(data, cf, "destroy");
|
||||
if(ctx) {
|
||||
cf_ip_happy_ctx_clear(cf, data);
|
||||
cf_ip_happy_ctx_destroy(ctx);
|
||||
}
|
||||
/* release any resources held in state */
|
||||
Curl_safefree(ctx);
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_ip_happy = {
|
||||
|
|
@ -954,7 +968,7 @@ static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf,
|
|||
out:
|
||||
if(result) {
|
||||
Curl_safefree(*pcf);
|
||||
curlx_free(ctx);
|
||||
cf_ip_happy_ctx_destroy(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ struct connectdata;
|
|||
struct Curl_addrinfo;
|
||||
struct Curl_cfilter;
|
||||
struct Curl_easy;
|
||||
struct Curl_sockaddr_ex;
|
||||
|
||||
/**
|
||||
* Create a cfilter for making an "ip" connection to the
|
||||
|
|
@ -44,7 +45,7 @@ struct Curl_easy;
|
|||
typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport);
|
||||
|
||||
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
|
||||
|
|
|
|||
|
|
@ -265,42 +265,30 @@ static void tcpkeepalive(struct Curl_cfilter *cf,
|
|||
}
|
||||
|
||||
/**
|
||||
* Assign the address `ai` to the Curl_sockaddr_ex `dest` and
|
||||
* set the transport used.
|
||||
* Assign the addrinfo `ai` to the Curl_sockaddr_ex `addr` with
|
||||
* transport determining socktype and protocol.
|
||||
*/
|
||||
static CURLcode sock_assign_addr(struct Curl_sockaddr_ex *dest,
|
||||
const struct Curl_addrinfo *ai,
|
||||
uint8_t transport)
|
||||
CURLcode Curl_socket_addr_from_ai(struct Curl_sockaddr_ex *addr,
|
||||
const struct Curl_addrinfo *ai,
|
||||
uint8_t transport)
|
||||
{
|
||||
/*
|
||||
* The Curl_sockaddr_ex structure is libcurl's external API curl_sockaddr
|
||||
* structure with enough space available to directly hold any
|
||||
* protocol-specific address structures. The variable declared here will be
|
||||
* used to pass / receive data to/from the fopensocket callback if this has
|
||||
* been set, before that, it is initialized from parameters.
|
||||
* The Curl_sockaddr_ex structure is libcurl's external API
|
||||
* curl_sockaddr structure with enough space available to directly hold
|
||||
* any protocol-specific address structures. The variable declared here
|
||||
* will be used to pass / receive data to/from the fopensocket callback
|
||||
* if this has been set, before that, it is initialized from parameters.
|
||||
*/
|
||||
dest->family = ai->ai_family;
|
||||
switch(transport) {
|
||||
case TRNSPRT_TCP:
|
||||
dest->socktype = SOCK_STREAM;
|
||||
dest->protocol = IPPROTO_TCP;
|
||||
break;
|
||||
case TRNSPRT_UNIX:
|
||||
dest->socktype = SOCK_STREAM;
|
||||
dest->protocol = IPPROTO_IP;
|
||||
break;
|
||||
default: /* UDP and QUIC */
|
||||
dest->socktype = SOCK_DGRAM;
|
||||
dest->protocol = IPPROTO_UDP;
|
||||
break;
|
||||
}
|
||||
dest->addrlen = (unsigned int)ai->ai_addrlen;
|
||||
addr->family = ai->ai_family;
|
||||
addr->socktype = Curl_socktype_for_transport(transport);
|
||||
addr->protocol = Curl_protocol_for_transport(transport);
|
||||
addr->addrlen = (unsigned int)ai->ai_addrlen;
|
||||
|
||||
DEBUGASSERT(dest->addrlen <= sizeof(dest->curl_sa_addrbuf));
|
||||
if(dest->addrlen > sizeof(dest->curl_sa_addrbuf))
|
||||
DEBUGASSERT(addr->addrlen <= sizeof(addr->curl_sa_addrbuf));
|
||||
if(addr->addrlen > sizeof(addr->curl_sa_addrbuf))
|
||||
return CURLE_TOO_LARGE;
|
||||
|
||||
memcpy(&dest->curl_sa_addrbuf, ai->ai_addr, dest->addrlen);
|
||||
memcpy(&addr->curl_sa_addrbuf, ai->ai_addr, addr->addrlen);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +400,7 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
|
|||
/* if the caller does not want info back, use a local temp copy */
|
||||
addr = &dummy;
|
||||
|
||||
result = sock_assign_addr(addr, ai, transport);
|
||||
result = Curl_socket_addr_from_ai(addr, ai, transport);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
|
@ -900,18 +888,13 @@ struct cf_socket_ctx {
|
|||
};
|
||||
|
||||
static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->sock = CURL_SOCKET_BAD;
|
||||
ctx->transport = transport;
|
||||
|
||||
result = sock_assign_addr(&ctx->addr, ai, transport);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->addr = *addr;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
{
|
||||
|
|
@ -942,7 +925,7 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
|
|||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
|
|
@ -1722,7 +1705,7 @@ struct Curl_cftype Curl_cft_tcp = {
|
|||
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = NULL;
|
||||
|
|
@ -1732,7 +1715,7 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
|||
(void)data;
|
||||
(void)conn;
|
||||
DEBUGASSERT(transport == TRNSPRT_TCP);
|
||||
if(!ai) {
|
||||
if(!addr) {
|
||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1743,7 +1726,7 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
result = cf_socket_ctx_init(ctx, ai, transport);
|
||||
result = cf_socket_ctx_init(ctx, addr, transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1888,7 +1871,7 @@ struct Curl_cftype Curl_cft_udp = {
|
|||
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = NULL;
|
||||
|
|
@ -1904,7 +1887,7 @@ CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
result = cf_socket_ctx_init(ctx, ai, transport);
|
||||
result = cf_socket_ctx_init(ctx, addr, transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1942,7 +1925,7 @@ struct Curl_cftype Curl_cft_unix = {
|
|||
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = NULL;
|
||||
|
|
@ -1958,7 +1941,7 @@ CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
result = cf_socket_ctx_init(ctx, ai, transport);
|
||||
result = cf_socket_ctx_init(ctx, addr, transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ struct Curl_sockaddr_ex {
|
|||
CURLcode Curl_parse_interface(const char *input,
|
||||
char **dev, char **iface, char **host);
|
||||
|
||||
CURLcode Curl_socket_addr_from_ai(struct Curl_sockaddr_ex *addr,
|
||||
const struct Curl_addrinfo *ai,
|
||||
uint8_t transport);
|
||||
|
||||
/*
|
||||
* Create a socket based on info from 'conn' and 'ai'.
|
||||
*
|
||||
|
|
@ -91,7 +95,7 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
|
|||
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport);
|
||||
|
||||
/**
|
||||
|
|
@ -104,7 +108,7 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
|||
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport);
|
||||
|
||||
/**
|
||||
|
|
@ -117,7 +121,7 @@ CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
|||
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -508,6 +508,11 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
if(!CONN_SOCK_IDX_VALID(sockindex))
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
if(data->conn->scheme->flags & PROTOPT_NONETWORK) {
|
||||
*done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
cf = data->conn->cfilter[sockindex];
|
||||
if(!cf) {
|
||||
*done = FALSE;
|
||||
|
|
@ -712,6 +717,18 @@ int Curl_socktype_for_transport(uint8_t transport)
|
|||
}
|
||||
}
|
||||
|
||||
int Curl_protocol_for_transport(uint8_t transport)
|
||||
{
|
||||
switch(transport) {
|
||||
case TRNSPRT_TCP:
|
||||
return IPPROTO_TCP;
|
||||
case TRNSPRT_UNIX:
|
||||
return IPPROTO_IP;
|
||||
default: /* UDP and QUIC */
|
||||
return IPPROTO_UDP;
|
||||
}
|
||||
}
|
||||
|
||||
const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data);
|
||||
|
||||
int Curl_socktype_for_transport(uint8_t transport);
|
||||
int Curl_protocol_for_transport(uint8_t transport);
|
||||
|
||||
const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
#include "strerror.h"
|
||||
#include "cfilters.h"
|
||||
#include "connect.h"
|
||||
#include "cf-dns.h"
|
||||
#include "cf-haproxy.h"
|
||||
#include "cf-https-connect.h"
|
||||
#include "cf-ip-happy.h"
|
||||
|
|
@ -343,7 +344,6 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
|
|||
{
|
||||
struct cf_setup_ctx *ctx = cf->ctx;
|
||||
CURLcode result = CURLE_OK;
|
||||
struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
|
|
@ -352,8 +352,6 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
|
|||
|
||||
/* connect current sub-chain */
|
||||
connect_sub_chain:
|
||||
if(!dns)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(cf->next && !cf->next->connected) {
|
||||
result = Curl_conn_cf_connect(cf->next, data, done);
|
||||
|
|
@ -562,10 +560,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(conn->scheme);
|
||||
DEBUGASSERT(dns);
|
||||
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[sockindex]);
|
||||
data->state.dns[sockindex] = dns;
|
||||
DEBUGASSERT(!conn->cfilter[sockindex]);
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(!conn->cfilter[sockindex] &&
|
||||
|
|
@ -585,13 +580,29 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
goto out;
|
||||
}
|
||||
|
||||
result = Curl_cf_dns_add(data, conn, sockindex,
|
||||
conn->transport_wanted, dns);
|
||||
DEBUGASSERT(conn->cfilter[sockindex]);
|
||||
out:
|
||||
if(result)
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[sockindex]);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
const char *Curl_conn_get_unix_path(struct connectdata *conn)
|
||||
{
|
||||
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
|
||||
|
||||
return unix_path;
|
||||
}
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn)
|
||||
{
|
||||
if(!conn->bits.multiplex) {
|
||||
|
|
|
|||
|
|
@ -127,6 +127,15 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
/* Set conn to allow multiplexing. */
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn);
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
#define UNIX_SOCKET_PREFIX "localhost"
|
||||
#endif
|
||||
const char *Curl_conn_get_unix_path(struct connectdata *conn);
|
||||
#else
|
||||
#define Curl_conn_get_unix_path(c) NULL
|
||||
#endif
|
||||
|
||||
extern struct Curl_cftype Curl_cft_setup;
|
||||
|
||||
#endif /* HEADER_CURL_CONNECT_H */
|
||||
|
|
|
|||
|
|
@ -422,10 +422,15 @@ CURLcode Curl_str2addr(const char *dotted, uint16_t port,
|
|||
return CURLE_BAD_FUNCTION_ARGUMENT; /* bad input format */
|
||||
}
|
||||
|
||||
bool Curl_is_ipaddr(const char *address)
|
||||
bool Curl_is_ipv4addr(const char *address)
|
||||
{
|
||||
struct in_addr in;
|
||||
if(curlx_inet_pton(AF_INET, address, &in) > 0)
|
||||
return (curlx_inet_pton(AF_INET, address, &in) > 0);
|
||||
}
|
||||
|
||||
bool Curl_is_ipaddr(const char *address)
|
||||
{
|
||||
if(Curl_is_ipv4addr(address))
|
||||
return TRUE;
|
||||
#ifdef USE_IPV6
|
||||
{
|
||||
|
|
@ -442,34 +447,31 @@ bool Curl_is_ipaddr(const char *address)
|
|||
/**
|
||||
* Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
|
||||
* struct initialized with this path.
|
||||
* Set '*longpath' to TRUE if the error is a too long path.
|
||||
* Returns CURLE_TOO_LARGE when path is too long.
|
||||
*/
|
||||
struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
|
||||
bool abstract)
|
||||
CURLcode Curl_unix2addr(const char *path, bool abstract,
|
||||
struct Curl_addrinfo **paddr)
|
||||
{
|
||||
struct Curl_addrinfo *ai;
|
||||
struct sockaddr_un *sa_un;
|
||||
size_t path_len;
|
||||
|
||||
*longpath = FALSE;
|
||||
*paddr = NULL;
|
||||
|
||||
/* sun_path must be able to store the null-terminated path */
|
||||
path_len = strlen(path) + 1;
|
||||
if(path_len > sizeof(sa_un->sun_path))
|
||||
return CURLE_TOO_LARGE;
|
||||
|
||||
ai = curlx_calloc(1,
|
||||
sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un));
|
||||
if(!ai)
|
||||
return NULL;
|
||||
ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
|
||||
sa_un = (void *)ai->ai_addr;
|
||||
sa_un->sun_family = AF_UNIX;
|
||||
|
||||
/* sun_path must be able to store the null-terminated path */
|
||||
path_len = strlen(path) + 1;
|
||||
if(path_len > sizeof(sa_un->sun_path)) {
|
||||
curlx_free(ai);
|
||||
*longpath = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ai->ai_family = AF_UNIX;
|
||||
ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
|
||||
ai->ai_addrlen = (curl_socklen_t)
|
||||
|
|
@ -481,7 +483,8 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
|
|||
else
|
||||
memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
|
||||
|
||||
return ai;
|
||||
*paddr = ai;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -71,13 +71,14 @@ int Curl_getaddrinfo_ex(const char *nodename,
|
|||
struct Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port);
|
||||
#endif
|
||||
|
||||
bool Curl_is_ipv4addr(const char *address);
|
||||
bool Curl_is_ipaddr(const char *address);
|
||||
CURLcode Curl_str2addr(const char *dotted, uint16_t port,
|
||||
struct Curl_addrinfo **addrp);
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
|
||||
bool abstract);
|
||||
CURLcode Curl_unix2addr(const char *path, bool abstract,
|
||||
struct Curl_addrinfo **paddr);
|
||||
#endif
|
||||
|
||||
#if defined(CURL_MEMDEBUG) && defined(HAVE_GETADDRINFO) && \
|
||||
|
|
|
|||
|
|
@ -423,10 +423,6 @@ CURLcode Curl_share_easy_unlink(struct Curl_easy *data)
|
|||
if(&share->psl == data->psl)
|
||||
data->psl = data->multi ? &data->multi->psl : NULL;
|
||||
#endif
|
||||
if(share->specifier & (1 << CURL_LOCK_DATA_DNS)) {
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[0]);
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[1]);
|
||||
}
|
||||
|
||||
share_unlink(&data->share, data, locked);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "cfilters.h"
|
||||
#include "multiif.h"
|
||||
|
||||
#include "cf-dns.h"
|
||||
#include "cf-socket.h"
|
||||
#include "connect.h"
|
||||
#include "http2.h"
|
||||
|
|
@ -349,7 +350,6 @@ static const char * const Curl_trc_mstate_names[] = {
|
|||
"PENDING",
|
||||
"SETUP",
|
||||
"CONNECT",
|
||||
"RESOLVING",
|
||||
"CONNECTING",
|
||||
"PROTOCONNECT",
|
||||
"PROTOCONNECTING",
|
||||
|
|
@ -548,6 +548,7 @@ struct trc_cft_def {
|
|||
};
|
||||
|
||||
static struct trc_cft_def trc_cfts[] = {
|
||||
{ &Curl_cft_dns, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_tcp, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_udp, TRC_CT_NETWORK },
|
||||
{ &Curl_cft_unix, TRC_CT_NETWORK },
|
||||
|
|
|
|||
|
|
@ -443,35 +443,22 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
|
|||
|
||||
static struct Curl_dns_entry *
|
||||
dnscache_entry_create(struct Curl_easy *data,
|
||||
struct Curl_addrinfo **paddr,
|
||||
struct Curl_addrinfo **paddr1,
|
||||
struct Curl_addrinfo **paddr2,
|
||||
const char *hostname,
|
||||
size_t hostlen, /* length or zero */
|
||||
size_t hostlen,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
bool permanent)
|
||||
{
|
||||
struct Curl_dns_entry *dns = NULL;
|
||||
|
||||
#ifndef CURL_DISABLE_SHUFFLE_DNS
|
||||
/* shuffle addresses if requested */
|
||||
if(data->set.dns_shuffle_addresses && paddr) {
|
||||
CURLcode result = Curl_shuffle_addr(data, paddr);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
(void)data;
|
||||
#endif
|
||||
if(!hostlen)
|
||||
hostlen = strlen(hostname);
|
||||
|
||||
/* Create a new cache entry */
|
||||
/* Create a new cache entry, struct already has the hostname NUL */
|
||||
dns = curlx_calloc(1, sizeof(struct Curl_dns_entry) + hostlen);
|
||||
if(!dns)
|
||||
goto out;
|
||||
|
||||
dns->refcount = 1; /* the cache has the first reference */
|
||||
dns->addr = paddr ? *paddr : NULL; /* this is the address(es) */
|
||||
if(permanent) {
|
||||
dns->timestamp.tv_sec = 0; /* an entry that never goes stale */
|
||||
dns->timestamp.tv_usec = 0; /* an entry that never goes stale */
|
||||
|
|
@ -484,11 +471,42 @@ dnscache_entry_create(struct Curl_easy *data,
|
|||
if(hostlen)
|
||||
memcpy(dns->hostname, hostname, hostlen);
|
||||
|
||||
/* Take the given address lists into the entry */
|
||||
if(paddr1 && *paddr1) {
|
||||
dns->addr = *paddr1;
|
||||
*paddr1 = NULL;
|
||||
}
|
||||
if(paddr2 && *paddr2) {
|
||||
struct Curl_addrinfo **phead = &dns->addr;
|
||||
while(*phead)
|
||||
phead = &(*phead)->ai_next;
|
||||
*phead = *paddr2;
|
||||
*paddr2 = NULL;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_SHUFFLE_DNS
|
||||
/* shuffle addresses if requested */
|
||||
if(data->set.dns_shuffle_addresses && dns->addr) {
|
||||
CURLcode result = Curl_shuffle_addr(data, &dns->addr);
|
||||
if(result) {
|
||||
/* free without lock, we are the sole owner */
|
||||
dnscache_entry_free(dns);
|
||||
dns = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)data;
|
||||
#endif
|
||||
|
||||
out:
|
||||
if(paddr) {
|
||||
if(!dns)
|
||||
Curl_freeaddrinfo(*paddr);
|
||||
*paddr = NULL;
|
||||
if(paddr1 && *paddr1) {
|
||||
Curl_freeaddrinfo(*paddr1);
|
||||
*paddr1 = NULL;
|
||||
}
|
||||
if(paddr2 && *paddr2) {
|
||||
Curl_freeaddrinfo(*paddr2);
|
||||
*paddr2 = NULL;
|
||||
}
|
||||
return dns;
|
||||
}
|
||||
|
|
@ -500,7 +518,20 @@ Curl_dnscache_mk_entry(struct Curl_easy *data,
|
|||
uint16_t port,
|
||||
uint8_t ip_version)
|
||||
{
|
||||
return dnscache_entry_create(data, paddr, hostname, 0,
|
||||
return dnscache_entry_create(data, paddr, NULL, hostname,
|
||||
hostname ? strlen(hostname) : 0,
|
||||
port, ip_version, FALSE);
|
||||
}
|
||||
|
||||
struct Curl_dns_entry *
|
||||
Curl_dnscache_mk_entry2(struct Curl_easy *data,
|
||||
struct Curl_addrinfo **paddr1,
|
||||
struct Curl_addrinfo **paddr2,
|
||||
const char *hostname,
|
||||
uint16_t port, uint8_t ip_version)
|
||||
{
|
||||
return dnscache_entry_create(data, paddr1, paddr2, hostname,
|
||||
hostname ? strlen(hostname) : 0,
|
||||
port, ip_version, FALSE);
|
||||
}
|
||||
|
||||
|
|
@ -509,7 +540,7 @@ dnscache_add_addr(struct Curl_easy *data,
|
|||
struct Curl_dnscache *dnscache,
|
||||
struct Curl_addrinfo **paddr,
|
||||
const char *hostname,
|
||||
size_t hlen, /* length or zero */
|
||||
size_t hlen,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
bool permanent)
|
||||
|
|
@ -519,7 +550,7 @@ dnscache_add_addr(struct Curl_easy *data,
|
|||
struct Curl_dns_entry *dns;
|
||||
struct Curl_dns_entry *dns2;
|
||||
|
||||
dns = dnscache_entry_create(data, paddr, hostname, hlen, port,
|
||||
dns = dnscache_entry_create(data, paddr, NULL, hostname, hlen, port,
|
||||
ip_version, permanent);
|
||||
if(!dns)
|
||||
return NULL;
|
||||
|
|
@ -576,7 +607,7 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data,
|
|||
return CURLE_FAILED_INIT;
|
||||
|
||||
/* put this new host in the cache */
|
||||
dns = dnscache_add_addr(data, dnscache, NULL, host, 0,
|
||||
dns = dnscache_add_addr(data, dnscache, NULL, host, strlen(host),
|
||||
port, ip_version, FALSE);
|
||||
if(dns) {
|
||||
/* release the returned reference; the cache itself will keep the
|
||||
|
|
@ -589,6 +620,20 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data,
|
|||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
struct Curl_dns_entry *Curl_dns_entry_link(struct Curl_easy *data,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
if(!dns)
|
||||
return NULL;
|
||||
else {
|
||||
struct Curl_dnscache *dnscache = dnscache_get(data);
|
||||
dnscache_lock(data, dnscache);
|
||||
dns->refcount++;
|
||||
dnscache_unlock(data, dnscache);
|
||||
return dns;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_dns_entry_unlink() releases a reference to the given cached DNS entry.
|
||||
* When the reference count reaches 0, the entry is destroyed. It is important
|
||||
|
|
|
|||
|
|
@ -68,6 +68,18 @@ Curl_dnscache_mk_entry(struct Curl_easy *data,
|
|||
uint16_t port,
|
||||
uint8_t ip_version);
|
||||
|
||||
struct Curl_dns_entry *
|
||||
Curl_dnscache_mk_entry2(struct Curl_easy *data,
|
||||
struct Curl_addrinfo **paddr1,
|
||||
struct Curl_addrinfo **paddr2,
|
||||
const char *hostname,
|
||||
uint16_t port, uint8_t ip_version);
|
||||
|
||||
/* Increase the ref counter and return it for storing in another place.
|
||||
* May be called with NULL, in which case it returns NULL. */
|
||||
struct Curl_dns_entry *Curl_dns_entry_link(struct Curl_easy *data,
|
||||
struct Curl_dns_entry *dns);
|
||||
|
||||
/* unlink a dns entry, frees all resources if it was the last reference.
|
||||
* Always clears `*pdns`` */
|
||||
void Curl_dns_entry_unlink(struct Curl_easy *data,
|
||||
|
|
|
|||
|
|
@ -1094,8 +1094,6 @@ void curl_easy_reset(CURL *d)
|
|||
Curl_meta_reset(data);
|
||||
/* clear any resolve data */
|
||||
Curl_async_shutdown(data);
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[0]);
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[1]);
|
||||
/* zero out UserDefined data: */
|
||||
Curl_freeset(data);
|
||||
memset(&data->set, 0, sizeof(struct UserDefined));
|
||||
|
|
|
|||
|
|
@ -2241,6 +2241,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
ftp_state(data, ftpc, FTP_STOP); /* this phase is completed */
|
||||
|
||||
error:
|
||||
Curl_dns_entry_unlink(data, &dns);
|
||||
curlx_free(newhost);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
483
lib/hostip.c
483
lib/hostip.c
|
|
@ -111,73 +111,6 @@
|
|||
* CURLRES_* defines based on the config*.h and curl_setup.h defines.
|
||||
*/
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
static void show_resolve_info(struct Curl_easy *data,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
const struct Curl_addrinfo *a;
|
||||
CURLcode result = CURLE_OK;
|
||||
#ifdef CURLRES_IPV6
|
||||
struct dynbuf out[2];
|
||||
#else
|
||||
struct dynbuf out[1];
|
||||
#endif
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(dns);
|
||||
|
||||
if(!data->set.verbose ||
|
||||
/* ignore no name or numerical IP addresses */
|
||||
!dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
|
||||
return;
|
||||
|
||||
a = dns->addr;
|
||||
|
||||
infof(data, "Host %s:%d was resolved.",
|
||||
(dns->hostname[0] ? dns->hostname : "(none)"), dns->port);
|
||||
|
||||
curlx_dyn_init(&out[0], 1024);
|
||||
#ifdef CURLRES_IPV6
|
||||
curlx_dyn_init(&out[1], 1024);
|
||||
#endif
|
||||
|
||||
while(a) {
|
||||
if(
|
||||
#ifdef CURLRES_IPV6
|
||||
a->ai_family == PF_INET6 ||
|
||||
#endif
|
||||
a->ai_family == PF_INET) {
|
||||
char buf[MAX_IPADR_LEN];
|
||||
struct dynbuf *d = &out[(a->ai_family != PF_INET)];
|
||||
Curl_printable_address(a, buf, sizeof(buf));
|
||||
if(curlx_dyn_len(d))
|
||||
result = curlx_dyn_addn(d, ", ", 2);
|
||||
if(!result)
|
||||
result = curlx_dyn_add(d, buf);
|
||||
if(result) {
|
||||
infof(data, "too many IP, cannot show");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
a = a->ai_next;
|
||||
}
|
||||
|
||||
#ifdef CURLRES_IPV6
|
||||
infof(data, "IPv6: %s",
|
||||
(curlx_dyn_len(&out[1]) ? curlx_dyn_ptr(&out[1]) : "(none)"));
|
||||
#endif
|
||||
infof(data, "IPv4: %s",
|
||||
(curlx_dyn_len(&out[0]) ? curlx_dyn_ptr(&out[0]) : "(none)"));
|
||||
|
||||
fail:
|
||||
curlx_dyn_free(&out[0]);
|
||||
#ifdef CURLRES_IPV6
|
||||
curlx_dyn_free(&out[1]);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define show_resolve_info(x, y) Curl_nop_stmt
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Curl_printable_address() stores a printable version of the 1st address
|
||||
* given in the 'ai' argument. The result will be stored in the buf that is
|
||||
|
|
@ -400,7 +333,196 @@ static CURLcode hostip_async_new(struct Curl_easy *data,
|
|||
data->state.async = async;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode hostip_resolv_take_result(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct Curl_resolv_async *async = data->state.async;
|
||||
CURLcode result;
|
||||
|
||||
/* If async resolving is ongoing, this must be set */
|
||||
if(!async)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
if(data->conn->bits.doh)
|
||||
result = Curl_doh_take_result(data, pdns);
|
||||
else
|
||||
#endif
|
||||
result = Curl_async_take_result(data, async, pdns);
|
||||
|
||||
if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
else if(result)
|
||||
Curl_resolver_error(data, NULL);
|
||||
else
|
||||
DEBUGASSERT(*pdns);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const struct Curl_addrinfo *
|
||||
Curl_resolv_get_ai(struct Curl_easy *data, int ai_family,
|
||||
unsigned int index)
|
||||
{
|
||||
#ifdef CURLRES_ASYNCH
|
||||
struct Curl_resolv_async *async = data->state.async;
|
||||
if(async)
|
||||
return Curl_async_get_ai(data, async, ai_family, index);
|
||||
#else
|
||||
(void)data;
|
||||
(void)ai_family;
|
||||
(void)index;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* USE_CURL_ASYNC */
|
||||
|
||||
static CURLcode hostip_resolv_announce(struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
uint8_t transport,
|
||||
timediff_t timeout_ms)
|
||||
{
|
||||
if(data->set.resolver_start) {
|
||||
void *resolver = NULL;
|
||||
int st;
|
||||
#ifdef CURLRES_ASYNCH
|
||||
CURLcode result;
|
||||
if(!data->state.async) {
|
||||
result = hostip_async_new(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Curl_async_get_impl(data, data->state.async, &resolver);
|
||||
if(result)
|
||||
return result;
|
||||
#else
|
||||
(void)hostname;
|
||||
(void)port;
|
||||
(void)ip_version;
|
||||
(void)timeout_ms;
|
||||
(void)transport;
|
||||
#endif
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
st = data->set.resolver_start(resolver, NULL,
|
||||
data->set.resolver_start_client);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
if(st) {
|
||||
return CURLE_ABORTED_BY_CALLBACK;
|
||||
}
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode hostip_resolv_start(struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t ip_version,
|
||||
uint8_t transport,
|
||||
timediff_t timeout_ms,
|
||||
bool allowDOH,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct Curl_addrinfo *addr = NULL;
|
||||
size_t hostname_len;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
*pdns = NULL;
|
||||
|
||||
/* really need to start a resolve operation */
|
||||
result = hostip_resolv_announce(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
/* Check for "known" things to resolve ourselves. */
|
||||
#ifndef USE_RESOLVE_ON_IPS
|
||||
if(Curl_is_ipaddr(hostname)) {
|
||||
/* shortcut literal IP addresses, if we are not told to resolve them. */
|
||||
result = Curl_str2addr(hostname, port, &addr);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
hostname_len = strlen(hostname);
|
||||
if(curl_strequal(hostname, "localhost") ||
|
||||
curl_strequal(hostname, "localhost.") ||
|
||||
tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
|
||||
tailmatch(hostname, hostname_len, STRCONST(".localhost."))) {
|
||||
addr = get_localhost(port, hostname);
|
||||
if(!addr)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
if(!Curl_is_ipaddr(hostname) && allowDOH && data->set.doh) {
|
||||
if(!data->state.async) {
|
||||
result = hostip_async_new(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
result = Curl_doh(data, data->state.async);
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
(void)allowDOH;
|
||||
#endif
|
||||
|
||||
/* Can we provide the requested IP specifics in resolving? */
|
||||
if(!can_resolve_ip_version(data, ip_version)) {
|
||||
result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CURLRES_ASYNCH
|
||||
(void)addr;
|
||||
if(!data->state.async) {
|
||||
result = hostip_async_new(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
result = Curl_async_getaddrinfo(data, data->state.async);
|
||||
if(result == CURLE_AGAIN) {
|
||||
/* the answer might be there already. Check. */
|
||||
CURLcode r2 = hostip_resolv_take_result(data, pdns);
|
||||
if(r2)
|
||||
result = r2;
|
||||
else if(*pdns)
|
||||
result = CURLE_OK;
|
||||
}
|
||||
#else
|
||||
addr = Curl_sync_getaddrinfo(data, hostname, port, ip_version, transport);
|
||||
if(!addr)
|
||||
result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
#endif
|
||||
|
||||
out:
|
||||
if(!result) {
|
||||
if(addr) {
|
||||
/* we got a response, create a dns entry, add to cache, return */
|
||||
DEBUGASSERT(!*pdns);
|
||||
*pdns = Curl_dnscache_mk_entry(data, &addr, hostname, port, ip_version);
|
||||
if(!*pdns)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else if(!*pdns)
|
||||
result = CURLE_AGAIN;
|
||||
}
|
||||
else if(*pdns)
|
||||
Curl_dns_entry_unlink(data, pdns);
|
||||
else if(addr)
|
||||
Curl_freeaddrinfo(addr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode hostip_resolv(struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
|
|
@ -409,15 +531,13 @@ static CURLcode hostip_resolv(struct Curl_easy *data,
|
|||
uint8_t transport,
|
||||
timediff_t timeout_ms,
|
||||
bool allowDOH,
|
||||
struct Curl_dns_entry **entry)
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct Curl_dns_entry *dns = NULL;
|
||||
struct Curl_addrinfo *addr = NULL;
|
||||
bool respwait = FALSE;
|
||||
size_t hostname_len;
|
||||
CURLcode r2, result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
CURLcode result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
bool cache_dns = FALSE;
|
||||
|
||||
*entry = NULL;
|
||||
*pdns = NULL;
|
||||
|
||||
#ifdef USE_CURL_ASYNC
|
||||
if(data->state.async)
|
||||
|
|
@ -439,7 +559,7 @@ static CURLcode hostip_resolv(struct Curl_easy *data,
|
|||
(curl_strequal(&hostname[hostname_len - 6], ".onion") ||
|
||||
curl_strequal(&hostname[hostname_len - 7], ".onion."))) {
|
||||
failf(data, "Not resolving .onion address (RFC 7686)");
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
|
@ -449,139 +569,50 @@ static CURLcode hostip_resolv(struct Curl_easy *data,
|
|||
getenv("CURL_DBG_RESOLV_FAIL_IPV6")) {
|
||||
infof(data, "DEBUG fail ipv6 resolve");
|
||||
result = Curl_resolver_error(data, NULL);
|
||||
goto error;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
/* Let's check our DNS cache first */
|
||||
r2 = Curl_dnscache_get(data, hostname, port, ip_version, &dns);
|
||||
if(dns) {
|
||||
result = Curl_dnscache_get(data, hostname, port, ip_version, pdns);
|
||||
if(*pdns) {
|
||||
infof(data, "Hostname %s was found in DNS cache", hostname);
|
||||
result = CURLE_OK;
|
||||
goto out;
|
||||
}
|
||||
else if(r2) {
|
||||
DEBUGASSERT(!dns);
|
||||
else if(result) {
|
||||
infof(data, "Negative DNS entry");
|
||||
result = Curl_resolver_error(data, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* No luck, we need to resolve hostname. Notify user callback. */
|
||||
if(data->set.resolver_start) {
|
||||
void *resolver = NULL;
|
||||
int st;
|
||||
#ifdef CURLRES_ASYNCH
|
||||
if(!data->state.async) {
|
||||
result = hostip_async_new(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
goto error;
|
||||
}
|
||||
result = Curl_async_get_impl(data, data->state.async, &resolver);
|
||||
if(result)
|
||||
goto error;
|
||||
#endif
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
st = data->set.resolver_start(resolver, NULL,
|
||||
data->set.resolver_start_client);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
if(st) {
|
||||
result = CURLE_ABORTED_BY_CALLBACK;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if(Curl_is_ipaddr(hostname)) {
|
||||
#ifndef USE_RESOLVE_ON_IPS
|
||||
/* shortcut literal IP addresses, if we are not told to resolve them. */
|
||||
result = Curl_str2addr(hostname, port, &addr);
|
||||
if(result)
|
||||
goto error;
|
||||
goto out;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(curl_strequal(hostname, "localhost") ||
|
||||
curl_strequal(hostname, "localhost.") ||
|
||||
tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
|
||||
tailmatch(hostname, hostname_len, STRCONST(".localhost."))) {
|
||||
addr = get_localhost(port, hostname);
|
||||
result = addr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
else if(!Curl_is_ipaddr(hostname) && allowDOH && data->set.doh) {
|
||||
if(!data->state.async) {
|
||||
result = hostip_async_new(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
goto error;
|
||||
}
|
||||
result = Curl_doh(data, data->state.async);
|
||||
respwait = TRUE;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* Can we provide the requested IP specifics in resolving? */
|
||||
if(!can_resolve_ip_version(data, ip_version)) {
|
||||
result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef CURLRES_ASYNCH
|
||||
if(!data->state.async) {
|
||||
result = hostip_async_new(data, hostname, port, ip_version,
|
||||
transport, timeout_ms);
|
||||
if(result)
|
||||
goto error;
|
||||
}
|
||||
result = Curl_async_getaddrinfo(data, data->state.async);
|
||||
respwait = TRUE;
|
||||
#else
|
||||
respwait = FALSE; /* no async waiting here */
|
||||
addr = Curl_sync_getaddrinfo(data, hostname, port, ip_version, transport);
|
||||
if(addr)
|
||||
result = CURLE_OK;
|
||||
#endif
|
||||
/* No luck, we need to start resolving. */
|
||||
cache_dns = TRUE;
|
||||
result = hostip_resolv_start(data, hostname, port, ip_version,
|
||||
transport, timeout_ms, allowDOH, pdns);
|
||||
}
|
||||
|
||||
out:
|
||||
/* We either have found a `dns` or looked up the `addr` or `respwait` is set
|
||||
* for an async operation. Everything else is a failure to resolve. */
|
||||
if(result)
|
||||
;
|
||||
else if(dns) {
|
||||
*entry = dns;
|
||||
return CURLE_OK;
|
||||
}
|
||||
else if(addr) {
|
||||
/* we got a response, create a dns entry, add to cache, return */
|
||||
dns = Curl_dnscache_mk_entry(data, &addr, hostname, port, ip_version);
|
||||
if(!dns || Curl_dnscache_add(data, dns)) {
|
||||
/* this is OOM or similar, do not store such negative resolves */
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
if(result && (result != CURLE_AGAIN)) {
|
||||
Curl_dns_entry_unlink(data, pdns);
|
||||
Curl_async_shutdown(data);
|
||||
if((result == CURLE_COULDNT_RESOLVE_HOST) ||
|
||||
(result == CURLE_COULDNT_RESOLVE_PROXY)) {
|
||||
if(cache_dns)
|
||||
Curl_dnscache_add_negative(data, hostname, port, ip_version);
|
||||
failf(data, "Could not resolve: %s:%u", hostname, port);
|
||||
}
|
||||
show_resolve_info(data, dns);
|
||||
*entry = dns;
|
||||
return CURLE_OK;
|
||||
}
|
||||
else if(respwait) {
|
||||
#ifdef USE_CURL_ASYNC
|
||||
result = Curl_resolv_take_result(data, &dns);
|
||||
if(!result) {
|
||||
*entry = dns;
|
||||
return dns ? CURLE_OK : CURLE_AGAIN;
|
||||
else {
|
||||
failf(data, "Error %d resolving %s:%u", result, hostname, port);
|
||||
}
|
||||
#endif
|
||||
result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
error:
|
||||
if(dns)
|
||||
Curl_dns_entry_unlink(data, &dns);
|
||||
Curl_async_shutdown(data);
|
||||
if(result == CURLE_COULDNT_RESOLVE_HOST)
|
||||
Curl_dnscache_add_negative(data, hostname, port, ip_version);
|
||||
DEBUGASSERT(result);
|
||||
else if(cache_dns && *pdns) {
|
||||
result = Curl_dnscache_add(data, *pdns);
|
||||
if(result)
|
||||
Curl_dns_entry_unlink(data, pdns);
|
||||
}
|
||||
|
||||
CURL_TRC_DNS(data, "hostip_resolv(%s:%u, ip=%x, timeout_ms=%" FMT_TIMEDIFF_T
|
||||
") -> %d, dns %sfound",
|
||||
hostname, port, ip_version, timeout_ms, result,
|
||||
*pdns ? "" : "not ");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -841,33 +872,32 @@ CURLcode Curl_resolv_take_result(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
else if(result) {
|
||||
result = Curl_resolver_error(data, NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
if(data->conn->bits.doh)
|
||||
result = Curl_doh_take_result(data, pdns);
|
||||
else
|
||||
#endif
|
||||
result = Curl_async_take_result(data, async, pdns);
|
||||
|
||||
if(!result) {
|
||||
DEBUGASSERT(*pdns);
|
||||
show_resolve_info(data, *pdns);
|
||||
}
|
||||
else if(result == CURLE_AGAIN)
|
||||
result = CURLE_OK;
|
||||
else {
|
||||
Curl_dnscache_add_negative(data, async->hostname, async->port,
|
||||
async->ip_version);
|
||||
Curl_async_shutdown(data);
|
||||
Curl_resolver_error(data, NULL);
|
||||
return Curl_resolver_error(data, NULL);
|
||||
}
|
||||
|
||||
result = hostip_resolv_take_result(data, pdns);
|
||||
|
||||
if(*pdns) {
|
||||
/* Add to cache */
|
||||
result = Curl_dnscache_add(data, *pdns);
|
||||
if(result)
|
||||
Curl_dns_entry_unlink(data, pdns);
|
||||
}
|
||||
else if((result == CURLE_COULDNT_RESOLVE_HOST) ||
|
||||
(result == CURLE_COULDNT_RESOLVE_PROXY)) {
|
||||
Curl_dnscache_add_negative(data, async->hostname,
|
||||
async->port, async->ip_version);
|
||||
failf(data, "Could not resolve: %s:%u", async->hostname, async->port);
|
||||
}
|
||||
else if(result) {
|
||||
failf(data, "Error %d resolving %s:%u",
|
||||
result, async->hostname, async->port);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USE_CURL_ASYNC */
|
||||
|
||||
CURLcode Curl_resolv_pollset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
|
|
@ -911,3 +941,30 @@ CURLcode Curl_resolver_error(struct Curl_easy *data, const char *detail)
|
|||
detail ? " (" : "", detail ? detail : "", detail ? ")" : "");
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
CURLcode Curl_resolv_unix(struct Curl_easy *data,
|
||||
const char *unix_path,
|
||||
bool abstract_path,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
struct Curl_addrinfo *addr;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(unix_path);
|
||||
*pdns = NULL;
|
||||
|
||||
result = Curl_unix2addr(unix_path, abstract_path, &addr);
|
||||
if(result) {
|
||||
if(result == CURLE_TOO_LARGE) {
|
||||
/* Long paths are not supported for now */
|
||||
failf(data, "Unix socket path too long: '%s'", unix_path);
|
||||
result = CURLE_COULDNT_RESOLVE_HOST;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
*pdns = Curl_dnscache_mk_entry(data, &addr, NULL, 0, 0);
|
||||
return *pdns ? CURLE_OK : CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
|
|
|
|||
11
lib/hostip.h
11
lib/hostip.h
|
|
@ -111,8 +111,12 @@ CURLcode Curl_resolv_timeout(struct Curl_easy *data,
|
|||
#ifdef USE_CURL_ASYNC
|
||||
CURLcode Curl_resolv_take_result(struct Curl_easy *data,
|
||||
struct Curl_dns_entry **pdns);
|
||||
const struct Curl_addrinfo *
|
||||
Curl_resolv_get_ai(struct Curl_easy *data, int ai_family,
|
||||
unsigned int index);
|
||||
#else
|
||||
#define Curl_resolv_take_result(x, y) CURLE_NOT_BUILT_IN
|
||||
#define Curl_resolv_get_ai(x,y,z) NULL
|
||||
#endif
|
||||
|
||||
CURLcode Curl_resolv_pollset(struct Curl_easy *data,
|
||||
|
|
@ -134,4 +138,11 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data,
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
CURLcode Curl_resolv_unix(struct Curl_easy *data,
|
||||
const char *unix_path,
|
||||
bool abstract_path,
|
||||
struct Curl_dns_entry **pdns);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_HOSTIP_H */
|
||||
|
|
|
|||
130
lib/multi.c
130
lib/multi.c
|
|
@ -140,7 +140,6 @@ static void mstate(struct Curl_easy *data, CURLMstate state
|
|||
NULL, /* PENDING */
|
||||
NULL, /* SETUP */
|
||||
Curl_init_CONNECT, /* CONNECT */
|
||||
NULL, /* RESOLVING */
|
||||
NULL, /* CONNECTING */
|
||||
NULL, /* PROTOCONNECT */
|
||||
NULL, /* PROTOCONNECTING */
|
||||
|
|
@ -654,8 +653,6 @@ static void multi_done_locked(struct connectdata *conn,
|
|||
data->state.done = TRUE; /* called now! */
|
||||
data->state.recent_conn_id = conn->connection_id;
|
||||
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[0]); /* done with this */
|
||||
Curl_dns_entry_unlink(data, &data->state.dns[1]);
|
||||
Curl_dnscache_prune(data);
|
||||
|
||||
if(multi_conn_should_close(conn, data, (bool)mdctx->premature)) {
|
||||
|
|
@ -731,9 +728,12 @@ static CURLcode multi_done(struct Curl_easy *data,
|
|||
else
|
||||
result = status;
|
||||
|
||||
if(result != CURLE_ABORTED_BY_CALLBACK) {
|
||||
/* avoid this if we already aborted by callback to avoid this calling
|
||||
another callback */
|
||||
if(data->mstate > MSTATE_CONNECTING &&
|
||||
(result != CURLE_ABORTED_BY_CALLBACK)) {
|
||||
/* avoid this if
|
||||
* - the transfer has not connected
|
||||
* - we already aborted by callback to avoid this calling another callback
|
||||
*/
|
||||
int rc = Curl_pgrsDone(data);
|
||||
if(!result && rc)
|
||||
result = CURLE_ABORTED_BY_CALLBACK;
|
||||
|
|
@ -1158,12 +1158,11 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data,
|
|||
/* nothing to poll for yet */
|
||||
break;
|
||||
|
||||
case MSTATE_RESOLVING:
|
||||
result = Curl_resolv_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_CONNECTING:
|
||||
result = mstate_connecting_pollset(data, ps);
|
||||
if(data->conn && !data->conn->bits.dns_resolved)
|
||||
result = Curl_resolv_pollset(data, ps);
|
||||
if(!result)
|
||||
result = mstate_connecting_pollset(data, ps);
|
||||
break;
|
||||
|
||||
case MSTATE_PROTOCONNECT:
|
||||
|
|
@ -1811,13 +1810,9 @@ static bool multi_handle_timeout(struct Curl_easy *data,
|
|||
since = data->progress.t_startsingle;
|
||||
else
|
||||
since = data->progress.t_startop;
|
||||
if(data->mstate == MSTATE_RESOLVING)
|
||||
failf(data, "Resolving timed out after %" FMT_TIMEDIFF_T
|
||||
" milliseconds",
|
||||
curlx_ptimediff_ms(Curl_pgrs_now(data), &since));
|
||||
else if(data->mstate == MSTATE_CONNECTING)
|
||||
failf(data, "Connection timed out after %" FMT_TIMEDIFF_T
|
||||
" milliseconds",
|
||||
if(data->mstate == MSTATE_CONNECTING)
|
||||
failf(data, "%s timed out after %" FMT_TIMEDIFF_T " milliseconds",
|
||||
data->conn->bits.dns_resolved ? "Connection" : "Resolving",
|
||||
curlx_ptimediff_ms(Curl_pgrs_now(data), &since));
|
||||
else {
|
||||
struct SingleRequest *k = &data->req;
|
||||
|
|
@ -2309,55 +2304,6 @@ static CURLMcode state_ratelimiting(struct Curl_easy *data,
|
|||
return mresult;
|
||||
}
|
||||
|
||||
static CURLMcode state_resolving(struct Curl_multi *multi,
|
||||
struct Curl_easy *data,
|
||||
bool *stream_errorp,
|
||||
CURLcode *resultp)
|
||||
{
|
||||
struct Curl_dns_entry *dns = NULL;
|
||||
CURLMcode mresult = CURLM_OK;
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_resolv_take_result(data, &dns);
|
||||
CURL_TRC_DNS(data, "Curl_resolv_take_result() -> %d, %s",
|
||||
result, dns ? "found" : "missing");
|
||||
|
||||
/* Update sockets here, because the socket(s) may have been closed and the
|
||||
application thus needs to be told, even if it is likely that the same
|
||||
socket(s) will again be used further down. If the name has not yet been
|
||||
resolved, it is likely that new sockets have been opened in an attempt to
|
||||
contact another resolver. */
|
||||
mresult = Curl_multi_ev_assess_xfer(multi, data);
|
||||
if(mresult)
|
||||
return mresult;
|
||||
|
||||
if(dns) {
|
||||
bool connected;
|
||||
/* Perform the next step in the connection phase, and then move on to the
|
||||
WAITCONNECT state */
|
||||
result = Curl_setup_conn(data, dns, &connected);
|
||||
if(result) {
|
||||
/* setup failed, terminate connection */
|
||||
struct connectdata *conn = data->conn;
|
||||
Curl_detach_connection(data);
|
||||
Curl_conn_terminate(data, conn, TRUE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* call again please so that we get the next socket setup */
|
||||
mresult = CURLM_CALL_MULTI_PERFORM;
|
||||
multistate(data, connected ? MSTATE_PROTOCONNECT : MSTATE_CONNECTING);
|
||||
}
|
||||
|
||||
out:
|
||||
if(result)
|
||||
/* failure detected */
|
||||
*stream_errorp = TRUE;
|
||||
|
||||
*resultp = result;
|
||||
return mresult;
|
||||
}
|
||||
|
||||
static CURLMcode state_connect(struct Curl_multi *multi,
|
||||
struct Curl_easy *data,
|
||||
CURLcode *resultp)
|
||||
|
|
@ -2365,9 +2311,8 @@ static CURLMcode state_connect(struct Curl_multi *multi,
|
|||
/* Connect. We want to get a connection identifier filled in. This state can
|
||||
be entered from SETUP and from PENDING. */
|
||||
bool connected;
|
||||
bool async;
|
||||
CURLMcode mresult = CURLM_OK;
|
||||
CURLcode result = Curl_connect(data, &async, &connected);
|
||||
CURLcode result = Curl_connect(data, &connected);
|
||||
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
|
||||
/* There was no connection available. We will go to the pending state and
|
||||
wait for an available connection. */
|
||||
|
|
@ -2383,26 +2328,21 @@ static CURLMcode state_connect(struct Curl_multi *multi,
|
|||
process_pending_handles(data->multi);
|
||||
|
||||
if(!result) {
|
||||
if(async)
|
||||
/* We are now waiting for an asynchronous name lookup */
|
||||
multistate(data, MSTATE_RESOLVING);
|
||||
else {
|
||||
/* after the connect has been sent off, go WAITCONNECT unless the
|
||||
protocol connect is already done and we can go directly to WAITDO or
|
||||
DO! */
|
||||
mresult = CURLM_CALL_MULTI_PERFORM;
|
||||
/* after the connect has been sent off, go WAITCONNECT unless the
|
||||
protocol connect is already done and we can go directly to WAITDO or
|
||||
DO! */
|
||||
mresult = CURLM_CALL_MULTI_PERFORM;
|
||||
|
||||
if(connected) {
|
||||
if(!data->conn->bits.reuse &&
|
||||
Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
|
||||
/* new connection, can multiplex, wake pending handles */
|
||||
process_pending_handles(data->multi);
|
||||
}
|
||||
multistate(data, MSTATE_PROTOCONNECT);
|
||||
}
|
||||
else {
|
||||
multistate(data, MSTATE_CONNECTING);
|
||||
if(connected) {
|
||||
if(!data->conn->bits.reuse &&
|
||||
Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
|
||||
/* new connection, can multiplex, wake pending handles */
|
||||
process_pending_handles(data->multi);
|
||||
}
|
||||
multistate(data, MSTATE_PROTOCONNECT);
|
||||
}
|
||||
else {
|
||||
multistate(data, MSTATE_CONNECTING);
|
||||
}
|
||||
}
|
||||
*resultp = result;
|
||||
|
|
@ -2451,7 +2391,7 @@ static CURLcode is_finished(struct Curl_multi *multi,
|
|||
return result;
|
||||
}
|
||||
/* if there is still a connection to use, call the progress function */
|
||||
else if(data->conn) {
|
||||
else if(data->conn && Curl_conn_is_connected(data->conn, FIRSTSOCKET)) {
|
||||
result = Curl_pgrsUpdate(data);
|
||||
if(result) {
|
||||
/* aborted due to progress callback return code must close the
|
||||
|
|
@ -2608,15 +2548,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||
mresult = state_connect(multi, data, &result);
|
||||
break;
|
||||
|
||||
case MSTATE_RESOLVING:
|
||||
/* awaiting an asynch name resolve to complete */
|
||||
mresult = state_resolving(multi, data, &stream_error, &result);
|
||||
break;
|
||||
|
||||
case MSTATE_CONNECTING:
|
||||
/* awaiting a completion of an asynch TCP connect */
|
||||
DEBUGASSERT(data->conn);
|
||||
if(!Curl_xfer_recv_is_paused(data)) {
|
||||
if(!data->conn) {
|
||||
DEBUGASSERT(0);
|
||||
result = CURLE_FAILED_INIT;
|
||||
break;
|
||||
}
|
||||
else if(!Curl_xfer_recv_is_paused(data)) {
|
||||
result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
|
||||
if(connected && !result) {
|
||||
if(!data->conn->bits.reuse &&
|
||||
|
|
@ -2629,6 +2568,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||
}
|
||||
else if(result) {
|
||||
/* failure detected */
|
||||
CURL_TRC_M(data, "connect failed -> %d", result);
|
||||
multi_posttransfer(data);
|
||||
multi_done(data, result, TRUE);
|
||||
stream_error = TRUE;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ typedef enum {
|
|||
MSTATE_PENDING, /* no connections, waiting for one */
|
||||
MSTATE_SETUP, /* start a new transfer */
|
||||
MSTATE_CONNECT, /* resolve/connect has been sent off */
|
||||
MSTATE_RESOLVING, /* awaiting the resolve to finalize */
|
||||
MSTATE_CONNECTING, /* awaiting the TCP connect to finalize */
|
||||
MSTATE_PROTOCONNECT, /* initiate protocol connect procedure */
|
||||
MSTATE_PROTOCONNECTING, /* completing the protocol-specific connect phase */
|
||||
|
|
|
|||
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
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ void Curl_init_userdefined(struct Curl_easy *data);
|
|||
void Curl_freeset(struct Curl_easy *data);
|
||||
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
|
||||
CURLcode Curl_close(struct Curl_easy **datap); /* opposite of Curl_open() */
|
||||
CURLcode Curl_connect(struct Curl_easy *data,
|
||||
bool *asyncp,
|
||||
bool *protocol_done);
|
||||
CURLcode Curl_connect(struct Curl_easy *data, bool *pconnected);
|
||||
CURLcode Curl_setup_conn(struct Curl_easy *data,
|
||||
struct Curl_dns_entry *dns,
|
||||
bool *protocol_done);
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ struct ConnectBits {
|
|||
BIT(shutdown_handler); /* connection shutdown: handler shut down */
|
||||
BIT(shutdown_filters); /* connection shutdown: filters shut down */
|
||||
BIT(in_cpool); /* connection is kept in a connection pool */
|
||||
BIT(dns_resolved); /* DNS records for connection were resolved */
|
||||
};
|
||||
|
||||
struct hostname {
|
||||
|
|
@ -720,7 +721,6 @@ struct UrlState {
|
|||
struct auth authhost; /* auth details for host */
|
||||
struct auth authproxy; /* auth details for proxy */
|
||||
|
||||
struct Curl_dns_entry *dns[2]; /* DNS to connect FIRST/SECONDARY */
|
||||
#ifdef USE_CURL_ASYNC
|
||||
struct Curl_resolv_async *async; /* asynchronous name resolver data */
|
||||
uint32_t next_async_id; /* id of the next async resolve operation */
|
||||
|
|
|
|||
|
|
@ -2940,7 +2940,7 @@ struct Curl_cftype Curl_cft_http3 = {
|
|||
CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai)
|
||||
struct Curl_sockaddr_ex *addr)
|
||||
{
|
||||
struct cf_ngtcp2_ctx *ctx = NULL;
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
|
|
@ -2958,7 +2958,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
cf->conn = conn;
|
||||
|
||||
result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC);
|
||||
result = Curl_cf_udp_create(&cf->next, data, conn, addr, TRNSPRT_QUIC);
|
||||
if(result)
|
||||
goto out;
|
||||
cf->next->conn = cf->conn;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ void Curl_ngtcp2_ver(char *p, size_t len);
|
|||
CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai);
|
||||
struct Curl_sockaddr_ex *addr);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_VQUIC_CURL_NGTCP2_H */
|
||||
|
|
|
|||
|
|
@ -1633,7 +1633,7 @@ struct Curl_cftype Curl_cft_http3 = {
|
|||
CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai)
|
||||
struct Curl_sockaddr_ex *addr)
|
||||
{
|
||||
struct cf_quiche_ctx *ctx = NULL;
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
|
|
@ -1651,7 +1651,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
cf->conn = conn;
|
||||
|
||||
result = Curl_cf_udp_create(&cf->next, data, conn, ai, TRNSPRT_QUIC);
|
||||
result = Curl_cf_udp_create(&cf->next, data, conn, addr, TRNSPRT_QUIC);
|
||||
if(result)
|
||||
goto out;
|
||||
cf->next->conn = cf->conn;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ void Curl_quiche_ver(char *p, size_t len);
|
|||
CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai);
|
||||
struct Curl_sockaddr_ex *addr);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -702,15 +702,15 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
|
|||
CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
(void)transport;
|
||||
DEBUGASSERT(transport == TRNSPRT_QUIC);
|
||||
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
|
||||
return Curl_cf_ngtcp2_create(pcf, data, conn, ai);
|
||||
return Curl_cf_ngtcp2_create(pcf, data, conn, addr);
|
||||
#elif defined(USE_QUICHE)
|
||||
return Curl_cf_quiche_create(pcf, data, conn, ai);
|
||||
return Curl_cf_quiche_create(pcf, data, conn, addr);
|
||||
#else
|
||||
*pcf = NULL;
|
||||
(void)data;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
|
|||
CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_http3;
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ RETR %TESTNUMBER
|
|||
QUIT
|
||||
</protocol>
|
||||
<limits>
|
||||
Allocations: 170
|
||||
Allocations: 180
|
||||
Maximum allocated: 150000
|
||||
</limits>
|
||||
</verify>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ via: 1.1 nghttpx
|
|||
s/^server: nghttpx.*\r?\n//
|
||||
</stripfile>
|
||||
<limits>
|
||||
Allocations: 160
|
||||
Allocations: 170
|
||||
Maximum allocated: 1800000
|
||||
</limits>
|
||||
</verify>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ Accept: */*
|
|||
|
||||
</protocol>
|
||||
<limits>
|
||||
Allocations: 82
|
||||
Allocations: 90
|
||||
Maximum allocated: 33400
|
||||
</limits>
|
||||
</verify>
|
||||
|
|
|
|||
|
|
@ -93,128 +93,128 @@ CURLOPT_SHARE
|
|||
lock: share [Pigs in space]: 0
|
||||
unlock: share [Pigs in space]: 1
|
||||
CURLOPT_COOKIELIST injected_and_clobbered
|
||||
lock: cookie [Pigs in space]: 0
|
||||
unlock: cookie [Pigs in space]: 1
|
||||
CURLOPT_COOKIELIST ALL
|
||||
lock: cookie [Pigs in space]: 2
|
||||
unlock: cookie [Pigs in space]: 3
|
||||
CURLOPT_COOKIELIST ALL
|
||||
CURLOPT_COOKIELIST session
|
||||
lock: cookie [Pigs in space]: 4
|
||||
unlock: cookie [Pigs in space]: 5
|
||||
CURLOPT_COOKIELIST session
|
||||
CURLOPT_COOKIELIST injected
|
||||
lock: cookie [Pigs in space]: 6
|
||||
unlock: cookie [Pigs in space]: 7
|
||||
CURLOPT_COOKIELIST injected
|
||||
CURLOPT_COOKIELIST SESS
|
||||
lock: cookie [Pigs in space]: 8
|
||||
unlock: cookie [Pigs in space]: 9
|
||||
CURLOPT_COOKIELIST SESS
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 10
|
||||
unlock: cookie [Pigs in space]: 11
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 12
|
||||
unlock: cookie [Pigs in space]: 13
|
||||
lock: share [Pigs in space]: 14
|
||||
unlock: share [Pigs in space]: 15
|
||||
lock: share [Pigs in space]: 2
|
||||
unlock: share [Pigs in space]: 3
|
||||
*** run 1
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 16
|
||||
unlock: share [Pigs in space]: 17
|
||||
lock: share [Pigs in space]: 4
|
||||
unlock: share [Pigs in space]: 5
|
||||
PERFORM
|
||||
lock: cookie [Pigs in space]: 12
|
||||
unlock: cookie [Pigs in space]: 13
|
||||
lock: cookie [Pigs in space]: 14
|
||||
unlock: cookie [Pigs in space]: 15
|
||||
lock: dns [Pigs in space]: 0
|
||||
unlock: dns [Pigs in space]: 1
|
||||
lock: dns [Pigs in space]: 2
|
||||
unlock: dns [Pigs in space]: 3
|
||||
lock: dns [Pigs in space]: 4
|
||||
unlock: dns [Pigs in space]: 5
|
||||
lock: cookie [Pigs in space]: 16
|
||||
unlock: cookie [Pigs in space]: 17
|
||||
lock: cookie [Pigs in space]: 18
|
||||
unlock: cookie [Pigs in space]: 19
|
||||
lock: cookie [Pigs in space]: 20
|
||||
unlock: cookie [Pigs in space]: 21
|
||||
lock: dns [Pigs in space]: 22
|
||||
unlock: dns [Pigs in space]: 23
|
||||
lock: dns [Pigs in space]: 24
|
||||
unlock: dns [Pigs in space]: 25
|
||||
lock: cookie [Pigs in space]: 22
|
||||
unlock: cookie [Pigs in space]: 23
|
||||
run 1: set cookie 1, 2 and 3
|
||||
lock: dns [Pigs in space]: 6
|
||||
unlock: dns [Pigs in space]: 7
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 24
|
||||
unlock: cookie [Pigs in space]: 25
|
||||
lock: share [Pigs in space]: 6
|
||||
unlock: share [Pigs in space]: 7
|
||||
*** run 2
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 8
|
||||
unlock: share [Pigs in space]: 9
|
||||
PERFORM
|
||||
lock: cookie [Pigs in space]: 26
|
||||
unlock: cookie [Pigs in space]: 27
|
||||
lock: cookie [Pigs in space]: 28
|
||||
unlock: cookie [Pigs in space]: 29
|
||||
lock: dns [Pigs in space]: 8
|
||||
unlock: dns [Pigs in space]: 9
|
||||
lock: dns [Pigs in space]: 10
|
||||
unlock: dns [Pigs in space]: 11
|
||||
lock: cookie [Pigs in space]: 30
|
||||
unlock: cookie [Pigs in space]: 31
|
||||
lock: cookie [Pigs in space]: 32
|
||||
unlock: cookie [Pigs in space]: 33
|
||||
run 1: set cookie 1, 2 and 3
|
||||
lock: dns [Pigs in space]: 34
|
||||
unlock: dns [Pigs in space]: 35
|
||||
lock: dns [Pigs in space]: 36
|
||||
unlock: dns [Pigs in space]: 37
|
||||
lock: cookie [Pigs in space]: 34
|
||||
unlock: cookie [Pigs in space]: 35
|
||||
run 2: set cookie 4 and 5
|
||||
lock: dns [Pigs in space]: 12
|
||||
unlock: dns [Pigs in space]: 13
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 36
|
||||
unlock: cookie [Pigs in space]: 37
|
||||
lock: share [Pigs in space]: 10
|
||||
unlock: share [Pigs in space]: 11
|
||||
*** run 3
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 12
|
||||
unlock: share [Pigs in space]: 13
|
||||
CURLOPT_COOKIEJAR
|
||||
CURLOPT_COOKIELIST FLUSH
|
||||
lock: cookie [Pigs in space]: 38
|
||||
unlock: cookie [Pigs in space]: 39
|
||||
lock: share [Pigs in space]: 40
|
||||
unlock: share [Pigs in space]: 41
|
||||
*** run 2
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 42
|
||||
unlock: share [Pigs in space]: 43
|
||||
PERFORM
|
||||
lock: cookie [Pigs in space]: 40
|
||||
unlock: cookie [Pigs in space]: 41
|
||||
lock: dns [Pigs in space]: 14
|
||||
unlock: dns [Pigs in space]: 15
|
||||
lock: dns [Pigs in space]: 16
|
||||
unlock: dns [Pigs in space]: 17
|
||||
lock: cookie [Pigs in space]: 42
|
||||
unlock: cookie [Pigs in space]: 43
|
||||
lock: cookie [Pigs in space]: 44
|
||||
unlock: cookie [Pigs in space]: 45
|
||||
lock: cookie [Pigs in space]: 46
|
||||
unlock: cookie [Pigs in space]: 47
|
||||
lock: dns [Pigs in space]: 48
|
||||
unlock: dns [Pigs in space]: 49
|
||||
lock: cookie [Pigs in space]: 48
|
||||
unlock: cookie [Pigs in space]: 49
|
||||
lock: cookie [Pigs in space]: 50
|
||||
unlock: cookie [Pigs in space]: 51
|
||||
run 3: overwrite cookie 1 and 4, set cookie 6 with and without tailmatch
|
||||
lock: dns [Pigs in space]: 18
|
||||
unlock: dns [Pigs in space]: 19
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 52
|
||||
unlock: cookie [Pigs in space]: 53
|
||||
lock: share [Pigs in space]: 14
|
||||
unlock: share [Pigs in space]: 15
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 16
|
||||
unlock: share [Pigs in space]: 17
|
||||
CURLOPT_COOKIELIST ALL
|
||||
lock: cookie [Pigs in space]: 54
|
||||
unlock: cookie [Pigs in space]: 55
|
||||
run 2: set cookie 4 and 5
|
||||
lock: dns [Pigs in space]: 56
|
||||
unlock: dns [Pigs in space]: 57
|
||||
lock: dns [Pigs in space]: 58
|
||||
unlock: dns [Pigs in space]: 59
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 60
|
||||
unlock: cookie [Pigs in space]: 61
|
||||
lock: share [Pigs in space]: 62
|
||||
unlock: share [Pigs in space]: 63
|
||||
*** run 3
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 64
|
||||
unlock: share [Pigs in space]: 65
|
||||
CURLOPT_COOKIEJAR
|
||||
CURLOPT_COOKIELIST FLUSH
|
||||
lock: cookie [Pigs in space]: 66
|
||||
unlock: cookie [Pigs in space]: 67
|
||||
PERFORM
|
||||
lock: cookie [Pigs in space]: 68
|
||||
unlock: cookie [Pigs in space]: 69
|
||||
lock: dns [Pigs in space]: 70
|
||||
unlock: dns [Pigs in space]: 71
|
||||
lock: cookie [Pigs in space]: 72
|
||||
unlock: cookie [Pigs in space]: 73
|
||||
lock: cookie [Pigs in space]: 74
|
||||
unlock: cookie [Pigs in space]: 75
|
||||
lock: cookie [Pigs in space]: 76
|
||||
unlock: cookie [Pigs in space]: 77
|
||||
lock: cookie [Pigs in space]: 78
|
||||
unlock: cookie [Pigs in space]: 79
|
||||
lock: cookie [Pigs in space]: 80
|
||||
unlock: cookie [Pigs in space]: 81
|
||||
run 3: overwrite cookie 1 and 4, set cookie 6 with and without tailmatch
|
||||
lock: dns [Pigs in space]: 82
|
||||
unlock: dns [Pigs in space]: 83
|
||||
lock: dns [Pigs in space]: 84
|
||||
unlock: dns [Pigs in space]: 85
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 86
|
||||
unlock: cookie [Pigs in space]: 87
|
||||
lock: share [Pigs in space]: 88
|
||||
unlock: share [Pigs in space]: 89
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 90
|
||||
unlock: share [Pigs in space]: 91
|
||||
CURLOPT_COOKIELIST ALL
|
||||
lock: cookie [Pigs in space]: 92
|
||||
unlock: cookie [Pigs in space]: 93
|
||||
CURLOPT_COOKIEJAR
|
||||
CURLOPT_COOKIELIST RELOAD
|
||||
lock: cookie [Pigs in space]: 94
|
||||
unlock: cookie [Pigs in space]: 95
|
||||
lock: cookie [Pigs in space]: 96
|
||||
unlock: cookie [Pigs in space]: 97
|
||||
lock: cookie [Pigs in space]: 56
|
||||
unlock: cookie [Pigs in space]: 57
|
||||
lock: cookie [Pigs in space]: 58
|
||||
unlock: cookie [Pigs in space]: 59
|
||||
loaded cookies:
|
||||
-----------------
|
||||
www.host.foo.com FALSE / FALSE %days[400] test6 six_more
|
||||
|
|
@ -229,13 +229,13 @@ loaded cookies:
|
|||
try SHARE_CLEANUP...
|
||||
SHARE_CLEANUP failed, correct
|
||||
CLEANUP
|
||||
lock: cookie [Pigs in space]: 98
|
||||
unlock: cookie [Pigs in space]: 99
|
||||
lock: share [Pigs in space]: 100
|
||||
unlock: share [Pigs in space]: 101
|
||||
lock: cookie [Pigs in space]: 60
|
||||
unlock: cookie [Pigs in space]: 61
|
||||
lock: share [Pigs in space]: 18
|
||||
unlock: share [Pigs in space]: 19
|
||||
SHARE_CLEANUP
|
||||
lock: share [Pigs in space]: 102
|
||||
unlock: share [Pigs in space]: 103
|
||||
lock: share [Pigs in space]: 20
|
||||
unlock: share [Pigs in space]: 21
|
||||
GLOBAL_CLEANUP
|
||||
</stdout>
|
||||
<file name="%LOGDIR/jar%TESTNUMBER" mode="text">
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ struct t506_Tdata {
|
|||
|
||||
struct t506_userdata {
|
||||
const char *text;
|
||||
int counter;
|
||||
int share_counter;
|
||||
int dns_counter;
|
||||
int cookie_counter;
|
||||
};
|
||||
|
||||
static int locks[3];
|
||||
|
|
@ -46,7 +48,7 @@ static void t506_test_lock(CURL *curl, curl_lock_data data,
|
|||
{
|
||||
const char *what;
|
||||
struct t506_userdata *user = (struct t506_userdata *)useptr;
|
||||
int locknum;
|
||||
int locknum, *pcounter;
|
||||
|
||||
(void)curl;
|
||||
(void)laccess;
|
||||
|
|
@ -55,14 +57,17 @@ static void t506_test_lock(CURL *curl, curl_lock_data data,
|
|||
case CURL_LOCK_DATA_SHARE:
|
||||
what = "share";
|
||||
locknum = 0;
|
||||
pcounter = &user->share_counter;
|
||||
break;
|
||||
case CURL_LOCK_DATA_DNS:
|
||||
what = "dns";
|
||||
locknum = 1;
|
||||
pcounter = &user->dns_counter;
|
||||
break;
|
||||
case CURL_LOCK_DATA_COOKIE:
|
||||
what = "cookie";
|
||||
locknum = 2;
|
||||
pcounter = &user->cookie_counter;
|
||||
break;
|
||||
default:
|
||||
curl_mfprintf(stderr, "lock: no such data: %d\n", data);
|
||||
|
|
@ -76,8 +81,8 @@ static void t506_test_lock(CURL *curl, curl_lock_data data,
|
|||
}
|
||||
locks[locknum]++;
|
||||
|
||||
curl_mprintf("lock: %-6s [%s]: %d\n", what, user->text, user->counter);
|
||||
user->counter++;
|
||||
curl_mprintf("lock: %-6s [%s]: %d\n", what, user->text, *pcounter);
|
||||
(*pcounter)++;
|
||||
}
|
||||
|
||||
/* unlock callback */
|
||||
|
|
@ -85,19 +90,22 @@ static void t506_test_unlock(CURL *curl, curl_lock_data data, void *useptr)
|
|||
{
|
||||
const char *what;
|
||||
struct t506_userdata *user = (struct t506_userdata *)useptr;
|
||||
int locknum;
|
||||
int locknum, *pcounter;
|
||||
(void)curl;
|
||||
switch(data) {
|
||||
case CURL_LOCK_DATA_SHARE:
|
||||
what = "share";
|
||||
locknum = 0;
|
||||
pcounter = &user->share_counter;
|
||||
break;
|
||||
case CURL_LOCK_DATA_DNS:
|
||||
what = "dns";
|
||||
locknum = 1;
|
||||
pcounter = &user->dns_counter;
|
||||
break;
|
||||
case CURL_LOCK_DATA_COOKIE:
|
||||
what = "cookie";
|
||||
pcounter = &user->cookie_counter;
|
||||
locknum = 2;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -112,8 +120,8 @@ static void t506_test_unlock(CURL *curl, curl_lock_data data, void *useptr)
|
|||
}
|
||||
locks[locknum]--;
|
||||
|
||||
curl_mprintf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter);
|
||||
user->counter++;
|
||||
curl_mprintf("unlock: %-6s [%s]: %d\n", what, user->text, *pcounter);
|
||||
(*pcounter)++;
|
||||
}
|
||||
|
||||
/* build host entry */
|
||||
|
|
@ -178,8 +186,8 @@ static CURLcode test_lib506(const char *URL)
|
|||
|
||||
const char *jar = libtest_arg2;
|
||||
|
||||
memset(&user, 0, sizeof(user));
|
||||
user.text = "Pigs in space";
|
||||
user.counter = 0;
|
||||
|
||||
curl_mprintf("GLOBAL_INIT\n");
|
||||
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||
|
|
|
|||
|
|
@ -73,16 +73,14 @@ static CURLcode test_unit1620(const char *arg)
|
|||
CURLcode result;
|
||||
struct Curl_easy *empty;
|
||||
enum dupstring i;
|
||||
|
||||
bool async = FALSE;
|
||||
bool protocol_connect = FALSE;
|
||||
bool connected = FALSE;
|
||||
|
||||
result = Curl_open(&empty);
|
||||
if(result)
|
||||
goto unit_test_abort;
|
||||
fail_unless(result == CURLE_OK, "Curl_open() failed");
|
||||
|
||||
result = Curl_connect(empty, &async, &protocol_connect);
|
||||
result = Curl_connect(empty, &connected);
|
||||
fail_unless(result == CURLE_URL_MALFORMAT,
|
||||
"Curl_connect() failed to return CURLE_URL_MALFORMAT");
|
||||
|
||||
|
|
@ -90,7 +88,7 @@ static CURLcode test_unit1620(const char *arg)
|
|||
"empty->magic should be equal to CURLEASY_MAGIC_NUMBER");
|
||||
|
||||
/* double invoke to ensure no dependency on internal state */
|
||||
result = Curl_connect(empty, &async, &protocol_connect);
|
||||
result = Curl_connect(empty, &connected);
|
||||
fail_unless(result == CURLE_URL_MALFORMAT,
|
||||
"Curl_connect() failed to return CURLE_URL_MALFORMAT");
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ static CURLcode cf_test_adjust_pollset(struct Curl_cfilter *cf,
|
|||
static CURLcode cf_test_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
const struct Curl_addrinfo *ai,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
static const struct Curl_cftype cft_test = {
|
||||
|
|
@ -195,7 +195,7 @@ static CURLcode cf_test_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
}
|
||||
ctx->idx = test_idx++;
|
||||
ctx->ai_family = ai->ai_family;
|
||||
ctx->ai_family = addr->family;
|
||||
ctx->transport = transport;
|
||||
ctx->started = curlx_now();
|
||||
#ifdef USE_IPV6
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue