mirror of
https://github.com/curl/curl.git
synced 2026-07-29 00:03:12 +03:00
asyn-thrdd: retry link-local ipv6 if missing scope id
When the threaded resolver gets AAAA results that carry a link-local address without scope-id, it now re-queues a query with AF_UNSPEC and strips ipv4 addresses from that result. Whatever the resulting addresses and scope-ids are, this becomes the result of the resolve. Fixes #22330 Reported-by: Bartel Sielski Closes #22368
This commit is contained in:
parent
489a4c1b48
commit
545cdd4b50
8 changed files with 194 additions and 66 deletions
175
lib/asyn-thrdd.c
175
lib/asyn-thrdd.c
|
|
@ -293,8 +293,12 @@ void Curl_async_thrdd_destroy(struct Curl_easy *data,
|
|||
curlx_safefree(async->thrdd.rr.https_name);
|
||||
Curl_httpsrr_destroy(async->thrdd.rr.hinfo);
|
||||
#endif
|
||||
async_thrdd_item_destroy(async->thrdd.inc_A);
|
||||
async->thrdd.inc_A = NULL;
|
||||
async_thrdd_item_destroy(async->thrdd.res_A);
|
||||
async->thrdd.res_A = NULL;
|
||||
async_thrdd_item_destroy(async->thrdd.inc_AAAA);
|
||||
async->thrdd.inc_AAAA = NULL;
|
||||
async_thrdd_item_destroy(async->thrdd.res_AAAA);
|
||||
async->thrdd.res_AAAA = NULL;
|
||||
}
|
||||
|
|
@ -309,28 +313,32 @@ CURLcode Curl_async_await(struct Curl_easy *data, uint32_t resolv_id,
|
|||
struct Curl_resolv_async *async = Curl_async_get(data, resolv_id);
|
||||
struct async_thrdd_ctx *thrdd = async ? &async->thrdd : NULL;
|
||||
timediff_t milli, ms;
|
||||
CURLcode result = CURLE_AGAIN;
|
||||
|
||||
if(!thrdd)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
while(async->queries_ongoing && !async->done) {
|
||||
Curl_async_thrdd_multi_process(data->multi);
|
||||
if(async->done)
|
||||
break;
|
||||
while(result == CURLE_AGAIN) {
|
||||
while(async->queries_ongoing && !async->done) {
|
||||
Curl_async_thrdd_multi_process(data->multi);
|
||||
if(async->done)
|
||||
break;
|
||||
|
||||
ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &async->start);
|
||||
if(ms < 3)
|
||||
milli = 0;
|
||||
else if(ms <= 50)
|
||||
milli = ms / 3;
|
||||
else if(ms <= 250)
|
||||
milli = 50;
|
||||
else
|
||||
milli = 200;
|
||||
CURL_TRC_DNS(data, "await, waiting %" FMT_TIMEDIFF_T "ms", milli);
|
||||
curlx_wait_ms(milli);
|
||||
ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &async->start);
|
||||
if(ms < 3)
|
||||
milli = 0;
|
||||
else if(ms <= 50)
|
||||
milli = ms / 3;
|
||||
else if(ms <= 250)
|
||||
milli = 50;
|
||||
else
|
||||
milli = 200;
|
||||
CURL_TRC_DNS(data, "await, waiting %" FMT_TIMEDIFF_T "ms", milli);
|
||||
curlx_wait_ms(milli);
|
||||
}
|
||||
result = Curl_async_take_result(data, async, pdns);
|
||||
}
|
||||
return Curl_async_take_result(data, async, pdns);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
|
|
@ -469,7 +477,7 @@ CURLcode Curl_async_thrdd_multi_init(struct Curl_multi *multi,
|
|||
{
|
||||
CURLcode result;
|
||||
DEBUGASSERT(!multi->resolv_thrdq);
|
||||
result = Curl_thrdq_create(&multi->resolv_thrdq, "DNS", 0,
|
||||
result = Curl_thrdq_create(&multi->resolv_thrdq, "DNS",
|
||||
min_threads, max_threads, idle_time_ms,
|
||||
async_thrdd_item_free,
|
||||
async_thrdd_item_process,
|
||||
|
|
@ -561,30 +569,25 @@ void Curl_async_thrdd_multi_process(struct Curl_multi *multi)
|
|||
if(data)
|
||||
async = Curl_async_get(data, item->resolv_id);
|
||||
if(async) {
|
||||
struct async_thrdd_item **pdest = &async->thrdd.res_A;
|
||||
|
||||
async->dns_responses |= item->dns_queries;
|
||||
--async->queries_ongoing;
|
||||
async->done = !async->queries_ongoing;
|
||||
struct async_thrdd_item **pdest = &async->thrdd.inc_A;
|
||||
|
||||
#ifdef CURLRES_IPV6
|
||||
if(item->dns_queries & CURL_DNSQ_AAAA)
|
||||
pdest = &async->thrdd.res_AAAA;
|
||||
pdest = &async->thrdd.inc_AAAA;
|
||||
#endif
|
||||
if(!*pdest) {
|
||||
VERBOSE(async_thrdd_report_item(data, item));
|
||||
*pdest = item;
|
||||
item = NULL;
|
||||
}
|
||||
else
|
||||
DEBUGASSERT(0); /* should not receive duplicates here */
|
||||
|
||||
--async->queries_ongoing;
|
||||
Curl_multi_mark_dirty(data);
|
||||
}
|
||||
async_thrdd_item_free(item);
|
||||
}
|
||||
#ifdef CURLVERBOSE
|
||||
Curl_thrdq_trace(multi->resolv_thrdq, multi->admin);
|
||||
#endif
|
||||
VERBOSE(Curl_thrdq_trace(multi->resolv_thrdq, multi->admin));
|
||||
}
|
||||
|
||||
CURLcode Curl_async_thrdd_multi_set_props(struct Curl_multi *multi,
|
||||
|
|
@ -592,7 +595,7 @@ CURLcode Curl_async_thrdd_multi_set_props(struct Curl_multi *multi,
|
|||
uint32_t max_threads,
|
||||
uint32_t idle_time_ms)
|
||||
{
|
||||
return Curl_thrdq_set_props(multi->resolv_thrdq, 0,
|
||||
return Curl_thrdq_set_props(multi->resolv_thrdq,
|
||||
min_threads, max_threads, idle_time_ms);
|
||||
}
|
||||
|
||||
|
|
@ -723,6 +726,113 @@ CURLcode Curl_async_pollset(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
|
||||
static bool async_thrdd_item_missing_scope(struct Curl_easy *data,
|
||||
struct async_thrdd_item *item)
|
||||
{
|
||||
const struct Curl_addrinfo *ai;
|
||||
|
||||
/* scope id already globally set */
|
||||
if(data->conn && data->conn->scope_id)
|
||||
return FALSE;
|
||||
|
||||
for(ai = item->res; ai; ai = ai->ai_next) {
|
||||
if(ai->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa6 = (void *)ai->ai_addr;
|
||||
if(IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && !sa6->sin6_scope_id)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void async_thrdd_item_strip_results(struct async_thrdd_item *item,
|
||||
int ai_family)
|
||||
{
|
||||
struct Curl_addrinfo *ai = item->res, **panchor = &item->res;
|
||||
while(ai) {
|
||||
if(ai->ai_family == ai_family) {
|
||||
*panchor = ai->ai_next;
|
||||
ai->ai_next = NULL;
|
||||
Curl_freeaddrinfo(ai);
|
||||
ai = *panchor;
|
||||
}
|
||||
else {
|
||||
panchor = &ai->ai_next;
|
||||
ai = ai->ai_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_IPV6 && HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID */
|
||||
|
||||
static CURLcode async_thrdd_check_done(struct Curl_easy *data,
|
||||
struct Curl_resolv_async *async)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &async->thrdd;
|
||||
|
||||
(void)data;
|
||||
if(thrdd->inc_A) {
|
||||
thrdd->res_A = thrdd->inc_A;
|
||||
thrdd->inc_A = NULL;
|
||||
VERBOSE(async_thrdd_report_item(data, thrdd->res_A));
|
||||
async->dns_responses |= thrdd->res_A->dns_queries;
|
||||
}
|
||||
|
||||
if(thrdd->inc_AAAA) {
|
||||
if(thrdd->res_AAAA) {
|
||||
DEBUGASSERT(0); /* should not happen */
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
|
||||
/* do we accept the incoming AAAA response? */
|
||||
if(!(thrdd->inc_AAAA->dns_queries & CURL_DNSQ_A) &&
|
||||
async_thrdd_item_missing_scope(data, thrdd->inc_AAAA)) {
|
||||
/* We queried "only" AF_INET6. This may be problematic when the
|
||||
* result has ipv6 link-local addresses and did not give
|
||||
* any scope id for it. glibc has a long outstanding bug
|
||||
* <https://sourceware.org/bugzilla/show_bug.cgi?id=14413>
|
||||
* that gives scope ids only on AF_UNSPEC queries. */
|
||||
struct async_thrdd_item *item = thrdd->inc_AAAA;
|
||||
CURLcode result;
|
||||
|
||||
/* Reuse the item and queue it again, this time with added
|
||||
* CURL_DNSQ_A which resolves using AF_UNSPEC. */
|
||||
thrdd->inc_AAAA = NULL;
|
||||
item->dns_queries |= CURL_DNSQ_A;
|
||||
if(item->res) {
|
||||
Curl_freeaddrinfo(item->res);
|
||||
item->res = NULL;
|
||||
}
|
||||
|
||||
CURL_TRC_DNS(data, "re-queueing query %s for AF_UNSPEC resolve",
|
||||
item->description);
|
||||
result = Curl_thrdq_send(data->multi->resolv_thrdq, item,
|
||||
async_item_description(item),
|
||||
async->timeout_ms);
|
||||
if(result) {
|
||||
async_thrdd_item_free(item);
|
||||
return result;
|
||||
}
|
||||
async->queries_ongoing++;
|
||||
return CURLE_AGAIN;
|
||||
}
|
||||
/* accepting the AAAA result, strip it of any AF_INET entries,
|
||||
* as we might have resolved it with AF_UNSPEC. */
|
||||
async_thrdd_item_strip_results(thrdd->inc_AAAA, AF_INET);
|
||||
#endif /* USE_IPV6 && HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID */
|
||||
thrdd->res_AAAA = thrdd->inc_AAAA;
|
||||
thrdd->inc_AAAA = NULL;
|
||||
VERBOSE(async_thrdd_report_item(data, thrdd->res_AAAA));
|
||||
async->dns_responses |= thrdd->res_AAAA->dns_queries;
|
||||
}
|
||||
|
||||
if(async->queries_ongoing)
|
||||
return CURLE_AGAIN;
|
||||
async->done = TRUE;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_async_take_result() is called repeatedly to check if a previous
|
||||
* name resolve request has completed. It should also make sure to time-out if
|
||||
|
|
@ -738,10 +848,6 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
|
|||
|
||||
DEBUGASSERT(pdns);
|
||||
*pdns = NULL;
|
||||
if(!async->queries_ongoing && !async->done) {
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
/* best effort, ignore errors */
|
||||
|
|
@ -752,8 +858,9 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
|
|||
Curl_async_thrdd_multi_process(data->multi);
|
||||
#endif
|
||||
|
||||
if(!async->done)
|
||||
return CURLE_AGAIN;
|
||||
result = async_thrdd_check_done(data, async);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
Curl_expire_done(data, EXPIRE_ASYNC_NAME);
|
||||
|
||||
|
|
|
|||
|
|
@ -140,8 +140,10 @@ struct async_thrdd_item;
|
|||
|
||||
/* Context for threaded resolver */
|
||||
struct async_thrdd_ctx {
|
||||
struct async_thrdd_item *res_A; /* IPv4 result */
|
||||
struct async_thrdd_item *res_AAAA; /* IPv6 result */
|
||||
struct async_thrdd_item *inc_A; /* IPv4 incoming result */
|
||||
struct async_thrdd_item *res_A; /* IPv4 final result */
|
||||
struct async_thrdd_item *inc_AAAA; /* IPv6 incoming result */
|
||||
struct async_thrdd_item *res_AAAA; /* IPv6 final result */
|
||||
#if defined(USE_HTTPSRR) && defined(USE_ARES)
|
||||
struct {
|
||||
ares_channel channel;
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
|
|||
|
||||
if(ctx->dns && !ctx->announced) {
|
||||
ctx->announced = TRUE;
|
||||
if(cf->sockindex == FIRSTSOCKET) {
|
||||
if((cf->sockindex == FIRSTSOCKET) && ip_query) {
|
||||
cf->conn->bits.dns_resolved = TRUE;
|
||||
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ struct curl_thrdq {
|
|||
Curl_thrdq_item_process_cb *fn_process;
|
||||
Curl_thrdq_ev_cb *fn_event;
|
||||
void *fn_user_data;
|
||||
uint32_t send_max_len;
|
||||
BIT(aborted);
|
||||
};
|
||||
|
||||
|
|
@ -198,7 +197,6 @@ static void thrdq_unlink(struct curl_thrdq *tqueue, bool locked, bool join)
|
|||
|
||||
CURLcode Curl_thrdq_create(struct curl_thrdq **ptqueue,
|
||||
const char *name,
|
||||
uint32_t max_len,
|
||||
uint32_t min_threads,
|
||||
uint32_t max_threads,
|
||||
uint32_t idle_time_ms,
|
||||
|
|
@ -222,7 +220,6 @@ CURLcode Curl_thrdq_create(struct curl_thrdq **ptqueue,
|
|||
tqueue->fn_process = fn_process;
|
||||
tqueue->fn_event = fn_event;
|
||||
tqueue->fn_user_data = user_data;
|
||||
tqueue->send_max_len = max_len;
|
||||
|
||||
tqueue->name = curlx_strdup(name);
|
||||
if(!tqueue->name)
|
||||
|
|
@ -253,11 +250,18 @@ void Curl_thrdq_destroy(struct curl_thrdq *tqueue, bool join)
|
|||
thrdq_unlink(tqueue, TRUE, join);
|
||||
}
|
||||
|
||||
static uint32_t thrdq_get_signals(struct curl_thrdq *tqueue)
|
||||
{
|
||||
size_t qlen = Curl_llist_count(&tqueue->sendq);
|
||||
return (qlen <= UINT32_MAX) ? (uint32_t)qlen : UINT32_MAX;
|
||||
}
|
||||
|
||||
CURLcode Curl_thrdq_send(struct curl_thrdq *tqueue, void *item,
|
||||
const char *description, timediff_t timeout_ms)
|
||||
{
|
||||
CURLcode result = CURLE_AGAIN;
|
||||
size_t signals = 0;
|
||||
struct thrdq_item *qitem;
|
||||
CURLcode result = CURLE_OK;
|
||||
uint32_t signals = 0;
|
||||
|
||||
Curl_mutex_acquire(&tqueue->lock);
|
||||
if(tqueue->aborted) {
|
||||
|
|
@ -270,19 +274,13 @@ CURLcode Curl_thrdq_send(struct curl_thrdq *tqueue, void *item,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if(!tqueue->send_max_len ||
|
||||
(Curl_llist_count(&tqueue->sendq) < tqueue->send_max_len)) {
|
||||
struct thrdq_item *qitem = thrdq_item_create(tqueue, item, description,
|
||||
timeout_ms);
|
||||
if(!qitem) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
item = NULL;
|
||||
Curl_llist_append(&tqueue->sendq, qitem, &qitem->node);
|
||||
signals = Curl_llist_count(&tqueue->sendq);
|
||||
result = CURLE_OK;
|
||||
qitem = thrdq_item_create(tqueue, item, description, timeout_ms);
|
||||
if(!qitem) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
Curl_llist_append(&tqueue->sendq, qitem, &qitem->node);
|
||||
signals = thrdq_get_signals(tqueue);
|
||||
|
||||
out:
|
||||
Curl_mutex_release(&tqueue->lock);
|
||||
|
|
@ -310,7 +308,7 @@ CURLcode Curl_thrdq_recv(struct curl_thrdq *tqueue, void **pitem)
|
|||
{
|
||||
CURLcode result = CURLE_AGAIN;
|
||||
struct Curl_llist_node *e;
|
||||
size_t signals = 0;
|
||||
uint32_t signals = 0;
|
||||
|
||||
*pitem = NULL;
|
||||
Curl_mutex_acquire(&tqueue->lock);
|
||||
|
|
@ -329,7 +327,8 @@ CURLcode Curl_thrdq_recv(struct curl_thrdq *tqueue, void **pitem)
|
|||
result = CURLE_OK;
|
||||
}
|
||||
else
|
||||
signals = Curl_llist_count(&tqueue->sendq);
|
||||
signals = thrdq_get_signals(tqueue);
|
||||
|
||||
out:
|
||||
Curl_mutex_release(&tqueue->lock);
|
||||
/* Signal thread pool unlocked to avoid deadlocks. If items await
|
||||
|
|
@ -384,17 +383,15 @@ UNITTEST CURLcode thrdq_await_done(struct curl_thrdq *tqueue,
|
|||
#endif
|
||||
|
||||
CURLcode Curl_thrdq_set_props(struct curl_thrdq *tqueue,
|
||||
uint32_t max_len,
|
||||
uint32_t min_threads,
|
||||
uint32_t max_threads,
|
||||
uint32_t idle_time_ms)
|
||||
{
|
||||
CURLcode result;
|
||||
size_t signals;
|
||||
uint32_t signals;
|
||||
|
||||
Curl_mutex_acquire(&tqueue->lock);
|
||||
tqueue->send_max_len = max_len;
|
||||
signals = Curl_llist_count(&tqueue->sendq);
|
||||
signals = thrdq_get_signals(tqueue);
|
||||
Curl_mutex_release(&tqueue->lock);
|
||||
|
||||
result = Curl_thrdpool_set_props(tqueue->tpool, min_threads,
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ typedef void Curl_thrdq_item_free_cb(void *item);
|
|||
*/
|
||||
CURLcode Curl_thrdq_create(struct curl_thrdq **ptqueue,
|
||||
const char *name,
|
||||
uint32_t max_len, /* 0 for unlimited */
|
||||
uint32_t min_threads,
|
||||
uint32_t max_threads,
|
||||
uint32_t idle_time_ms,
|
||||
|
|
@ -74,7 +73,6 @@ void Curl_thrdq_destroy(struct curl_thrdq *tqueue, bool join);
|
|||
* to "item" on success, e.g. the queue takes ownership.
|
||||
* `description` is an optional string describing the item for tracing
|
||||
* purposes. It needs to have the same lifetime as `item`.
|
||||
* Returns CURLE_AGAIN when the queue has already been full.
|
||||
*
|
||||
* With`timeout_ms` != 0, items that get stuck that long in the send
|
||||
* queue are removed and added to the receive queue right away.
|
||||
|
|
@ -115,7 +113,6 @@ CURLcode Curl_thrdq_await_done(struct curl_thrdq *tqueue,
|
|||
uint32_t timeout_ms);
|
||||
|
||||
CURLcode Curl_thrdq_set_props(struct curl_thrdq *tqueue,
|
||||
uint32_t max_len, /* 0 for unlimited */
|
||||
uint32_t min_threads,
|
||||
uint32_t max_threads,
|
||||
uint32_t idle_time_ms);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from datetime import timedelta
|
||||
from typing import Generator
|
||||
|
||||
|
|
@ -283,6 +284,30 @@ class TestResolve:
|
|||
r.check_stats(count=1, http_status=0, exitcode=6)
|
||||
assert r.duration < timedelta(seconds=20), f'{r}'
|
||||
|
||||
# dnsd with one answer for AAAA, delayed one for A
|
||||
@pytest.mark.skipif(condition=not Env.curl_override_dns(), reason="no DNS override")
|
||||
@pytest.mark.skipif(condition=not Env.curl_has_feature('IPv6'), reason="no IPv6")
|
||||
@pytest.mark.skipif(condition=not Env.curl_resolv_threaded(), reason="no threaded resolver")
|
||||
def test_21_16_dnsd_link_local(self, env: Env, httpd, dnsd):
|
||||
dnsd.set_answers(addr_aaaa=['[fe80::1]'])
|
||||
run_env = os.environ.copy()
|
||||
run_env['CURL_DNS_SERVER'] = f'127.0.0.1:{dnsd.port}'
|
||||
run_env['CURL_QUICK_EXIT'] = '1'
|
||||
run_env['CURL_DEBUG'] = 'dns'
|
||||
curl = CurlClient(env=env, run_env=run_env, force_resolv=False)
|
||||
url = f'https://{env.authority_for(env.domain1, "http/1.1")}/data.json'
|
||||
r = curl.http_download(urls=[url], with_stats=True, extra_args=[
|
||||
'--connect-timeout', '1'
|
||||
])
|
||||
# should fail with CURLE_OPERATION_TIMEOUT or COULDNT_CONNECT
|
||||
assert r.exit_code in (7, 28), f'{r.dump_logs()}'
|
||||
af_unspec_resolves = [line for line in r.trace_lines if
|
||||
re.match(r'.* \[DNS] re-queueing query .+ for AF_UNSPEC resolve', line)]
|
||||
assert len(af_unspec_resolves) == 1, f'{r.dump_logs()}'
|
||||
aaaa_resolves = [line for line in r.trace_lines if
|
||||
re.match(r'.* \* IPv6: fe80::1', line)]
|
||||
assert len(aaaa_resolves) == 1, f'{r.dump_logs()}'
|
||||
|
||||
def _clean_files(self, files):
|
||||
for file in files:
|
||||
if os.path.exists(file):
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ static CURLcode test_unit3301(const char *arg)
|
|||
|
||||
/* create and teardown queue */
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
result = Curl_thrdq_create(&tqueue, "unit3301-a", 0, 0, 2, 1,
|
||||
result = Curl_thrdq_create(&tqueue, "unit3301-a", 0, 2, 1,
|
||||
unit3301_item_free, unit3301_process,
|
||||
unit3301_event, &ctx);
|
||||
fail_unless(!result, "queue-a create");
|
||||
|
|
@ -99,7 +99,7 @@ static CURLcode test_unit3301(const char *arg)
|
|||
/* create queue, have it process `count` items */
|
||||
count = 10;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
result = Curl_thrdq_create(&tqueue, "unit3301-b", 0, 0, 2, 1,
|
||||
result = Curl_thrdq_create(&tqueue, "unit3301-b", 0, 2, 1,
|
||||
unit3301_item_free, unit3301_process,
|
||||
unit3301_event, &ctx);
|
||||
fail_unless(!result, "queue-b create");
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ static CURLcode test_unit3306(const char *arg)
|
|||
fail_unless(getenv("CURL_DBG_THRDPOOL_FAIL_STARTS"),
|
||||
"CURL_DBG_THRDPOOL_FAIL_STARTS must be set for this test");
|
||||
|
||||
result = Curl_thrdq_create(&tqueue, "unit3306", 0, 0, 2, 1,
|
||||
result = Curl_thrdq_create(&tqueue, "unit3306", 0, 2, 1,
|
||||
unit3306_item_free, unit3306_process,
|
||||
NULL, NULL);
|
||||
fail_unless(!result, "queue create");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue