Strip copyright headers from examples
[platform/upstream/glib.git] / gio / tests / gdbus-example-server.c
1 #include <gio/gio.h>
2 #include <stdlib.h>
3
4 #ifdef G_OS_UNIX
5 /* For STDOUT_FILENO */
6 #include <unistd.h>
7 #endif
8
9 /* ---------------------------------------------------------------------------------------------------- */
10
11 static GDBusNodeInfo *introspection_data = NULL;
12
13 /* Introspection data for the service we are exporting */
14 static const gchar introspection_xml[] =
15   "<node>"
16   "  <interface name='org.gtk.GDBus.TestInterface'>"
17   "    <method name='HelloWorld'>"
18   "      <arg type='s' name='greeting' direction='in'/>"
19   "      <arg type='s' name='response' direction='out'/>"
20   "    </method>"
21   "    <method name='EmitSignal'>"
22   "      <arg type='d' name='speed_in_mph' direction='in'/>"
23   "    </method>"
24   "    <method name='GimmeStdout'/>"
25   "    <signal name='VelocityChanged'>"
26   "      <arg type='d' name='speed_in_mph'/>"
27   "      <arg type='s' name='speed_as_string'/>"
28   "    </signal>"
29   "    <property type='s' name='FluxCapicitorName' access='read'/>"
30   "    <property type='s' name='Title' access='readwrite'/>"
31   "    <property type='s' name='ReadingAlwaysThrowsError' access='read'/>"
32   "    <property type='s' name='WritingAlwaysThrowsError' access='readwrite'/>"
33   "    <property type='s' name='OnlyWritable' access='write'/>"
34   "    <property type='s' name='Foo' access='read'/>"
35   "    <property type='s' name='Bar' access='read'/>"
36   "  </interface>"
37   "</node>";
38
39 /* ---------------------------------------------------------------------------------------------------- */
40
41 static void
42 handle_method_call (GDBusConnection       *connection,
43                     const gchar           *sender,
44                     const gchar           *object_path,
45                     const gchar           *interface_name,
46                     const gchar           *method_name,
47                     GVariant              *parameters,
48                     GDBusMethodInvocation *invocation,
49                     gpointer               user_data)
50 {
51   if (g_strcmp0 (method_name, "HelloWorld") == 0)
52     {
53       const gchar *greeting;
54
55       g_variant_get (parameters, "(s)", &greeting);
56
57       if (g_strcmp0 (greeting, "Return Unregistered") == 0)
58         {
59           g_dbus_method_invocation_return_error (invocation,
60                                                  G_IO_ERROR,
61                                                  G_IO_ERROR_FAILED_HANDLED,
62                                                  "As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)");
63         }
64       else if (g_strcmp0 (greeting, "Return Registered") == 0)
65         {
66           g_dbus_method_invocation_return_error (invocation,
67                                                  G_DBUS_ERROR,
68                                                  G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
69                                                  "As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
70         }
71       else if (g_strcmp0 (greeting, "Return Raw") == 0)
72         {
73           g_dbus_method_invocation_return_dbus_error (invocation,
74                                                       "org.gtk.GDBus.SomeErrorName",
75                                                       "As requested, here's a raw D-Bus error");
76         }
77       else
78         {
79           gchar *response;
80           response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
81           g_dbus_method_invocation_return_value (invocation,
82                                                  g_variant_new ("(s)", response));
83           g_free (response);
84         }
85     }
86   else if (g_strcmp0 (method_name, "EmitSignal") == 0)
87     {
88       GError *local_error;
89       gdouble speed_in_mph;
90       gchar *speed_as_string;
91
92       g_variant_get (parameters, "(d)", &speed_in_mph);
93       speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph);
94
95       local_error = NULL;
96       g_dbus_connection_emit_signal (connection,
97                                      NULL,
98                                      object_path,
99                                      interface_name,
100                                      "VelocityChanged",
101                                      g_variant_new ("(ds)",
102                                                     speed_in_mph,
103                                                     speed_as_string),
104                                      &local_error);
105       g_assert_no_error (local_error);
106       g_free (speed_as_string);
107
108       g_dbus_method_invocation_return_value (invocation, NULL);
109     }
110   else if (g_strcmp0 (method_name, "GimmeStdout") == 0)
111     {
112 #ifdef G_OS_UNIX
113       if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
114         {
115           GDBusMessage *reply;
116           GUnixFDList *fd_list;
117           GError *error;
118
119           fd_list = g_unix_fd_list_new ();
120           error = NULL;
121           g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error);
122           g_assert_no_error (error);
123
124           reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
125           g_dbus_message_set_unix_fd_list (reply, fd_list);
126
127           error = NULL;
128           g_dbus_connection_send_message (connection,
129                                           reply,
130                                           NULL, /* out_serial */
131                                           &error);
132           g_assert_no_error (error);
133
134           g_object_unref (invocation);
135           g_object_unref (fd_list);
136           g_object_unref (reply);
137         }
138       else
139         {
140           g_dbus_method_invocation_return_dbus_error (invocation,
141                                                       "org.gtk.GDBus.Failed",
142                                                       "Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)");
143         }
144 #else
145       g_dbus_method_invocation_return_dbus_error (invocation,
146                                                   "org.gtk.GDBus.NotOnUnix",
147                                                   "Your OS does not support file descriptor passing");
148 #endif
149     }
150 }
151
152 static gchar *_global_title = NULL;
153
154 static gboolean swap_a_and_b = FALSE;
155
156 static GVariant *
157 handle_get_property (GDBusConnection  *connection,
158                      const gchar      *sender,
159                      const gchar      *object_path,
160                      const gchar      *interface_name,
161                      const gchar      *property_name,
162                      GError          **error,
163                      gpointer          user_data)
164 {
165   GVariant *ret;
166
167   ret = NULL;
168   if (g_strcmp0 (property_name, "FluxCapicitorName") == 0)
169     {
170       ret = g_variant_new_string ("DeLorean");
171     }
172   else if (g_strcmp0 (property_name, "Title") == 0)
173     {
174       if (_global_title == NULL)
175         _global_title = g_strdup ("Back To C!");
176       ret = g_variant_new_string (_global_title);
177     }
178   else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
179     {
180       g_set_error (error,
181                    G_IO_ERROR,
182                    G_IO_ERROR_FAILED,
183                    "Hello %s. I thought I said reading this property "
184                    "always results in an error. kthxbye",
185                    sender);
186     }
187   else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
188     {
189       ret = g_variant_new_string ("There's no home like home");
190     }
191   else if (g_strcmp0 (property_name, "Foo") == 0)
192     {
193       ret = g_variant_new_string (swap_a_and_b ? "Tock" : "Tick");
194     }
195   else if (g_strcmp0 (property_name, "Bar") == 0)
196     {
197       ret = g_variant_new_string (swap_a_and_b ? "Tick" : "Tock");
198     }
199
200   return ret;
201 }
202
203 static gboolean
204 handle_set_property (GDBusConnection  *connection,
205                      const gchar      *sender,
206                      const gchar      *object_path,
207                      const gchar      *interface_name,
208                      const gchar      *property_name,
209                      GVariant         *value,
210                      GError          **error,
211                      gpointer          user_data)
212 {
213   if (g_strcmp0 (property_name, "Title") == 0)
214     {
215       if (g_strcmp0 (_global_title, g_variant_get_string (value, NULL)) != 0)
216         {
217           GVariantBuilder *builder;
218           GError *local_error;
219
220           g_free (_global_title);
221           _global_title = g_variant_dup_string (value, NULL);
222
223           local_error = NULL;
224           builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
225           g_variant_builder_add (builder,
226                                  "{sv}",
227                                  "Title",
228                                  g_variant_new_string (_global_title));
229           g_dbus_connection_emit_signal (connection,
230                                          NULL,
231                                          object_path,
232                                          "org.freedesktop.DBus.Properties",
233                                          "PropertiesChanged",
234                                          g_variant_new ("(sa{sv})",
235                                                         interface_name,
236                                                         builder),
237                                          &local_error);
238           g_assert_no_error (local_error);
239         }
240     }
241   else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
242     {
243       /* do nothing - they can't read it after all! */
244     }
245   else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
246     {
247       g_set_error (error,
248                    G_IO_ERROR,
249                    G_IO_ERROR_FAILED,
250                    "Hello AGAIN %s. I thought I said writing this property "
251                    "always results in an error. kthxbye",
252                    sender);
253     }
254
255   return *error == NULL;
256 }
257
258
259 /* for now */
260 static const GDBusInterfaceVTable interface_vtable =
261 {
262   handle_method_call,
263   handle_get_property,
264   handle_set_property
265 };
266
267 /* ---------------------------------------------------------------------------------------------------- */
268
269 static gboolean
270 on_timeout_cb (gpointer user_data)
271 {
272   GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
273   GVariantBuilder *builder;
274   GError *error;
275
276   swap_a_and_b = !swap_a_and_b;
277
278   error = NULL;
279   builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
280   g_variant_builder_add (builder,
281                          "{sv}",
282                          "Foo",
283                          g_variant_new_string (swap_a_and_b ? "Tock" : "Tick"));
284   g_variant_builder_add (builder,
285                          "{sv}",
286                          "Bar",
287                          g_variant_new_string (swap_a_and_b ? "Tick" : "Tock"));
288   g_dbus_connection_emit_signal (connection,
289                                  NULL,
290                                  "/org/gtk/GDBus/TestObject",
291                                  "org.freedesktop.DBus.Properties",
292                                  "PropertiesChanged",
293                                  g_variant_new ("(sa{sv})",
294                                                 "org.gtk.GDBus.TestInterface",
295                                                 builder),
296                                  &error);
297   g_assert_no_error (error);
298
299
300   return TRUE;
301 }
302
303 /* ---------------------------------------------------------------------------------------------------- */
304
305 static void
306 on_bus_acquired (GDBusConnection *connection,
307                  const gchar     *name,
308                  gpointer         user_data)
309 {
310   guint registration_id;
311
312   registration_id = g_dbus_connection_register_object (connection,
313                                                        "/org/gtk/GDBus/TestObject",
314                                                        "org.gtk.GDBus.TestInterface",
315                                                        introspection_data->interfaces[0],
316                                                        &interface_vtable,
317                                                        NULL,  /* user_data */
318                                                        NULL,  /* user_data_free_func */
319                                                        NULL); /* GError** */
320   g_assert (registration_id > 0);
321
322   /* swap value of properties Foo and Bar every two seconds */
323   g_timeout_add_seconds (2,
324                          on_timeout_cb,
325                          connection);
326 }
327
328 static void
329 on_name_acquired (GDBusConnection *connection,
330                   const gchar     *name,
331                   gpointer         user_data)
332 {
333 }
334
335 static void
336 on_name_lost (GDBusConnection *connection,
337               const gchar     *name,
338               gpointer         user_data)
339 {
340   exit (1);
341 }
342
343 int
344 main (int argc, char *argv[])
345 {
346   guint owner_id;
347   GMainLoop *loop;
348
349   g_type_init ();
350
351   /* We are lazy here - we don't want to manually provide
352    * the introspection data structures - so we just build
353    * them from XML.
354    */
355   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
356   g_assert (introspection_data != NULL);
357
358   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
359                              "org.gtk.GDBus.TestServer",
360                              G_BUS_NAME_OWNER_FLAGS_NONE,
361                              on_bus_acquired,
362                              on_name_acquired,
363                              on_name_lost,
364                              NULL,
365                              NULL);
366
367   loop = g_main_loop_new (NULL, FALSE);
368   g_main_loop_run (loop);
369
370   g_bus_unown_name (owner_id);
371
372   g_dbus_node_info_unref (introspection_data);
373
374   return 0;
375 }