gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / tests / gdbus-example-export.c
1 #include <gio/gio.h>
2 #include <stdlib.h>
3
4 /* ---------------------------------------------------------------------------------------------------- */
5
6 /* The object we want to export */
7 typedef struct _MyObjectClass MyObjectClass;
8 typedef struct _MyObject MyObject;
9
10 struct _MyObjectClass
11 {
12   GObjectClass parent_class;
13 };
14
15 struct _MyObject
16 {
17   GObject parent_instance;
18
19   gint count;
20   gchar *name;
21 };
22
23 enum
24 {
25   PROP_0,
26   PROP_COUNT,
27   PROP_NAME
28 };
29
30 static GType my_object_get_type (void);
31 G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT)
32
33 static void
34 my_object_finalize (GObject *object)
35 {
36   MyObject *myobj = (MyObject*)object;
37
38   g_free (myobj->name);
39
40   G_OBJECT_CLASS (my_object_parent_class)->finalize (object);
41 }
42
43 static void
44 my_object_init (MyObject *object)
45 {
46   object->count = 0;
47   object->name = NULL;
48 }
49
50 static void
51 my_object_get_property (GObject    *object,
52                         guint       prop_id,
53                         GValue     *value,
54                         GParamSpec *pspec)
55 {
56   MyObject *myobj = (MyObject*)object;
57
58   switch (prop_id)
59     {
60     case PROP_COUNT:
61       g_value_set_int (value, myobj->count);
62       break;
63
64     case PROP_NAME:
65       g_value_set_string (value, myobj->name);
66       break;
67
68     default:
69       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
70     }
71 }
72
73 static void
74 my_object_set_property (GObject      *object,
75                         guint         prop_id,
76                         const GValue *value,
77                         GParamSpec   *pspec)
78 {
79   MyObject *myobj = (MyObject*)object;
80
81   switch (prop_id)
82     {
83     case PROP_COUNT:
84       myobj->count = g_value_get_int (value);
85       break;
86
87     case PROP_NAME:
88       g_free (myobj->name);
89       myobj->name = g_value_dup_string (value);
90       break;
91
92     default:
93       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
94     }
95 }
96
97 static void
98 my_object_class_init (MyObjectClass *class)
99 {
100   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
101
102   gobject_class->finalize = my_object_finalize;
103   gobject_class->set_property = my_object_set_property;
104   gobject_class->get_property = my_object_get_property;
105
106   g_object_class_install_property (gobject_class,
107                                    PROP_COUNT,
108                                    g_param_spec_int ("count",
109                                                      "Count",
110                                                      "Count",
111                                                      0, 99999, 0,
112                                                      G_PARAM_READWRITE));
113
114   g_object_class_install_property (gobject_class,
115                                    PROP_NAME,
116                                    g_param_spec_string ("name",
117                                                         "Name",
118                                                         "Name",
119                                                         NULL,
120                                                         G_PARAM_READWRITE));
121 }
122
123 /* A method that we want to export */
124 static void
125 my_object_change_count (MyObject *myobj,
126                         gint      change)
127 {
128   myobj->count = 2 * myobj->count + change;
129
130   g_object_notify (G_OBJECT (myobj), "count");
131 }
132
133 /* ---------------------------------------------------------------------------------------------------- */
134
135 static GDBusNodeInfo *introspection_data = NULL;
136
137 /* Introspection data for the service we are exporting */
138 static const gchar introspection_xml[] =
139   "<node>"
140   "  <interface name='org.myorg.MyObject'>"
141   "    <method name='ChangeCount'>"
142   "      <arg type='i' name='change' direction='in'/>"
143   "    </method>"
144   "    <property type='i' name='Count' access='read'/>"
145   "    <property type='s' name='Name' access='readwrite'/>"
146   "  </interface>"
147   "</node>";
148
149
150 static void
151 handle_method_call (GDBusConnection       *connection,
152                     const gchar           *sender,
153                     const gchar           *object_path,
154                     const gchar           *interface_name,
155                     const gchar           *method_name,
156                     GVariant              *parameters,
157                     GDBusMethodInvocation *invocation,
158                     gpointer               user_data)
159 {
160   MyObject *myobj = user_data;
161
162   if (g_strcmp0 (method_name, "ChangeCount") == 0)
163     {
164       gint change;
165       g_variant_get (parameters, "(i)", &change);
166
167       my_object_change_count (myobj, change);
168
169       g_dbus_method_invocation_return_value (invocation, NULL);
170     }
171 }
172
173 static GVariant *
174 handle_get_property (GDBusConnection  *connection,
175                      const gchar      *sender,
176                      const gchar      *object_path,
177                      const gchar      *interface_name,
178                      const gchar      *property_name,
179                      GError          **error,
180                      gpointer          user_data)
181 {
182   GVariant *ret;
183   MyObject *myobj = user_data;
184
185   ret = NULL;
186   if (g_strcmp0 (property_name, "Count") == 0)
187     {
188       ret = g_variant_new_int32 (myobj->count);
189     }
190   else if (g_strcmp0 (property_name, "Name") == 0)
191     {
192       ret = g_variant_new_string (myobj->name ? myobj->name : "");
193     }
194
195   return ret;
196 }
197
198 static gboolean
199 handle_set_property (GDBusConnection  *connection,
200                      const gchar      *sender,
201                      const gchar      *object_path,
202                      const gchar      *interface_name,
203                      const gchar      *property_name,
204                      GVariant         *value,
205                      GError          **error,
206                      gpointer          user_data)
207 {
208   MyObject *myobj = user_data;
209
210   if (g_strcmp0 (property_name, "Count") == 0)
211     {
212       g_object_set (myobj, "count", g_variant_get_int32 (value), NULL);
213     }
214   else if (g_strcmp0 (property_name, "Name") == 0)
215     {
216       g_object_set (myobj, "name", g_variant_get_string (value, NULL), NULL);
217     }
218
219   return TRUE;
220 }
221
222
223 /* for now */
224 static const GDBusInterfaceVTable interface_vtable =
225 {
226   handle_method_call,
227   handle_get_property,
228   handle_set_property,
229   { 0 }
230 };
231
232 static void
233 send_property_change (GObject         *obj,
234                       GParamSpec      *pspec,
235                       GDBusConnection *connection)
236 {
237   GVariantBuilder *builder;
238   GVariantBuilder *invalidated_builder;
239   MyObject *myobj = (MyObject *)obj;
240
241   builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
242   invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
243
244   if (g_strcmp0 (pspec->name, "count") == 0)
245     g_variant_builder_add (builder,
246                            "{sv}",
247                            "Count", g_variant_new_int32 (myobj->count));
248   else if (g_strcmp0 (pspec->name, "name") == 0)
249     g_variant_builder_add (builder,
250                            "{sv}",
251                            "Name", g_variant_new_string (myobj->name ? myobj->name : ""));
252
253   g_dbus_connection_emit_signal (connection,
254                                  NULL,
255                                  "/org/myorg/MyObject",
256                                  "org.freedesktop.DBus.Properties",
257                                  "PropertiesChanged",
258                                  g_variant_new ("(sa{sv}as)",
259                                                 "org.myorg.MyObject",
260                                                 builder,
261                                                 invalidated_builder),
262                                  NULL);
263 }
264
265 static void
266 on_bus_acquired (GDBusConnection *connection,
267                  const gchar     *name,
268                  gpointer         user_data)
269 {
270   MyObject *myobj = user_data;
271   guint registration_id;
272
273   g_signal_connect (myobj, "notify",
274                     G_CALLBACK (send_property_change), connection);
275   registration_id = g_dbus_connection_register_object (connection,
276                                                        "/org/myorg/MyObject",
277                                                        introspection_data->interfaces[0],
278                                                        &interface_vtable,
279                                                        myobj,
280                                                        NULL,  /* user_data_free_func */
281                                                        NULL); /* GError** */
282   g_assert (registration_id > 0);
283 }
284
285 static void
286 on_name_acquired (GDBusConnection *connection,
287                   const gchar     *name,
288                   gpointer         user_data)
289 {
290 }
291
292 static void
293 on_name_lost (GDBusConnection *connection,
294               const gchar     *name,
295               gpointer         user_data)
296 {
297   exit (1);
298 }
299
300 int
301 main (int argc, char *argv[])
302 {
303   guint owner_id;
304   GMainLoop *loop;
305   MyObject *myobj;
306
307   /* We are lazy here - we don't want to manually provide
308    * the introspection data structures - so we just build
309    * them from XML.
310    */
311   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
312   g_assert (introspection_data != NULL);
313
314   myobj = g_object_new (my_object_get_type (), NULL);
315
316   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
317                              "org.myorg.MyObject",
318                              G_BUS_NAME_OWNER_FLAGS_NONE,
319                              on_bus_acquired,
320                              on_name_acquired,
321                              on_name_lost,
322                              myobj,
323                              NULL);
324
325   loop = g_main_loop_new (NULL, FALSE);
326   g_main_loop_run (loop);
327
328   g_bus_unown_name (owner_id);
329
330   g_dbus_node_info_unref (introspection_data);
331
332   g_object_unref (myobj);
333
334   return 0;
335 }