(root)/
glib-2.79.0/
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    { 0 }
     121  };
     122  
     123  /* ---------------------------------------------------------------------------------------------------- */
     124  
     125  static void
     126  connection_closed (GDBusConnection *connection,
     127                     gboolean remote_peer_vanished,
     128                     GError *Error,
     129                     gpointer user_data)
     130  {
     131    g_print ("Client disconnected.\n");
     132    g_object_unref (connection);
     133  }
     134  
     135  static gboolean
     136  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    credentials = g_dbus_connection_get_peer_credentials (connection);
     145    if (credentials == NULL)
     146      s = g_strdup ("(no credentials received)");
     147    else
     148      s = g_credentials_to_string (credentials);
     149  
     150    g_print ("Client connected.\n"
     151             "Peer credentials: %s\n"
     152             "Negotiated capabilities: unix-fd-passing=%d\n",
     153             s,
     154             g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
     155  
     156    g_object_ref (connection);
     157    g_signal_connect (connection, "closed", G_CALLBACK (connection_closed), NULL);
     158    registration_id = g_dbus_connection_register_object (connection,
     159                                                         "/org/gtk/GDBus/TestObject",
     160                                                         introspection_data->interfaces[0],
     161                                                         &interface_vtable,
     162                                                         NULL,  /* user_data */
     163                                                         NULL,  /* user_data_free_func */
     164                                                         NULL); /* GError** */
     165    g_assert (registration_id > 0);
     166  
     167    g_free (s);
     168  
     169    return TRUE;
     170  }
     171  
     172  /* ---------------------------------------------------------------------------------------------------- */
     173  
     174  static gboolean
     175  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    g_print ("Considering whether to accept %s authentication...\n", mechanism);
     194    return TRUE;
     195  }
     196  
     197  static gboolean
     198  authorize_authenticated_peer_cb (GDBusAuthObserver *observer,
     199                                   G_GNUC_UNUSED GIOStream *stream,
     200                                   GCredentials *credentials,
     201                                   G_GNUC_UNUSED gpointer user_data)
     202  {
     203    gboolean authorized = FALSE;
     204  
     205    g_print ("Considering whether to authorize authenticated peer...\n");
     206  
     207    if (credentials != NULL)
     208      {
     209        GCredentials *own_credentials;
     210        gchar *credentials_string = NULL;
     211  
     212        credentials_string = g_credentials_to_string (credentials);
     213        g_print ("Peer's credentials: %s\n", credentials_string);
     214        g_free (credentials_string);
     215  
     216        own_credentials = g_credentials_new ();
     217  
     218        credentials_string = g_credentials_to_string (own_credentials);
     219        g_print ("Server's credentials: %s\n", credentials_string);
     220        g_free (credentials_string);
     221  
     222        if (g_credentials_is_same_user (credentials, own_credentials, NULL))
     223          authorized = TRUE;
     224  
     225        g_object_unref (own_credentials);
     226      }
     227  
     228    if (!authorized)
     229      {
     230        /* In most servers you'd want to reject this, but for this example
     231         * we allow it. */
     232        g_print ("A server would often not want to authorize this identity\n");
     233        g_print ("Authorizing it anyway for demonstration purposes\n");
     234        authorized = TRUE;
     235      }
     236  
     237    return authorized;
     238  }
     239  
     240  /* ---------------------------------------------------------------------------------------------------- */
     241  
     242  int
     243  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    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    ret = 1;
     260  
     261    opt_address = NULL;
     262    opt_server = FALSE;
     263    opt_allow_anonymous = FALSE;
     264  
     265    opt_context = g_option_context_new ("peer-to-peer example");
     266    error = NULL;
     267    g_option_context_add_main_entries (opt_context, opt_entries, NULL);
     268    if (!g_option_context_parse (opt_context, &argc, &argv, &error))
     269      {
     270        g_option_context_free (opt_context);
     271        g_printerr ("Error parsing options: %s\n", error->message);
     272        g_error_free (error);
     273        goto out;
     274      }
     275  
     276    g_option_context_free (opt_context);
     277  
     278    if (opt_address == NULL)
     279      {
     280        g_printerr ("Incorrect usage, try --help.\n");
     281        goto out;
     282      }
     283    if (!opt_server && opt_allow_anonymous)
     284      {
     285        g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
     286        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    introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
     294    g_assert (introspection_data != NULL);
     295  
     296    if (opt_server)
     297      {
     298        GDBusAuthObserver *observer;
     299        GDBusServer *server;
     300        gchar *guid;
     301        GMainLoop *loop;
     302        GDBusServerFlags server_flags;
     303  
     304        guid = g_dbus_generate_guid ();
     305  
     306        server_flags = G_DBUS_SERVER_FLAGS_NONE;
     307        if (opt_allow_anonymous)
     308          server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
     309  
     310        observer = g_dbus_auth_observer_new ();
     311        g_signal_connect (observer, "allow-mechanism", G_CALLBACK (allow_mechanism_cb), NULL);
     312        g_signal_connect (observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL);
     313  
     314        error = NULL;
     315        server = g_dbus_server_new_sync (opt_address,
     316                                         server_flags,
     317                                         guid,
     318                                         observer,
     319                                         NULL, /* GCancellable */
     320                                         &error);
     321        g_dbus_server_start (server);
     322  
     323        g_object_unref (observer);
     324        g_free (guid);
     325  
     326        if (server == NULL)
     327          {
     328            g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
     329            g_error_free (error);
     330            goto out;
     331          }
     332        g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
     333        g_signal_connect (server,
     334                          "new-connection",
     335                          G_CALLBACK (on_new_connection),
     336                          NULL);
     337  
     338        loop = g_main_loop_new (NULL, FALSE);
     339        g_main_loop_run (loop);
     340  
     341        g_object_unref (server);
     342        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        error = NULL;
     352        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        if (connection == NULL)
     358          {
     359            g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
     360            g_error_free (error);
     361            goto out;
     362          }
     363  
     364        g_print ("Connected.\n"
     365                 "Negotiated capabilities: unix-fd-passing=%d\n",
     366                 g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
     367  
     368        greeting = g_strdup_printf ("Hey, it's %" G_GINT64_FORMAT " already!",
     369                                    g_get_real_time () / G_USEC_PER_SEC);
     370        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        g_free (greeting);
     382  
     383        if (value == NULL)
     384          {
     385            g_printerr ("Error invoking HelloWorld(): %s\n", error->message);
     386            g_error_free (error);
     387            goto out;
     388          }
     389        g_variant_get (value, "(&s)", &greeting_response);
     390        g_print ("Server said: %s\n", greeting_response);
     391        g_variant_unref (value);
     392  
     393        g_object_unref (connection);
     394      }
     395    g_dbus_node_info_unref (introspection_data);
     396  
     397    ret = 0;
     398  
     399   out:
     400    g_free (opt_address);
     401  
     402    return ret;
     403  }