Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2018 Igalia S.L.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include <gio/gio.h>
22 : :
23 : : static void
24 : 1 : on_connected (GObject *source_object,
25 : : GAsyncResult *result,
26 : : gpointer user_data)
27 : : {
28 : : GSocketConnection *conn;
29 : 1 : GError *error = NULL;
30 : :
31 : 1 : conn = g_socket_client_connect_to_uri_finish (G_SOCKET_CLIENT (source_object), result, &error);
32 : 1 : g_assert_no_error (error);
33 : :
34 : 1 : g_object_unref (conn);
35 : 1 : g_main_loop_quit (user_data);
36 : 1 : }
37 : :
38 : : static void
39 : 1 : test_happy_eyeballs (void)
40 : : {
41 : : GSocketClient *client;
42 : : GSocketService *service;
43 : 1 : GError *error = NULL;
44 : : guint16 port;
45 : : GMainLoop *loop;
46 : :
47 : 1 : loop = g_main_loop_new (NULL, FALSE);
48 : :
49 : 1 : service = g_socket_service_new ();
50 : 1 : port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
51 : 1 : g_assert_no_error (error);
52 : 1 : g_socket_service_start (service);
53 : :
54 : : /* All of the magic here actually happens in slow-connect-preload.c
55 : : * which as you would guess is preloaded. So this is just making a
56 : : * normal connection that happens to take 600ms each time. This will
57 : : * trigger the logic to make multiple parallel connections.
58 : : */
59 : 1 : client = g_socket_client_new ();
60 : 1 : g_socket_client_connect_to_host_async (client, "localhost", port, NULL, on_connected, loop);
61 : 1 : g_main_loop_run (loop);
62 : :
63 : 1 : g_main_loop_unref (loop);
64 : 1 : g_object_unref (service);
65 : 1 : g_object_unref (client);
66 : 1 : }
67 : :
68 : : static void
69 : 2 : on_connected_cancelled (GObject *source_object,
70 : : GAsyncResult *result,
71 : : gpointer user_data)
72 : : {
73 : : GSocketConnection *conn;
74 : 2 : GError *error = NULL;
75 : :
76 : 2 : conn = g_socket_client_connect_to_uri_finish (G_SOCKET_CLIENT (source_object), result, &error);
77 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
78 : 2 : g_assert_null (conn);
79 : :
80 : 2 : g_error_free (error);
81 : 2 : g_main_loop_quit (user_data);
82 : 2 : }
83 : :
84 : : typedef struct
85 : : {
86 : : GCancellable *cancellable;
87 : : gboolean completed;
88 : : } EventCallbackData;
89 : :
90 : : static void
91 : 5 : on_event (GSocketClient *client,
92 : : GSocketClientEvent event,
93 : : GSocketConnectable *connectable,
94 : : GIOStream *connection,
95 : : EventCallbackData *data)
96 : : {
97 [ + + + + ]: 5 : if (data->cancellable && event == G_SOCKET_CLIENT_CONNECTED)
98 : : {
99 : 1 : g_cancellable_cancel (data->cancellable);
100 : : }
101 [ + + ]: 4 : else if (event == G_SOCKET_CLIENT_COMPLETE)
102 : : {
103 : 2 : data->completed = TRUE;
104 : 2 : g_assert_null (connection);
105 : : }
106 : 5 : }
107 : :
108 : : static void
109 : 1 : test_happy_eyeballs_cancel_delayed (void)
110 : : {
111 : : GSocketClient *client;
112 : : GSocketService *service;
113 : 1 : GError *error = NULL;
114 : : guint16 port;
115 : : GMainLoop *loop;
116 : 1 : EventCallbackData data = { NULL, FALSE };
117 : :
118 : : /* This just tests that cancellation works as expected, still emits the completed signal,
119 : : * and never returns a connection */
120 : :
121 : 1 : loop = g_main_loop_new (NULL, FALSE);
122 : :
123 : 1 : service = g_socket_service_new ();
124 : 1 : port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
125 : 1 : g_assert_no_error (error);
126 : 1 : g_socket_service_start (service);
127 : :
128 : 1 : client = g_socket_client_new ();
129 : 1 : data.cancellable = g_cancellable_new ();
130 : 1 : g_socket_client_connect_to_host_async (client, "localhost", port, data.cancellable, on_connected_cancelled, loop);
131 : 1 : g_signal_connect (client, "event", G_CALLBACK (on_event), &data);
132 : 1 : g_main_loop_run (loop);
133 : :
134 : 1 : g_assert_true (data.completed);
135 : 1 : g_main_loop_unref (loop);
136 : 1 : g_object_unref (service);
137 : 1 : g_object_unref (client);
138 : 1 : g_object_unref (data.cancellable);
139 : 1 : }
140 : :
141 : : static void
142 : 1 : test_happy_eyeballs_cancel_instant (void)
143 : : {
144 : : GSocketClient *client;
145 : : GSocketService *service;
146 : 1 : GError *error = NULL;
147 : : guint16 port;
148 : : GMainLoop *loop;
149 : : GCancellable *cancel;
150 : 1 : EventCallbackData data = { NULL, FALSE };
151 : :
152 : : /* This tests the same things as above, test_happy_eyeballs_cancel_delayed(), but
153 : : * with different timing since it sends an already cancelled cancellable */
154 : :
155 : 1 : loop = g_main_loop_new (NULL, FALSE);
156 : :
157 : 1 : service = g_socket_service_new ();
158 : 1 : port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
159 : 1 : g_assert_no_error (error);
160 : 1 : g_socket_service_start (service);
161 : :
162 : 1 : client = g_socket_client_new ();
163 : 1 : cancel = g_cancellable_new ();
164 : 1 : g_cancellable_cancel (cancel);
165 : 1 : g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop);
166 : 1 : g_signal_connect (client, "event", G_CALLBACK (on_event), &data);
167 : 1 : g_main_loop_run (loop);
168 : :
169 : 1 : g_assert_true (data.completed);
170 : 1 : g_main_loop_unref (loop);
171 : 1 : g_object_unref (service);
172 : 1 : g_object_unref (client);
173 : 1 : g_object_unref (cancel);
174 : 1 : }
175 : :
176 : : int
177 : 1 : main (int argc, char *argv[])
178 : : {
179 : 1 : g_test_init (&argc, &argv, NULL);
180 : :
181 : 1 : g_test_add_func ("/socket-client/happy-eyeballs/slow", test_happy_eyeballs);
182 : 1 : g_test_add_func ("/socket-client/happy-eyeballs/cancellation/instant", test_happy_eyeballs_cancel_instant);
183 : 1 : g_test_add_func ("/socket-client/happy-eyeballs/cancellation/delayed", test_happy_eyeballs_cancel_delayed);
184 : :
185 : :
186 : 1 : return g_test_run ();
187 : : }
|