1 | /* GLib testing framework examples and tests |
2 | * |
3 | * Copyright 2012 Red Hat, Inc. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General |
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include <string.h> |
20 | |
21 | #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_34 |
22 | #include <gio/gio.h> |
23 | |
24 | /* Overview: |
25 | * |
26 | * We have an echo server, two proxy servers, two GProxy |
27 | * implementations, and two GProxyResolver implementations. |
28 | * |
29 | * The echo server runs at @server.server_addr (on |
30 | * @server.server_port). |
31 | * |
32 | * The two proxy servers, A and B, run on @proxy_a.port and |
33 | * @proxy_b.port, with @proxy_a.uri and @proxy_b.uri pointing to them. |
34 | * The "negotiation" with the two proxies is just sending the single |
35 | * letter "a" or "b" and receiving it back in uppercase; the proxy |
36 | * then connects to @server_addr. |
37 | * |
38 | * Proxy A supports "alpha://" URIs, and does not support hostname |
39 | * resolution, and Proxy B supports "beta://" URIs, and does support |
40 | * hostname resolution (but it just ignores the hostname and always |
41 | * connects to @server_addr anyway). |
42 | * |
43 | * The default GProxyResolver (GTestProxyResolver) looks at its URI |
44 | * and returns [ "direct://" ] for "simple://" URIs, and [ |
45 | * proxy_a.uri, proxy_b.uri ] for other URIs. The other GProxyResolver |
46 | * (GTestAltProxyResolver) always returns [ proxy_a.uri ]. |
47 | */ |
48 | |
49 | typedef struct { |
50 | gchar *proxy_command; |
51 | gchar *supported_protocol; |
52 | |
53 | GSocket *server; |
54 | GThread *thread; |
55 | GCancellable *cancellable; |
56 | gchar *uri; |
57 | gushort port; |
58 | |
59 | GSocket *client_sock, *server_sock; |
60 | GMainLoop *loop; |
61 | |
62 | GError *last_error; |
63 | } ProxyData; |
64 | |
65 | static ProxyData proxy_a, proxy_b; |
66 | |
67 | typedef struct { |
68 | GSocket *server; |
69 | GThread *server_thread; |
70 | GCancellable *cancellable; |
71 | GSocketAddress *server_addr; |
72 | gushort server_port; |
73 | } ServerData; |
74 | |
75 | static ServerData server; |
76 | |
77 | static gchar **last_proxies; |
78 | |
79 | static GSocketClient *client; |
80 | |
81 | |
82 | /**************************************/ |
83 | /* Test GProxyResolver implementation */ |
84 | /**************************************/ |
85 | |
86 | typedef struct { |
87 | GObject parent_instance; |
88 | } GTestProxyResolver; |
89 | |
90 | typedef struct { |
91 | GObjectClass parent_class; |
92 | } GTestProxyResolverClass; |
93 | |
94 | static void g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface); |
95 | |
96 | static GType _g_test_proxy_resolver_get_type (void); |
97 | #define g_test_proxy_resolver_get_type _g_test_proxy_resolver_get_type |
98 | G_DEFINE_TYPE_WITH_CODE (GTestProxyResolver, g_test_proxy_resolver, G_TYPE_OBJECT, |
99 | G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER, |
100 | g_test_proxy_resolver_iface_init) |
101 | g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME, |
102 | g_define_type_id, |
103 | "test" , |
104 | 0)) |
105 | |
106 | static void |
107 | g_test_proxy_resolver_init (GTestProxyResolver *resolver) |
108 | { |
109 | } |
110 | |
111 | static gboolean |
112 | g_test_proxy_resolver_is_supported (GProxyResolver *resolver) |
113 | { |
114 | return TRUE; |
115 | } |
116 | |
117 | static gchar ** |
118 | g_test_proxy_resolver_lookup (GProxyResolver *resolver, |
119 | const gchar *uri, |
120 | GCancellable *cancellable, |
121 | GError **error) |
122 | { |
123 | gchar **proxies; |
124 | |
125 | g_assert (last_proxies == NULL); |
126 | |
127 | if (g_cancellable_set_error_if_cancelled (cancellable, error)) |
128 | return NULL; |
129 | |
130 | proxies = g_new (gchar *, 3); |
131 | |
132 | if (!strncmp (s1: uri, s2: "simple://" , n: 4)) |
133 | { |
134 | proxies[0] = g_strdup (str: "direct://" ); |
135 | proxies[1] = NULL; |
136 | } |
137 | else |
138 | { |
139 | /* Proxy A can only deal with "alpha://" URIs, not |
140 | * "beta://", but we always return both URIs |
141 | * anyway so we can test error handling when the first |
142 | * fails. |
143 | */ |
144 | proxies[0] = g_strdup (str: proxy_a.uri); |
145 | proxies[1] = g_strdup (str: proxy_b.uri); |
146 | proxies[2] = NULL; |
147 | } |
148 | |
149 | last_proxies = g_strdupv (str_array: proxies); |
150 | |
151 | return proxies; |
152 | } |
153 | |
154 | static void |
155 | g_test_proxy_resolver_lookup_async (GProxyResolver *resolver, |
156 | const gchar *uri, |
157 | GCancellable *cancellable, |
158 | GAsyncReadyCallback callback, |
159 | gpointer user_data) |
160 | { |
161 | GError *error = NULL; |
162 | GTask *task; |
163 | gchar **proxies; |
164 | |
165 | proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, error: &error); |
166 | |
167 | task = g_task_new (source_object: resolver, NULL, callback, callback_data: user_data); |
168 | if (proxies == NULL) |
169 | g_task_return_error (task, error); |
170 | else |
171 | g_task_return_pointer (task, result: proxies, result_destroy: (GDestroyNotify) g_strfreev); |
172 | |
173 | g_object_unref (object: task); |
174 | } |
175 | |
176 | static gchar ** |
177 | g_test_proxy_resolver_lookup_finish (GProxyResolver *resolver, |
178 | GAsyncResult *result, |
179 | GError **error) |
180 | { |
181 | return g_task_propagate_pointer (G_TASK (result), error); |
182 | } |
183 | |
184 | static void |
185 | g_test_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class) |
186 | { |
187 | } |
188 | |
189 | static void |
190 | g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface) |
191 | { |
192 | iface->is_supported = g_test_proxy_resolver_is_supported; |
193 | iface->lookup = g_test_proxy_resolver_lookup; |
194 | iface->lookup_async = g_test_proxy_resolver_lookup_async; |
195 | iface->lookup_finish = g_test_proxy_resolver_lookup_finish; |
196 | } |
197 | |
198 | /****************************/ |
199 | /* Alternate GProxyResolver */ |
200 | /****************************/ |
201 | |
202 | typedef GTestProxyResolver GTestAltProxyResolver; |
203 | typedef GTestProxyResolverClass GTestAltProxyResolverClass; |
204 | |
205 | static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface); |
206 | |
207 | static GType _g_test_alt_proxy_resolver_get_type (void); |
208 | #define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type |
209 | G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (), |
210 | G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER, |
211 | g_test_alt_proxy_resolver_iface_init); |
212 | ) |
213 | |
214 | static void |
215 | g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver) |
216 | { |
217 | } |
218 | |
219 | static gchar ** |
220 | g_test_alt_proxy_resolver_lookup (GProxyResolver *resolver, |
221 | const gchar *uri, |
222 | GCancellable *cancellable, |
223 | GError **error) |
224 | { |
225 | gchar **proxies; |
226 | |
227 | proxies = g_new (gchar *, 2); |
228 | |
229 | proxies[0] = g_strdup (str: proxy_a.uri); |
230 | proxies[1] = NULL; |
231 | |
232 | last_proxies = g_strdupv (str_array: proxies); |
233 | |
234 | return proxies; |
235 | } |
236 | |
237 | static void |
238 | g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class) |
239 | { |
240 | } |
241 | |
242 | static void |
243 | g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface) |
244 | { |
245 | iface->lookup = g_test_alt_proxy_resolver_lookup; |
246 | } |
247 | |
248 | |
249 | /****************************************/ |
250 | /* Test proxy implementation base class */ |
251 | /****************************************/ |
252 | |
253 | typedef struct { |
254 | GObject parent; |
255 | |
256 | ProxyData *proxy_data; |
257 | } GProxyBase; |
258 | |
259 | typedef struct { |
260 | GObjectClass parent_class; |
261 | } GProxyBaseClass; |
262 | |
263 | static GType _g_proxy_base_get_type (void); |
264 | #define g_proxy_base_get_type _g_proxy_base_get_type |
265 | G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT) |
266 | |
267 | static void |
268 | g_proxy_base_init (GProxyBase *proxy) |
269 | { |
270 | } |
271 | |
272 | static GIOStream * |
273 | g_proxy_base_connect (GProxy *proxy, |
274 | GIOStream *io_stream, |
275 | GProxyAddress *proxy_address, |
276 | GCancellable *cancellable, |
277 | GError **error) |
278 | { |
279 | ProxyData *data = ((GProxyBase *) proxy)->proxy_data; |
280 | const gchar *protocol; |
281 | GOutputStream *ostream; |
282 | GInputStream *istream; |
283 | gchar response; |
284 | |
285 | g_assert_no_error (data->last_error); |
286 | |
287 | protocol = g_proxy_address_get_destination_protocol (proxy: proxy_address); |
288 | if (strcmp (s1: protocol, s2: data->supported_protocol) != 0) |
289 | { |
290 | g_set_error_literal (err: &data->last_error, |
291 | G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED, |
292 | message: "Unsupported protocol" ); |
293 | goto fail; |
294 | } |
295 | |
296 | ostream = g_io_stream_get_output_stream (stream: io_stream); |
297 | if (g_output_stream_write (stream: ostream, buffer: data->proxy_command, count: 1, cancellable, |
298 | error: &data->last_error) != 1) |
299 | goto fail; |
300 | |
301 | istream = g_io_stream_get_input_stream (stream: io_stream); |
302 | if (g_input_stream_read (stream: istream, buffer: &response, count: 1, cancellable, |
303 | error: &data->last_error) != 1) |
304 | goto fail; |
305 | |
306 | if (response != g_ascii_toupper (c: *data->proxy_command)) |
307 | { |
308 | g_set_error_literal (err: &data->last_error, |
309 | G_IO_ERROR, code: G_IO_ERROR_FAILED, |
310 | message: "Failed" ); |
311 | goto fail; |
312 | } |
313 | |
314 | return g_object_ref (io_stream); |
315 | |
316 | fail: |
317 | g_propagate_error (dest: error, src: g_error_copy (error: data->last_error)); |
318 | return NULL; |
319 | } |
320 | |
321 | static void |
322 | g_proxy_base_connect_async (GProxy *proxy, |
323 | GIOStream *io_stream, |
324 | GProxyAddress *proxy_address, |
325 | GCancellable *cancellable, |
326 | GAsyncReadyCallback callback, |
327 | gpointer user_data) |
328 | { |
329 | GError *error = NULL; |
330 | GTask *task; |
331 | GIOStream *proxy_io_stream; |
332 | |
333 | task = g_task_new (source_object: proxy, NULL, callback, callback_data: user_data); |
334 | |
335 | proxy_io_stream = g_proxy_connect (proxy, connection: io_stream, proxy_address, |
336 | cancellable, error: &error); |
337 | if (proxy_io_stream) |
338 | g_task_return_pointer (task, result: proxy_io_stream, result_destroy: g_object_unref); |
339 | else |
340 | g_task_return_error (task, error); |
341 | g_object_unref (object: task); |
342 | } |
343 | |
344 | static GIOStream * |
345 | g_proxy_base_connect_finish (GProxy *proxy, |
346 | GAsyncResult *result, |
347 | GError **error) |
348 | { |
349 | return g_task_propagate_pointer (G_TASK (result), error); |
350 | } |
351 | |
352 | static void |
353 | g_proxy_base_class_init (GProxyBaseClass *class) |
354 | { |
355 | } |
356 | |
357 | |
358 | /********************************************/ |
359 | /* Test proxy implementation #1 ("Proxy A") */ |
360 | /********************************************/ |
361 | |
362 | typedef GProxyBase GProxyA; |
363 | typedef GProxyBaseClass GProxyAClass; |
364 | |
365 | static void g_proxy_a_iface_init (GProxyInterface *proxy_iface); |
366 | |
367 | static GType _g_proxy_a_get_type (void); |
368 | #define g_proxy_a_get_type _g_proxy_a_get_type |
369 | G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (), |
370 | G_IMPLEMENT_INTERFACE (G_TYPE_PROXY, |
371 | g_proxy_a_iface_init) |
372 | g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME, |
373 | g_define_type_id, |
374 | "proxy-a" , |
375 | 0)) |
376 | |
377 | static void |
378 | g_proxy_a_init (GProxyA *proxy) |
379 | { |
380 | ((GProxyBase *) proxy)->proxy_data = &proxy_a; |
381 | } |
382 | |
383 | static gboolean |
384 | g_proxy_a_supports_hostname (GProxy *proxy) |
385 | { |
386 | return FALSE; |
387 | } |
388 | |
389 | static void |
390 | g_proxy_a_class_init (GProxyAClass *class) |
391 | { |
392 | } |
393 | |
394 | static void |
395 | g_proxy_a_iface_init (GProxyInterface *proxy_iface) |
396 | { |
397 | proxy_iface->connect = g_proxy_base_connect; |
398 | proxy_iface->connect_async = g_proxy_base_connect_async; |
399 | proxy_iface->connect_finish = g_proxy_base_connect_finish; |
400 | proxy_iface->supports_hostname = g_proxy_a_supports_hostname; |
401 | } |
402 | |
403 | /********************************************/ |
404 | /* Test proxy implementation #2 ("Proxy B") */ |
405 | /********************************************/ |
406 | |
407 | typedef GProxyBase GProxyB; |
408 | typedef GProxyBaseClass GProxyBClass; |
409 | |
410 | static void g_proxy_b_iface_init (GProxyInterface *proxy_iface); |
411 | |
412 | static GType _g_proxy_b_get_type (void); |
413 | #define g_proxy_b_get_type _g_proxy_b_get_type |
414 | G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (), |
415 | G_IMPLEMENT_INTERFACE (G_TYPE_PROXY, |
416 | g_proxy_b_iface_init) |
417 | g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME, |
418 | g_define_type_id, |
419 | "proxy-b" , |
420 | 0)) |
421 | |
422 | static void |
423 | g_proxy_b_init (GProxyB *proxy) |
424 | { |
425 | ((GProxyBase *) proxy)->proxy_data = &proxy_b; |
426 | } |
427 | |
428 | static gboolean |
429 | g_proxy_b_supports_hostname (GProxy *proxy) |
430 | { |
431 | return TRUE; |
432 | } |
433 | |
434 | static void |
435 | g_proxy_b_class_init (GProxyBClass *class) |
436 | { |
437 | } |
438 | |
439 | static void |
440 | g_proxy_b_iface_init (GProxyInterface *proxy_iface) |
441 | { |
442 | proxy_iface->connect = g_proxy_base_connect; |
443 | proxy_iface->connect_async = g_proxy_base_connect_async; |
444 | proxy_iface->connect_finish = g_proxy_base_connect_finish; |
445 | proxy_iface->supports_hostname = g_proxy_b_supports_hostname; |
446 | } |
447 | |
448 | |
449 | /***********************************/ |
450 | /* The proxy server implementation */ |
451 | /***********************************/ |
452 | |
453 | static gboolean |
454 | proxy_bytes (GSocket *socket, |
455 | GIOCondition condition, |
456 | gpointer user_data) |
457 | { |
458 | ProxyData *proxy = user_data; |
459 | gssize nread, nwrote, total; |
460 | gchar buffer[8]; |
461 | GSocket *out_socket; |
462 | GError *error = NULL; |
463 | |
464 | nread = g_socket_receive_with_blocking (socket, buffer, size: sizeof (buffer), |
465 | TRUE, NULL, error: &error); |
466 | if (nread == -1) |
467 | { |
468 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); |
469 | return FALSE; |
470 | } |
471 | else |
472 | g_assert_no_error (error); |
473 | |
474 | if (nread == 0) |
475 | { |
476 | g_main_loop_quit (loop: proxy->loop); |
477 | return FALSE; |
478 | } |
479 | |
480 | if (socket == proxy->client_sock) |
481 | out_socket = proxy->server_sock; |
482 | else |
483 | out_socket = proxy->client_sock; |
484 | |
485 | for (total = 0; total < nread; total += nwrote) |
486 | { |
487 | nwrote = g_socket_send_with_blocking (socket: out_socket, |
488 | buffer: buffer + total, size: nread - total, |
489 | TRUE, NULL, error: &error); |
490 | g_assert_no_error (error); |
491 | } |
492 | |
493 | return TRUE; |
494 | } |
495 | |
496 | static gpointer |
497 | proxy_thread (gpointer user_data) |
498 | { |
499 | ProxyData *proxy = user_data; |
500 | GError *error = NULL; |
501 | gssize nread, nwrote; |
502 | gchar command[2] = { 0, 0 }; |
503 | GMainContext *context; |
504 | GSource *read_source, *write_source; |
505 | |
506 | context = g_main_context_new (); |
507 | proxy->loop = g_main_loop_new (context, FALSE); |
508 | |
509 | while (TRUE) |
510 | { |
511 | proxy->client_sock = g_socket_accept (socket: proxy->server, cancellable: proxy->cancellable, error: &error); |
512 | if (!proxy->client_sock) |
513 | { |
514 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); |
515 | g_error_free (error); |
516 | break; |
517 | } |
518 | else |
519 | g_assert_no_error (error); |
520 | |
521 | nread = g_socket_receive (socket: proxy->client_sock, buffer: command, size: 1, NULL, error: &error); |
522 | g_assert_no_error (error); |
523 | |
524 | if (nread == 0) |
525 | { |
526 | g_clear_object (&proxy->client_sock); |
527 | continue; |
528 | } |
529 | |
530 | g_assert_cmpint (nread, ==, 1); |
531 | g_assert_cmpstr (command, ==, proxy->proxy_command); |
532 | |
533 | *command = g_ascii_toupper (c: *command); |
534 | nwrote = g_socket_send (socket: proxy->client_sock, buffer: command, size: 1, NULL, error: &error); |
535 | g_assert_no_error (error); |
536 | g_assert_cmpint (nwrote, ==, 1); |
537 | |
538 | proxy->server_sock = g_socket_new (family: G_SOCKET_FAMILY_IPV4, |
539 | type: G_SOCKET_TYPE_STREAM, |
540 | protocol: G_SOCKET_PROTOCOL_DEFAULT, |
541 | error: &error); |
542 | g_assert_no_error (error); |
543 | g_socket_connect (socket: proxy->server_sock, address: server.server_addr, NULL, error: &error); |
544 | g_assert_no_error (error); |
545 | |
546 | read_source = g_socket_create_source (socket: proxy->client_sock, condition: G_IO_IN, NULL); |
547 | g_source_set_callback (source: read_source, func: (GSourceFunc)proxy_bytes, data: proxy, NULL); |
548 | g_source_attach (source: read_source, context); |
549 | |
550 | write_source = g_socket_create_source (socket: proxy->server_sock, condition: G_IO_IN, NULL); |
551 | g_source_set_callback (source: write_source, func: (GSourceFunc)proxy_bytes, data: proxy, NULL); |
552 | g_source_attach (source: write_source, context); |
553 | |
554 | g_main_loop_run (loop: proxy->loop); |
555 | |
556 | g_socket_close (socket: proxy->client_sock, error: &error); |
557 | g_assert_no_error (error); |
558 | g_clear_object (&proxy->client_sock); |
559 | |
560 | g_socket_close (socket: proxy->server_sock, error: &error); |
561 | g_assert_no_error (error); |
562 | g_clear_object (&proxy->server_sock); |
563 | |
564 | g_source_destroy (source: read_source); |
565 | g_source_unref (source: read_source); |
566 | g_source_destroy (source: write_source); |
567 | g_source_unref (source: write_source); |
568 | } |
569 | |
570 | g_main_loop_unref (loop: proxy->loop); |
571 | g_main_context_unref (context); |
572 | |
573 | g_object_unref (object: proxy->server); |
574 | g_object_unref (object: proxy->cancellable); |
575 | |
576 | g_free (mem: proxy->proxy_command); |
577 | g_free (mem: proxy->supported_protocol); |
578 | g_free (mem: proxy->uri); |
579 | |
580 | return NULL; |
581 | } |
582 | |
583 | static void |
584 | create_proxy (ProxyData *proxy, |
585 | gchar proxy_protocol, |
586 | const gchar *destination_protocol, |
587 | GCancellable *cancellable) |
588 | { |
589 | GError *error = NULL; |
590 | GSocketAddress *addr; |
591 | GInetAddress *iaddr; |
592 | |
593 | proxy->proxy_command = g_strdup_printf (format: "%c" , proxy_protocol); |
594 | proxy->supported_protocol = g_strdup (str: destination_protocol); |
595 | proxy->cancellable = g_object_ref (cancellable); |
596 | |
597 | proxy->server = g_socket_new (family: G_SOCKET_FAMILY_IPV4, |
598 | type: G_SOCKET_TYPE_STREAM, |
599 | protocol: G_SOCKET_PROTOCOL_DEFAULT, |
600 | error: &error); |
601 | g_assert_no_error (error); |
602 | |
603 | iaddr = g_inet_address_new_loopback (family: G_SOCKET_FAMILY_IPV4); |
604 | addr = g_inet_socket_address_new (address: iaddr, port: 0); |
605 | g_object_unref (object: iaddr); |
606 | |
607 | g_socket_bind (socket: proxy->server, address: addr, TRUE, error: &error); |
608 | g_assert_no_error (error); |
609 | g_object_unref (object: addr); |
610 | |
611 | addr = g_socket_get_local_address (socket: proxy->server, error: &error); |
612 | proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); |
613 | proxy->uri = g_strdup_printf (format: "proxy-%c://127.0.0.1:%u" , |
614 | g_ascii_tolower (c: proxy_protocol), |
615 | proxy->port); |
616 | g_object_unref (object: addr); |
617 | |
618 | g_socket_listen (socket: proxy->server, error: &error); |
619 | g_assert_no_error (error); |
620 | |
621 | proxy->thread = g_thread_new (name: "proxy" , func: proxy_thread, data: proxy); |
622 | } |
623 | |
624 | |
625 | |
626 | /**************************/ |
627 | /* The actual echo server */ |
628 | /**************************/ |
629 | |
630 | static gpointer |
631 | echo_server_thread (gpointer user_data) |
632 | { |
633 | ServerData *data = user_data; |
634 | GSocket *sock; |
635 | GError *error = NULL; |
636 | gssize nread, nwrote; |
637 | gchar buf[128]; |
638 | |
639 | while (TRUE) |
640 | { |
641 | sock = g_socket_accept (socket: data->server, cancellable: data->cancellable, error: &error); |
642 | if (!sock) |
643 | { |
644 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); |
645 | g_error_free (error); |
646 | break; |
647 | } |
648 | else |
649 | g_assert_no_error (error); |
650 | |
651 | while (TRUE) |
652 | { |
653 | nread = g_socket_receive (socket: sock, buffer: buf, size: sizeof (buf), NULL, error: &error); |
654 | g_assert_no_error (error); |
655 | g_assert_cmpint (nread, >=, 0); |
656 | |
657 | if (nread == 0) |
658 | break; |
659 | |
660 | nwrote = g_socket_send (socket: sock, buffer: buf, size: nread, NULL, error: &error); |
661 | g_assert_no_error (error); |
662 | g_assert_cmpint (nwrote, ==, nread); |
663 | } |
664 | |
665 | g_socket_close (socket: sock, error: &error); |
666 | g_assert_no_error (error); |
667 | g_object_unref (object: sock); |
668 | } |
669 | |
670 | g_object_unref (object: data->server); |
671 | g_object_unref (object: data->server_addr); |
672 | g_object_unref (object: data->cancellable); |
673 | |
674 | return NULL; |
675 | } |
676 | |
677 | static void |
678 | create_server (ServerData *data, GCancellable *cancellable) |
679 | { |
680 | GError *error = NULL; |
681 | GSocketAddress *addr; |
682 | GInetAddress *iaddr; |
683 | |
684 | data->cancellable = g_object_ref (cancellable); |
685 | |
686 | data->server = g_socket_new (family: G_SOCKET_FAMILY_IPV4, |
687 | type: G_SOCKET_TYPE_STREAM, |
688 | protocol: G_SOCKET_PROTOCOL_DEFAULT, |
689 | error: &error); |
690 | g_assert_no_error (error); |
691 | |
692 | g_socket_set_blocking (socket: data->server, TRUE); |
693 | iaddr = g_inet_address_new_loopback (family: G_SOCKET_FAMILY_IPV4); |
694 | addr = g_inet_socket_address_new (address: iaddr, port: 0); |
695 | g_object_unref (object: iaddr); |
696 | |
697 | g_socket_bind (socket: data->server, address: addr, TRUE, error: &error); |
698 | g_assert_no_error (error); |
699 | g_object_unref (object: addr); |
700 | |
701 | data->server_addr = g_socket_get_local_address (socket: data->server, error: &error); |
702 | g_assert_no_error (error); |
703 | |
704 | data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr)); |
705 | |
706 | g_socket_listen (socket: data->server, error: &error); |
707 | g_assert_no_error (error); |
708 | |
709 | data->server_thread = g_thread_new (name: "server" , func: echo_server_thread, data); |
710 | } |
711 | |
712 | |
713 | /******************************************************************/ |
714 | /* Now a GResolver implementation, so the can't-resolve test will */ |
715 | /* pass even if you have an evil DNS-faking ISP. */ |
716 | /******************************************************************/ |
717 | |
718 | typedef GResolver GFakeResolver; |
719 | typedef GResolverClass GFakeResolverClass; |
720 | |
721 | static GType g_fake_resolver_get_type (void); |
722 | G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER) |
723 | |
724 | static void |
725 | g_fake_resolver_init (GFakeResolver *gtr) |
726 | { |
727 | } |
728 | |
729 | static GList * |
730 | g_fake_resolver_lookup_by_name (GResolver *resolver, |
731 | const gchar *hostname, |
732 | GCancellable *cancellable, |
733 | GError **error) |
734 | { |
735 | if (!strcmp (s1: hostname, s2: "example.com" )) |
736 | return g_list_prepend (NULL, data: g_inet_address_new_from_string (string: "127.0.0.1" )); |
737 | else |
738 | { |
739 | /* Anything else is expected to fail. */ |
740 | g_set_error (err: error, |
741 | G_RESOLVER_ERROR, |
742 | code: G_RESOLVER_ERROR_NOT_FOUND, |
743 | format: "Not found" ); |
744 | return NULL; |
745 | } |
746 | } |
747 | |
748 | static void |
749 | g_fake_resolver_lookup_by_name_async (GResolver *resolver, |
750 | const gchar *hostname, |
751 | GCancellable *cancellable, |
752 | GAsyncReadyCallback callback, |
753 | gpointer user_data) |
754 | { |
755 | GTask *task; |
756 | |
757 | task = g_task_new (source_object: resolver, cancellable, callback, callback_data: user_data); |
758 | |
759 | if (!strcmp (s1: hostname, s2: "example.com" )) |
760 | { |
761 | GList *result; |
762 | |
763 | result = g_list_prepend (NULL, data: g_inet_address_new_from_string (string: "127.0.0.1" )); |
764 | g_task_return_pointer (task, result, result_destroy: (GDestroyNotify) g_resolver_free_addresses); |
765 | } |
766 | else |
767 | { |
768 | g_task_return_new_error (task, |
769 | G_RESOLVER_ERROR, code: G_RESOLVER_ERROR_NOT_FOUND, |
770 | format: "Not found" ); |
771 | } |
772 | g_object_unref (object: task); |
773 | } |
774 | |
775 | static void |
776 | g_fake_resolver_lookup_by_name_with_flags_async (GResolver *resolver, |
777 | const gchar *hostname, |
778 | GResolverNameLookupFlags flags, |
779 | GCancellable *cancellable, |
780 | GAsyncReadyCallback callback, |
781 | gpointer user_data) |
782 | { |
783 | /* Note this isn't a real implementation as it ignores the flags */ |
784 | g_fake_resolver_lookup_by_name_async (resolver, |
785 | hostname, |
786 | cancellable, |
787 | callback, |
788 | user_data); |
789 | } |
790 | |
791 | static GList * |
792 | g_fake_resolver_lookup_by_name_finish (GResolver *resolver, |
793 | GAsyncResult *result, |
794 | GError **error) |
795 | { |
796 | return g_task_propagate_pointer (G_TASK (result), error); |
797 | } |
798 | |
799 | static void |
800 | g_fake_resolver_class_init (GFakeResolverClass *fake_class) |
801 | { |
802 | GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class); |
803 | |
804 | resolver_class->lookup_by_name = g_fake_resolver_lookup_by_name; |
805 | resolver_class->lookup_by_name_async = g_fake_resolver_lookup_by_name_async; |
806 | resolver_class->lookup_by_name_finish = g_fake_resolver_lookup_by_name_finish; |
807 | resolver_class->lookup_by_name_with_flags_async = g_fake_resolver_lookup_by_name_with_flags_async; |
808 | resolver_class->lookup_by_name_with_flags_finish = g_fake_resolver_lookup_by_name_finish; |
809 | } |
810 | |
811 | |
812 | |
813 | /****************************************/ |
814 | /* We made it! Now for the actual test! */ |
815 | /****************************************/ |
816 | |
817 | static void |
818 | setup_test (gpointer fixture, |
819 | gconstpointer user_data) |
820 | { |
821 | } |
822 | |
823 | static void |
824 | teardown_test (gpointer fixture, |
825 | gconstpointer user_data) |
826 | { |
827 | if (last_proxies) |
828 | { |
829 | g_strfreev (str_array: last_proxies); |
830 | last_proxies = NULL; |
831 | } |
832 | g_clear_error (err: &proxy_a.last_error); |
833 | g_clear_error (err: &proxy_b.last_error); |
834 | } |
835 | |
836 | |
837 | static const gchar *testbuf = "0123456789abcdef" ; |
838 | |
839 | static void |
840 | do_echo_test (GSocketConnection *conn) |
841 | { |
842 | GIOStream *iostream = G_IO_STREAM (conn); |
843 | GInputStream *istream = g_io_stream_get_input_stream (stream: iostream); |
844 | GOutputStream *ostream = g_io_stream_get_output_stream (stream: iostream); |
845 | gssize nread, total; |
846 | gsize nwrote; |
847 | gchar buf[128]; |
848 | GError *error = NULL; |
849 | |
850 | g_output_stream_write_all (stream: ostream, buffer: testbuf, count: strlen (s: testbuf), |
851 | bytes_written: &nwrote, NULL, error: &error); |
852 | g_assert_no_error (error); |
853 | g_assert_cmpint (nwrote, ==, strlen (testbuf)); |
854 | |
855 | for (total = 0; total < nwrote; total += nread) |
856 | { |
857 | nread = g_input_stream_read (stream: istream, |
858 | buffer: buf + total, count: sizeof (buf) - total, |
859 | NULL, error: &error); |
860 | g_assert_no_error (error); |
861 | g_assert_cmpint (nread, >, 0); |
862 | } |
863 | |
864 | buf[total] = '\0'; |
865 | g_assert_cmpstr (buf, ==, testbuf); |
866 | } |
867 | |
868 | static void |
869 | async_got_conn (GObject *source, |
870 | GAsyncResult *result, |
871 | gpointer user_data) |
872 | { |
873 | GSocketConnection **conn = user_data; |
874 | GError *error = NULL; |
875 | |
876 | *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source), |
877 | result, error: &error); |
878 | g_assert_no_error (error); |
879 | } |
880 | |
881 | static void |
882 | async_got_error (GObject *source, |
883 | GAsyncResult *result, |
884 | gpointer user_data) |
885 | { |
886 | GError **error = user_data; |
887 | |
888 | g_assert (error != NULL && *error == NULL); |
889 | g_socket_client_connect_finish (G_SOCKET_CLIENT (source), |
890 | result, error); |
891 | g_assert (*error != NULL); |
892 | } |
893 | |
894 | |
895 | static void |
896 | assert_direct (GSocketConnection *conn) |
897 | { |
898 | GSocketAddress *addr; |
899 | GError *error = NULL; |
900 | |
901 | g_assert_cmpint (g_strv_length (last_proxies), ==, 1); |
902 | g_assert_cmpstr (last_proxies[0], ==, "direct://" ); |
903 | g_assert_no_error (proxy_a.last_error); |
904 | g_assert_no_error (proxy_b.last_error); |
905 | |
906 | addr = g_socket_connection_get_remote_address (connection: conn, error: &error); |
907 | g_assert_no_error (error); |
908 | g_assert (addr != NULL && !G_IS_PROXY_ADDRESS (addr)); |
909 | g_object_unref (object: addr); |
910 | |
911 | addr = g_socket_connection_get_local_address (connection: conn, error: &error); |
912 | g_assert_no_error (error); |
913 | g_object_unref (object: addr); |
914 | |
915 | g_assert (g_socket_connection_is_connected (conn)); |
916 | } |
917 | |
918 | static void |
919 | test_direct_sync (gpointer fixture, |
920 | gconstpointer user_data) |
921 | { |
922 | GSocketConnection *conn; |
923 | gchar *uri; |
924 | GError *error = NULL; |
925 | |
926 | /* The simple:// URI should not require any proxy. */ |
927 | |
928 | uri = g_strdup_printf (format: "simple://127.0.0.1:%u" , server.server_port); |
929 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
930 | g_free (mem: uri); |
931 | g_assert_no_error (error); |
932 | |
933 | assert_direct (conn); |
934 | do_echo_test (conn); |
935 | g_object_unref (object: conn); |
936 | } |
937 | |
938 | static void |
939 | test_direct_async (gpointer fixture, |
940 | gconstpointer user_data) |
941 | { |
942 | GSocketConnection *conn; |
943 | gchar *uri; |
944 | |
945 | /* The simple:// URI should not require any proxy. */ |
946 | uri = g_strdup_printf (format: "simple://127.0.0.1:%u" , server.server_port); |
947 | conn = NULL; |
948 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
949 | callback: async_got_conn, user_data: &conn); |
950 | g_free (mem: uri); |
951 | while (conn == NULL) |
952 | g_main_context_iteration (NULL, TRUE); |
953 | |
954 | assert_direct (conn); |
955 | do_echo_test (conn); |
956 | g_object_unref (object: conn); |
957 | } |
958 | |
959 | static void |
960 | assert_single (GSocketConnection *conn) |
961 | { |
962 | GSocketAddress *addr; |
963 | const gchar *proxy_uri; |
964 | gushort proxy_port; |
965 | GError *error = NULL; |
966 | |
967 | g_assert_cmpint (g_strv_length (last_proxies), ==, 2); |
968 | g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri); |
969 | g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri); |
970 | g_assert_no_error (proxy_a.last_error); |
971 | g_assert_no_error (proxy_b.last_error); |
972 | |
973 | addr = g_socket_connection_get_remote_address (connection: conn, error: &error); |
974 | g_assert_no_error (error); |
975 | g_assert (G_IS_PROXY_ADDRESS (addr)); |
976 | proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr)); |
977 | g_assert_cmpstr (proxy_uri, ==, proxy_a.uri); |
978 | proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); |
979 | g_assert_cmpint (proxy_port, ==, proxy_a.port); |
980 | |
981 | g_object_unref (object: addr); |
982 | } |
983 | |
984 | static void |
985 | test_single_sync (gpointer fixture, |
986 | gconstpointer user_data) |
987 | { |
988 | GSocketConnection *conn; |
989 | GError *error = NULL; |
990 | gchar *uri; |
991 | |
992 | /* The alpha:// URI should be proxied via Proxy A */ |
993 | uri = g_strdup_printf (format: "alpha://127.0.0.1:%u" , server.server_port); |
994 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
995 | g_free (mem: uri); |
996 | g_assert_no_error (error); |
997 | |
998 | assert_single (conn); |
999 | |
1000 | do_echo_test (conn); |
1001 | g_object_unref (object: conn); |
1002 | } |
1003 | |
1004 | static void |
1005 | test_single_async (gpointer fixture, |
1006 | gconstpointer user_data) |
1007 | { |
1008 | GSocketConnection *conn; |
1009 | gchar *uri; |
1010 | |
1011 | /* The alpha:// URI should be proxied via Proxy A */ |
1012 | uri = g_strdup_printf (format: "alpha://127.0.0.1:%u" , server.server_port); |
1013 | conn = NULL; |
1014 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1015 | callback: async_got_conn, user_data: &conn); |
1016 | g_free (mem: uri); |
1017 | while (conn == NULL) |
1018 | g_main_context_iteration (NULL, TRUE); |
1019 | |
1020 | assert_single (conn); |
1021 | do_echo_test (conn); |
1022 | g_object_unref (object: conn); |
1023 | } |
1024 | |
1025 | static void |
1026 | assert_multiple (GSocketConnection *conn) |
1027 | { |
1028 | GSocketAddress *addr; |
1029 | const gchar *proxy_uri; |
1030 | gushort proxy_port; |
1031 | GError *error = NULL; |
1032 | |
1033 | g_assert_cmpint (g_strv_length (last_proxies), ==, 2); |
1034 | g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri); |
1035 | g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri); |
1036 | g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1037 | g_assert_no_error (proxy_b.last_error); |
1038 | |
1039 | addr = g_socket_connection_get_remote_address (connection: conn, error: &error); |
1040 | g_assert_no_error (error); |
1041 | g_assert (G_IS_PROXY_ADDRESS (addr)); |
1042 | proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr)); |
1043 | g_assert_cmpstr (proxy_uri, ==, proxy_b.uri); |
1044 | proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); |
1045 | g_assert_cmpint (proxy_port, ==, proxy_b.port); |
1046 | |
1047 | g_object_unref (object: addr); |
1048 | } |
1049 | |
1050 | static void |
1051 | test_multiple_sync (gpointer fixture, |
1052 | gconstpointer user_data) |
1053 | { |
1054 | GSocketConnection *conn; |
1055 | GError *error = NULL; |
1056 | gchar *uri; |
1057 | |
1058 | /* The beta:// URI should be proxied via Proxy B, after failing |
1059 | * via Proxy A. |
1060 | */ |
1061 | uri = g_strdup_printf (format: "beta://127.0.0.1:%u" , server.server_port); |
1062 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1063 | g_free (mem: uri); |
1064 | g_assert_no_error (error); |
1065 | |
1066 | assert_multiple (conn); |
1067 | do_echo_test (conn); |
1068 | g_object_unref (object: conn); |
1069 | } |
1070 | |
1071 | static void |
1072 | test_multiple_async (gpointer fixture, |
1073 | gconstpointer user_data) |
1074 | { |
1075 | GSocketConnection *conn; |
1076 | gchar *uri; |
1077 | |
1078 | /* The beta:// URI should be proxied via Proxy B, after failing |
1079 | * via Proxy A. |
1080 | */ |
1081 | uri = g_strdup_printf (format: "beta://127.0.0.1:%u" , server.server_port); |
1082 | conn = NULL; |
1083 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1084 | callback: async_got_conn, user_data: &conn); |
1085 | g_free (mem: uri); |
1086 | while (conn == NULL) |
1087 | g_main_context_iteration (NULL, TRUE); |
1088 | |
1089 | assert_multiple (conn); |
1090 | do_echo_test (conn); |
1091 | g_object_unref (object: conn); |
1092 | } |
1093 | |
1094 | static void |
1095 | test_dns (gpointer fixture, |
1096 | gconstpointer user_data) |
1097 | { |
1098 | GSocketConnection *conn; |
1099 | GError *error = NULL; |
1100 | gchar *uri; |
1101 | |
1102 | /* The simple:// and alpha:// URIs should fail with a DNS error, |
1103 | * but the beta:// URI should succeed, because we pass it to |
1104 | * Proxy B without trying to resolve it first |
1105 | */ |
1106 | |
1107 | /* simple */ |
1108 | uri = g_strdup_printf (format: "simple://no-such-host.xx:%u" , server.server_port); |
1109 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1110 | g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND); |
1111 | g_clear_error (err: &error); |
1112 | |
1113 | g_assert_no_error (proxy_a.last_error); |
1114 | g_assert_no_error (proxy_b.last_error); |
1115 | teardown_test (NULL, NULL); |
1116 | |
1117 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1118 | callback: async_got_error, user_data: &error); |
1119 | while (error == NULL) |
1120 | g_main_context_iteration (NULL, TRUE); |
1121 | g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND); |
1122 | g_clear_error (err: &error); |
1123 | g_free (mem: uri); |
1124 | |
1125 | g_assert_no_error (proxy_a.last_error); |
1126 | g_assert_no_error (proxy_b.last_error); |
1127 | teardown_test (NULL, NULL); |
1128 | |
1129 | /* alpha */ |
1130 | uri = g_strdup_printf (format: "alpha://no-such-host.xx:%u" , server.server_port); |
1131 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1132 | /* Since Proxy A fails, @client will try Proxy B too, which won't |
1133 | * load an alpha:// URI. |
1134 | */ |
1135 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1136 | g_clear_error (err: &error); |
1137 | |
1138 | g_assert_no_error (proxy_a.last_error); |
1139 | g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1140 | teardown_test (NULL, NULL); |
1141 | |
1142 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1143 | callback: async_got_error, user_data: &error); |
1144 | while (error == NULL) |
1145 | g_main_context_iteration (NULL, TRUE); |
1146 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1147 | g_clear_error (err: &error); |
1148 | g_free (mem: uri); |
1149 | |
1150 | g_assert_no_error (proxy_a.last_error); |
1151 | g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1152 | teardown_test (NULL, NULL); |
1153 | |
1154 | /* beta */ |
1155 | uri = g_strdup_printf (format: "beta://no-such-host.xx:%u" , server.server_port); |
1156 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1157 | g_assert_no_error (error); |
1158 | |
1159 | g_assert_no_error (proxy_a.last_error); |
1160 | g_assert_no_error (proxy_b.last_error); |
1161 | |
1162 | do_echo_test (conn); |
1163 | g_clear_object (&conn); |
1164 | teardown_test (NULL, NULL); |
1165 | |
1166 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1167 | callback: async_got_conn, user_data: &conn); |
1168 | while (conn == NULL) |
1169 | g_main_context_iteration (NULL, TRUE); |
1170 | g_free (mem: uri); |
1171 | |
1172 | g_assert_no_error (proxy_a.last_error); |
1173 | g_assert_no_error (proxy_b.last_error); |
1174 | |
1175 | do_echo_test (conn); |
1176 | g_clear_object (&conn); |
1177 | teardown_test (NULL, NULL); |
1178 | } |
1179 | |
1180 | static void |
1181 | assert_override (GSocketConnection *conn) |
1182 | { |
1183 | g_assert_cmpint (g_strv_length (last_proxies), ==, 1); |
1184 | g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri); |
1185 | |
1186 | if (conn) |
1187 | g_assert_no_error (proxy_a.last_error); |
1188 | else |
1189 | g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1190 | } |
1191 | |
1192 | static void |
1193 | test_override (gpointer fixture, |
1194 | gconstpointer user_data) |
1195 | { |
1196 | GProxyResolver *alt_resolver; |
1197 | GSocketConnection *conn; |
1198 | GError *error = NULL; |
1199 | gchar *uri; |
1200 | |
1201 | g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ()); |
1202 | alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL); |
1203 | g_socket_client_set_proxy_resolver (client, proxy_resolver: alt_resolver); |
1204 | g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver); |
1205 | |
1206 | /* Alt proxy resolver always returns Proxy A, so alpha:// should |
1207 | * succeed, and simple:// and beta:// should fail. |
1208 | */ |
1209 | |
1210 | /* simple */ |
1211 | uri = g_strdup_printf (format: "simple://127.0.0.1:%u" , server.server_port); |
1212 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1213 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1214 | g_clear_error (err: &error); |
1215 | assert_override (conn); |
1216 | teardown_test (NULL, NULL); |
1217 | |
1218 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1219 | callback: async_got_error, user_data: &error); |
1220 | while (error == NULL) |
1221 | g_main_context_iteration (NULL, TRUE); |
1222 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1223 | g_clear_error (err: &error); |
1224 | assert_override (conn); |
1225 | g_free (mem: uri); |
1226 | teardown_test (NULL, NULL); |
1227 | |
1228 | /* alpha */ |
1229 | uri = g_strdup_printf (format: "alpha://127.0.0.1:%u" , server.server_port); |
1230 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1231 | g_assert_no_error (error); |
1232 | assert_override (conn); |
1233 | do_echo_test (conn); |
1234 | g_clear_object (&conn); |
1235 | teardown_test (NULL, NULL); |
1236 | |
1237 | conn = NULL; |
1238 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1239 | callback: async_got_conn, user_data: &conn); |
1240 | while (conn == NULL) |
1241 | g_main_context_iteration (NULL, TRUE); |
1242 | assert_override (conn); |
1243 | do_echo_test (conn); |
1244 | g_clear_object (&conn); |
1245 | g_free (mem: uri); |
1246 | teardown_test (NULL, NULL); |
1247 | |
1248 | /* beta */ |
1249 | uri = g_strdup_printf (format: "beta://127.0.0.1:%u" , server.server_port); |
1250 | conn = g_socket_client_connect_to_uri (client, uri, default_port: 0, NULL, error: &error); |
1251 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1252 | g_clear_error (err: &error); |
1253 | assert_override (conn); |
1254 | teardown_test (NULL, NULL); |
1255 | |
1256 | g_socket_client_connect_to_uri_async (client, uri, default_port: 0, NULL, |
1257 | callback: async_got_error, user_data: &error); |
1258 | while (error == NULL) |
1259 | g_main_context_iteration (NULL, TRUE); |
1260 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); |
1261 | g_clear_error (err: &error); |
1262 | assert_override (conn); |
1263 | g_free (mem: uri); |
1264 | teardown_test (NULL, NULL); |
1265 | |
1266 | g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver); |
1267 | g_socket_client_set_proxy_resolver (client, NULL); |
1268 | g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ()); |
1269 | g_object_unref (object: alt_resolver); |
1270 | } |
1271 | |
1272 | static void |
1273 | assert_destination_port (GSocketAddressEnumerator *etor, |
1274 | guint16 port) |
1275 | { |
1276 | GSocketAddress *addr; |
1277 | GProxyAddress *paddr; |
1278 | GError *error = NULL; |
1279 | |
1280 | while ((addr = g_socket_address_enumerator_next (enumerator: etor, NULL, error: &error))) |
1281 | { |
1282 | g_assert_no_error (error); |
1283 | |
1284 | g_assert (G_IS_PROXY_ADDRESS (addr)); |
1285 | paddr = G_PROXY_ADDRESS (addr); |
1286 | g_assert_cmpint (g_proxy_address_get_destination_port (paddr), ==, port); |
1287 | g_object_unref (object: addr); |
1288 | } |
1289 | g_assert_no_error (error); |
1290 | } |
1291 | |
1292 | static void |
1293 | test_proxy_enumerator_ports (void) |
1294 | { |
1295 | GSocketAddressEnumerator *etor; |
1296 | |
1297 | etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, |
1298 | first_property_name: "uri" , "http://example.com/" , |
1299 | NULL); |
1300 | assert_destination_port (etor, port: 0); |
1301 | g_object_unref (object: etor); |
1302 | |
1303 | /* Have to call this to clear last_proxies so the next call to |
1304 | * g_test_proxy_resolver_lookup() won't assert. |
1305 | */ |
1306 | teardown_test (NULL, NULL); |
1307 | |
1308 | etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, |
1309 | first_property_name: "uri" , "http://example.com:8080/" , |
1310 | NULL); |
1311 | assert_destination_port (etor, port: 8080); |
1312 | g_object_unref (object: etor); |
1313 | |
1314 | teardown_test (NULL, NULL); |
1315 | |
1316 | etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, |
1317 | first_property_name: "uri" , "http://example.com/" , |
1318 | "default-port" , 80, |
1319 | NULL); |
1320 | assert_destination_port (etor, port: 80); |
1321 | g_object_unref (object: etor); |
1322 | |
1323 | teardown_test (NULL, NULL); |
1324 | |
1325 | etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, |
1326 | first_property_name: "uri" , "http://example.com:8080/" , |
1327 | "default-port" , 80, |
1328 | NULL); |
1329 | assert_destination_port (etor, port: 8080); |
1330 | g_object_unref (object: etor); |
1331 | |
1332 | teardown_test (NULL, NULL); |
1333 | } |
1334 | |
1335 | int |
1336 | main (int argc, |
1337 | char *argv[]) |
1338 | { |
1339 | GResolver *fake_resolver; |
1340 | GCancellable *cancellable; |
1341 | gint result; |
1342 | |
1343 | g_test_init (argc: &argc, argv: &argv, NULL); |
1344 | |
1345 | /* Register stuff. The dummy g_proxy_get_default_for_protocol() call |
1346 | * is to force _g_io_modules_ensure_extension_points_registered() to |
1347 | * get called, so we can then register a proxy resolver extension |
1348 | * point. |
1349 | */ |
1350 | g_proxy_get_default_for_protocol (protocol: "foo" ); |
1351 | g_test_proxy_resolver_get_type (); |
1352 | g_proxy_a_get_type (); |
1353 | g_proxy_b_get_type (); |
1354 | g_setenv (variable: "GIO_USE_PROXY_RESOLVER" , value: "test" , TRUE); |
1355 | |
1356 | fake_resolver = g_object_new (object_type: g_fake_resolver_get_type (), NULL); |
1357 | g_resolver_set_default (resolver: fake_resolver); |
1358 | |
1359 | cancellable = g_cancellable_new (); |
1360 | create_server (data: &server, cancellable); |
1361 | create_proxy (proxy: &proxy_a, proxy_protocol: 'a', destination_protocol: "alpha" , cancellable); |
1362 | create_proxy (proxy: &proxy_b, proxy_protocol: 'b', destination_protocol: "beta" , cancellable); |
1363 | |
1364 | client = g_socket_client_new (); |
1365 | g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE); |
1366 | |
1367 | g_test_add_vtable (testpath: "/proxy/direct_sync" , data_size: 0, NULL, data_setup: setup_test, data_test: test_direct_sync, data_teardown: teardown_test); |
1368 | g_test_add_vtable (testpath: "/proxy/direct_async" , data_size: 0, NULL, data_setup: setup_test, data_test: test_direct_async, data_teardown: teardown_test); |
1369 | g_test_add_vtable (testpath: "/proxy/single_sync" , data_size: 0, NULL, data_setup: setup_test, data_test: test_single_sync, data_teardown: teardown_test); |
1370 | g_test_add_vtable (testpath: "/proxy/single_async" , data_size: 0, NULL, data_setup: setup_test, data_test: test_single_async, data_teardown: teardown_test); |
1371 | g_test_add_vtable (testpath: "/proxy/multiple_sync" , data_size: 0, NULL, data_setup: setup_test, data_test: test_multiple_sync, data_teardown: teardown_test); |
1372 | g_test_add_vtable (testpath: "/proxy/multiple_async" , data_size: 0, NULL, data_setup: setup_test, data_test: test_multiple_async, data_teardown: teardown_test); |
1373 | g_test_add_vtable (testpath: "/proxy/dns" , data_size: 0, NULL, data_setup: setup_test, data_test: test_dns, data_teardown: teardown_test); |
1374 | g_test_add_vtable (testpath: "/proxy/override" , data_size: 0, NULL, data_setup: setup_test, data_test: test_override, data_teardown: teardown_test); |
1375 | g_test_add_func (testpath: "/proxy/enumerator-ports" , test_func: test_proxy_enumerator_ports); |
1376 | |
1377 | result = g_test_run(); |
1378 | |
1379 | g_object_unref (object: client); |
1380 | |
1381 | g_cancellable_cancel (cancellable); |
1382 | g_thread_join (thread: proxy_a.thread); |
1383 | g_thread_join (thread: proxy_b.thread); |
1384 | g_thread_join (thread: server.server_thread); |
1385 | |
1386 | g_object_unref (object: cancellable); |
1387 | |
1388 | return result; |
1389 | } |
1390 | |