1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "curlcheck.h"
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
27*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
28*6236dae4SAndroid Build Coastguard Worker #endif
29*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN6_H
30*6236dae4SAndroid Build Coastguard Worker #include <netinet/in6.h>
31*6236dae4SAndroid Build Coastguard Worker #endif
32*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
33*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
34*6236dae4SAndroid Build Coastguard Worker #endif
35*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
36*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker #ifdef __VMS
39*6236dae4SAndroid Build Coastguard Worker #include <in.h>
40*6236dae4SAndroid Build Coastguard Worker #include <inet.h>
41*6236dae4SAndroid Build Coastguard Worker #endif
42*6236dae4SAndroid Build Coastguard Worker
43*6236dae4SAndroid Build Coastguard Worker #include <setjmp.h>
44*6236dae4SAndroid Build Coastguard Worker #include <signal.h>
45*6236dae4SAndroid Build Coastguard Worker
46*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
47*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
48*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
49*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
50*6236dae4SAndroid Build Coastguard Worker #include "select.h"
51*6236dae4SAndroid Build Coastguard Worker #include "curl_trc.h"
52*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
53*6236dae4SAndroid Build Coastguard Worker
54*6236dae4SAndroid Build Coastguard Worker static CURL *easy;
55*6236dae4SAndroid Build Coastguard Worker
unit_setup(void)56*6236dae4SAndroid Build Coastguard Worker static CURLcode unit_setup(void)
57*6236dae4SAndroid Build Coastguard Worker {
58*6236dae4SAndroid Build Coastguard Worker CURLcode res = CURLE_OK;
59*6236dae4SAndroid Build Coastguard Worker
60*6236dae4SAndroid Build Coastguard Worker global_init(CURL_GLOBAL_ALL);
61*6236dae4SAndroid Build Coastguard Worker easy = curl_easy_init();
62*6236dae4SAndroid Build Coastguard Worker if(!easy) {
63*6236dae4SAndroid Build Coastguard Worker curl_global_cleanup();
64*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
65*6236dae4SAndroid Build Coastguard Worker }
66*6236dae4SAndroid Build Coastguard Worker curl_global_trace("all");
67*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
68*6236dae4SAndroid Build Coastguard Worker return res;
69*6236dae4SAndroid Build Coastguard Worker }
70*6236dae4SAndroid Build Coastguard Worker
unit_stop(void)71*6236dae4SAndroid Build Coastguard Worker static void unit_stop(void)
72*6236dae4SAndroid Build Coastguard Worker {
73*6236dae4SAndroid Build Coastguard Worker curl_easy_cleanup(easy);
74*6236dae4SAndroid Build Coastguard Worker curl_global_cleanup();
75*6236dae4SAndroid Build Coastguard Worker }
76*6236dae4SAndroid Build Coastguard Worker
77*6236dae4SAndroid Build Coastguard Worker struct test_case {
78*6236dae4SAndroid Build Coastguard Worker int id;
79*6236dae4SAndroid Build Coastguard Worker const char *url;
80*6236dae4SAndroid Build Coastguard Worker const char *resolve_info;
81*6236dae4SAndroid Build Coastguard Worker unsigned char ip_version;
82*6236dae4SAndroid Build Coastguard Worker timediff_t connect_timeout_ms;
83*6236dae4SAndroid Build Coastguard Worker timediff_t he_timeout_ms;
84*6236dae4SAndroid Build Coastguard Worker timediff_t cf4_fail_delay_ms;
85*6236dae4SAndroid Build Coastguard Worker timediff_t cf6_fail_delay_ms;
86*6236dae4SAndroid Build Coastguard Worker
87*6236dae4SAndroid Build Coastguard Worker int exp_cf4_creations;
88*6236dae4SAndroid Build Coastguard Worker int exp_cf6_creations;
89*6236dae4SAndroid Build Coastguard Worker timediff_t min_duration_ms;
90*6236dae4SAndroid Build Coastguard Worker timediff_t max_duration_ms;
91*6236dae4SAndroid Build Coastguard Worker CURLcode exp_result;
92*6236dae4SAndroid Build Coastguard Worker const char *pref_family;
93*6236dae4SAndroid Build Coastguard Worker };
94*6236dae4SAndroid Build Coastguard Worker
95*6236dae4SAndroid Build Coastguard Worker struct ai_family_stats {
96*6236dae4SAndroid Build Coastguard Worker const char *family;
97*6236dae4SAndroid Build Coastguard Worker int creations;
98*6236dae4SAndroid Build Coastguard Worker timediff_t first_created;
99*6236dae4SAndroid Build Coastguard Worker timediff_t last_created;
100*6236dae4SAndroid Build Coastguard Worker };
101*6236dae4SAndroid Build Coastguard Worker
102*6236dae4SAndroid Build Coastguard Worker struct test_result {
103*6236dae4SAndroid Build Coastguard Worker CURLcode result;
104*6236dae4SAndroid Build Coastguard Worker struct curltime started;
105*6236dae4SAndroid Build Coastguard Worker struct curltime ended;
106*6236dae4SAndroid Build Coastguard Worker struct ai_family_stats cf4;
107*6236dae4SAndroid Build Coastguard Worker struct ai_family_stats cf6;
108*6236dae4SAndroid Build Coastguard Worker };
109*6236dae4SAndroid Build Coastguard Worker
110*6236dae4SAndroid Build Coastguard Worker static struct test_case *current_tc;
111*6236dae4SAndroid Build Coastguard Worker static struct test_result *current_tr;
112*6236dae4SAndroid Build Coastguard Worker
113*6236dae4SAndroid Build Coastguard Worker struct cf_test_ctx {
114*6236dae4SAndroid Build Coastguard Worker int ai_family;
115*6236dae4SAndroid Build Coastguard Worker int transport;
116*6236dae4SAndroid Build Coastguard Worker char id[16];
117*6236dae4SAndroid Build Coastguard Worker struct curltime started;
118*6236dae4SAndroid Build Coastguard Worker timediff_t fail_delay_ms;
119*6236dae4SAndroid Build Coastguard Worker struct ai_family_stats *stats;
120*6236dae4SAndroid Build Coastguard Worker };
121*6236dae4SAndroid Build Coastguard Worker
cf_test_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)122*6236dae4SAndroid Build Coastguard Worker static void cf_test_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
123*6236dae4SAndroid Build Coastguard Worker {
124*6236dae4SAndroid Build Coastguard Worker struct cf_test_ctx *ctx = cf->ctx;
125*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
126*6236dae4SAndroid Build Coastguard Worker infof(data, "%04dms: cf[%s] destroyed",
127*6236dae4SAndroid Build Coastguard Worker (int)Curl_timediff(Curl_now(), current_tr->started), ctx->id);
128*6236dae4SAndroid Build Coastguard Worker #else
129*6236dae4SAndroid Build Coastguard Worker (void)data;
130*6236dae4SAndroid Build Coastguard Worker #endif
131*6236dae4SAndroid Build Coastguard Worker free(ctx);
132*6236dae4SAndroid Build Coastguard Worker cf->ctx = NULL;
133*6236dae4SAndroid Build Coastguard Worker }
134*6236dae4SAndroid Build Coastguard Worker
cf_test_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)135*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_test_connect(struct Curl_cfilter *cf,
136*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
137*6236dae4SAndroid Build Coastguard Worker bool blocking, bool *done)
138*6236dae4SAndroid Build Coastguard Worker {
139*6236dae4SAndroid Build Coastguard Worker struct cf_test_ctx *ctx = cf->ctx;
140*6236dae4SAndroid Build Coastguard Worker timediff_t duration_ms;
141*6236dae4SAndroid Build Coastguard Worker
142*6236dae4SAndroid Build Coastguard Worker (void)data;
143*6236dae4SAndroid Build Coastguard Worker (void)blocking;
144*6236dae4SAndroid Build Coastguard Worker *done = FALSE;
145*6236dae4SAndroid Build Coastguard Worker duration_ms = Curl_timediff(Curl_now(), ctx->started);
146*6236dae4SAndroid Build Coastguard Worker if(duration_ms >= ctx->fail_delay_ms) {
147*6236dae4SAndroid Build Coastguard Worker infof(data, "%04dms: cf[%s] fail delay reached",
148*6236dae4SAndroid Build Coastguard Worker (int)duration_ms, ctx->id);
149*6236dae4SAndroid Build Coastguard Worker return CURLE_COULDNT_CONNECT;
150*6236dae4SAndroid Build Coastguard Worker }
151*6236dae4SAndroid Build Coastguard Worker if(duration_ms) {
152*6236dae4SAndroid Build Coastguard Worker infof(data, "%04dms: cf[%s] continuing", (int)duration_ms, ctx->id);
153*6236dae4SAndroid Build Coastguard Worker Curl_wait_ms(10);
154*6236dae4SAndroid Build Coastguard Worker }
155*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, ctx->fail_delay_ms - duration_ms, EXPIRE_RUN_NOW);
156*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
157*6236dae4SAndroid Build Coastguard Worker }
158*6236dae4SAndroid Build Coastguard Worker
cf_test_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)159*6236dae4SAndroid Build Coastguard Worker static void cf_test_adjust_pollset(struct Curl_cfilter *cf,
160*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
161*6236dae4SAndroid Build Coastguard Worker struct easy_pollset *ps)
162*6236dae4SAndroid Build Coastguard Worker {
163*6236dae4SAndroid Build Coastguard Worker /* just for testing, give one socket with events back */
164*6236dae4SAndroid Build Coastguard Worker (void)cf;
165*6236dae4SAndroid Build Coastguard Worker Curl_pollset_set(data, ps, 1, TRUE, TRUE);
166*6236dae4SAndroid Build Coastguard Worker }
167*6236dae4SAndroid Build Coastguard Worker
168*6236dae4SAndroid Build Coastguard Worker static struct Curl_cftype cft_test = {
169*6236dae4SAndroid Build Coastguard Worker "TEST",
170*6236dae4SAndroid Build Coastguard Worker CF_TYPE_IP_CONNECT,
171*6236dae4SAndroid Build Coastguard Worker CURL_LOG_LVL_NONE,
172*6236dae4SAndroid Build Coastguard Worker cf_test_destroy,
173*6236dae4SAndroid Build Coastguard Worker cf_test_connect,
174*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_close,
175*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_shutdown,
176*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_get_host,
177*6236dae4SAndroid Build Coastguard Worker cf_test_adjust_pollset,
178*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_data_pending,
179*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_send,
180*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_recv,
181*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_cntrl,
182*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_conn_is_alive,
183*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_conn_keep_alive,
184*6236dae4SAndroid Build Coastguard Worker Curl_cf_def_query,
185*6236dae4SAndroid Build Coastguard Worker };
186*6236dae4SAndroid Build Coastguard Worker
cf_test_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)187*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_test_create(struct Curl_cfilter **pcf,
188*6236dae4SAndroid Build Coastguard Worker struct Curl_easy *data,
189*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
190*6236dae4SAndroid Build Coastguard Worker const struct Curl_addrinfo *ai,
191*6236dae4SAndroid Build Coastguard Worker int transport)
192*6236dae4SAndroid Build Coastguard Worker {
193*6236dae4SAndroid Build Coastguard Worker struct cf_test_ctx *ctx = NULL;
194*6236dae4SAndroid Build Coastguard Worker struct Curl_cfilter *cf = NULL;
195*6236dae4SAndroid Build Coastguard Worker timediff_t created_at;
196*6236dae4SAndroid Build Coastguard Worker CURLcode result;
197*6236dae4SAndroid Build Coastguard Worker
198*6236dae4SAndroid Build Coastguard Worker (void)data;
199*6236dae4SAndroid Build Coastguard Worker (void)conn;
200*6236dae4SAndroid Build Coastguard Worker ctx = calloc(1, sizeof(*ctx));
201*6236dae4SAndroid Build Coastguard Worker if(!ctx) {
202*6236dae4SAndroid Build Coastguard Worker result = CURLE_OUT_OF_MEMORY;
203*6236dae4SAndroid Build Coastguard Worker goto out;
204*6236dae4SAndroid Build Coastguard Worker }
205*6236dae4SAndroid Build Coastguard Worker ctx->ai_family = ai->ai_family;
206*6236dae4SAndroid Build Coastguard Worker ctx->transport = transport;
207*6236dae4SAndroid Build Coastguard Worker ctx->started = Curl_now();
208*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
209*6236dae4SAndroid Build Coastguard Worker if(ctx->ai_family == AF_INET6) {
210*6236dae4SAndroid Build Coastguard Worker ctx->stats = ¤t_tr->cf6;
211*6236dae4SAndroid Build Coastguard Worker ctx->fail_delay_ms = current_tc->cf6_fail_delay_ms;
212*6236dae4SAndroid Build Coastguard Worker curl_msprintf(ctx->id, "v6-%d", ctx->stats->creations);
213*6236dae4SAndroid Build Coastguard Worker ctx->stats->creations++;
214*6236dae4SAndroid Build Coastguard Worker }
215*6236dae4SAndroid Build Coastguard Worker else
216*6236dae4SAndroid Build Coastguard Worker #endif
217*6236dae4SAndroid Build Coastguard Worker {
218*6236dae4SAndroid Build Coastguard Worker ctx->stats = ¤t_tr->cf4;
219*6236dae4SAndroid Build Coastguard Worker ctx->fail_delay_ms = current_tc->cf4_fail_delay_ms;
220*6236dae4SAndroid Build Coastguard Worker curl_msprintf(ctx->id, "v4-%d", ctx->stats->creations);
221*6236dae4SAndroid Build Coastguard Worker ctx->stats->creations++;
222*6236dae4SAndroid Build Coastguard Worker }
223*6236dae4SAndroid Build Coastguard Worker
224*6236dae4SAndroid Build Coastguard Worker created_at = Curl_timediff(ctx->started, current_tr->started);
225*6236dae4SAndroid Build Coastguard Worker if(ctx->stats->creations == 1)
226*6236dae4SAndroid Build Coastguard Worker ctx->stats->first_created = created_at;
227*6236dae4SAndroid Build Coastguard Worker ctx->stats->last_created = created_at;
228*6236dae4SAndroid Build Coastguard Worker infof(data, "%04dms: cf[%s] created", (int)created_at, ctx->id);
229*6236dae4SAndroid Build Coastguard Worker
230*6236dae4SAndroid Build Coastguard Worker result = Curl_cf_create(&cf, &cft_test, ctx);
231*6236dae4SAndroid Build Coastguard Worker if(result)
232*6236dae4SAndroid Build Coastguard Worker goto out;
233*6236dae4SAndroid Build Coastguard Worker
234*6236dae4SAndroid Build Coastguard Worker Curl_expire(data, ctx->fail_delay_ms, EXPIRE_RUN_NOW);
235*6236dae4SAndroid Build Coastguard Worker
236*6236dae4SAndroid Build Coastguard Worker out:
237*6236dae4SAndroid Build Coastguard Worker *pcf = (!result) ? cf : NULL;
238*6236dae4SAndroid Build Coastguard Worker if(result) {
239*6236dae4SAndroid Build Coastguard Worker free(cf);
240*6236dae4SAndroid Build Coastguard Worker free(ctx);
241*6236dae4SAndroid Build Coastguard Worker }
242*6236dae4SAndroid Build Coastguard Worker return result;
243*6236dae4SAndroid Build Coastguard Worker }
244*6236dae4SAndroid Build Coastguard Worker
check_result(struct test_case * tc,struct test_result * tr)245*6236dae4SAndroid Build Coastguard Worker static void check_result(struct test_case *tc,
246*6236dae4SAndroid Build Coastguard Worker struct test_result *tr)
247*6236dae4SAndroid Build Coastguard Worker {
248*6236dae4SAndroid Build Coastguard Worker char msg[256];
249*6236dae4SAndroid Build Coastguard Worker timediff_t duration_ms;
250*6236dae4SAndroid Build Coastguard Worker
251*6236dae4SAndroid Build Coastguard Worker duration_ms = Curl_timediff(tr->ended, tr->started);
252*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "%d: test case took %dms\n", tc->id, (int)duration_ms);
253*6236dae4SAndroid Build Coastguard Worker
254*6236dae4SAndroid Build Coastguard Worker if(tr->result != tc->exp_result
255*6236dae4SAndroid Build Coastguard Worker && CURLE_OPERATION_TIMEDOUT != tr->result) {
256*6236dae4SAndroid Build Coastguard Worker /* on CI we encounter the TIMEOUT result, since images get less CPU
257*6236dae4SAndroid Build Coastguard Worker * and events are not as sharply timed. */
258*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected result %d but got %d",
259*6236dae4SAndroid Build Coastguard Worker tc->id, tc->exp_result, tr->result);
260*6236dae4SAndroid Build Coastguard Worker fail(msg);
261*6236dae4SAndroid Build Coastguard Worker }
262*6236dae4SAndroid Build Coastguard Worker if(tr->cf4.creations != tc->exp_cf4_creations) {
263*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected %d ipv4 creations, but got %d",
264*6236dae4SAndroid Build Coastguard Worker tc->id, tc->exp_cf4_creations, tr->cf4.creations);
265*6236dae4SAndroid Build Coastguard Worker fail(msg);
266*6236dae4SAndroid Build Coastguard Worker }
267*6236dae4SAndroid Build Coastguard Worker if(tr->cf6.creations != tc->exp_cf6_creations) {
268*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected %d ipv6 creations, but got %d",
269*6236dae4SAndroid Build Coastguard Worker tc->id, tc->exp_cf6_creations, tr->cf6.creations);
270*6236dae4SAndroid Build Coastguard Worker fail(msg);
271*6236dae4SAndroid Build Coastguard Worker }
272*6236dae4SAndroid Build Coastguard Worker
273*6236dae4SAndroid Build Coastguard Worker duration_ms = Curl_timediff(tr->ended, tr->started);
274*6236dae4SAndroid Build Coastguard Worker if(duration_ms < tc->min_duration_ms) {
275*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected min duration of %dms, but took %dms",
276*6236dae4SAndroid Build Coastguard Worker tc->id, (int)tc->min_duration_ms, (int)duration_ms);
277*6236dae4SAndroid Build Coastguard Worker fail(msg);
278*6236dae4SAndroid Build Coastguard Worker }
279*6236dae4SAndroid Build Coastguard Worker if(duration_ms > tc->max_duration_ms) {
280*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected max duration of %dms, but took %dms",
281*6236dae4SAndroid Build Coastguard Worker tc->id, (int)tc->max_duration_ms, (int)duration_ms);
282*6236dae4SAndroid Build Coastguard Worker fail(msg);
283*6236dae4SAndroid Build Coastguard Worker }
284*6236dae4SAndroid Build Coastguard Worker if(tr->cf6.creations && tr->cf4.creations && tc->pref_family) {
285*6236dae4SAndroid Build Coastguard Worker /* did ipv4 and ipv6 both, expect the preferred family to start right arway
286*6236dae4SAndroid Build Coastguard Worker * with the other being delayed by the happy_eyeball_timeout */
287*6236dae4SAndroid Build Coastguard Worker struct ai_family_stats *stats1 = !strcmp(tc->pref_family, "v6") ?
288*6236dae4SAndroid Build Coastguard Worker &tr->cf6 : &tr->cf4;
289*6236dae4SAndroid Build Coastguard Worker struct ai_family_stats *stats2 = !strcmp(tc->pref_family, "v6") ?
290*6236dae4SAndroid Build Coastguard Worker &tr->cf4 : &tr->cf6;
291*6236dae4SAndroid Build Coastguard Worker
292*6236dae4SAndroid Build Coastguard Worker if(stats1->first_created > 100) {
293*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected ip%s to start right away, instead "
294*6236dae4SAndroid Build Coastguard Worker "first attempt made after %dms",
295*6236dae4SAndroid Build Coastguard Worker tc->id, stats1->family, (int)stats1->first_created);
296*6236dae4SAndroid Build Coastguard Worker fail(msg);
297*6236dae4SAndroid Build Coastguard Worker }
298*6236dae4SAndroid Build Coastguard Worker if(stats2->first_created < tc->he_timeout_ms) {
299*6236dae4SAndroid Build Coastguard Worker curl_msprintf(msg, "%d: expected ip%s to start delayed after %dms, "
300*6236dae4SAndroid Build Coastguard Worker "instead first attempt made after %dms",
301*6236dae4SAndroid Build Coastguard Worker tc->id, stats2->family, (int)tc->he_timeout_ms,
302*6236dae4SAndroid Build Coastguard Worker (int)stats2->first_created);
303*6236dae4SAndroid Build Coastguard Worker fail(msg);
304*6236dae4SAndroid Build Coastguard Worker }
305*6236dae4SAndroid Build Coastguard Worker }
306*6236dae4SAndroid Build Coastguard Worker }
307*6236dae4SAndroid Build Coastguard Worker
test_connect(struct test_case * tc)308*6236dae4SAndroid Build Coastguard Worker static void test_connect(struct test_case *tc)
309*6236dae4SAndroid Build Coastguard Worker {
310*6236dae4SAndroid Build Coastguard Worker struct test_result tr;
311*6236dae4SAndroid Build Coastguard Worker struct curl_slist *list = NULL;
312*6236dae4SAndroid Build Coastguard Worker
313*6236dae4SAndroid Build Coastguard Worker Curl_debug_set_transport_provider(TRNSPRT_TCP, cf_test_create);
314*6236dae4SAndroid Build Coastguard Worker current_tc = tc;
315*6236dae4SAndroid Build Coastguard Worker current_tr = &tr;
316*6236dae4SAndroid Build Coastguard Worker
317*6236dae4SAndroid Build Coastguard Worker list = curl_slist_append(NULL, tc->resolve_info);
318*6236dae4SAndroid Build Coastguard Worker fail_unless(list, "error allocating resolve list entry");
319*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_RESOLVE, list);
320*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_IPRESOLVE, (long)tc->ip_version);
321*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_CONNECTTIMEOUT_MS,
322*6236dae4SAndroid Build Coastguard Worker (long)tc->connect_timeout_ms);
323*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
324*6236dae4SAndroid Build Coastguard Worker (long)tc->he_timeout_ms);
325*6236dae4SAndroid Build Coastguard Worker
326*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_URL, tc->url);
327*6236dae4SAndroid Build Coastguard Worker memset(&tr, 0, sizeof(tr));
328*6236dae4SAndroid Build Coastguard Worker tr.cf6.family = "v6";
329*6236dae4SAndroid Build Coastguard Worker tr.cf4.family = "v4";
330*6236dae4SAndroid Build Coastguard Worker
331*6236dae4SAndroid Build Coastguard Worker tr.started = Curl_now();
332*6236dae4SAndroid Build Coastguard Worker tr.result = curl_easy_perform(easy);
333*6236dae4SAndroid Build Coastguard Worker tr.ended = Curl_now();
334*6236dae4SAndroid Build Coastguard Worker
335*6236dae4SAndroid Build Coastguard Worker curl_easy_setopt(easy, CURLOPT_RESOLVE, NULL);
336*6236dae4SAndroid Build Coastguard Worker curl_slist_free_all(list);
337*6236dae4SAndroid Build Coastguard Worker list = NULL;
338*6236dae4SAndroid Build Coastguard Worker current_tc = NULL;
339*6236dae4SAndroid Build Coastguard Worker current_tr = NULL;
340*6236dae4SAndroid Build Coastguard Worker
341*6236dae4SAndroid Build Coastguard Worker check_result(tc, &tr);
342*6236dae4SAndroid Build Coastguard Worker }
343*6236dae4SAndroid Build Coastguard Worker
344*6236dae4SAndroid Build Coastguard Worker /*
345*6236dae4SAndroid Build Coastguard Worker * How these test cases work:
346*6236dae4SAndroid Build Coastguard Worker * - replace the creation of the TCP socket filter with our test filter
347*6236dae4SAndroid Build Coastguard Worker * - test filter does nothing and reports failure after configured delay
348*6236dae4SAndroid Build Coastguard Worker * - we feed addresses into the resolve cache to simulate different cases
349*6236dae4SAndroid Build Coastguard Worker * - we monitor how many instances of ipv4/v6 attempts are made and when
350*6236dae4SAndroid Build Coastguard Worker * - for mixed families, we expect HAPPY_EYEBALLS_TIMEOUT to trigger
351*6236dae4SAndroid Build Coastguard Worker *
352*6236dae4SAndroid Build Coastguard Worker * Max Duration checks needs to be conservative since CI jobs are not
353*6236dae4SAndroid Build Coastguard Worker * as sharp.
354*6236dae4SAndroid Build Coastguard Worker */
355*6236dae4SAndroid Build Coastguard Worker #define TURL "http://test.com:123"
356*6236dae4SAndroid Build Coastguard Worker
357*6236dae4SAndroid Build Coastguard Worker #define R_FAIL CURLE_COULDNT_CONNECT
358*6236dae4SAndroid Build Coastguard Worker /* timeout values accounting for low cpu resources in CI */
359*6236dae4SAndroid Build Coastguard Worker #define TC_TMOT 90000 /* 90 sec max test duration */
360*6236dae4SAndroid Build Coastguard Worker #define CNCT_TMOT 60000 /* 60sec connect timeout */
361*6236dae4SAndroid Build Coastguard Worker
362*6236dae4SAndroid Build Coastguard Worker static struct test_case TEST_CASES[] = {
363*6236dae4SAndroid Build Coastguard Worker /* TIMEOUT_MS, FAIL_MS CREATED DURATION Result, HE_PREF */
364*6236dae4SAndroid Build Coastguard Worker /* CNCT HE v4 v6 v4 v6 MIN MAX */
365*6236dae4SAndroid Build Coastguard Worker { 1, TURL, "test.com:123:192.0.2.1", CURL_IPRESOLVE_WHATEVER,
366*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 200, 200, 1, 0, 200, TC_TMOT, R_FAIL, NULL },
367*6236dae4SAndroid Build Coastguard Worker /* 1 ipv4, fails after ~200ms, reports COULDNT_CONNECT */
368*6236dae4SAndroid Build Coastguard Worker { 2, TURL, "test.com:123:192.0.2.1,192.0.2.2", CURL_IPRESOLVE_WHATEVER,
369*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 200, 200, 2, 0, 400, TC_TMOT, R_FAIL, NULL },
370*6236dae4SAndroid Build Coastguard Worker /* 2 ipv4, fails after ~400ms, reports COULDNT_CONNECT */
371*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
372*6236dae4SAndroid Build Coastguard Worker { 3, TURL, "test.com:123:::1", CURL_IPRESOLVE_WHATEVER,
373*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 200, 200, 0, 1, 200, TC_TMOT, R_FAIL, NULL },
374*6236dae4SAndroid Build Coastguard Worker /* 1 ipv6, fails after ~200ms, reports COULDNT_CONNECT */
375*6236dae4SAndroid Build Coastguard Worker { 4, TURL, "test.com:123:::1,::2", CURL_IPRESOLVE_WHATEVER,
376*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 200, 200, 0, 2, 400, TC_TMOT, R_FAIL, NULL },
377*6236dae4SAndroid Build Coastguard Worker /* 2 ipv6, fails after ~400ms, reports COULDNT_CONNECT */
378*6236dae4SAndroid Build Coastguard Worker
379*6236dae4SAndroid Build Coastguard Worker { 5, TURL, "test.com:123:192.0.2.1,::1", CURL_IPRESOLVE_WHATEVER,
380*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 200, 200, 1, 1, 350, TC_TMOT, R_FAIL, "v6" },
381*6236dae4SAndroid Build Coastguard Worker /* mixed ip4+6, v6 always first, v4 kicks in on HE, fails after ~350ms */
382*6236dae4SAndroid Build Coastguard Worker { 6, TURL, "test.com:123:::1,192.0.2.1", CURL_IPRESOLVE_WHATEVER,
383*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 200, 200, 1, 1, 350, TC_TMOT, R_FAIL, "v6" },
384*6236dae4SAndroid Build Coastguard Worker /* mixed ip6+4, v6 starts, v4 never starts due to high HE, TIMEOUT */
385*6236dae4SAndroid Build Coastguard Worker { 7, TURL, "test.com:123:192.0.2.1,::1", CURL_IPRESOLVE_V4,
386*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 500, 500, 1, 0, 400, TC_TMOT, R_FAIL, NULL },
387*6236dae4SAndroid Build Coastguard Worker /* mixed ip4+6, but only use v4, check it uses full connect timeout,
388*6236dae4SAndroid Build Coastguard Worker although another address of the 'wrong' family is available */
389*6236dae4SAndroid Build Coastguard Worker { 8, TURL, "test.com:123:::1,192.0.2.1", CURL_IPRESOLVE_V6,
390*6236dae4SAndroid Build Coastguard Worker CNCT_TMOT, 150, 500, 500, 0, 1, 400, TC_TMOT, R_FAIL, NULL },
391*6236dae4SAndroid Build Coastguard Worker /* mixed ip4+6, but only use v6, check it uses full connect timeout,
392*6236dae4SAndroid Build Coastguard Worker although another address of the 'wrong' family is available */
393*6236dae4SAndroid Build Coastguard Worker #endif
394*6236dae4SAndroid Build Coastguard Worker };
395*6236dae4SAndroid Build Coastguard Worker
396*6236dae4SAndroid Build Coastguard Worker UNITTEST_START
397*6236dae4SAndroid Build Coastguard Worker
398*6236dae4SAndroid Build Coastguard Worker size_t i;
399*6236dae4SAndroid Build Coastguard Worker
400*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < sizeof(TEST_CASES)/sizeof(TEST_CASES[0]); ++i) {
401*6236dae4SAndroid Build Coastguard Worker test_connect(&TEST_CASES[i]);
402*6236dae4SAndroid Build Coastguard Worker }
403*6236dae4SAndroid Build Coastguard Worker
404*6236dae4SAndroid Build Coastguard Worker UNITTEST_STOP
405