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