Branch data Line data Source code
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 : 0 : 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 [ # # ]: 0 : if (g_strcmp0 (method_name, "HelloWorld") == 0)
102 : : {
103 : : const gchar *greeting;
104 : : gchar *response;
105 : :
106 : 0 : g_variant_get (parameters, "(&s)", &greeting);
107 : 0 : response = g_strdup_printf ("You said '%s'. KTHXBYE!", greeting);
108 : 0 : g_dbus_method_invocation_return_value (invocation,
109 : : g_variant_new ("(s)", response));
110 : 0 : g_free (response);
111 : 0 : g_print ("Client said: %s\n", greeting);
112 : : }
113 : 0 : }
114 : :
115 : : static const GDBusInterfaceVTable interface_vtable =
116 : : {
117 : : handle_method_call,
118 : : NULL,
119 : : NULL,
120 : : { 0 }
121 : : };
122 : :
123 : : /* ---------------------------------------------------------------------------------------------------- */
124 : :
125 : : static void
126 : 0 : connection_closed (GDBusConnection *connection,
127 : : gboolean remote_peer_vanished,
128 : : GError *Error,
129 : : gpointer user_data)
130 : : {
131 : 0 : g_print ("Client disconnected.\n");
132 : 0 : g_object_unref (connection);
133 : 0 : }
134 : :
135 : : static gboolean
136 : 0 : on_new_connection (GDBusServer *server,
137 : : GDBusConnection *connection,
138 : : gpointer user_data)
139 : : {
140 : : guint registration_id;
141 : : GCredentials *credentials;
142 : : gchar *s;
143 : :
144 : 0 : credentials = g_dbus_connection_get_peer_credentials (connection);
145 [ # # ]: 0 : if (credentials == NULL)
146 : 0 : s = g_strdup ("(no credentials received)");
147 : : else
148 : 0 : s = g_credentials_to_string (credentials);
149 : :
150 : 0 : g_print ("Client connected.\n"
151 : : "Peer credentials: %s\n"
152 : : "Negotiated capabilities: unix-fd-passing=%d\n",
153 : : s,
154 : 0 : g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
155 : :
156 : 0 : g_object_ref (connection);
157 : 0 : g_signal_connect (connection, "closed", G_CALLBACK (connection_closed), NULL);
158 : 0 : registration_id = g_dbus_connection_register_object (connection,
159 : : "/org/gtk/GDBus/TestObject",
160 : 0 : introspection_data->interfaces[0],
161 : : &interface_vtable,
162 : : NULL, /* user_data */
163 : : NULL, /* user_data_free_func */
164 : : NULL); /* GError** */
165 : 0 : g_assert (registration_id > 0);
166 : :
167 : 0 : g_free (s);
168 : :
169 : 0 : return TRUE;
170 : : }
171 : :
172 : : /* ---------------------------------------------------------------------------------------------------- */
173 : :
174 : : static gboolean
175 : 0 : allow_mechanism_cb (GDBusAuthObserver *observer,
176 : : const gchar *mechanism,
177 : : G_GNUC_UNUSED gpointer user_data)
178 : : {
179 : : /*
180 : : * In a production GDBusServer that only needs to work on modern Unix
181 : : * platforms, consider requiring EXTERNAL (credentials-passing),
182 : : * which is the recommended authentication mechanism for AF_UNIX
183 : : * sockets:
184 : : *
185 : : * if (g_strcmp0 (mechanism, "EXTERNAL") == 0)
186 : : * return TRUE;
187 : : *
188 : : * return FALSE;
189 : : *
190 : : * For this example we accept everything.
191 : : */
192 : :
193 : 0 : g_print ("Considering whether to accept %s authentication...\n", mechanism);
194 : 0 : return TRUE;
195 : : }
196 : :
197 : : static gboolean
198 : 0 : authorize_authenticated_peer_cb (GDBusAuthObserver *observer,
199 : : G_GNUC_UNUSED GIOStream *stream,
200 : : GCredentials *credentials,
201 : : G_GNUC_UNUSED gpointer user_data)
202 : : {
203 : 0 : gboolean authorized = FALSE;
204 : :
205 : 0 : g_print ("Considering whether to authorize authenticated peer...\n");
206 : :
207 [ # # ]: 0 : if (credentials != NULL)
208 : : {
209 : : GCredentials *own_credentials;
210 : 0 : gchar *credentials_string = NULL;
211 : :
212 : 0 : credentials_string = g_credentials_to_string (credentials);
213 : 0 : g_print ("Peer's credentials: %s\n", credentials_string);
214 : 0 : g_free (credentials_string);
215 : :
216 : 0 : own_credentials = g_credentials_new ();
217 : :
218 : 0 : credentials_string = g_credentials_to_string (own_credentials);
219 : 0 : g_print ("Server's credentials: %s\n", credentials_string);
220 : 0 : g_free (credentials_string);
221 : :
222 [ # # ]: 0 : if (g_credentials_is_same_user (credentials, own_credentials, NULL))
223 : 0 : authorized = TRUE;
224 : :
225 : 0 : g_object_unref (own_credentials);
226 : : }
227 : :
228 [ # # ]: 0 : if (!authorized)
229 : : {
230 : : /* In most servers you'd want to reject this, but for this example
231 : : * we allow it. */
232 : 0 : g_print ("A server would often not want to authorize this identity\n");
233 : 0 : g_print ("Authorizing it anyway for demonstration purposes\n");
234 : 0 : authorized = TRUE;
235 : : }
236 : :
237 : 0 : return authorized;
238 : : }
239 : :
240 : : /* ---------------------------------------------------------------------------------------------------- */
241 : :
242 : : int
243 : 0 : main (int argc, char *argv[])
244 : : {
245 : : gint ret;
246 : : gboolean opt_server;
247 : : gchar *opt_address;
248 : : GOptionContext *opt_context;
249 : : gboolean opt_allow_anonymous;
250 : : GError *error;
251 : 0 : GOptionEntry opt_entries[] =
252 : : {
253 : : { "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL },
254 : : { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL },
255 : : { "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL },
256 : : G_OPTION_ENTRY_NULL
257 : : };
258 : :
259 : 0 : ret = 1;
260 : :
261 : 0 : opt_address = NULL;
262 : 0 : opt_server = FALSE;
263 : 0 : opt_allow_anonymous = FALSE;
264 : :
265 : 0 : opt_context = g_option_context_new ("peer-to-peer example");
266 : 0 : error = NULL;
267 : 0 : g_option_context_add_main_entries (opt_context, opt_entries, NULL);
268 [ # # ]: 0 : if (!g_option_context_parse (opt_context, &argc, &argv, &error))
269 : : {
270 : 0 : g_option_context_free (opt_context);
271 : 0 : g_printerr ("Error parsing options: %s\n", error->message);
272 : 0 : g_error_free (error);
273 : 0 : goto out;
274 : : }
275 : :
276 : 0 : g_option_context_free (opt_context);
277 : :
278 [ # # ]: 0 : if (opt_address == NULL)
279 : : {
280 : 0 : g_printerr ("Incorrect usage, try --help.\n");
281 : 0 : goto out;
282 : : }
283 [ # # # # ]: 0 : if (!opt_server && opt_allow_anonymous)
284 : : {
285 : 0 : g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
286 : 0 : goto out;
287 : : }
288 : :
289 : : /* We are lazy here - we don't want to manually provide
290 : : * the introspection data structures - so we just build
291 : : * them from XML.
292 : : */
293 : 0 : introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
294 : 0 : g_assert (introspection_data != NULL);
295 : :
296 [ # # ]: 0 : if (opt_server)
297 : : {
298 : : GDBusAuthObserver *observer;
299 : : GDBusServer *server;
300 : : gchar *guid;
301 : : GMainLoop *loop;
302 : : GDBusServerFlags server_flags;
303 : :
304 : 0 : guid = g_dbus_generate_guid ();
305 : :
306 : 0 : server_flags = G_DBUS_SERVER_FLAGS_NONE;
307 [ # # ]: 0 : if (opt_allow_anonymous)
308 : 0 : server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
309 : :
310 : 0 : observer = g_dbus_auth_observer_new ();
311 : 0 : g_signal_connect (observer, "allow-mechanism", G_CALLBACK (allow_mechanism_cb), NULL);
312 : 0 : g_signal_connect (observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL);
313 : :
314 : 0 : error = NULL;
315 : 0 : server = g_dbus_server_new_sync (opt_address,
316 : : server_flags,
317 : : guid,
318 : : observer,
319 : : NULL, /* GCancellable */
320 : : &error);
321 : 0 : g_dbus_server_start (server);
322 : :
323 : 0 : g_object_unref (observer);
324 : 0 : g_free (guid);
325 : :
326 [ # # ]: 0 : if (server == NULL)
327 : : {
328 : 0 : g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
329 : 0 : g_error_free (error);
330 : 0 : goto out;
331 : : }
332 : 0 : g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
333 : 0 : g_signal_connect (server,
334 : : "new-connection",
335 : : G_CALLBACK (on_new_connection),
336 : : NULL);
337 : :
338 : 0 : loop = g_main_loop_new (NULL, FALSE);
339 : 0 : g_main_loop_run (loop);
340 : :
341 : 0 : g_object_unref (server);
342 : 0 : g_main_loop_unref (loop);
343 : : }
344 : : else
345 : : {
346 : : GDBusConnection *connection;
347 : : const gchar *greeting_response;
348 : : GVariant *value;
349 : : gchar *greeting;
350 : :
351 : 0 : error = NULL;
352 : 0 : connection = g_dbus_connection_new_for_address_sync (opt_address,
353 : : G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
354 : : NULL, /* GDBusAuthObserver */
355 : : NULL, /* GCancellable */
356 : : &error);
357 [ # # ]: 0 : if (connection == NULL)
358 : : {
359 : 0 : g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
360 : 0 : g_error_free (error);
361 : 0 : goto out;
362 : : }
363 : :
364 : 0 : g_print ("Connected.\n"
365 : : "Negotiated capabilities: unix-fd-passing=%d\n",
366 : 0 : g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
367 : :
368 : 0 : greeting = g_strdup_printf ("Hey, it's %" G_GINT64_FORMAT " already!",
369 : 0 : g_get_real_time () / G_USEC_PER_SEC);
370 : 0 : value = g_dbus_connection_call_sync (connection,
371 : : NULL, /* bus_name */
372 : : "/org/gtk/GDBus/TestObject",
373 : : "org.gtk.GDBus.TestPeerInterface",
374 : : "HelloWorld",
375 : : g_variant_new ("(s)", greeting),
376 : : G_VARIANT_TYPE ("(s)"),
377 : : G_DBUS_CALL_FLAGS_NONE,
378 : : -1,
379 : : NULL,
380 : : &error);
381 : 0 : g_free (greeting);
382 : :
383 [ # # ]: 0 : if (value == NULL)
384 : : {
385 : 0 : g_printerr ("Error invoking HelloWorld(): %s\n", error->message);
386 : 0 : g_error_free (error);
387 : 0 : goto out;
388 : : }
389 : 0 : g_variant_get (value, "(&s)", &greeting_response);
390 : 0 : g_print ("Server said: %s\n", greeting_response);
391 : 0 : g_variant_unref (value);
392 : :
393 : 0 : g_object_unref (connection);
394 : : }
395 : 0 : g_dbus_node_info_unref (introspection_data);
396 : :
397 : 0 : ret = 0;
398 : :
399 : 0 : out:
400 : 0 : g_free (opt_address);
401 : :
402 : 0 : return ret;
403 : : }
|