e8da6da8832d851421997878f4a40554e485faa8
[platform/upstream/glib.git] / gio / tests / gdbus-example-subtree.c
1 /*
2  * Copyright © 2010 Red Hat, Inc.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; either version 2 of the licence or (at
7  * your option) any later version.
8  *
9  * See the included COPYING file for more information.
10  *
11  * Author: David Zeuthen <davidz@redhat.com>
12  */
13
14 #include <gio/gio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 /* ---------------------------------------------------------------------------------------------------- */
19
20 static GDBusNodeInfo *introspection_data = NULL;
21 static const GDBusInterfaceInfo *manager_interface_info = NULL;
22 static const GDBusInterfaceInfo *block_interface_info = NULL;
23 static const GDBusInterfaceInfo *partition_interface_info = NULL;
24
25 /* Introspection data for the service we are exporting */
26 static const gchar introspection_xml[] =
27   "<node>"
28   "  <interface name='org.gtk.GDBus.Example.Manager'>"
29   "    <method name='Hello'>"
30   "      <arg type='s' name='greeting' direction='in'/>"
31   "      <arg type='s' name='response' direction='out'/>"
32   "    </method>"
33   "  </interface>"
34   "  <interface name='org.gtk.GDBus.Example.Block'>"
35   "    <method name='Hello'>"
36   "      <arg type='s' name='greeting' direction='in'/>"
37   "      <arg type='s' name='response' direction='out'/>"
38   "    </method>"
39   "    <property type='i' name='Major' access='read'/>"
40   "    <property type='i' name='Minor' access='read'/>"
41   "    <property type='s' name='Notes' access='readwrite'/>"
42   "  </interface>"
43   "  <interface name='org.gtk.GDBus.Example.Partition'>"
44   "    <method name='Hello'>"
45   "      <arg type='s' name='greeting' direction='in'/>"
46   "      <arg type='s' name='response' direction='out'/>"
47   "    </method>"
48   "    <property type='i' name='PartitionNumber' access='read'/>"
49   "    <property type='s' name='Notes' access='readwrite'/>"
50   "  </interface>"
51   "</node>";
52
53 /* ---------------------------------------------------------------------------------------------------- */
54
55 static void
56 manager_method_call (GDBusConnection       *connection,
57                      const gchar           *sender,
58                      const gchar           *object_path,
59                      const gchar           *interface_name,
60                      const gchar           *method_name,
61                      GVariant              *parameters,
62                      GDBusMethodInvocation *invocation,
63                      gpointer               user_data)
64 {
65   const gchar *greeting;
66   gchar *response;
67
68   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Manager");
69   g_assert_cmpstr (method_name, ==, "Hello");
70
71   g_variant_get (parameters, "(s)", &greeting);
72
73   response = g_strdup_printf ("Method %s.%s with user_data `%s' on object path %s called with arg '%s'",
74                               interface_name,
75                               method_name,
76                               (const gchar *) user_data,
77                               object_path,
78                               greeting);
79   g_dbus_method_invocation_return_value (invocation,
80                                          g_variant_new ("(s)", response));
81   g_free (response);
82 }
83
84 const GDBusInterfaceVTable manager_vtable =
85 {
86   manager_method_call,
87   NULL,                 /* get_property */
88   NULL                  /* set_property */
89 };
90
91 /* ---------------------------------------------------------------------------------------------------- */
92
93 static void
94 block_method_call (GDBusConnection       *connection,
95                    const gchar           *sender,
96                    const gchar           *object_path,
97                    const gchar           *interface_name,
98                    const gchar           *method_name,
99                    GVariant              *parameters,
100                    GDBusMethodInvocation *invocation,
101                    gpointer               user_data)
102 {
103   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Block");
104
105   if (g_strcmp0 (method_name, "Hello") == 0)
106     {
107       const gchar *greeting;
108       gchar *response;
109
110       g_variant_get (parameters, "(s)", &greeting);
111
112       response = g_strdup_printf ("Method %s.%s with user_data `%s' on object path %s called with arg '%s'",
113                                   interface_name,
114                                   method_name,
115                                   (const gchar *) user_data,
116                                   object_path,
117                                   greeting);
118       g_dbus_method_invocation_return_value (invocation,
119                                              g_variant_new ("(s)", response));
120       g_free (response);
121     }
122   else if (g_strcmp0 (method_name, "DoStuff") == 0)
123     {
124       g_dbus_method_invocation_return_dbus_error (invocation,
125                                                   "org.gtk.GDBus.TestSubtree.Error.Failed",
126                                                   "This method intentionally always fails");
127     }
128   else
129     {
130       g_assert_not_reached ();
131     }
132 }
133
134 static GVariant *
135 block_get_property (GDBusConnection  *connection,
136                     const gchar      *sender,
137                     const gchar      *object_path,
138                     const gchar      *interface_name,
139                     const gchar      *property_name,
140                     GError          **error,
141                     gpointer          user_data)
142 {
143   GVariant *ret;
144   const gchar *node;
145   gint major;
146   gint minor;
147
148   node = strrchr (object_path, '/') + 1;
149   if (g_str_has_prefix (node, "sda"))
150     major = 8;
151   else
152     major = 9;
153   if (strlen (node) == 4)
154     minor = node[3] - '0';
155   else
156     minor = 0;
157
158   ret = NULL;
159   if (g_strcmp0 (property_name, "Major") == 0)
160     {
161       ret = g_variant_new_int32 (major);
162     }
163   else if (g_strcmp0 (property_name, "Minor") == 0)
164     {
165       ret = g_variant_new_int32 (minor);
166     }
167   else if (g_strcmp0 (property_name, "Notes") == 0)
168     {
169       g_set_error (error,
170                    G_IO_ERROR,
171                    G_IO_ERROR_FAILED,
172                    "Hello %s. I thought I said reading this property "
173                    "always results in an error. kthxbye",
174                    sender);
175     }
176   else
177     {
178       g_assert_not_reached ();
179     }
180
181   return ret;
182 }
183
184 static gboolean
185 block_set_property (GDBusConnection  *connection,
186                     const gchar      *sender,
187                     const gchar      *object_path,
188                     const gchar      *interface_name,
189                     const gchar      *property_name,
190                     GVariant         *value,
191                     GError          **error,
192                     gpointer          user_data)
193 {
194   /* TODO */
195   g_assert_not_reached ();
196 }
197
198 const GDBusInterfaceVTable block_vtable =
199 {
200   block_method_call,
201   block_get_property,
202   block_set_property,
203 };
204
205 /* ---------------------------------------------------------------------------------------------------- */
206
207 static void
208 partition_method_call (GDBusConnection       *connection,
209                        const gchar           *sender,
210                        const gchar           *object_path,
211                        const gchar           *interface_name,
212                        const gchar           *method_name,
213                        GVariant              *parameters,
214                        GDBusMethodInvocation *invocation,
215                        gpointer               user_data)
216 {
217   const gchar *greeting;
218   gchar *response;
219
220   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Partition");
221   g_assert_cmpstr (method_name, ==, "Hello");
222
223   g_variant_get (parameters, "(s)", &greeting);
224
225   response = g_strdup_printf ("Method %s.%s with user_data `%s' on object path %s called with arg '%s'",
226                               interface_name,
227                               method_name,
228                               (const gchar *) user_data,
229                               object_path,
230                               greeting);
231   g_dbus_method_invocation_return_value (invocation,
232                                          g_variant_new ("(s)", response));
233   g_free (response);
234 }
235
236 const GDBusInterfaceVTable partition_vtable =
237 {
238   partition_method_call,
239   //partition_get_property,
240   //partition_set_property
241 };
242
243 /* ---------------------------------------------------------------------------------------------------- */
244
245 static gchar **
246 subtree_enumerate (GDBusConnection       *connection,
247                    const gchar           *sender,
248                    const gchar           *object_path,
249                    gpointer               user_data)
250 {
251   gchar **nodes;
252   GPtrArray *p;
253
254   p = g_ptr_array_new ();
255   g_ptr_array_add (p, g_strdup ("sda"));
256   g_ptr_array_add (p, g_strdup ("sda1"));
257   g_ptr_array_add (p, g_strdup ("sda2"));
258   g_ptr_array_add (p, g_strdup ("sda3"));
259   g_ptr_array_add (p, g_strdup ("sdb"));
260   g_ptr_array_add (p, g_strdup ("sdb1"));
261   g_ptr_array_add (p, g_strdup ("sdc"));
262   g_ptr_array_add (p, g_strdup ("sdc1"));
263   g_ptr_array_add (p, NULL);
264   nodes = (gchar **) g_ptr_array_free (p, FALSE);
265
266   return nodes;
267 }
268
269 static GPtrArray *
270 subtree_introspect (GDBusConnection       *connection,
271                     const gchar           *sender,
272                     const gchar           *object_path,
273                     const gchar           *node,
274                     gpointer               user_data)
275 {
276   GPtrArray *p;
277
278   p = g_ptr_array_new ();
279   if (g_strcmp0 (node, "/") == 0)
280     {
281       g_ptr_array_add (p, (gpointer) manager_interface_info);
282     }
283   else
284     {
285       g_ptr_array_add (p, (gpointer) block_interface_info);
286       if (strlen (node) == 4)
287         g_ptr_array_add (p, (gpointer) partition_interface_info);
288     }
289
290   return p;
291 }
292
293 static const GDBusInterfaceVTable *
294 subtree_dispatch (GDBusConnection             *connection,
295                   const gchar                 *sender,
296                   const gchar                 *object_path,
297                   const gchar                 *interface_name,
298                   const gchar                 *node,
299                   gpointer                    *out_user_data,
300                   gpointer                     user_data)
301 {
302   const GDBusInterfaceVTable *vtable_to_return;
303   gpointer user_data_to_return;
304
305   if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Manager") == 0)
306     {
307       user_data_to_return = "The Root";
308       vtable_to_return = &manager_vtable;
309     }
310   else
311     {
312       if (strlen (node) == 4)
313         user_data_to_return = "A partition";
314       else
315         user_data_to_return = "A block device";
316
317       if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Block") == 0)
318         vtable_to_return = &block_vtable;
319       else if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Partition") == 0)
320         vtable_to_return = &partition_vtable;
321       else
322         g_assert_not_reached ();
323     }
324
325   *out_user_data = user_data_to_return;
326
327   return vtable_to_return;
328 }
329
330 const GDBusSubtreeVTable subtree_vtable =
331 {
332   subtree_enumerate,
333   subtree_introspect,
334   subtree_dispatch
335 };
336
337 /* ---------------------------------------------------------------------------------------------------- */
338
339 static void
340 on_bus_acquired (GDBusConnection *connection,
341                  const gchar     *name,
342                  gpointer         user_data)
343 {
344   guint registration_id;
345
346   registration_id = g_dbus_connection_register_subtree (connection,
347                                                         "/org/gtk/GDBus/TestSubtree/Devices",
348                                                         &subtree_vtable,
349                                                         G_DBUS_SUBTREE_FLAGS_NONE,
350                                                         NULL,  /* user_data */
351                                                         NULL,  /* user_data_free_func */
352                                                         NULL); /* GError** */
353   g_assert (registration_id > 0);
354 }
355
356 static void
357 on_name_acquired (GDBusConnection *connection,
358                   const gchar     *name,
359                   gpointer         user_data)
360 {
361 }
362
363 static void
364 on_name_lost (GDBusConnection *connection,
365               const gchar     *name,
366               gpointer         user_data)
367 {
368   exit (1);
369 }
370
371 int
372 main (int argc, char *argv[])
373 {
374   guint owner_id;
375   GMainLoop *loop;
376
377   g_type_init ();
378
379   /* We are lazy here - we don't want to manually provide
380    * the introspection data structures - so we just build
381    * them from XML.
382    */
383   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
384   g_assert (introspection_data != NULL);
385
386   manager_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Manager");
387   block_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Block");
388   partition_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Partition");
389   g_assert (manager_interface_info != NULL);
390   g_assert (block_interface_info != NULL);
391   g_assert (partition_interface_info != NULL);
392
393   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
394                              "org.gtk.GDBus.TestSubtree",
395                              G_BUS_NAME_OWNER_FLAGS_NONE,
396                              on_bus_acquired,
397                              on_name_acquired,
398                              on_name_lost,
399                              NULL,
400                              NULL);
401
402   loop = g_main_loop_new (NULL, FALSE);
403   g_main_loop_run (loop);
404
405   g_bus_unown_name (owner_id);
406
407   g_dbus_node_info_unref (introspection_data);
408
409   return 0;
410 }