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