cf8853f8a83347c882ce85966db6cc1d9a7cc3a6
[platform/upstream/glib.git] / gio / tests / gdbus-non-socket.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2010 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 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include <gio/gio.h>
24 #include <unistd.h>
25 #include <string.h>
26
27 #include <stdlib.h>
28
29 #ifdef G_OS_UNIX
30 #include <gio/gunixinputstream.h>
31 #include <gio/gunixoutputstream.h>
32 #include <gio/gunixconnection.h>
33 #endif
34
35 #include "gdbus-tests.h"
36
37 static GMainLoop *loop = NULL;
38
39 /* ---------------------------------------------------------------------------------------------------- */
40 #ifdef G_OS_UNIX
41
42 #define MY_TYPE_IO_STREAM  (my_io_stream_get_type ())
43 #define MY_IO_STREAM(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), MY_TYPE_IO_STREAM, MyIOStream))
44 #define MY_IS_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MY_TYPE_IO_STREAM))
45
46 typedef struct
47 {
48   GIOStream parent_instance;
49   GInputStream *input_stream;
50   GOutputStream *output_stream;
51 } MyIOStream;
52
53 typedef struct
54 {
55   GIOStreamClass parent_class;
56 } MyIOStreamClass;
57
58 static GType my_io_stream_get_type (void) G_GNUC_CONST;
59
60 G_DEFINE_TYPE (MyIOStream, my_io_stream, G_TYPE_IO_STREAM);
61
62 static void
63 my_io_stream_finalize (GObject *object)
64 {
65   MyIOStream *stream = MY_IO_STREAM (object);
66   g_object_unref (stream->input_stream);
67   g_object_unref (stream->output_stream);
68   G_OBJECT_CLASS (my_io_stream_parent_class)->finalize (object);
69 }
70
71 static void
72 my_io_stream_init (MyIOStream *stream)
73 {
74 }
75
76 static GInputStream *
77 my_io_stream_get_input_stream (GIOStream *_stream)
78 {
79   MyIOStream *stream = MY_IO_STREAM (_stream);
80   return stream->input_stream;
81 }
82
83 static GOutputStream *
84 my_io_stream_get_output_stream (GIOStream *_stream)
85 {
86   MyIOStream *stream = MY_IO_STREAM (_stream);
87   return stream->output_stream;
88 }
89
90 static void
91 my_io_stream_class_init (MyIOStreamClass *klass)
92 {
93   GObjectClass *gobject_class;
94   GIOStreamClass *giostream_class;
95
96   gobject_class = G_OBJECT_CLASS (klass);
97   gobject_class->finalize = my_io_stream_finalize;
98
99   giostream_class = G_IO_STREAM_CLASS (klass);
100   giostream_class->get_input_stream  = my_io_stream_get_input_stream;
101   giostream_class->get_output_stream = my_io_stream_get_output_stream;
102 }
103
104 static GIOStream *
105 my_io_stream_new (GInputStream  *input_stream,
106                   GOutputStream *output_stream)
107 {
108   MyIOStream *stream;
109   g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL);
110   g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), NULL);
111   stream = MY_IO_STREAM (g_object_new (MY_TYPE_IO_STREAM, NULL));
112   stream->input_stream = g_object_ref (input_stream);
113   stream->output_stream = g_object_ref (output_stream);
114   return G_IO_STREAM (stream);
115 }
116
117 static GIOStream *
118 my_io_stream_new_for_fds (gint fd_in, gint fd_out)
119 {
120   GIOStream *stream;
121   GInputStream  *input_stream;
122   GOutputStream *output_stream;
123
124   input_stream = g_unix_input_stream_new (fd_in, TRUE);
125   output_stream = g_unix_output_stream_new (fd_out, TRUE);
126   stream = my_io_stream_new (input_stream, output_stream);
127   g_object_unref (input_stream);
128   g_object_unref (output_stream);
129   return stream;
130 }
131
132 /* ---------------------------------------------------------------------------------------------------- */
133
134 static const GDBusArgInfo pokee_method_poke_out_arg0 = {
135   -1,   /* ref_count */
136   "result",
137   "s",
138   NULL  /* annotations */
139 };
140
141 static const GDBusArgInfo *pokee_method_poke_out_args[2] = {
142   &pokee_method_poke_out_arg0,
143   NULL,
144 };
145
146 static const GDBusArgInfo pokee_method_poke_in_arg0 = {
147   -1,   /* ref_count */
148   "value",
149   "s",
150   NULL  /* annotations */
151 };
152
153 static const GDBusArgInfo *pokee_method_poke_in_args[2] = {
154   &pokee_method_poke_in_arg0,
155   NULL,
156 };
157
158 static const GDBusMethodInfo pokee_method_poke = {
159   -1,   /* ref_count */
160   "Poke",
161   (GDBusArgInfo**) pokee_method_poke_in_args,
162   (GDBusArgInfo**) pokee_method_poke_out_args,
163   NULL  /* annotations */
164 };
165
166 static const GDBusMethodInfo *pokee_methods[2] = {
167   &pokee_method_poke,
168   NULL
169 };
170
171 static const GDBusInterfaceInfo pokee_object_info = {
172   -1,  /* ref_count */
173   "org.gtk.GDBus.Pokee",
174   (GDBusMethodInfo**) pokee_methods,
175   NULL, /* signals */
176   NULL, /* properties */
177   NULL  /* annotations */
178 };
179
180 static void
181 pokee_method_call (GDBusConnection       *connection,
182                    const gchar           *sender,
183                    const gchar           *object_path,
184                    const gchar           *interface_name,
185                    const gchar           *method_name,
186                    GVariant              *parameters,
187                    GDBusMethodInvocation *invocation,
188                    gpointer               user_data)
189 {
190   const gchar *str;
191   gchar *ret;
192
193   g_assert_cmpstr (method_name, ==, "Poke");
194
195   g_variant_get (parameters, "(&s)", &str);
196   ret = g_strdup_printf ("You poked me with: `%s'", str);
197   g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", ret));
198   g_free (ret);
199 }
200
201 static const GDBusInterfaceVTable pokee_vtable = {
202   pokee_method_call,
203   NULL, /* get_property */
204   NULL  /* set_property */
205 };
206
207 static void
208 test_non_socket (void)
209 {
210   gint in_pipes[2];
211   gint out_pipes[2];
212   GIOStream *stream;
213   GDBusConnection *connection;
214   GError *error;
215   gchar *guid;
216   pid_t child;
217   gint read_fd;
218   gint write_fd;
219   GVariant *ret;
220   const gchar *str;
221
222   g_assert_cmpint (pipe (in_pipes), ==, 0);
223   g_assert_cmpint (pipe (out_pipes), ==, 0);
224
225   switch ((child = fork ()))
226     {
227     case -1:
228       g_assert_not_reached ();
229       break;
230
231     case 0:
232       /* child */
233       read_fd  =  in_pipes[0];
234       write_fd = out_pipes[1];
235       g_assert_cmpint (close ( in_pipes[1]), ==, 0); /* close unused write end */
236       g_assert_cmpint (close (out_pipes[0]), ==, 0); /* close unused read end */
237       stream = my_io_stream_new_for_fds (read_fd, write_fd);
238       guid = g_dbus_generate_guid ();
239       error = NULL;
240       /* We need to delay message processing to avoid the race
241        * described in
242        *
243        *  https://bugzilla.gnome.org/show_bug.cgi?id=627188
244        *
245        * This is because (early) dispatching is done on the IO thread
246        * (method_call() isn't called until we're in the right thread
247        * though) so in rare cases the parent sends the message before
248        * we (the child) register the object
249        */
250       connection = g_dbus_connection_new_sync (stream,
251                                                guid,
252                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER |
253                                                G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
254                                                NULL, /* GDBusAuthObserver */
255                                                NULL,
256                                                &error);
257       g_free (guid);
258       g_assert_no_error (error);
259       g_object_unref (stream);
260
261       /* make sure we exit along with the parent */
262       g_dbus_connection_set_exit_on_close (connection, TRUE);
263
264       error = NULL;
265       g_dbus_connection_register_object (connection,
266                                          "/pokee",
267                                          (GDBusInterfaceInfo *) &pokee_object_info,
268                                          &pokee_vtable,
269                                          NULL, /* user_data */
270                                          NULL, /* user_data_free_func */
271                                          &error);
272       g_assert_no_error (error);
273
274       /* and now start message processing */
275       g_dbus_connection_start_message_processing (connection);
276
277       g_main_loop_run (loop);
278
279       g_assert_not_reached ();
280       break;
281
282     default:
283       /* parent continues below */
284       break;
285     }
286
287   /* parent */
288   read_fd  = out_pipes[0];
289   write_fd =  in_pipes[1];
290   g_assert_cmpint (close (out_pipes[1]), ==, 0); /* close unused write end */
291   g_assert_cmpint (close ( in_pipes[0]), ==, 0); /* close unused read end */
292   stream = my_io_stream_new_for_fds (read_fd, write_fd);
293   error = NULL;
294   connection = g_dbus_connection_new_sync (stream,
295                                            NULL, /* guid */
296                                            G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
297                                            NULL, /* GDBusAuthObserver */
298                                            NULL,
299                                            &error);
300   g_assert_no_error (error);
301   g_object_unref (stream);
302
303   /* poke the child */
304   error = NULL;
305   ret = g_dbus_connection_call_sync (connection,
306                                      NULL, /* name */
307                                      "/pokee",
308                                      "org.gtk.GDBus.Pokee",
309                                      "Poke",
310                                      g_variant_new ("(s)", "I am the POKER!"),
311                                      G_VARIANT_TYPE ("(s)"), /* return type */
312                                      G_DBUS_CALL_FLAGS_NONE,
313                                      -1,
314                                      NULL, /* cancellable */
315                                      &error);
316   g_assert_no_error (error);
317   g_variant_get (ret, "(&s)", &str);
318   g_assert_cmpstr (str, ==, "You poked me with: `I am the POKER!'");
319   g_variant_unref (ret);
320
321   g_object_unref (connection);
322
323   g_assert_cmpint (kill (child, SIGTERM), ==, 0);
324 }
325
326 #else /* G_OS_UNIX */
327
328 static void
329 test_non_socket (void)
330 {
331   /* TODO: test this with e.g. GWin32InputStream/GWin32OutputStream */
332 }
333 #endif
334
335 /* ---------------------------------------------------------------------------------------------------- */
336
337 int
338 main (int   argc,
339       char *argv[])
340 {
341   gint ret;
342
343   g_type_init ();
344   g_thread_init (NULL);
345   g_test_init (&argc, &argv, NULL);
346
347   /* all the tests rely on a shared main loop */
348   loop = g_main_loop_new (NULL, FALSE);
349
350   g_test_add_func ("/gdbus/non-socket", test_non_socket);
351
352   ret = g_test_run();
353
354   g_main_loop_unref (loop);
355
356   return ret;
357 }