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