xref: /aosp_15_r20/external/curl/tests/unit/unit2600.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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 = &current_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 = &current_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