GDBus: Use call() instead of invoke_method()
[platform/upstream/glib.git] / gio / tests / gdbus-example-peer.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 /*
15
16 Usage examples (modulo addresses / credentials).
17
18 UNIX domain socket transport:
19
20  Server:
21    $ ./gdbus-example-peer --server --address unix:abstract=myaddr
22    Server is listening at: unix:abstract=myaddr
23    Client connected.
24    Peer credentials: GCredentials:unix-user=500,unix-group=500,unix-process=13378
25    Negotiated capabilities: unix-fd-passing=1
26    Client said: Hey, it's 1273093080 already!
27
28  Client:
29    $ ./gdbus-example-peer --address unix:abstract=myaddr
30    Connected.
31    Negotiated capabilities: unix-fd-passing=1
32    Server said: You said 'Hey, it's 1273093080 already!'. KTHXBYE!
33
34 Nonce-secured TCP transport on the same host:
35
36  Server:
37    $ ./gdbus-example-peer --server --address nonce-tcp:
38    Server is listening at: nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV
39    Client connected.
40    Peer credentials: (no credentials received)
41    Negotiated capabilities: unix-fd-passing=0
42    Client said: Hey, it's 1273093206 already!
43
44  Client:
45    $ ./gdbus-example-peer -address nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV
46    Connected.
47    Negotiated capabilities: unix-fd-passing=0
48    Server said: You said 'Hey, it's 1273093206 already!'. KTHXBYE!
49
50 TCP transport on two different hosts with a shared home directory:
51
52  Server:
53    host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0
54    Server is listening at: tcp:host=0.0.0.0,port=46314
55    Client connected.
56    Peer credentials: (no credentials received)
57    Negotiated capabilities: unix-fd-passing=0
58    Client said: Hey, it's 1273093337 already!
59
60  Client:
61    host2 $ ./gdbus-example-peer -a tcp:host=host1,port=46314
62    Connected.
63    Negotiated capabilities: unix-fd-passing=0
64    Server said: You said 'Hey, it's 1273093337 already!'. KTHXBYE!
65
66 TCP transport on two different hosts without authentication:
67
68  Server:
69    host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0 --allow-anonymous
70    Server is listening at: tcp:host=0.0.0.0,port=59556
71    Client connected.
72    Peer credentials: (no credentials received)
73    Negotiated capabilities: unix-fd-passing=0
74    Client said: Hey, it's 1273093652 already!
75
76  Client:
77    host2 $ ./gdbus-example-peer -a tcp:host=host1,port=59556
78    Connected.
79    Negotiated capabilities: unix-fd-passing=0
80    Server said: You said 'Hey, it's 1273093652 already!'. KTHXBYE!
81
82  */
83
84 #include <gio/gio.h>
85 #include <stdlib.h>
86
87 /* ---------------------------------------------------------------------------------------------------- */
88
89 static GDBusNodeInfo *introspection_data = NULL;
90
91 /* Introspection data for the service we are exporting */
92 static const gchar introspection_xml[] =
93   "<node>"
94   "  <interface name='org.gtk.GDBus.TestPeerInterface'>"
95   "    <method name='HelloWorld'>"
96   "      <arg type='s' name='greeting' direction='in'/>"
97   "      <arg type='s' name='response' direction='out'/>"
98   "    </method>"
99   "  </interface>"
100   "</node>";
101
102 /* ---------------------------------------------------------------------------------------------------- */
103
104 static void
105 handle_method_call (GDBusConnection       *connection,
106                     const gchar           *sender,
107                     const gchar           *object_path,
108                     const gchar           *interface_name,
109                     const gchar           *method_name,
110                     GVariant              *parameters,
111                     GDBusMethodInvocation *invocation,
112                     gpointer               user_data)
113 {
114   if (g_strcmp0 (method_name, "HelloWorld") == 0)
115     {
116       const gchar *greeting;
117       gchar *response;
118
119       g_variant_get (parameters, "(s)", &greeting);
120       response = g_strdup_printf ("You said '%s'. KTHXBYE!", greeting);
121       g_dbus_method_invocation_return_value (invocation,
122                                              g_variant_new ("(s)", response));
123       g_free (response);
124       g_print ("Client said: %s\n", greeting);
125     }
126 }
127
128 static const GDBusInterfaceVTable interface_vtable =
129 {
130   handle_method_call,
131   NULL,
132   NULL,
133 };
134
135 /* ---------------------------------------------------------------------------------------------------- */
136
137 static void
138 on_new_connection (GDBusServer *server,
139                    GDBusConnection *connection,
140                    gpointer user_data)
141 {
142   guint registration_id;
143   GCredentials *credentials;
144   gchar *s;
145
146   credentials = g_dbus_connection_get_peer_credentials (connection);
147   if (credentials == NULL)
148     s = g_strdup ("(no credentials received)");
149   else
150     s = g_credentials_to_string (credentials);
151
152
153   g_print ("Client connected.\n"
154            "Peer credentials: %s\n"
155            "Negotiated capabilities: unix-fd-passing=%d\n",
156            s,
157            g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
158
159   g_object_ref (connection);
160   registration_id = g_dbus_connection_register_object (connection,
161                                                        "/org/gtk/GDBus/TestObject",
162                                                        "org.gtk.GDBus.TestPeerInterface",
163                                                        introspection_data->interfaces[0],
164                                                        &interface_vtable,
165                                                        NULL,  /* user_data */
166                                                        NULL,  /* user_data_free_func */
167                                                        NULL); /* GError** */
168   g_assert (registration_id > 0);
169 }
170
171 /* ---------------------------------------------------------------------------------------------------- */
172
173 int
174 main (int argc, char *argv[])
175 {
176   gint ret;
177   gboolean opt_server;
178   gchar *opt_address;
179   GOptionContext *opt_context;
180   gboolean opt_allow_anonymous;
181   GError *error;
182   GOptionEntry opt_entries[] =
183     {
184       { "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL },
185       { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL },
186       { "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL },
187       { NULL}
188     };
189
190   ret = 1;
191
192   g_type_init ();
193
194   opt_address = NULL;
195   opt_server = FALSE;
196   opt_allow_anonymous = FALSE;
197
198   opt_context = g_option_context_new ("peer-to-peer example");
199   error = NULL;
200   g_option_context_add_main_entries (opt_context, opt_entries, NULL);
201   if (!g_option_context_parse (opt_context, &argc, &argv, &error))
202     {
203       g_printerr ("Error parsing options: %s\n", error->message);
204       g_error_free (error);
205       goto out;
206     }
207   if (opt_address == NULL)
208     {
209       g_printerr ("Incorrect usage, try --help.\n");
210       goto out;
211     }
212   if (!opt_server && opt_allow_anonymous)
213     {
214       g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
215       goto out;
216     }
217
218   /* We are lazy here - we don't want to manually provide
219    * the introspection data structures - so we just build
220    * them from XML.
221    */
222   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
223   g_assert (introspection_data != NULL);
224
225   if (opt_server)
226     {
227       GDBusServer *server;
228       gchar *guid;
229       GMainLoop *loop;
230       GDBusServerFlags server_flags;
231
232       guid = g_dbus_generate_guid ();
233
234       server_flags = G_DBUS_SERVER_FLAGS_NONE;
235       if (opt_allow_anonymous)
236         server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
237
238       error = NULL;
239       server = g_dbus_server_new_sync (opt_address,
240                                        server_flags,
241                                        guid,
242                                        NULL, /* GDBusAuthObserver */
243                                        NULL, /* GCancellable */
244                                        &error);
245       g_dbus_server_start (server);
246       g_free (guid);
247
248       if (server == NULL)
249         {
250           g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
251           g_error_free (error);
252           goto out;
253         }
254       g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
255       g_signal_connect (server,
256                         "new-connection",
257                         G_CALLBACK (on_new_connection),
258                         NULL);
259
260       loop = g_main_loop_new (NULL, FALSE);
261       g_main_loop_run (loop);
262
263       g_object_unref (server);
264       g_main_loop_unref (loop);
265     }
266   else
267     {
268       GDBusConnection *connection;
269       const gchar *greeting_response;
270       GVariant *value;
271       gchar *greeting;
272
273       error = NULL;
274       connection = g_dbus_connection_new_for_address_sync (opt_address,
275                                                            G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
276                                                            NULL, /* GCancellable */
277                                                            &error);
278       if (connection == NULL)
279         {
280           g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
281           g_error_free (error);
282           goto out;
283         }
284
285       g_print ("Connected.\n"
286                "Negotiated capabilities: unix-fd-passing=%d\n",
287                g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
288
289       greeting = g_strdup_printf ("Hey, it's %" G_GUINT64_FORMAT " already!", (guint64) time (NULL));
290       value = g_dbus_connection_call_sync (connection,
291                                            NULL, /* bus_name */
292                                            "/org/gtk/GDBus/TestObject",
293                                            "org.gtk.GDBus.TestPeerInterface",
294                                            "HelloWorld",
295                                            g_variant_new ("(s)", greeting),
296                                            G_DBUS_CALL_FLAGS_NONE,
297                                            -1,
298                                            NULL,
299                                            &error);
300       if (value == NULL)
301         {
302           g_printerr ("Error invoking HelloWorld(): %s\n", error->message);
303           g_error_free (error);
304           goto out;
305         }
306       g_variant_get (value, "(s)", &greeting_response);
307       g_print ("Server said: %s\n", greeting_response);
308       g_variant_unref (value);
309
310       g_object_unref (connection);
311     }
312   g_dbus_node_info_unref (introspection_data);
313
314   ret = 0;
315
316  out:
317   return ret;
318 }