← Commit list

335dc0e3c5

Stefan Eissing
Stefan Eissing
2026-03-30
SUCCESS Duration: 333s

Subject

cf-dns: connection filter for DNS queries

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/Makefile.inc+2 -0
@@ -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 \
lib/asyn-ares.c+13 -0
@@ -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()
*
lib/asyn-thrdd.c+182 -68
@@ -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.queued;
+ async->thrdd.done = !async->thrdd.queued;
- async->thrdd.resolved = item;
- async->thrdd.done = TRUE;
- item = NULL;
+#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 */
lib/asyn.h+9 -3
@@ -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)
lib/cf-dns.c+556 -0
@@ -0,0 +1,556 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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 */
lib/cf-dns.h+70 -0
@@ -0,0 +1,70 @@
+#ifndef HEADER_CURL_CF_DNS_H
+#define HEADER_CURL_CF_DNS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, 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 */
lib/cf-https-connect.c+205 -168
@@ -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
-
- /* 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((conn->scheme->protocol != CURLPROTO_HTTPS) ||
+ !conn->bits.tls_enable_alpn)
+ goto out;
- 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;
lib/cf-https-connect.h+0 -6
@@ -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);
lib/cf-ip-happy.c+88 -74
@@ -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) {
- 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) {
+
+ 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->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;
}
lib/cf-ip-happy.h+2 -1
@@ -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,
lib/cf-socket.c+28 -45
@@ -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;
lib/cf-socket.h+7 -3
@@ -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);
/**
lib/cfilters.c+17 -0
@@ -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)
{
lib/cfilters.h+1 -0
@@ -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);
lib/connect.c+20 -9
@@ -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) {
lib/connect.h+9 -0
@@ -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 */
lib/curl_addrinfo.c+20 -17
@@ -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
lib/curl_addrinfo.h+3 -2
@@ -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) && \
lib/curl_share.c+0 -4
@@ -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);
}
lib/curl_trc.c+2 -1
@@ -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 },
lib/dnscache.c+70 -25
@@ -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
lib/dnscache.h+12 -0
@@ -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,
lib/easy.c+0 -2
@@ -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));
lib/ftp.c+1 -0
@@ -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;
}
lib/hostip.c+264 -207
@@ -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,188 +333,286 @@ static CURLcode hostip_async_new(struct Curl_easy *data,
data->state.async = async;
return CURLE_OK;
}
-#endif
-static CURLcode hostip_resolv(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 **entry)
+static CURLcode hostip_resolv_take_result(struct Curl_easy *data,
+ 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;
-
- *entry = NULL;
+ struct Curl_resolv_async *async = data->state.async;
+ CURLcode result;
-#ifdef USE_CURL_ASYNC
- if(data->state.async)
- Curl_async_destroy(data);
-#else
- (void)timeout_ms;
-#endif
+ /* If async resolving is ongoing, this must be set */
+ if(!async)
+ return CURLE_FAILED_INIT;
#ifndef CURL_DISABLE_DOH
- data->conn->bits.doh = FALSE; /* default is not */
-#else
- (void)allowDOH;
+ if(data->conn->bits.doh)
+ result = Curl_doh_take_result(data, pdns);
+ else
#endif
+ result = Curl_async_take_result(data, async, pdns);
- /* We should intentionally error and not resolve .onion TLDs */
- hostname_len = strlen(hostname);
- DEBUGASSERT(hostname_len);
- if(hostname_len >= 7 &&
- (curl_strequal(&hostname[hostname_len - 6], ".onion") ||
- curl_strequal(&hostname[hostname_len - 7], ".onion."))) {
- failf(data, "Not resolving .onion address (RFC 7686)");
- goto error;
- }
+ if(result == CURLE_AGAIN)
+ result = CURLE_OK;
+ else if(result)
+ Curl_resolver_error(data, NULL);
+ else
+ DEBUGASSERT(*pdns);
-#ifdef DEBUGBUILD
- CURL_TRC_DNS(data, "hostip_resolv(%s:%u, ip=%x)",
- hostname, port, ip_version);
- if((ip_version == CURL_IPRESOLVE_V6) &&
- getenv("CURL_DBG_RESOLV_FAIL_IPV6")) {
- infof(data, "DEBUG fail ipv6 resolve");
- result = Curl_resolver_error(data, NULL);
- goto error;
- }
+ 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
- /* Let's check our DNS cache first */
- r2 = Curl_dnscache_get(data, hostname, port, ip_version, &dns);
- if(dns) {
- infof(data, "Hostname %s was found in DNS cache", hostname);
- result = CURLE_OK;
- goto out;
- }
- else if(r2) {
- DEBUGASSERT(!dns);
- infof(data, "Negative DNS entry");
- result = Curl_resolver_error(data, NULL);
- goto error;
- }
+ return NULL;
+}
+
+#endif /* USE_CURL_ASYNC */
- /* No luck, we need to resolve hostname. Notify user callback. */
+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)
- goto error;
+ return result;
}
+
result = Curl_async_get_impl(data, data->state.async, &resolver);
if(result)
- goto error;
+ 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) {
- result = CURLE_ABORTED_BY_CALLBACK;
- goto error;
+ return CURLE_ABORTED_BY_CALLBACK;
}
}
+ return CURLE_OK;
+}
- if(Curl_is_ipaddr(hostname)) {
+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);
- if(result)
- goto error;
goto out;
-#endif
}
+#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);
- result = addr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
+ if(!addr)
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
+
#ifndef CURL_DISABLE_DOH
- else if(!Curl_is_ipaddr(hostname) && allowDOH && data->set.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 error;
+ goto out;
}
result = Curl_doh(data, data->state.async);
- respwait = TRUE;
+ goto out;
}
+#else
+ (void)allowDOH;
#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;
- }
+
+ /* 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
- 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)
+ (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;
-#endif
}
+#else
+ addr = Curl_sync_getaddrinfo(data, hostname, port, ip_version, transport);
+ if(!addr)
+ result = CURLE_COULDNT_RESOLVE_HOST;
+#endif
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) {
+ 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;
}
- show_resolve_info(data, dns);
- *entry = dns;
- return CURLE_OK;
+ else if(!*pdns)
+ result = CURLE_AGAIN;
}
- else if(respwait) {
+ 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,
+ uint16_t port,
+ uint8_t ip_version,
+ uint8_t transport,
+ timediff_t timeout_ms,
+ bool allowDOH,
+ struct Curl_dns_entry **pdns)
+{
+ size_t hostname_len;
+ CURLcode result = CURLE_COULDNT_RESOLVE_HOST;
+ bool cache_dns = FALSE;
+
+ *pdns = NULL;
+
#ifdef USE_CURL_ASYNC
- result = Curl_resolv_take_result(data, &dns);
- if(!result) {
- *entry = dns;
- return dns ? CURLE_OK : CURLE_AGAIN;
- }
+ if(data->state.async)
+ Curl_async_destroy(data);
+#else
+ (void)timeout_ms;
#endif
- result = CURLE_COULDNT_RESOLVE_HOST;
+
+#ifndef CURL_DISABLE_DOH
+ data->conn->bits.doh = FALSE; /* default is not */
+#else
+ (void)allowDOH;
+#endif
+
+ /* We should intentionally error and not resolve .onion TLDs */
+ hostname_len = strlen(hostname);
+ DEBUGASSERT(hostname_len);
+ if(hostname_len >= 7 &&
+ (curl_strequal(&hostname[hostname_len - 6], ".onion") ||
+ curl_strequal(&hostname[hostname_len - 7], ".onion."))) {
+ failf(data, "Not resolving .onion address (RFC 7686)");
+ goto out;
}
-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);
+
+#ifdef DEBUGBUILD
+ CURL_TRC_DNS(data, "hostip_resolv(%s:%u, ip=%x)",
+ hostname, port, ip_version);
+ if((ip_version == CURL_IPRESOLVE_V6) &&
+ getenv("CURL_DBG_RESOLV_FAIL_IPV6")) {
+ infof(data, "DEBUG fail ipv6 resolve");
+ result = Curl_resolver_error(data, NULL);
+ goto out;
+ }
+#endif
+ /* Let's check our DNS cache first */
+ 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;
+ }
+ else if(result) {
+ infof(data, "Negative DNS entry");
+ result = Curl_resolver_error(data, NULL);
+ }
+ else {
+ /* 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:
+ 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);
+ }
+ else {
+ failf(data, "Error %d resolving %s:%u", result, hostname, port);
+ }
+ }
+ 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;
+ Curl_async_shutdown(data);
+ return Curl_resolver_error(data, NULL);
}
-#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);
+ result = hostip_resolv_take_result(data, pdns);
- if(!result) {
- DEBUGASSERT(*pdns);
- show_resolve_info(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_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);
+ 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 */
lib/hostip.h+11 -0
@@ -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 */
lib/multi.c+35 -95
@@ -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;
lib/multihandle.h+0 -1
@@ -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 */
lib/url.c+29 -161
@@ -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,44 +3453,32 @@ 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;
- 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;
- }
- }
+ 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);
}
+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
connectdata struct, free those here */
lib/url.h+1 -3
@@ -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);
lib/urldata.h+1 -1
@@ -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 */
lib/vquic/curl_ngtcp2.c+2 -2
@@ -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;
lib/vquic/curl_ngtcp2.h+1 -1
@@ -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 */
lib/vquic/curl_quiche.c+2 -2
@@ -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;
lib/vquic/curl_quiche.h+1 -1
@@ -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
lib/vquic/vquic.c+3 -3
@@ -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;
lib/vquic/vquic.h+1 -1
@@ -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;
tests/data/test142+1 -1
@@ -188,7 +188,7 @@ RETR %TESTNUMBER
QUIT
</protocol>
<limits>
-Allocations: 170
+Allocations: 180
Maximum allocated: 150000
</limits>
</verify>
tests/data/test2500+1 -1
@@ -72,7 +72,7 @@ via: 1.1 nghttpx
s/^server: nghttpx.*\r?\n//
</stripfile>
<limits>
-Allocations: 160
+Allocations: 170
Maximum allocated: 1800000
</limits>
</verify>
tests/data/test500+1 -1
@@ -54,7 +54,7 @@ Accept: */*
</protocol>
<limits>
-Allocations: 82
+Allocations: 90
Maximum allocated: 33400
</limits>
</verify>
tests/data/test506+87 -87
@@ -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
-lock: cookie [Pigs in space]: 52
-unlock: cookie [Pigs in space]: 53
-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
+lock: dns [Pigs in space]: 18
+unlock: dns [Pigs in space]: 19
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
+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]: 90
-unlock: share [Pigs in space]: 91
+lock: share [Pigs in space]: 16
+unlock: share [Pigs in space]: 17
CURLOPT_COOKIELIST ALL
-lock: cookie [Pigs in space]: 92
-unlock: cookie [Pigs in space]: 93
+lock: cookie [Pigs in space]: 54
+unlock: cookie [Pigs in space]: 55
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">
tests/libtest/lib506.c+16 -8
@@ -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) {
tests/unit/unit1620.c+3 -5
@@ -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");
tests/unit/unit2600.c+2 -2
@@ -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