Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
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 : : * Author: David Zeuthen <davidz@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <gio/gio.h>
26 : : #include <unistd.h>
27 : : #include <string.h>
28 : :
29 : : /* for open(2) */
30 : : #include <sys/types.h>
31 : : #include <sys/stat.h>
32 : : #include <fcntl.h>
33 : : #include <string.h>
34 : :
35 : : /* for g_unlink() */
36 : : #include <glib/gstdio.h>
37 : :
38 : : #include <gio/gnetworking.h>
39 : : #include <gio/gunixsocketaddress.h>
40 : : #include <gio/gunixfdlist.h>
41 : :
42 : : /* used in test_overflow */
43 : : #ifdef G_OS_UNIX
44 : : #include <gio/gunixconnection.h>
45 : : #include <errno.h>
46 : : #endif
47 : :
48 : : #ifdef G_OS_UNIX
49 : : static gboolean is_unix = TRUE;
50 : : #else
51 : : static gboolean is_unix = FALSE;
52 : : #endif
53 : :
54 : : static gchar *tmp_address = NULL;
55 : : static gchar *test_guid = NULL;
56 : : static GMainLoop *loop = NULL;
57 : :
58 : : static const gchar *test_interface_introspection_xml =
59 : : "<node>"
60 : : " <interface name='org.gtk.GDBus.PeerTestInterface'>"
61 : : " <method name='HelloPeer'>"
62 : : " <arg type='s' name='greeting' direction='in'/>"
63 : : " <arg type='s' name='response' direction='out'/>"
64 : : " </method>"
65 : : " <method name='EmitSignal'/>"
66 : : " <method name='EmitSignalWithNameSet'/>"
67 : : " <method name='OpenFile'>"
68 : : " <arg type='s' name='path' direction='in'/>"
69 : : " </method>"
70 : : " <signal name='PeerSignal'>"
71 : : " <arg type='s' name='a_string'/>"
72 : : " </signal>"
73 : : " <property type='s' name='PeerProperty' access='read'/>"
74 : : " </interface>"
75 : : "</node>";
76 : : static GDBusInterfaceInfo *test_interface_introspection_data = NULL;
77 : :
78 : :
79 : : #ifdef G_OS_UNIX
80 : :
81 : : /* Chosen to be big enough to overflow the socket buffer */
82 : : #define OVERFLOW_NUM_SIGNALS 5000
83 : : #define OVERFLOW_TIMEOUT_SEC 10
84 : :
85 : : static GDBusMessage *
86 : 0 : overflow_filter_func (GDBusConnection *connection,
87 : : GDBusMessage *message,
88 : : gboolean incoming,
89 : : gpointer user_data)
90 : : {
91 : 0 : gint *counter = user_data; /* (atomic) */
92 : 0 : g_atomic_int_inc (counter);
93 : 0 : return message;
94 : : }
95 : :
96 : : static gboolean
97 : 0 : overflow_on_500ms_later_func (gpointer user_data)
98 : : {
99 : 0 : g_main_loop_quit (loop);
100 : 0 : return G_SOURCE_REMOVE;
101 : : }
102 : :
103 : : static void
104 : 0 : test_overflow (void)
105 : : {
106 : : gint sv[2];
107 : : gint n;
108 : : GSocket *socket;
109 : : GSocketConnection *socket_connection;
110 : : GDBusConnection *producer, *consumer;
111 : : GError *error;
112 : : GTimer *timer;
113 : : gint n_messages_received; /* (atomic) */
114 : : gint n_messages_sent; /* (atomic) */
115 : :
116 : 0 : g_assert_cmpint (socketpair (AF_UNIX, SOCK_STREAM, 0, sv), ==, 0);
117 : :
118 : 0 : error = NULL;
119 : 0 : socket = g_socket_new_from_fd (sv[0], &error);
120 : 0 : g_assert_no_error (error);
121 : 0 : socket_connection = g_socket_connection_factory_create_connection (socket);
122 : 0 : g_assert (socket_connection != NULL);
123 : 0 : g_object_unref (socket);
124 : 0 : producer = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
125 : : NULL, /* guid */
126 : : G_DBUS_CONNECTION_FLAGS_NONE,
127 : : NULL, /* GDBusAuthObserver */
128 : : NULL, /* GCancellable */
129 : :
130 : : &error);
131 : 0 : g_dbus_connection_set_exit_on_close (producer, TRUE);
132 : 0 : g_assert_no_error (error);
133 : 0 : g_object_unref (socket_connection);
134 : 0 : g_atomic_int_set (&n_messages_sent, 0);
135 : 0 : g_dbus_connection_add_filter (producer, overflow_filter_func, (gpointer) &n_messages_sent, NULL);
136 : :
137 : : /* send enough data that we get an EAGAIN */
138 : 0 : for (n = 0; n < OVERFLOW_NUM_SIGNALS; n++)
139 : : {
140 : 0 : error = NULL;
141 : 0 : g_dbus_connection_emit_signal (producer,
142 : : NULL, /* destination */
143 : : "/org/foo/Object",
144 : : "org.foo.Interface",
145 : : "Member",
146 : : g_variant_new ("(s)", "a string"),
147 : : &error);
148 : 0 : g_assert_no_error (error);
149 : : }
150 : :
151 : : /* sleep for 0.5 sec (to allow the GDBus IO thread to fill up the
152 : : * kernel buffers) and verify that n_messages_sent <
153 : : * OVERFLOW_NUM_SIGNALS
154 : : *
155 : : * This is to verify that not all the submitted messages have been
156 : : * sent to the underlying transport.
157 : : */
158 : 0 : g_timeout_add (500, overflow_on_500ms_later_func, NULL);
159 : 0 : g_main_loop_run (loop);
160 : 0 : g_assert_cmpint (g_atomic_int_get (&n_messages_sent), <, OVERFLOW_NUM_SIGNALS);
161 : :
162 : : /* now suck it all out as a client, and add it up */
163 : 0 : socket = g_socket_new_from_fd (sv[1], &error);
164 : 0 : g_assert_no_error (error);
165 : 0 : socket_connection = g_socket_connection_factory_create_connection (socket);
166 : 0 : g_assert (socket_connection != NULL);
167 : 0 : g_object_unref (socket);
168 : 0 : consumer = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
169 : : NULL, /* guid */
170 : : G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
171 : : NULL, /* GDBusAuthObserver */
172 : : NULL, /* GCancellable */
173 : : &error);
174 : 0 : g_assert_no_error (error);
175 : 0 : g_object_unref (socket_connection);
176 : 0 : g_atomic_int_set (&n_messages_received, 0);
177 : 0 : g_dbus_connection_add_filter (consumer, overflow_filter_func, (gpointer) &n_messages_received, NULL);
178 : 0 : g_dbus_connection_start_message_processing (consumer);
179 : :
180 : 0 : timer = g_timer_new ();
181 : 0 : g_timer_start (timer);
182 : :
183 : 0 : while (g_atomic_int_get (&n_messages_received) < OVERFLOW_NUM_SIGNALS && g_timer_elapsed (timer, NULL) < OVERFLOW_TIMEOUT_SEC)
184 : 0 : g_main_context_iteration (NULL, FALSE);
185 : :
186 : 0 : g_assert_cmpint (g_atomic_int_get (&n_messages_sent), ==, OVERFLOW_NUM_SIGNALS);
187 : 0 : g_assert_cmpint (g_atomic_int_get (&n_messages_received), ==, OVERFLOW_NUM_SIGNALS);
188 : :
189 : 0 : g_timer_destroy (timer);
190 : 0 : g_object_unref (consumer);
191 : 0 : g_object_unref (producer);
192 : 0 : }
193 : : #else
194 : : static void
195 : : test_overflow (void)
196 : : {
197 : : /* TODO: test this with e.g. GWin32InputStream/GWin32OutputStream */
198 : : }
199 : : #endif
200 : :
201 : : /* ---------------------------------------------------------------------------------------------------- */
202 : :
203 : :
204 : : int
205 : 0 : main (int argc,
206 : : char *argv[])
207 : : {
208 : : gint ret;
209 : 0 : GDBusNodeInfo *introspection_data = NULL;
210 : 0 : gchar *tmpdir = NULL;
211 : :
212 : 0 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
213 : :
214 : 0 : introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
215 : 0 : g_assert (introspection_data != NULL);
216 : 0 : test_interface_introspection_data = introspection_data->interfaces[0];
217 : :
218 : 0 : test_guid = g_dbus_generate_guid ();
219 : :
220 : 0 : if (is_unix)
221 : : {
222 : 0 : tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL);
223 : 0 : tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
224 : : }
225 : : else
226 : 0 : tmp_address = g_strdup ("nonce-tcp:");
227 : :
228 : : /* all the tests rely on a shared main loop */
229 : 0 : loop = g_main_loop_new (NULL, FALSE);
230 : :
231 : 0 : g_test_add_func ("/gdbus/overflow", test_overflow);
232 : :
233 : 0 : ret = g_test_run();
234 : :
235 : 0 : g_main_loop_unref (loop);
236 : 0 : g_free (test_guid);
237 : 0 : g_dbus_node_info_unref (introspection_data);
238 : 0 : if (is_unix)
239 : 0 : g_free (tmp_address);
240 : 0 : if (tmpdir)
241 : : {
242 : 0 : g_rmdir (tmpdir);
243 : 0 : g_free (tmpdir);
244 : : }
245 : :
246 : 0 : return ret;
247 : : }
|