/* Usage examples (modulo addresses / credentials). UNIX domain socket transport: Server: $ ./gdbus-example-peer --server --address unix:abstract=myaddr Server is listening at: unix:abstract=myaddr Client connected. Peer credentials: GCredentials:unix-user=500,unix-group=500,unix-process=13378 Negotiated capabilities: unix-fd-passing=1 Client said: Hey, it's 1273093080 already! Client: $ ./gdbus-example-peer --address unix:abstract=myaddr Connected. Negotiated capabilities: unix-fd-passing=1 Server said: You said 'Hey, it's 1273093080 already!'. KTHXBYE! Nonce-secured TCP transport on the same host: Server: $ ./gdbus-example-peer --server --address nonce-tcp: Server is listening at: nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV Client connected. Peer credentials: (no credentials received) Negotiated capabilities: unix-fd-passing=0 Client said: Hey, it's 1273093206 already! Client: $ ./gdbus-example-peer -address nonce-tcp:host=localhost,port=43077,noncefile=/tmp/gdbus-nonce-file-X1ZNCV Connected. Negotiated capabilities: unix-fd-passing=0 Server said: You said 'Hey, it's 1273093206 already!'. KTHXBYE! TCP transport on two different hosts with a shared home directory: Server: host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0 Server is listening at: tcp:host=0.0.0.0,port=46314 Client connected. Peer credentials: (no credentials received) Negotiated capabilities: unix-fd-passing=0 Client said: Hey, it's 1273093337 already! Client: host2 $ ./gdbus-example-peer -a tcp:host=host1,port=46314 Connected. Negotiated capabilities: unix-fd-passing=0 Server said: You said 'Hey, it's 1273093337 already!'. KTHXBYE! TCP transport on two different hosts without authentication: Server: host1 $ ./gdbus-example-peer --server --address tcp:host=0.0.0.0 --allow-anonymous Server is listening at: tcp:host=0.0.0.0,port=59556 Client connected. Peer credentials: (no credentials received) Negotiated capabilities: unix-fd-passing=0 Client said: Hey, it's 1273093652 already! Client: host2 $ ./gdbus-example-peer -a tcp:host=host1,port=59556 Connected. Negotiated capabilities: unix-fd-passing=0 Server said: You said 'Hey, it's 1273093652 already!'. KTHXBYE! */ #include #include /* ---------------------------------------------------------------------------------------------------- */ static GDBusNodeInfo *introspection_data = NULL; /* Introspection data for the service we are exporting */ static const gchar introspection_xml[] = "" " " " " " " " " " " " " ""; /* ---------------------------------------------------------------------------------------------------- */ static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { if (g_strcmp0 (method_name, "HelloWorld") == 0) { const gchar *greeting; gchar *response; g_variant_get (parameters, "(&s)", &greeting); response = g_strdup_printf ("You said '%s'. KTHXBYE!", greeting); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", response)); g_free (response); g_print ("Client said: %s\n", greeting); } } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, NULL, { 0 } }; /* ---------------------------------------------------------------------------------------------------- */ static void connection_closed (GDBusConnection *connection, gboolean remote_peer_vanished, GError *Error, gpointer user_data) { g_print ("Client disconnected.\n"); g_object_unref (connection); } static gboolean on_new_connection (GDBusServer *server, GDBusConnection *connection, gpointer user_data) { guint registration_id; GCredentials *credentials; gchar *s; credentials = g_dbus_connection_get_peer_credentials (connection); if (credentials == NULL) s = g_strdup ("(no credentials received)"); else s = g_credentials_to_string (credentials); g_print ("Client connected.\n" "Peer credentials: %s\n" "Negotiated capabilities: unix-fd-passing=%d\n", s, g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); g_object_ref (connection); g_signal_connect (connection, "closed", G_CALLBACK (connection_closed), NULL); registration_id = g_dbus_connection_register_object (connection, "/org/gtk/GDBus/TestObject", introspection_data->interfaces[0], &interface_vtable, NULL, /* user_data */ NULL, /* user_data_free_func */ NULL); /* GError** */ g_assert (registration_id > 0); g_free (s); return TRUE; } /* ---------------------------------------------------------------------------------------------------- */ static gboolean allow_mechanism_cb (GDBusAuthObserver *observer, const gchar *mechanism, G_GNUC_UNUSED gpointer user_data) { /* * In a production GDBusServer that only needs to work on modern Unix * platforms, consider requiring EXTERNAL (credentials-passing), * which is the recommended authentication mechanism for AF_UNIX * sockets: * * if (g_strcmp0 (mechanism, "EXTERNAL") == 0) * return TRUE; * * return FALSE; * * For this example we accept everything. */ g_print ("Considering whether to accept %s authentication...\n", mechanism); return TRUE; } static gboolean authorize_authenticated_peer_cb (GDBusAuthObserver *observer, G_GNUC_UNUSED GIOStream *stream, GCredentials *credentials, G_GNUC_UNUSED gpointer user_data) { gboolean authorized = FALSE; g_print ("Considering whether to authorize authenticated peer...\n"); if (credentials != NULL) { GCredentials *own_credentials; gchar *credentials_string = NULL; credentials_string = g_credentials_to_string (credentials); g_print ("Peer's credentials: %s\n", credentials_string); g_free (credentials_string); own_credentials = g_credentials_new (); credentials_string = g_credentials_to_string (own_credentials); g_print ("Server's credentials: %s\n", credentials_string); g_free (credentials_string); if (g_credentials_is_same_user (credentials, own_credentials, NULL)) authorized = TRUE; g_object_unref (own_credentials); } if (!authorized) { /* In most servers you'd want to reject this, but for this example * we allow it. */ g_print ("A server would often not want to authorize this identity\n"); g_print ("Authorizing it anyway for demonstration purposes\n"); authorized = TRUE; } return authorized; } /* ---------------------------------------------------------------------------------------------------- */ int main (int argc, char *argv[]) { gint ret; gboolean opt_server; gchar *opt_address; GOptionContext *opt_context; gboolean opt_allow_anonymous; GError *error; GOptionEntry opt_entries[] = { { "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL }, { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL }, { "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL }, G_OPTION_ENTRY_NULL }; ret = 1; opt_address = NULL; opt_server = FALSE; opt_allow_anonymous = FALSE; opt_context = g_option_context_new ("peer-to-peer example"); error = NULL; g_option_context_add_main_entries (opt_context, opt_entries, NULL); if (!g_option_context_parse (opt_context, &argc, &argv, &error)) { g_option_context_free (opt_context); g_printerr ("Error parsing options: %s\n", error->message); g_error_free (error); goto out; } g_option_context_free (opt_context); if (opt_address == NULL) { g_printerr ("Incorrect usage, try --help.\n"); goto out; } if (!opt_server && opt_allow_anonymous) { g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n"); goto out; } /* We are lazy here - we don't want to manually provide * the introspection data structures - so we just build * them from XML. */ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (introspection_data != NULL); if (opt_server) { GDBusAuthObserver *observer; GDBusServer *server; gchar *guid; GMainLoop *loop; GDBusServerFlags server_flags; guid = g_dbus_generate_guid (); server_flags = G_DBUS_SERVER_FLAGS_NONE; if (opt_allow_anonymous) server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS; observer = g_dbus_auth_observer_new (); g_signal_connect (observer, "allow-mechanism", G_CALLBACK (allow_mechanism_cb), NULL); g_signal_connect (observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL); error = NULL; server = g_dbus_server_new_sync (opt_address, server_flags, guid, observer, NULL, /* GCancellable */ &error); g_dbus_server_start (server); g_object_unref (observer); g_free (guid); if (server == NULL) { g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message); g_error_free (error); goto out; } g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server)); g_signal_connect (server, "new-connection", G_CALLBACK (on_new_connection), NULL); loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); g_object_unref (server); g_main_loop_unref (loop); } else { GDBusConnection *connection; const gchar *greeting_response; GVariant *value; gchar *greeting; error = NULL; connection = g_dbus_connection_new_for_address_sync (opt_address, G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, /* GDBusAuthObserver */ NULL, /* GCancellable */ &error); if (connection == NULL) { g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message); g_error_free (error); goto out; } g_print ("Connected.\n" "Negotiated capabilities: unix-fd-passing=%d\n", g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); greeting = g_strdup_printf ("Hey, it's %" G_GINT64_FORMAT " already!", g_get_real_time () / G_USEC_PER_SEC); value = g_dbus_connection_call_sync (connection, NULL, /* bus_name */ "/org/gtk/GDBus/TestObject", "org.gtk.GDBus.TestPeerInterface", "HelloWorld", g_variant_new ("(s)", greeting), G_VARIANT_TYPE ("(s)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); g_free (greeting); if (value == NULL) { g_printerr ("Error invoking HelloWorld(): %s\n", error->message); g_error_free (error); goto out; } g_variant_get (value, "(&s)", &greeting_response); g_print ("Server said: %s\n", greeting_response); g_variant_unref (value); g_object_unref (connection); } g_dbus_node_info_unref (introspection_data); ret = 0; out: g_free (opt_address); return ret; }