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