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