Branch data Line data Source code
1 : : #include "config.h"
2 : : #include "mock-resolver.h"
3 : :
4 : : #include <gio/gio.h>
5 : : #include <gio/gnetworking.h>
6 : :
7 : : static void
8 : 1 : test_basic (void)
9 : : {
10 : : GNetworkAddress *address;
11 : : guint port;
12 : : gchar *hostname;
13 : : gchar *scheme;
14 : :
15 : 1 : address = (GNetworkAddress*)g_network_address_new ("www.gnome.org", 8080);
16 : :
17 : 1 : g_assert_cmpstr (g_network_address_get_hostname (address), ==, "www.gnome.org");
18 : 1 : g_assert_cmpint (g_network_address_get_port (address), ==, 8080);
19 : :
20 : 1 : g_object_get (address, "hostname", &hostname, "port", &port, "scheme", &scheme, NULL);
21 : 1 : g_assert_cmpstr (hostname, ==, "www.gnome.org");
22 : 1 : g_assert_cmpint (port, ==, 8080);
23 : 1 : g_assert_null (scheme);
24 : 1 : g_free (hostname);
25 : :
26 : 1 : g_object_unref (address);
27 : 1 : }
28 : :
29 : : typedef struct {
30 : : const gchar *input;
31 : : const gchar *scheme;
32 : : const gchar *hostname;
33 : : guint16 port;
34 : : gint error_code;
35 : : } ParseTest;
36 : :
37 : : static ParseTest uri_tests[] = {
38 : : { "http://www.gnome.org:2020/start", "http", "www.gnome.org", 2020, -1 },
39 : : { "ftp://joe~:(*)%46@ftp.gnome.org:2020/start", "ftp", "ftp.gnome.org", 2020, -1 },
40 : : { "ftp://[fec0::abcd]/start", "ftp", "fec0::abcd", 8080, -1 },
41 : : { "ftp://[fec0::abcd]:999/start", "ftp", "fec0::abcd", 999, -1 },
42 : : { "ftp://joe%x-@ftp.gnome.org:2020/start", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
43 : : { "http://[fec0::abcd%em1]/start", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
44 : : { "http://[fec0::abcd%25em1]/start", "http", "fec0::abcd%em1", 8080, -1 },
45 : : { "http://[fec0::abcd%10]/start", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
46 : : { "http://[fec0::abcd%25em%31]/start", "http", "fec0::abcd%em1", 8080, -1 },
47 : : { "ftp://ftp.gnome.org/start?foo=bar@baz", "ftp", "ftp.gnome.org", 8080, -1 }
48 : : };
49 : :
50 : : static void
51 : 10 : test_parse_uri (gconstpointer d)
52 : : {
53 : 10 : const ParseTest *test = d;
54 : : GNetworkAddress *address;
55 : : GError *error;
56 : :
57 : 10 : error = NULL;
58 : 10 : address = (GNetworkAddress*)g_network_address_parse_uri (test->input, 8080, &error);
59 : :
60 : 10 : if (address)
61 : : {
62 : 7 : g_assert_cmpstr (g_network_address_get_scheme (address), ==, test->scheme);
63 : 7 : g_assert_cmpstr (g_network_address_get_hostname (address), ==, test->hostname);
64 : 7 : g_assert_cmpint (g_network_address_get_port (address), ==, test->port);
65 : 7 : g_assert_no_error (error);
66 : : }
67 : : else
68 : 3 : g_assert_error (error, G_IO_ERROR, test->error_code);
69 : :
70 : 10 : if (address)
71 : 7 : g_object_unref (address);
72 : 10 : if (error)
73 : 3 : g_error_free (error);
74 : 10 : }
75 : :
76 : : static ParseTest host_tests[] = {
77 : : { "www.gnome.org", NULL, "www.gnome.org", 1234, -1 },
78 : : { "www.gnome.org:8080", NULL, "www.gnome.org", 8080, -1 },
79 : : { "www.gnome.org:http", NULL, "www.gnome.org", 80, -1 },
80 : : { "1.2.3.4:imaps", NULL, "1.2.3.4", 993, -1 },
81 : : { "1.2.3.4:doesnotexist", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
82 : : { "[2001:db8::1]", NULL, "2001:db8::1", 1234, -1 },
83 : : { "[2001:db8::1]:888", NULL, "2001:db8::1", 888, -1 },
84 : : { "[2001:db8::1%em1]", NULL, "2001:db8::1%em1", 1234, -1 },
85 : : { "[2001:db8::1%25em1]", NULL, "2001:db8::1%25em1", 1234, -1 },
86 : : { "[hostname", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
87 : : { "[hostnam]e", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
88 : : { "hostname:", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
89 : : { "hostname:-1", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
90 : : { "hostname:9999999", NULL, NULL, 0, G_IO_ERROR_INVALID_ARGUMENT },
91 : : };
92 : :
93 : : static void
94 : 14 : test_parse_host (gconstpointer d)
95 : : {
96 : 14 : const ParseTest *test = d;
97 : : ParseTest test_cpy;
98 : : GNetworkAddress *address;
99 : : GError *error;
100 : 14 : const char *port_by_name = NULL;
101 : :
102 : 14 : if (g_str_equal (test->input, "www.gnome.org:http"))
103 : 1 : port_by_name = "http";
104 : 13 : else if (g_str_equal (test->input, "1.2.3.4:imaps"))
105 : 1 : port_by_name = "imaps";
106 : 12 : else if (g_str_equal (test->input, "1.2.3.4:doesnotexist"))
107 : 1 : port_by_name = "doesnotexist";
108 : :
109 : 14 : if (port_by_name)
110 : : {
111 : : const struct servent *ent;
112 : : guint16 port;
113 : : gint error_code;
114 : :
115 : : /* If using a named port, check that what’s resolved from the system’s
116 : : * `/etc/services` matches what’s hard-coded in `host_tests`. */
117 : :
118 : 3 : ent = getservbyname (port_by_name, "tcp");
119 : 3 : port = ent ? g_ntohs (ent->s_port) : 0;
120 : 3 : error_code = ent ? -1 : G_IO_ERROR_INVALID_ARGUMENT;
121 : :
122 : 3 : if (port != test->port || error_code != test->error_code)
123 : : {
124 : : /* We will lookup the port via getservbyname(), but on the
125 : : * tested system, the result is not as expected. Instead,
126 : : * adjust our expected test result. */
127 : 0 : test_cpy = *test;
128 : 0 : test_cpy.port = port;
129 : 0 : test_cpy.error_code = error_code;
130 : 0 : test = &test_cpy;
131 : : }
132 : : }
133 : :
134 : 14 : error = NULL;
135 : 14 : address = (GNetworkAddress*)g_network_address_parse (test->input, 1234, &error);
136 : :
137 : 14 : if (address)
138 : : {
139 : 8 : g_assert_null (g_network_address_get_scheme (address));
140 : 8 : g_assert_cmpstr (g_network_address_get_hostname (address), ==, test->hostname);
141 : 8 : g_assert_cmpint (g_network_address_get_port (address), ==, test->port);
142 : 8 : g_assert_no_error (error);
143 : : }
144 : : else
145 : : {
146 : 6 : g_assert_error (error, G_IO_ERROR, test->error_code);
147 : : }
148 : :
149 : 14 : if (address)
150 : 8 : g_object_unref (address);
151 : 14 : if (error)
152 : 6 : g_error_free (error);
153 : :
154 : 14 : if (test == &test_cpy)
155 : : {
156 : : char *msg;
157 : :
158 : : /* We tested something, but it's not what we originally wanted to test. Mark the
159 : : * test as skipped. */
160 : 0 : msg = g_strdup_printf ("getservbyname(\"%s\", \"tcp\") did not give expected result to validate the test", port_by_name);
161 : 0 : g_test_skip (msg);
162 : 0 : g_free (msg);
163 : : }
164 : 14 : }
165 : :
166 : : typedef struct {
167 : : const gchar *input;
168 : : gboolean valid_parse, valid_resolve, valid_ip;
169 : : } ResolveTest;
170 : :
171 : : static ResolveTest address_tests[] = {
172 : : { "192.168.1.2", TRUE, TRUE, TRUE },
173 : : { "fe80::42", TRUE, TRUE, TRUE },
174 : :
175 : : /* g_network_address_parse() accepts these, but they are not
176 : : * (just) IP addresses.
177 : : */
178 : : { "192.168.1.2:80", TRUE, FALSE, FALSE },
179 : : #ifndef G_OS_WIN32 /* getaddrinfo on Windows is more forgiving about format and accepts these strings */
180 : : { "[fe80::42]", TRUE, FALSE, FALSE },
181 : : { "[fe80::42]:80", TRUE, FALSE, FALSE },
182 : : #else
183 : : { "[fe80::42]", TRUE, TRUE, FALSE },
184 : : { "[fe80::42]:80", TRUE, TRUE, FALSE },
185 : : #endif
186 : :
187 : : /* These should not be considered IP addresses by anyone. */
188 : : { "192.168.258", FALSE, FALSE, FALSE },
189 : : { "192.11010306", FALSE, FALSE, FALSE },
190 : : { "3232235778", FALSE, FALSE, FALSE },
191 : : { "0300.0250.0001.0001", FALSE, FALSE, FALSE },
192 : : { "0xC0.0xA8.0x01.0x02", FALSE, FALSE, FALSE },
193 : : { "0xc0.0xa8.0x01.0x02", FALSE, FALSE, FALSE },
194 : : { "0xc0a80102", FALSE, FALSE, FALSE }
195 : : };
196 : :
197 : : static void
198 : 12 : test_resolve_address (gconstpointer d)
199 : : {
200 : 12 : const ResolveTest *test = d;
201 : : GSocketConnectable *connectable;
202 : : GSocketAddressEnumerator *addr_enum;
203 : : GSocketAddress *addr;
204 : 12 : GError *error = NULL;
205 : :
206 : 12 : g_test_message ("Input: %s", test->input);
207 : :
208 : 12 : g_assert_cmpint (test->valid_ip, ==, g_hostname_is_ip_address (test->input));
209 : :
210 : 12 : connectable = g_network_address_parse (test->input, 1234, &error);
211 : 12 : g_assert_no_error (error);
212 : :
213 : 12 : addr_enum = g_socket_connectable_enumerate (connectable);
214 : 12 : addr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
215 : 12 : g_object_unref (addr_enum);
216 : 12 : g_object_unref (connectable);
217 : :
218 : 12 : if (addr)
219 : : {
220 : 5 : g_assert_true (test->valid_parse);
221 : 5 : g_assert_true (G_IS_INET_SOCKET_ADDRESS (addr));
222 : 5 : g_object_unref (addr);
223 : : }
224 : : else
225 : : {
226 : 7 : g_assert_false (test->valid_parse);
227 : 7 : g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
228 : 7 : g_error_free (error);
229 : 7 : return;
230 : : }
231 : : }
232 : :
233 : : /* Technically this should be in a GResolver test program, but we don't
234 : : * have one of those since it's mostly impossible to test programmatically.
235 : : * So it goes here so it can share the tests.
236 : : */
237 : : static void
238 : 12 : test_resolve_address_gresolver (gconstpointer d)
239 : : {
240 : 12 : const ResolveTest *test = d;
241 : : GResolver *resolver;
242 : : GList *addrs;
243 : : GInetAddress *iaddr;
244 : 12 : GError *error = NULL;
245 : :
246 : 12 : g_test_message ("Input: %s", test->input);
247 : :
248 : 12 : resolver = g_resolver_get_default ();
249 : 12 : addrs = g_resolver_lookup_by_name (resolver, test->input, NULL, &error);
250 : 12 : g_object_unref (resolver);
251 : :
252 : 12 : if (addrs)
253 : : {
254 : 2 : g_assert_true (test->valid_resolve);
255 : 2 : g_assert_cmpint (g_list_length (addrs), ==, 1);
256 : :
257 : 2 : iaddr = addrs->data;
258 : 2 : g_assert_true (G_IS_INET_ADDRESS (iaddr));
259 : :
260 : 2 : g_object_unref (iaddr);
261 : 2 : g_list_free (addrs);
262 : : }
263 : : else
264 : : {
265 : 10 : g_assert_nonnull (error);
266 : 10 : g_test_message ("Error: %s", error->message);
267 : 10 : g_assert_false (test->valid_resolve);
268 : :
269 : 10 : if (!test->valid_parse)
270 : : {
271 : : /* GResolver should have rejected the address internally, in
272 : : * which case we're guaranteed to get G_RESOLVER_ERROR_NOT_FOUND.
273 : : */
274 : 7 : g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
275 : : }
276 : : else
277 : : {
278 : : /* If GResolver didn't reject the string itself, then we
279 : : * might have attempted to send it over the network. If that
280 : : * attempt succeeded, we'd get back NOT_FOUND, but if
281 : : * there's no network available we might have gotten some
282 : : * other error instead.
283 : : */
284 : : }
285 : :
286 : 10 : g_error_free (error);
287 : 10 : return;
288 : : }
289 : : }
290 : :
291 : : #define SCOPE_ID_TEST_ADDR "fe80::42"
292 : : #define SCOPE_ID_TEST_PORT 99
293 : :
294 : : #if defined (HAVE_IF_INDEXTONAME) && defined (HAVE_IF_NAMETOINDEX)
295 : : static char SCOPE_ID_TEST_IFNAME[IF_NAMESIZE];
296 : : static int SCOPE_ID_TEST_INDEX;
297 : : #else
298 : : #define SCOPE_ID_TEST_IFNAME "1"
299 : : #define SCOPE_ID_TEST_INDEX 1
300 : : #endif
301 : :
302 : : static void
303 : 2 : find_ifname_and_index (void)
304 : : {
305 : 2 : if (SCOPE_ID_TEST_INDEX != 0)
306 : 1 : return;
307 : :
308 : : #if defined (HAVE_IF_INDEXTONAME) && defined (HAVE_IF_NAMETOINDEX)
309 : 1 : SCOPE_ID_TEST_INDEX = if_nametoindex ("lo");
310 : 1 : if (SCOPE_ID_TEST_INDEX != 0)
311 : : {
312 : 1 : g_strlcpy (SCOPE_ID_TEST_IFNAME, "lo", sizeof (SCOPE_ID_TEST_IFNAME));
313 : 1 : return;
314 : : }
315 : :
316 : 0 : for (SCOPE_ID_TEST_INDEX = 1; SCOPE_ID_TEST_INDEX < 1024; SCOPE_ID_TEST_INDEX++) {
317 : 0 : if (if_indextoname (SCOPE_ID_TEST_INDEX, SCOPE_ID_TEST_IFNAME))
318 : 0 : break;
319 : : }
320 : 0 : g_assert_cmpstr (SCOPE_ID_TEST_IFNAME, !=, "");
321 : : #endif
322 : : }
323 : :
324 : : static void
325 : 2 : test_scope_id (GSocketConnectable *addr)
326 : : {
327 : : #ifndef G_OS_WIN32
328 : : GSocketAddressEnumerator *addr_enum;
329 : : GSocketAddress *saddr;
330 : : GInetSocketAddress *isaddr;
331 : : GInetAddress *iaddr;
332 : : char *tostring;
333 : 2 : GError *error = NULL;
334 : :
335 : 2 : addr_enum = g_socket_connectable_enumerate (addr);
336 : 2 : saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
337 : 2 : g_assert_no_error (error);
338 : :
339 : 2 : g_assert_nonnull (saddr);
340 : 2 : g_assert_true (G_IS_INET_SOCKET_ADDRESS (saddr));
341 : :
342 : 2 : isaddr = G_INET_SOCKET_ADDRESS (saddr);
343 : 2 : g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, SCOPE_ID_TEST_INDEX);
344 : 2 : g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, SCOPE_ID_TEST_PORT);
345 : :
346 : 2 : iaddr = g_inet_socket_address_get_address (isaddr);
347 : 2 : tostring = g_inet_address_to_string (iaddr);
348 : 2 : g_assert_cmpstr (tostring, ==, SCOPE_ID_TEST_ADDR);
349 : 2 : g_free (tostring);
350 : :
351 : 2 : g_object_unref (saddr);
352 : 2 : saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
353 : 2 : g_assert_no_error (error);
354 : 2 : g_assert_null (saddr);
355 : :
356 : 2 : g_object_unref (addr_enum);
357 : : #else
358 : : g_test_skip ("winsock2 getaddrinfo() can’t understand scope IDs");
359 : : #endif
360 : 2 : }
361 : :
362 : : static void
363 : 1 : test_host_scope_id (void)
364 : : {
365 : : GSocketConnectable *addr;
366 : : char *str;
367 : :
368 : 1 : find_ifname_and_index ();
369 : :
370 : 1 : str = g_strdup_printf ("%s%%%s", SCOPE_ID_TEST_ADDR, SCOPE_ID_TEST_IFNAME);
371 : 1 : addr = g_network_address_new (str, SCOPE_ID_TEST_PORT);
372 : 1 : g_free (str);
373 : :
374 : 1 : test_scope_id (addr);
375 : 1 : g_object_unref (addr);
376 : 1 : }
377 : :
378 : : static void
379 : 1 : test_uri_scope_id (void)
380 : : {
381 : : GSocketConnectable *addr;
382 : : char *uri;
383 : 1 : GError *error = NULL;
384 : :
385 : 1 : find_ifname_and_index ();
386 : :
387 : 1 : uri = g_strdup_printf ("http://[%s%%%s]:%d/foo",
388 : : SCOPE_ID_TEST_ADDR,
389 : : SCOPE_ID_TEST_IFNAME,
390 : : SCOPE_ID_TEST_PORT);
391 : 1 : addr = g_network_address_parse_uri (uri, 0, &error);
392 : 1 : g_free (uri);
393 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
394 : 1 : g_assert_null (addr);
395 : 1 : g_clear_error (&error);
396 : :
397 : 1 : uri = g_strdup_printf ("http://[%s%%25%s]:%d/foo",
398 : : SCOPE_ID_TEST_ADDR,
399 : : SCOPE_ID_TEST_IFNAME,
400 : : SCOPE_ID_TEST_PORT);
401 : 1 : addr = g_network_address_parse_uri (uri, 0, &error);
402 : 1 : g_free (uri);
403 : 1 : g_assert_no_error (error);
404 : :
405 : 1 : test_scope_id (addr);
406 : 1 : g_object_unref (addr);
407 : 1 : }
408 : :
409 : : static void
410 : 1 : test_loopback_basic (void)
411 : : {
412 : : GNetworkAddress *addr; /* owned */
413 : :
414 : 1 : addr = G_NETWORK_ADDRESS (g_network_address_new_loopback (666));
415 : :
416 : : /* Test basic properties. */
417 : 1 : g_assert_cmpstr (g_network_address_get_hostname (addr), ==, "localhost");
418 : 1 : g_assert_cmpuint (g_network_address_get_port (addr), ==, 666);
419 : 1 : g_assert_null (g_network_address_get_scheme (addr));
420 : :
421 : 1 : g_object_unref (addr);
422 : 1 : }
423 : :
424 : : static void
425 : 15 : assert_socket_address_matches (GSocketAddress *a,
426 : : const gchar *expected_address,
427 : : guint16 expected_port)
428 : : {
429 : : GInetSocketAddress *sa;
430 : : gchar *str; /* owned */
431 : :
432 : 15 : g_assert_true (G_IS_INET_SOCKET_ADDRESS (a));
433 : :
434 : 15 : sa = G_INET_SOCKET_ADDRESS (a);
435 : 15 : g_assert_cmpint (g_inet_socket_address_get_port (sa), ==, expected_port);
436 : :
437 : 15 : str = g_inet_address_to_string (g_inet_socket_address_get_address (sa));
438 : 15 : g_assert_cmpstr (str, ==, expected_address);
439 : 15 : g_free (str);
440 : 15 : }
441 : :
442 : : static void
443 : 1 : test_loopback_sync (void)
444 : : {
445 : : GSocketConnectable *addr; /* owned */
446 : : GSocketAddressEnumerator *enumerator; /* owned */
447 : : GSocketAddress *a; /* owned */
448 : 1 : GError *error = NULL;
449 : :
450 : 1 : addr = g_network_address_new_loopback (616);
451 : 1 : enumerator = g_socket_connectable_enumerate (addr);
452 : :
453 : : /* IPv6 address. */
454 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
455 : 1 : g_assert_no_error (error);
456 : 1 : assert_socket_address_matches (a, "::1", 616);
457 : 1 : g_object_unref (a);
458 : :
459 : : /* IPv4 address. */
460 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
461 : 1 : g_assert_no_error (error);
462 : 1 : assert_socket_address_matches (a, "127.0.0.1", 616);
463 : 1 : g_object_unref (a);
464 : :
465 : : /* End of results. */
466 : 1 : g_assert_null (g_socket_address_enumerator_next (enumerator, NULL, &error));
467 : 1 : g_assert_no_error (error);
468 : :
469 : 1 : g_object_unref (enumerator);
470 : 1 : g_object_unref (addr);
471 : 1 : }
472 : :
473 : : static void
474 : 1 : test_localhost_sync (void)
475 : : {
476 : : GSocketConnectable *addr; /* owned */
477 : : GSocketAddressEnumerator *enumerator; /* owned */
478 : : GSocketAddress *a; /* owned */
479 : 1 : GError *error = NULL;
480 : : GResolver *original_resolver; /* owned */
481 : : MockResolver *mock_resolver; /* owned */
482 : 1 : GList *ipv4_results = NULL; /* owned */
483 : :
484 : : /* This test ensures that variations of the "localhost" hostname always resolve to a loopback address */
485 : :
486 : : /* Set up a DNS resolver that returns nonsense for "localhost" */
487 : 1 : original_resolver = g_resolver_get_default ();
488 : 1 : mock_resolver = mock_resolver_new ();
489 : 1 : g_resolver_set_default (G_RESOLVER (mock_resolver));
490 : 1 : ipv4_results = g_list_append (ipv4_results, g_inet_address_new_from_string ("123.123.123.123"));
491 : 1 : mock_resolver_set_ipv4_results (mock_resolver, ipv4_results);
492 : :
493 : 1 : addr = g_network_address_new ("localhost.", 616);
494 : 1 : enumerator = g_socket_connectable_enumerate (addr);
495 : :
496 : : /* IPv6 address. */
497 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
498 : 1 : g_assert_no_error (error);
499 : 1 : assert_socket_address_matches (a, "::1", 616);
500 : 1 : g_object_unref (a);
501 : :
502 : : /* IPv4 address. */
503 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
504 : 1 : g_assert_no_error (error);
505 : 1 : assert_socket_address_matches (a, "127.0.0.1", 616);
506 : 1 : g_object_unref (a);
507 : :
508 : : /* End of results. */
509 : 1 : g_assert_null (g_socket_address_enumerator_next (enumerator, NULL, &error));
510 : 1 : g_assert_no_error (error);
511 : 1 : g_object_unref (enumerator);
512 : 1 : g_object_unref (addr);
513 : :
514 : 1 : addr = g_network_address_new (".localhost", 616);
515 : 1 : enumerator = g_socket_connectable_enumerate (addr);
516 : :
517 : : /* IPv6 address. */
518 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
519 : 1 : g_assert_no_error (error);
520 : 1 : assert_socket_address_matches (a, "::1", 616);
521 : 1 : g_object_unref (a);
522 : :
523 : : /* IPv4 address. */
524 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
525 : 1 : g_assert_no_error (error);
526 : 1 : assert_socket_address_matches (a, "127.0.0.1", 616);
527 : 1 : g_object_unref (a);
528 : :
529 : : /* End of results. */
530 : 1 : g_assert_null (g_socket_address_enumerator_next (enumerator, NULL, &error));
531 : 1 : g_assert_no_error (error);
532 : 1 : g_object_unref (enumerator);
533 : 1 : g_object_unref (addr);
534 : :
535 : 1 : addr = g_network_address_new ("foo.localhost", 616);
536 : 1 : enumerator = g_socket_connectable_enumerate (addr);
537 : :
538 : : /* IPv6 address. */
539 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
540 : 1 : g_assert_no_error (error);
541 : 1 : assert_socket_address_matches (a, "::1", 616);
542 : 1 : g_object_unref (a);
543 : :
544 : : /* IPv4 address. */
545 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
546 : 1 : g_assert_no_error (error);
547 : 1 : assert_socket_address_matches (a, "127.0.0.1", 616);
548 : 1 : g_object_unref (a);
549 : :
550 : : /* End of results. */
551 : 1 : g_assert_null (g_socket_address_enumerator_next (enumerator, NULL, &error));
552 : 1 : g_assert_no_error (error);
553 : 1 : g_object_unref (enumerator);
554 : 1 : g_object_unref (addr);
555 : :
556 : 1 : addr = g_network_address_new (".localhost.", 616);
557 : 1 : enumerator = g_socket_connectable_enumerate (addr);
558 : :
559 : : /* IPv6 address. */
560 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
561 : 1 : g_assert_no_error (error);
562 : 1 : assert_socket_address_matches (a, "::1", 616);
563 : 1 : g_object_unref (a);
564 : :
565 : : /* IPv4 address. */
566 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
567 : 1 : g_assert_no_error (error);
568 : 1 : assert_socket_address_matches (a, "127.0.0.1", 616);
569 : 1 : g_object_unref (a);
570 : :
571 : : /* End of results. */
572 : 1 : g_assert_null (g_socket_address_enumerator_next (enumerator, NULL, &error));
573 : 1 : g_assert_no_error (error);
574 : 1 : g_object_unref (enumerator);
575 : 1 : g_object_unref (addr);
576 : :
577 : 1 : addr = g_network_address_new ("invalid", 616);
578 : 1 : enumerator = g_socket_connectable_enumerate (addr);
579 : :
580 : : /* IPv4 address. */
581 : 1 : a = g_socket_address_enumerator_next (enumerator, NULL, &error);
582 : 1 : g_assert_no_error (error);
583 : 1 : assert_socket_address_matches (a, "123.123.123.123", 616);
584 : 1 : g_object_unref (a);
585 : :
586 : : /* End of results. */
587 : 1 : g_assert_null (g_socket_address_enumerator_next (enumerator, NULL, &error));
588 : 1 : g_assert_no_error (error);
589 : 1 : g_object_unref (enumerator);
590 : 1 : g_object_unref (addr);
591 : :
592 : 1 : g_resolver_set_default (original_resolver);
593 : 1 : g_list_free_full (ipv4_results, (GDestroyNotify) g_object_unref);
594 : 1 : g_object_unref (original_resolver);
595 : 1 : g_object_unref (mock_resolver);
596 : 1 : }
597 : :
598 : : typedef struct {
599 : : GList/*<owned GSocketAddress> */ *addrs; /* owned */
600 : : GMainLoop *loop; /* owned */
601 : : GSocketAddressEnumerator *enumerator; /* unowned */
602 : : guint delay_ms;
603 : : gint expected_error_code;
604 : : } AsyncData;
605 : :
606 : : static void got_addr (GObject *source_object, GAsyncResult *result, gpointer user_data);
607 : :
608 : : static int
609 : 18 : on_delayed_get_addr (gpointer user_data)
610 : : {
611 : 18 : AsyncData *data = user_data;
612 : 18 : g_socket_address_enumerator_next_async (data->enumerator, NULL,
613 : : got_addr, user_data);
614 : 18 : return G_SOURCE_REMOVE;
615 : : }
616 : :
617 : : static void
618 : 60 : got_addr (GObject *source_object,
619 : : GAsyncResult *result,
620 : : gpointer user_data)
621 : : {
622 : : GSocketAddressEnumerator *enumerator;
623 : : AsyncData *data;
624 : : GSocketAddress *a; /* owned */
625 : 60 : GError *error = NULL;
626 : :
627 : 60 : enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source_object);
628 : 60 : data = user_data;
629 : :
630 : 60 : a = g_socket_address_enumerator_next_finish (enumerator, result, &error);
631 : :
632 : 60 : if (data->expected_error_code)
633 : : {
634 : 4 : g_assert_error (error, G_IO_ERROR, data->expected_error_code);
635 : 4 : g_clear_error (&error);
636 : : }
637 : : else
638 : 56 : g_assert_no_error (error);
639 : :
640 : 60 : if (a == NULL)
641 : : {
642 : : /* End of results. */
643 : 18 : data->addrs = g_list_reverse (data->addrs);
644 : 18 : g_main_loop_quit (data->loop);
645 : : }
646 : : else
647 : : {
648 : 42 : g_assert_true (G_IS_INET_SOCKET_ADDRESS (a));
649 : 42 : data->addrs = g_list_prepend (data->addrs, a);
650 : :
651 : 42 : if (!data->delay_ms)
652 : 24 : g_socket_address_enumerator_next_async (enumerator, NULL,
653 : : got_addr, user_data);
654 : : else
655 : : {
656 : 18 : data->enumerator = enumerator;
657 : 18 : g_timeout_add (data->delay_ms, on_delayed_get_addr, data);
658 : : }
659 : : }
660 : 60 : }
661 : :
662 : : static void
663 : 5 : got_addr_ignored (GObject *source_object,
664 : : GAsyncResult *result,
665 : : gpointer user_data)
666 : : {
667 : : GSocketAddressEnumerator *enumerator;
668 : : GSocketAddress *a; /* owned */
669 : 5 : GError *error = NULL;
670 : :
671 : : /* This function simply ignores the returned addresses but keeps enumerating */
672 : :
673 : 5 : enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source_object);
674 : :
675 : 5 : a = g_socket_address_enumerator_next_finish (enumerator, result, &error);
676 : 5 : g_assert_no_error (error);
677 : 5 : if (a != NULL)
678 : : {
679 : 4 : g_object_unref (a);
680 : 4 : g_socket_address_enumerator_next_async (enumerator, NULL,
681 : : got_addr_ignored, user_data);
682 : : }
683 : 5 : }
684 : :
685 : :
686 : : static void
687 : 1 : test_loopback_async (void)
688 : : {
689 : : GSocketConnectable *addr; /* owned */
690 : : GSocketAddressEnumerator *enumerator; /* owned */
691 : 1 : AsyncData data = { 0, };
692 : :
693 : 1 : addr = g_network_address_new_loopback (610);
694 : 1 : enumerator = g_socket_connectable_enumerate (addr);
695 : :
696 : : /* Get all the addresses. */
697 : 1 : data.addrs = NULL;
698 : 1 : data.loop = g_main_loop_new (NULL, FALSE);
699 : :
700 : 1 : g_socket_address_enumerator_next_async (enumerator, NULL, got_addr, &data);
701 : :
702 : 1 : g_main_loop_run (data.loop);
703 : 1 : g_main_loop_unref (data.loop);
704 : :
705 : : /* Check results. */
706 : 1 : g_assert_cmpuint (g_list_length (data.addrs), ==, 2);
707 : 1 : assert_socket_address_matches (data.addrs->data, "::1", 610);
708 : 1 : assert_socket_address_matches (data.addrs->next->data, "127.0.0.1", 610);
709 : :
710 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
711 : :
712 : 1 : g_object_unref (enumerator);
713 : 1 : g_object_unref (addr);
714 : 1 : }
715 : :
716 : : static void
717 : 1 : test_localhost_async (void)
718 : : {
719 : : GSocketConnectable *addr; /* owned */
720 : : GSocketAddressEnumerator *enumerator; /* owned */
721 : 1 : AsyncData data = { 0, };
722 : : GResolver *original_resolver; /* owned */
723 : : MockResolver *mock_resolver; /* owned */
724 : 1 : GList *ipv4_results = NULL; /* owned */
725 : :
726 : : /* This test ensures that variations of the "localhost" hostname always resolve to a loopback address */
727 : :
728 : : /* Set up a DNS resolver that returns nonsense for "localhost" */
729 : 1 : original_resolver = g_resolver_get_default ();
730 : 1 : mock_resolver = mock_resolver_new ();
731 : 1 : g_resolver_set_default (G_RESOLVER (mock_resolver));
732 : 1 : ipv4_results = g_list_append (ipv4_results, g_inet_address_new_from_string ("123.123.123.123"));
733 : 1 : mock_resolver_set_ipv4_results (mock_resolver, ipv4_results);
734 : :
735 : 1 : addr = g_network_address_new ("localhost", 610);
736 : 1 : enumerator = g_socket_connectable_enumerate (addr);
737 : :
738 : : /* Get all the addresses. */
739 : 1 : data.addrs = NULL;
740 : 1 : data.delay_ms = 1;
741 : 1 : data.loop = g_main_loop_new (NULL, FALSE);
742 : :
743 : 1 : g_socket_address_enumerator_next_async (enumerator, NULL, got_addr, &data);
744 : 1 : g_main_loop_run (data.loop);
745 : :
746 : : /* Check results. */
747 : 1 : g_assert_cmpuint (g_list_length (data.addrs), ==, 2);
748 : 1 : assert_socket_address_matches (data.addrs->data, "::1", 610);
749 : 1 : assert_socket_address_matches (data.addrs->next->data, "127.0.0.1", 610);
750 : :
751 : 1 : g_resolver_set_default (original_resolver);
752 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
753 : 1 : g_list_free_full (ipv4_results, (GDestroyNotify) g_object_unref);
754 : 1 : g_object_unref (original_resolver);
755 : 1 : g_object_unref (mock_resolver);
756 : 1 : g_object_unref (enumerator);
757 : 1 : g_object_unref (addr);
758 : 1 : g_main_loop_unref (data.loop);
759 : 1 : }
760 : :
761 : : static void
762 : 1 : test_to_string (void)
763 : : {
764 : 1 : GSocketConnectable *addr = NULL;
765 : 1 : gchar *str = NULL;
766 : 1 : GError *error = NULL;
767 : :
768 : : /* Without port. */
769 : 1 : addr = g_network_address_new ("some-hostname", 0);
770 : 1 : str = g_socket_connectable_to_string (addr);
771 : 1 : g_assert_cmpstr (str, ==, "some-hostname");
772 : 1 : g_free (str);
773 : 1 : g_object_unref (addr);
774 : :
775 : : /* With port. */
776 : 1 : addr = g_network_address_new ("some-hostname", 123);
777 : 1 : str = g_socket_connectable_to_string (addr);
778 : 1 : g_assert_cmpstr (str, ==, "some-hostname:123");
779 : 1 : g_free (str);
780 : 1 : g_object_unref (addr);
781 : :
782 : : /* With scheme and port. */
783 : 1 : addr = g_network_address_parse_uri ("http://some-hostname:123", 80, &error);
784 : 1 : g_assert_no_error (error);
785 : 1 : str = g_socket_connectable_to_string (addr);
786 : 1 : g_assert_cmpstr (str, ==, "http:some-hostname:123");
787 : 1 : g_free (str);
788 : 1 : g_object_unref (addr);
789 : :
790 : : /* Loopback. */
791 : 1 : addr = g_network_address_new ("localhost", 456);
792 : 1 : str = g_socket_connectable_to_string (addr);
793 : 1 : g_assert_cmpstr (str, ==, "localhost:456");
794 : 1 : g_free (str);
795 : 1 : g_object_unref (addr);
796 : 1 : }
797 : :
798 : : static int
799 : 112 : sort_addresses (gconstpointer a, gconstpointer b)
800 : : {
801 : 112 : GSocketFamily family_a = g_inet_address_get_family (G_INET_ADDRESS (a));
802 : 112 : GSocketFamily family_b = g_inet_address_get_family (G_INET_ADDRESS (b));
803 : :
804 : 112 : if (family_a == family_b)
805 : 49 : return 0;
806 : 63 : else if (family_a == G_SOCKET_FAMILY_IPV4)
807 : 34 : return -1;
808 : : else
809 : 29 : return 1;
810 : : }
811 : :
812 : : static int
813 : 37 : sort_socket_addresses (gconstpointer a, gconstpointer b)
814 : : {
815 : 37 : GInetAddress *addr_a = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (a));
816 : 37 : GInetAddress *addr_b = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (b));
817 : 37 : return sort_addresses (addr_a, addr_b);
818 : : }
819 : :
820 : : static void
821 : 12 : assert_list_matches_expected (GList *result, GList *expected)
822 : : {
823 : 12 : GList *result_copy = NULL;
824 : :
825 : 12 : g_assert_cmpint (g_list_length (result), ==, g_list_length (expected));
826 : :
827 : : /* Sort by ipv4 first which matches the expected list. Do this on a copy of
828 : : * @result to avoid modifying the original. */
829 : 12 : result_copy = g_list_copy (result);
830 : 12 : result = result_copy = g_list_sort (result_copy, sort_socket_addresses);
831 : :
832 : 50 : for (; result != NULL; result = result->next, expected = expected->next)
833 : : {
834 : 38 : GInetAddress *address = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (result->data));
835 : 38 : g_assert_true (g_inet_address_equal (address, expected->data));
836 : : }
837 : :
838 : 12 : g_list_free (result_copy);
839 : 12 : }
840 : :
841 : : typedef struct {
842 : : MockResolver *mock_resolver;
843 : : GResolver *original_resolver;
844 : : GList *input_ipv4_results;
845 : : GList *input_ipv6_results;
846 : : GList *input_all_results;
847 : : GSocketConnectable *addr;
848 : : GSocketAddressEnumerator *enumerator;
849 : : GMainLoop *loop;
850 : : } HappyEyeballsFixture;
851 : :
852 : : static void
853 : 15 : happy_eyeballs_setup (HappyEyeballsFixture *fixture,
854 : : gconstpointer data)
855 : : {
856 : : static const char * const ipv4_address_strings[] = { "1.1.1.1", "2.2.2.2" };
857 : : static const char * const ipv6_address_strings[] = { "ff::11", "ff::22" };
858 : : gsize i;
859 : :
860 : 15 : fixture->original_resolver = g_resolver_get_default ();
861 : 15 : fixture->mock_resolver = mock_resolver_new ();
862 : 15 : g_resolver_set_default (G_RESOLVER (fixture->mock_resolver));
863 : :
864 : 45 : for (i = 0; i < G_N_ELEMENTS (ipv4_address_strings); ++i)
865 : : {
866 : 30 : GInetAddress *ipv4_addr = g_inet_address_new_from_string (ipv4_address_strings[i]);
867 : 30 : GInetAddress *ipv6_addr = g_inet_address_new_from_string (ipv6_address_strings[i]);
868 : 30 : fixture->input_ipv4_results = g_list_append (fixture->input_ipv4_results, ipv4_addr);
869 : 30 : fixture->input_ipv6_results = g_list_append (fixture->input_ipv6_results, ipv6_addr);
870 : 30 : fixture->input_all_results = g_list_append (fixture->input_all_results, ipv4_addr);
871 : 30 : fixture->input_all_results = g_list_append (fixture->input_all_results, ipv6_addr);
872 : : }
873 : 15 : fixture->input_all_results = g_list_sort (fixture->input_all_results, sort_addresses);
874 : 15 : mock_resolver_set_ipv4_results (fixture->mock_resolver, fixture->input_ipv4_results);
875 : 15 : mock_resolver_set_ipv6_results (fixture->mock_resolver, fixture->input_ipv6_results);
876 : :
877 : 15 : fixture->addr = g_network_address_new ("test.fake", 80);
878 : 15 : fixture->enumerator = g_socket_connectable_enumerate (fixture->addr);
879 : :
880 : 15 : fixture->loop = g_main_loop_new (NULL, FALSE);
881 : 15 : }
882 : :
883 : : static void
884 : 15 : happy_eyeballs_teardown (HappyEyeballsFixture *fixture,
885 : : gconstpointer data)
886 : : {
887 : 15 : g_object_unref (fixture->addr);
888 : 15 : g_object_unref (fixture->enumerator);
889 : 15 : g_resolver_free_addresses (fixture->input_all_results);
890 : 15 : g_list_free (fixture->input_ipv4_results);
891 : 15 : g_list_free (fixture->input_ipv6_results);
892 : 15 : g_resolver_set_default (fixture->original_resolver);
893 : 15 : g_object_unref (fixture->original_resolver);
894 : 15 : g_object_unref (fixture->mock_resolver);
895 : 15 : g_main_loop_unref (fixture->loop);
896 : 15 : }
897 : :
898 : : static const guint FAST_DELAY_LESS_THAN_TIMEOUT = 25;
899 : : static const guint SLOW_DELAY_MORE_THAN_TIMEOUT = 100;
900 : :
901 : : static void
902 : 1 : test_happy_eyeballs_basic (HappyEyeballsFixture *fixture,
903 : : gconstpointer user_data)
904 : : {
905 : 1 : AsyncData data = { 0 };
906 : :
907 : 1 : data.delay_ms = FAST_DELAY_LESS_THAN_TIMEOUT;
908 : 1 : data.loop = fixture->loop;
909 : :
910 : : /* This just tests in the common case it gets all results */
911 : :
912 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
913 : 1 : g_main_loop_run (fixture->loop);
914 : :
915 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
916 : :
917 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
918 : 1 : }
919 : :
920 : : static void
921 : 1 : test_happy_eyeballs_parallel (HappyEyeballsFixture *fixture,
922 : : gconstpointer user_data)
923 : : {
924 : 1 : AsyncData data = { 0 };
925 : : GSocketAddressEnumerator *enumerator2;
926 : :
927 : 1 : enumerator2 = g_socket_connectable_enumerate (fixture->addr);
928 : :
929 : 1 : data.delay_ms = FAST_DELAY_LESS_THAN_TIMEOUT;
930 : 1 : data.loop = fixture->loop;
931 : :
932 : : /* We run multiple enumerations at once, the results shouldn't be affected. */
933 : :
934 : 1 : g_socket_address_enumerator_next_async (enumerator2, NULL, got_addr_ignored, &data);
935 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
936 : 1 : g_main_loop_run (fixture->loop);
937 : :
938 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
939 : :
940 : : /* Run again to ensure the cache from the previous one is correct */
941 : :
942 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
943 : 1 : data.addrs = NULL;
944 : 1 : g_object_unref (enumerator2);
945 : :
946 : 1 : enumerator2 = g_socket_connectable_enumerate (fixture->addr);
947 : 1 : g_socket_address_enumerator_next_async (enumerator2, NULL, got_addr, &data);
948 : 1 : g_main_loop_run (fixture->loop);
949 : :
950 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
951 : :
952 : 1 : g_object_unref (enumerator2);
953 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
954 : 1 : }
955 : :
956 : : static void
957 : 1 : test_happy_eyeballs_slow_ipv4 (HappyEyeballsFixture *fixture,
958 : : gconstpointer user_data)
959 : : {
960 : 1 : AsyncData data = { 0 };
961 : :
962 : : /* If ipv4 dns response is a bit slow we still get everything */
963 : :
964 : 1 : data.loop = fixture->loop;
965 : 1 : mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
966 : :
967 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
968 : 1 : g_main_loop_run (fixture->loop);
969 : :
970 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
971 : :
972 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
973 : 1 : }
974 : :
975 : : static void
976 : 1 : test_happy_eyeballs_slow_ipv6 (HappyEyeballsFixture *fixture,
977 : : gconstpointer user_data)
978 : : {
979 : 1 : AsyncData data = { 0 };
980 : :
981 : : /* If ipv6 is a bit slow it waits for them */
982 : :
983 : 1 : data.loop = fixture->loop;
984 : 1 : mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
985 : :
986 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
987 : 1 : g_main_loop_run (fixture->loop);
988 : :
989 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
990 : :
991 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
992 : 1 : }
993 : :
994 : : static void
995 : 1 : test_happy_eyeballs_very_slow_ipv6 (HappyEyeballsFixture *fixture,
996 : : gconstpointer user_data)
997 : : {
998 : 1 : AsyncData data = { 0 };
999 : :
1000 : : /* If ipv6 is very slow we still get everything */
1001 : :
1002 : 1 : data.loop = fixture->loop;
1003 : 1 : mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT);
1004 : :
1005 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1006 : 1 : g_main_loop_run (fixture->loop);
1007 : :
1008 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
1009 : :
1010 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1011 : 1 : }
1012 : :
1013 : : static void
1014 : 1 : test_happy_eyeballs_slow_connection_and_ipv4 (HappyEyeballsFixture *fixture,
1015 : : gconstpointer user_data)
1016 : : {
1017 : 1 : AsyncData data = { 0 };
1018 : :
1019 : : /* Even if the dns response is slow we still get them if our connection attempts
1020 : : * take long enough. */
1021 : :
1022 : 1 : data.loop = fixture->loop;
1023 : 1 : data.delay_ms = SLOW_DELAY_MORE_THAN_TIMEOUT * 2;
1024 : 1 : mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT);
1025 : :
1026 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1027 : 1 : g_main_loop_run (fixture->loop);
1028 : :
1029 : 1 : assert_list_matches_expected (data.addrs, fixture->input_all_results);
1030 : :
1031 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1032 : 1 : }
1033 : :
1034 : : static void
1035 : 1 : test_happy_eyeballs_ipv6_error_ipv4_first (HappyEyeballsFixture *fixture,
1036 : : gconstpointer user_data)
1037 : : {
1038 : 1 : AsyncData data = { 0 };
1039 : : GError *ipv6_error;
1040 : :
1041 : : /* If ipv6 fails, ensuring that ipv4 finishes before ipv6 errors, we still get ipv4. */
1042 : :
1043 : 1 : data.loop = fixture->loop;
1044 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1045 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1046 : 1 : mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
1047 : :
1048 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1049 : 1 : g_main_loop_run (fixture->loop);
1050 : :
1051 : 1 : assert_list_matches_expected (data.addrs, fixture->input_ipv4_results);
1052 : :
1053 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1054 : 1 : g_error_free (ipv6_error);
1055 : 1 : }
1056 : :
1057 : : static void
1058 : 1 : test_happy_eyeballs_ipv6_error_ipv6_first (HappyEyeballsFixture *fixture,
1059 : : gconstpointer user_data)
1060 : : {
1061 : 1 : AsyncData data = { 0 };
1062 : : GError *ipv6_error;
1063 : :
1064 : : /* If ipv6 fails, ensuring that ipv6 errors before ipv4 finishes, we still get ipv4. */
1065 : :
1066 : 1 : data.loop = fixture->loop;
1067 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1068 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1069 : 1 : mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
1070 : :
1071 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1072 : 1 : g_main_loop_run (fixture->loop);
1073 : :
1074 : 1 : assert_list_matches_expected (data.addrs, fixture->input_ipv4_results);
1075 : :
1076 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1077 : 1 : g_error_free (ipv6_error);
1078 : 1 : }
1079 : :
1080 : : static void
1081 : 1 : test_happy_eyeballs_ipv6_error_ipv4_very_slow (HappyEyeballsFixture *fixture,
1082 : : gconstpointer user_data)
1083 : : {
1084 : 1 : AsyncData data = { 0 };
1085 : : GError *ipv6_error;
1086 : :
1087 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/merge_requests/865");
1088 : 1 : g_test_summary ("Ensure that we successfully return IPv4 results even when they come significantly later than an IPv6 failure.");
1089 : :
1090 : : /* If ipv6 fails, ensuring that ipv6 errors before ipv4 finishes, we still get ipv4. */
1091 : :
1092 : 1 : data.loop = fixture->loop;
1093 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1094 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1095 : 1 : mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT);
1096 : :
1097 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1098 : 1 : g_main_loop_run (fixture->loop);
1099 : :
1100 : 1 : assert_list_matches_expected (data.addrs, fixture->input_ipv4_results);
1101 : :
1102 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1103 : 1 : g_error_free (ipv6_error);
1104 : 1 : }
1105 : :
1106 : : static void
1107 : 1 : test_happy_eyeballs_ipv4_error_ipv4_first (HappyEyeballsFixture *fixture,
1108 : : gconstpointer user_data)
1109 : : {
1110 : 1 : AsyncData data = { 0 };
1111 : : GError *ipv4_error;
1112 : :
1113 : : /* If ipv4 fails, ensuring that ipv4 errors before ipv6 finishes, we still get ipv6. */
1114 : :
1115 : 1 : data.loop = fixture->loop;
1116 : 1 : ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken");
1117 : 1 : mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error);
1118 : 1 : mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
1119 : :
1120 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1121 : 1 : g_main_loop_run (fixture->loop);
1122 : :
1123 : 1 : assert_list_matches_expected (data.addrs, fixture->input_ipv6_results);
1124 : :
1125 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1126 : 1 : g_error_free (ipv4_error);
1127 : 1 : }
1128 : :
1129 : : static void
1130 : 1 : test_happy_eyeballs_ipv4_error_ipv6_first (HappyEyeballsFixture *fixture,
1131 : : gconstpointer user_data)
1132 : : {
1133 : 1 : AsyncData data = { 0 };
1134 : : GError *ipv4_error;
1135 : :
1136 : : /* If ipv4 fails, ensuring that ipv6 finishes before ipv4 errors, we still get ipv6. */
1137 : :
1138 : 1 : data.loop = fixture->loop;
1139 : 1 : ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken");
1140 : 1 : mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error);
1141 : 1 : mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
1142 : :
1143 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1144 : 1 : g_main_loop_run (fixture->loop);
1145 : :
1146 : 1 : assert_list_matches_expected (data.addrs, fixture->input_ipv6_results);
1147 : :
1148 : 1 : g_list_free_full (data.addrs, (GDestroyNotify) g_object_unref);
1149 : 1 : g_error_free (ipv4_error);
1150 : 1 : }
1151 : :
1152 : : static void
1153 : 1 : test_happy_eyeballs_both_error (HappyEyeballsFixture *fixture,
1154 : : gconstpointer user_data)
1155 : : {
1156 : 1 : AsyncData data = { 0 };
1157 : : GError *ipv4_error, *ipv6_error;
1158 : :
1159 : : /* If both fail we get an error. */
1160 : :
1161 : 1 : data.loop = fixture->loop;
1162 : 1 : data.expected_error_code = G_IO_ERROR_TIMED_OUT;
1163 : 1 : ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken");
1164 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1165 : :
1166 : 1 : mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error);
1167 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1168 : :
1169 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1170 : 1 : g_main_loop_run (fixture->loop);
1171 : :
1172 : 1 : g_assert_null (data.addrs);
1173 : :
1174 : 1 : g_error_free (ipv4_error);
1175 : 1 : g_error_free (ipv6_error);
1176 : 1 : }
1177 : :
1178 : : static void
1179 : 1 : test_happy_eyeballs_both_error_delays_1 (HappyEyeballsFixture *fixture,
1180 : : gconstpointer user_data)
1181 : : {
1182 : 1 : AsyncData data = { 0 };
1183 : : GError *ipv4_error, *ipv6_error;
1184 : :
1185 : : /* The same with some different timings */
1186 : :
1187 : 1 : data.loop = fixture->loop;
1188 : 1 : data.expected_error_code = G_IO_ERROR_TIMED_OUT;
1189 : 1 : ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken");
1190 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1191 : :
1192 : 1 : mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error);
1193 : 1 : mock_resolver_set_ipv4_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
1194 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1195 : :
1196 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1197 : 1 : g_main_loop_run (fixture->loop);
1198 : :
1199 : 1 : g_assert_null (data.addrs);
1200 : :
1201 : 1 : g_error_free (ipv4_error);
1202 : 1 : g_error_free (ipv6_error);
1203 : 1 : }
1204 : :
1205 : : static void
1206 : 1 : test_happy_eyeballs_both_error_delays_2 (HappyEyeballsFixture *fixture,
1207 : : gconstpointer user_data)
1208 : : {
1209 : 1 : AsyncData data = { 0 };
1210 : : GError *ipv4_error, *ipv6_error;
1211 : :
1212 : : /* The same with some different timings */
1213 : :
1214 : 1 : data.loop = fixture->loop;
1215 : 1 : data.expected_error_code = G_IO_ERROR_TIMED_OUT;
1216 : 1 : ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken");
1217 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1218 : :
1219 : 1 : mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error);
1220 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1221 : 1 : mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, FAST_DELAY_LESS_THAN_TIMEOUT);
1222 : :
1223 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1224 : 1 : g_main_loop_run (fixture->loop);
1225 : :
1226 : 1 : g_assert_null (data.addrs);
1227 : :
1228 : 1 : g_error_free (ipv4_error);
1229 : 1 : g_error_free (ipv6_error);
1230 : 1 : }
1231 : :
1232 : : static void
1233 : 1 : test_happy_eyeballs_both_error_delays_3 (HappyEyeballsFixture *fixture,
1234 : : gconstpointer user_data)
1235 : : {
1236 : 1 : AsyncData data = { 0 };
1237 : : GError *ipv4_error, *ipv6_error;
1238 : :
1239 : : /* The same with some different timings */
1240 : :
1241 : 1 : data.loop = fixture->loop;
1242 : 1 : data.expected_error_code = G_IO_ERROR_TIMED_OUT;
1243 : 1 : ipv4_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv4 Broken");
1244 : 1 : ipv6_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "IPv6 Broken");
1245 : :
1246 : 1 : mock_resolver_set_ipv4_error (fixture->mock_resolver, ipv4_error);
1247 : 1 : mock_resolver_set_ipv6_error (fixture->mock_resolver, ipv6_error);
1248 : 1 : mock_resolver_set_ipv6_delay_ms (fixture->mock_resolver, SLOW_DELAY_MORE_THAN_TIMEOUT);
1249 : :
1250 : 1 : g_socket_address_enumerator_next_async (fixture->enumerator, NULL, got_addr, &data);
1251 : 1 : g_main_loop_run (fixture->loop);
1252 : :
1253 : 1 : g_assert_null (data.addrs);
1254 : :
1255 : 1 : g_error_free (ipv4_error);
1256 : 1 : g_error_free (ipv6_error);
1257 : 1 : }
1258 : :
1259 : : int
1260 : 1 : main (int argc, char *argv[])
1261 : : {
1262 : : gsize i;
1263 : : gchar *path;
1264 : :
1265 : 1 : g_test_init (&argc, &argv, NULL);
1266 : :
1267 : 1 : g_test_add_func ("/network-address/basic", test_basic);
1268 : :
1269 : 15 : for (i = 0; i < G_N_ELEMENTS (host_tests); i++)
1270 : : {
1271 : 14 : path = g_strdup_printf ("/network-address/parse-host/%" G_GSIZE_FORMAT, i);
1272 : 14 : g_test_add_data_func (path, &host_tests[i], test_parse_host);
1273 : 14 : g_free (path);
1274 : : }
1275 : :
1276 : 11 : for (i = 0; i < G_N_ELEMENTS (uri_tests); i++)
1277 : : {
1278 : 10 : path = g_strdup_printf ("/network-address/parse-uri/%" G_GSIZE_FORMAT, i);
1279 : 10 : g_test_add_data_func (path, &uri_tests[i], test_parse_uri);
1280 : 10 : g_free (path);
1281 : : }
1282 : :
1283 : 13 : for (i = 0; i < G_N_ELEMENTS (address_tests); i++)
1284 : : {
1285 : 12 : path = g_strdup_printf ("/network-address/resolve-address/%" G_GSIZE_FORMAT, i);
1286 : 12 : g_test_add_data_func (path, &address_tests[i], test_resolve_address);
1287 : 12 : g_free (path);
1288 : : }
1289 : :
1290 : 13 : for (i = 0; i < G_N_ELEMENTS (address_tests); i++)
1291 : : {
1292 : 12 : path = g_strdup_printf ("/gresolver/resolve-address/%" G_GSIZE_FORMAT, i);
1293 : 12 : g_test_add_data_func (path, &address_tests[i], test_resolve_address_gresolver);
1294 : 12 : g_free (path);
1295 : : }
1296 : :
1297 : 1 : g_test_add_func ("/network-address/scope-id", test_host_scope_id);
1298 : 1 : g_test_add_func ("/network-address/uri-scope-id", test_uri_scope_id);
1299 : 1 : g_test_add_func ("/network-address/loopback/basic", test_loopback_basic);
1300 : 1 : g_test_add_func ("/network-address/loopback/sync", test_loopback_sync);
1301 : 1 : g_test_add_func ("/network-address/loopback/async", test_loopback_async);
1302 : 1 : g_test_add_func ("/network-address/localhost/async", test_localhost_async);
1303 : 1 : g_test_add_func ("/network-address/localhost/sync", test_localhost_sync);
1304 : 1 : g_test_add_func ("/network-address/to-string", test_to_string);
1305 : :
1306 : 1 : g_test_add ("/network-address/happy-eyeballs/basic", HappyEyeballsFixture, NULL,
1307 : : happy_eyeballs_setup, test_happy_eyeballs_basic, happy_eyeballs_teardown);
1308 : 1 : g_test_add ("/network-address/happy-eyeballs/parallel", HappyEyeballsFixture, NULL,
1309 : : happy_eyeballs_setup, test_happy_eyeballs_parallel, happy_eyeballs_teardown);
1310 : 1 : g_test_add ("/network-address/happy-eyeballs/slow-ipv4", HappyEyeballsFixture, NULL,
1311 : : happy_eyeballs_setup, test_happy_eyeballs_slow_ipv4, happy_eyeballs_teardown);
1312 : 1 : g_test_add ("/network-address/happy-eyeballs/slow-ipv6", HappyEyeballsFixture, NULL,
1313 : : happy_eyeballs_setup, test_happy_eyeballs_slow_ipv6, happy_eyeballs_teardown);
1314 : 1 : g_test_add ("/network-address/happy-eyeballs/very-slow-ipv6", HappyEyeballsFixture, NULL,
1315 : : happy_eyeballs_setup, test_happy_eyeballs_very_slow_ipv6, happy_eyeballs_teardown);
1316 : 1 : g_test_add ("/network-address/happy-eyeballs/slow-connection-and-ipv4", HappyEyeballsFixture, NULL,
1317 : : happy_eyeballs_setup, test_happy_eyeballs_slow_connection_and_ipv4, happy_eyeballs_teardown);
1318 : 1 : g_test_add ("/network-address/happy-eyeballs/ipv6-error-ipv4-first", HappyEyeballsFixture, NULL,
1319 : : happy_eyeballs_setup, test_happy_eyeballs_ipv6_error_ipv4_first, happy_eyeballs_teardown);
1320 : 1 : g_test_add ("/network-address/happy-eyeballs/ipv6-error-ipv6-first", HappyEyeballsFixture, NULL,
1321 : : happy_eyeballs_setup, test_happy_eyeballs_ipv6_error_ipv6_first, happy_eyeballs_teardown);
1322 : 1 : g_test_add ("/network-address/happy-eyeballs/ipv6-error-ipv4-very-slow", HappyEyeballsFixture, NULL,
1323 : : happy_eyeballs_setup, test_happy_eyeballs_ipv6_error_ipv4_very_slow, happy_eyeballs_teardown);
1324 : 1 : g_test_add ("/network-address/happy-eyeballs/ipv4-error-ipv6-first", HappyEyeballsFixture, NULL,
1325 : : happy_eyeballs_setup, test_happy_eyeballs_ipv4_error_ipv6_first, happy_eyeballs_teardown);
1326 : 1 : g_test_add ("/network-address/happy-eyeballs/ipv4-error-ipv4-first", HappyEyeballsFixture, NULL,
1327 : : happy_eyeballs_setup, test_happy_eyeballs_ipv4_error_ipv4_first, happy_eyeballs_teardown);
1328 : 1 : g_test_add ("/network-address/happy-eyeballs/both-error", HappyEyeballsFixture, NULL,
1329 : : happy_eyeballs_setup, test_happy_eyeballs_both_error, happy_eyeballs_teardown);
1330 : 1 : g_test_add ("/network-address/happy-eyeballs/both-error-delays-1", HappyEyeballsFixture, NULL,
1331 : : happy_eyeballs_setup, test_happy_eyeballs_both_error_delays_1, happy_eyeballs_teardown);
1332 : 1 : g_test_add ("/network-address/happy-eyeballs/both-error-delays-2", HappyEyeballsFixture, NULL,
1333 : : happy_eyeballs_setup, test_happy_eyeballs_both_error_delays_2, happy_eyeballs_teardown);
1334 : 1 : g_test_add ("/network-address/happy-eyeballs/both-error-delays-3", HappyEyeballsFixture, NULL,
1335 : : happy_eyeballs_setup, test_happy_eyeballs_both_error_delays_3, happy_eyeballs_teardown);
1336 : :
1337 : 1 : return g_test_run ();
1338 : : }
|