_dbus_system_log: rename to _dbus_log
[platform/upstream/dbus.git] / test / loopback.c
1 /* Simple sanity-check for loopback through TCP and Unix sockets.
2  *
3  * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
4  * Copyright © 2010-2012 Nokia Corporation
5  * Copyright © 2015 Collabora Ltd.
6  *
7  * Permission is hereby granted, free of charge, to any person
8  * obtaining a copy of this software and associated documentation files
9  * (the "Software"), to deal in the Software without restriction,
10  * including without limitation the rights to use, copy, modify, merge,
11  * publish, distribute, sublicense, and/or sell copies of the Software,
12  * and to permit persons to whom the Software is furnished to do so,
13  * subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27
28 #include <config.h>
29
30 #include <glib.h>
31 #include <glib/gstdio.h>
32
33 #include <dbus/dbus.h>
34
35 #include <errno.h>
36 #include <string.h>
37
38 #include "test-utils-glib.h"
39
40 typedef struct {
41     TestMainContext *ctx;
42     DBusError e;
43
44     DBusServer *server;
45     DBusConnection *server_conn;
46     /* queue of DBusMessage */
47     GQueue server_messages;
48
49     DBusConnection *client_conn;
50
51     gchar *tmp_runtime_dir;
52     gchar *saved_runtime_dir;
53 } Fixture;
54
55 static void
56 assert_no_error (const DBusError *e)
57 {
58   if (G_UNLIKELY (dbus_error_is_set (e)))
59     g_error ("expected success but got error: %s: %s", e->name, e->message);
60 }
61
62 static DBusHandlerResult
63 server_message_cb (DBusConnection *server_conn,
64     DBusMessage *message,
65     void *data)
66 {
67   Fixture *f = data;
68
69   g_assert (server_conn == f->server_conn);
70   g_queue_push_tail (&f->server_messages, dbus_message_ref (message));
71
72   return DBUS_HANDLER_RESULT_HANDLED;
73 }
74
75 static void
76 new_conn_cb (DBusServer *server,
77     DBusConnection *server_conn,
78     void *data)
79 {
80   Fixture *f = data;
81   dbus_bool_t have_mem;
82
83   g_assert (f->server_conn == NULL);
84   f->server_conn = dbus_connection_ref (server_conn);
85   test_connection_setup (f->ctx, server_conn);
86
87   have_mem = dbus_connection_add_filter (server_conn,
88       server_message_cb, f, NULL);
89   g_assert (have_mem);
90 }
91
92 static void
93 setup (Fixture *f,
94     gconstpointer addr)
95 {
96   f->ctx = test_main_context_get ();
97   dbus_error_init (&f->e);
98   g_queue_init (&f->server_messages);
99
100   f->server = dbus_server_listen (addr, &f->e);
101   assert_no_error (&f->e);
102   g_assert (f->server != NULL);
103
104   dbus_server_set_new_connection_function (f->server,
105       new_conn_cb, f, NULL);
106   test_server_setup (f->ctx, f->server);
107 }
108
109 #ifdef DBUS_UNIX
110 static void
111 setup_runtime (Fixture *f,
112     gconstpointer addr)
113 {
114   char *listening_at;
115   GError *error = NULL;
116
117   /* this is chosen to be something needing escaping */
118   f->tmp_runtime_dir = g_dir_make_tmp ("dbus=daemon=test.XXXXXX", &error);
119   g_assert_no_error (error);
120
121   /* we're relying on being single-threaded for this to be safe */
122   f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
123   g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE);
124
125   setup (f, addr);
126
127   listening_at = dbus_server_get_address (f->server);
128   g_test_message ("listening at %s", listening_at);
129   g_assert (g_str_has_prefix (listening_at, "unix:path="));
130   g_assert (strstr (listening_at, "dbus%3ddaemon%3dtest.") != NULL);
131   g_assert (strstr (listening_at, "/bus,") != NULL ||
132       g_str_has_suffix (listening_at, "/bus"));
133
134   dbus_free (listening_at);
135 }
136
137 static void
138 setup_no_runtime (Fixture *f,
139     gconstpointer addr)
140 {
141   char *listening_at;
142
143   /* we're relying on being single-threaded for this to be safe */
144   f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
145   g_unsetenv ("XDG_RUNTIME_DIR");
146
147   setup (f, addr);
148
149   listening_at = dbus_server_get_address (f->server);
150   g_test_message ("listening at %s", listening_at);
151   /* we have fallen back to something in /tmp, either abstract or not */
152   g_assert (g_str_has_prefix (listening_at, "unix:"));
153   g_assert (strstr (listening_at, "=/tmp/") != NULL);
154
155   dbus_free (listening_at);
156 }
157 #endif
158
159 static void
160 test_connect (Fixture *f,
161     gconstpointer addr G_GNUC_UNUSED)
162 {
163   g_assert (f->server_conn == NULL);
164
165   f->client_conn = dbus_connection_open_private (
166       dbus_server_get_address (f->server), &f->e);
167   assert_no_error (&f->e);
168   g_assert (f->client_conn != NULL);
169   test_connection_setup (f->ctx, f->client_conn);
170
171   while (f->server_conn == NULL)
172     {
173       test_progress ('.');
174       test_main_context_iterate (f->ctx, TRUE);
175     }
176 }
177
178 static void
179 test_bad_guid (Fixture *f,
180     gconstpointer addr G_GNUC_UNUSED)
181 {
182   DBusMessage *incoming;
183   gchar *address = g_strdup (dbus_server_get_address (f->server));
184   gchar *guid;
185
186   g_test_bug ("39720");
187
188   g_assert (f->server_conn == NULL);
189
190   g_assert (strstr (address, "guid=") != NULL);
191   guid = strstr (address, "guid=");
192   g_assert_cmpuint (strlen (guid), >=, 5 + 32);
193
194   /* Change the first char of the guid to something different */
195   if (guid[5] == '0')
196     guid[5] = 'f';
197   else
198     guid[5] = '0';
199
200   f->client_conn = dbus_connection_open_private (address, &f->e);
201   assert_no_error (&f->e);
202   g_assert (f->client_conn != NULL);
203   test_connection_setup (f->ctx, f->client_conn);
204
205   while (f->server_conn == NULL)
206     {
207       test_progress ('.');
208       test_main_context_iterate (f->ctx, TRUE);
209     }
210
211   /* We get disconnected */
212
213   while (g_queue_is_empty (&f->server_messages))
214     {
215       test_progress ('.');
216       test_main_context_iterate (f->ctx, TRUE);
217     }
218
219   g_assert_cmpuint (g_queue_get_length (&f->server_messages), ==, 1);
220
221   incoming = g_queue_pop_head (&f->server_messages);
222
223   g_assert (!dbus_message_contains_unix_fds (incoming));
224   g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
225   g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
226   g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
227       DBUS_INTERFACE_LOCAL);
228   g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Disconnected");
229   g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
230   g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
231   g_assert_cmpstr (dbus_message_get_path (incoming), ==, DBUS_PATH_LOCAL);
232
233   dbus_message_unref (incoming);
234
235   g_free (address);
236 }
237
238 static void
239 test_message (Fixture *f,
240     gconstpointer addr)
241 {
242   dbus_bool_t have_mem;
243   dbus_uint32_t serial;
244   DBusMessage *outgoing, *incoming;
245
246   test_connect (f, addr);
247
248   outgoing = dbus_message_new_signal ("/com/example/Hello",
249       "com.example.Hello", "Greeting");
250   g_assert (outgoing != NULL);
251
252   have_mem = dbus_connection_send (f->client_conn, outgoing, &serial);
253   g_assert (have_mem);
254   g_assert (serial != 0);
255
256   while (g_queue_is_empty (&f->server_messages))
257     {
258       test_progress ('.');
259       test_main_context_iterate (f->ctx, TRUE);
260     }
261
262   g_assert_cmpuint (g_queue_get_length (&f->server_messages), ==, 1);
263
264   incoming = g_queue_pop_head (&f->server_messages);
265
266   g_assert (!dbus_message_contains_unix_fds (incoming));
267   g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
268   g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
269   g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
270       "com.example.Hello");
271   g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
272   g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
273   g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
274   g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
275   g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
276
277   dbus_message_unref (incoming);
278
279   dbus_message_unref (outgoing);
280 }
281
282 static void
283 teardown (Fixture *f,
284     gconstpointer addr G_GNUC_UNUSED)
285 {
286   if (f->client_conn != NULL)
287     {
288       dbus_connection_close (f->client_conn);
289       dbus_connection_unref (f->client_conn);
290       f->client_conn = NULL;
291     }
292
293   if (f->server_conn != NULL)
294     {
295       dbus_connection_close (f->server_conn);
296       dbus_connection_unref (f->server_conn);
297       f->server_conn = NULL;
298     }
299
300   if (f->server != NULL)
301     {
302       dbus_server_disconnect (f->server);
303       dbus_server_unref (f->server);
304       f->server = NULL;
305     }
306
307   test_main_context_unref (f->ctx);
308 }
309
310 #ifdef DBUS_UNIX
311 static void
312 teardown_no_runtime (Fixture *f,
313     gconstpointer addr)
314 {
315   teardown (f, addr);
316
317   /* we're relying on being single-threaded for this to be safe */
318   if (f->saved_runtime_dir != NULL)
319     g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE);
320   else
321     g_unsetenv ("XDG_RUNTIME_DIR");
322   g_free (f->saved_runtime_dir);
323 }
324
325 static void
326 teardown_runtime (Fixture *f,
327     gconstpointer addr)
328 {
329   gchar *path;
330
331   teardown (f, addr);
332
333   /* the socket may exist */
334   path = g_strdup_printf ("%s/bus", f->tmp_runtime_dir);
335   g_assert (g_remove (path) == 0 || errno == ENOENT);
336   g_free (path);
337   /* there shouldn't be anything else in there */
338   g_assert_cmpint (g_rmdir (f->tmp_runtime_dir), ==, 0);
339
340   /* we're relying on being single-threaded for this to be safe */
341   if (f->saved_runtime_dir != NULL)
342     g_setenv ("XDG_RUNTIME_DIR", f->saved_runtime_dir, TRUE);
343   else
344     g_unsetenv ("XDG_RUNTIME_DIR");
345   g_free (f->saved_runtime_dir);
346   g_free (f->tmp_runtime_dir);
347 }
348 #endif
349
350 int
351 main (int argc,
352     char **argv)
353 {
354   test_init (&argc, &argv);
355
356   g_test_add ("/connect/tcp", Fixture, "tcp:host=127.0.0.1", setup,
357       test_connect, teardown);
358   g_test_add ("/message/tcp", Fixture, "tcp:host=127.0.0.1", setup,
359       test_message, teardown);
360
361   g_test_add ("/connect/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup,
362       test_connect, teardown);
363   g_test_add ("/message/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup,
364       test_message, teardown);
365
366 #ifdef DBUS_UNIX
367   g_test_add ("/connect/unix", Fixture, "unix:tmpdir=/tmp", setup,
368       test_connect, teardown);
369   g_test_add ("/message/unix", Fixture, "unix:tmpdir=/tmp", setup,
370       test_message, teardown);
371
372   g_test_add ("/connect/unix/runtime", Fixture,
373       "unix:runtime=yes;unix:tmpdir=/tmp", setup_runtime, test_connect,
374       teardown_runtime);
375   g_test_add ("/connect/unix/no-runtime", Fixture,
376       "unix:runtime=yes;unix:tmpdir=/tmp", setup_no_runtime, test_connect,
377       teardown_no_runtime);
378 #endif
379
380   g_test_add ("/message/bad-guid", Fixture, "tcp:host=127.0.0.1", setup,
381       test_bad_guid, teardown);
382
383   return g_test_run ();
384 }