(root)/
glib-2.79.0/
gio/
tests/
gdbus-example-server.c
       1  #include <gio/gio.h>
       2  #include <stdlib.h>
       3  
       4  #ifdef G_OS_UNIX
       5  #include <gio/gunixfdlist.h>
       6  /* For STDOUT_FILENO */
       7  #include <unistd.h>
       8  #endif
       9  
      10  /* ---------------------------------------------------------------------------------------------------- */
      11  
      12  static GDBusNodeInfo *introspection_data = NULL;
      13  
      14  /* Introspection data for the service we are exporting */
      15  static const gchar introspection_xml[] =
      16    "<node>"
      17    "  <interface name='org.gtk.GDBus.TestInterface'>"
      18    "    <annotation name='org.gtk.GDBus.Annotation' value='OnInterface'/>"
      19    "    <annotation name='org.gtk.GDBus.Annotation' value='AlsoOnInterface'/>"
      20    "    <method name='HelloWorld'>"
      21    "      <annotation name='org.gtk.GDBus.Annotation' value='OnMethod'/>"
      22    "      <arg type='s' name='greeting' direction='in'/>"
      23    "      <arg type='s' name='response' direction='out'/>"
      24    "    </method>"
      25    "    <method name='EmitSignal'>"
      26    "      <arg type='d' name='speed_in_mph' direction='in'>"
      27    "        <annotation name='org.gtk.GDBus.Annotation' value='OnArg'/>"
      28    "      </arg>"
      29    "    </method>"
      30    "    <method name='GimmeStdout'/>"
      31    "    <signal name='VelocityChanged'>"
      32    "      <annotation name='org.gtk.GDBus.Annotation' value='Onsignal'/>"
      33    "      <arg type='d' name='speed_in_mph'/>"
      34    "      <arg type='s' name='speed_as_string'>"
      35    "        <annotation name='org.gtk.GDBus.Annotation' value='OnArg_NonFirst'/>"
      36    "      </arg>"
      37    "    </signal>"
      38    "    <property type='s' name='FluxCapicitorName' access='read'>"
      39    "      <annotation name='org.gtk.GDBus.Annotation' value='OnProperty'>"
      40    "        <annotation name='org.gtk.GDBus.Annotation' value='OnAnnotation_YesThisIsCrazy'/>"
      41    "      </annotation>"
      42    "    </property>"
      43    "    <property type='s' name='Title' access='readwrite'/>"
      44    "    <property type='s' name='ReadingAlwaysThrowsError' access='read'/>"
      45    "    <property type='s' name='WritingAlwaysThrowsError' access='readwrite'/>"
      46    "    <property type='s' name='OnlyWritable' access='write'/>"
      47    "    <property type='s' name='Foo' access='read'/>"
      48    "    <property type='s' name='Bar' access='read'/>"
      49    "  </interface>"
      50    "</node>";
      51  
      52  /* ---------------------------------------------------------------------------------------------------- */
      53  
      54  static void
      55  handle_method_call (GDBusConnection       *connection,
      56                      const gchar           *sender,
      57                      const gchar           *object_path,
      58                      const gchar           *interface_name,
      59                      const gchar           *method_name,
      60                      GVariant              *parameters,
      61                      GDBusMethodInvocation *invocation,
      62                      gpointer               user_data)
      63  {
      64    if (g_strcmp0 (method_name, "HelloWorld") == 0)
      65      {
      66        const gchar *greeting;
      67  
      68        g_variant_get (parameters, "(&s)", &greeting);
      69  
      70        if (g_strcmp0 (greeting, "Return Unregistered") == 0)
      71          {
      72            g_dbus_method_invocation_return_error (invocation,
      73                                                   G_IO_ERROR,
      74                                                   G_IO_ERROR_FAILED_HANDLED,
      75                                                   "As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)");
      76          }
      77        else if (g_strcmp0 (greeting, "Return Registered") == 0)
      78          {
      79            g_dbus_method_invocation_return_error (invocation,
      80                                                   G_DBUS_ERROR,
      81                                                   G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
      82                                                   "As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
      83          }
      84        else if (g_strcmp0 (greeting, "Return Raw") == 0)
      85          {
      86            g_dbus_method_invocation_return_dbus_error (invocation,
      87                                                        "org.gtk.GDBus.SomeErrorName",
      88                                                        "As requested, here's a raw D-Bus error");
      89          }
      90        else
      91          {
      92            gchar *response;
      93            response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
      94            g_dbus_method_invocation_return_value (invocation,
      95                                                   g_variant_new ("(s)", response));
      96            g_free (response);
      97          }
      98      }
      99    else if (g_strcmp0 (method_name, "EmitSignal") == 0)
     100      {
     101        GError *local_error;
     102        gdouble speed_in_mph;
     103        gchar *speed_as_string;
     104  
     105        g_variant_get (parameters, "(d)", &speed_in_mph);
     106        speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph);
     107  
     108        local_error = NULL;
     109        g_dbus_connection_emit_signal (connection,
     110                                       NULL,
     111                                       object_path,
     112                                       interface_name,
     113                                       "VelocityChanged",
     114                                       g_variant_new ("(ds)",
     115                                                      speed_in_mph,
     116                                                      speed_as_string),
     117                                       &local_error);
     118        g_assert_no_error (local_error);
     119        g_free (speed_as_string);
     120  
     121        g_dbus_method_invocation_return_value (invocation, NULL);
     122      }
     123    else if (g_strcmp0 (method_name, "GimmeStdout") == 0)
     124      {
     125  #ifdef G_OS_UNIX
     126        if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
     127          {
     128            GDBusMessage *reply;
     129            GUnixFDList *fd_list;
     130            GError *error;
     131  
     132            fd_list = g_unix_fd_list_new ();
     133            error = NULL;
     134            g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error);
     135            g_assert_no_error (error);
     136  
     137            reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
     138            g_dbus_message_set_unix_fd_list (reply, fd_list);
     139  
     140            error = NULL;
     141            g_dbus_connection_send_message (connection,
     142                                            reply,
     143                                            G_DBUS_SEND_MESSAGE_FLAGS_NONE,
     144                                            NULL, /* out_serial */
     145                                            &error);
     146            g_assert_no_error (error);
     147  
     148            g_object_unref (invocation);
     149            g_object_unref (fd_list);
     150            g_object_unref (reply);
     151          }
     152        else
     153          {
     154            g_dbus_method_invocation_return_dbus_error (invocation,
     155                                                        "org.gtk.GDBus.Failed",
     156                                                        "Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)");
     157          }
     158  #else
     159        g_dbus_method_invocation_return_dbus_error (invocation,
     160                                                    "org.gtk.GDBus.NotOnUnix",
     161                                                    "Your OS does not support file descriptor passing");
     162  #endif
     163      }
     164  }
     165  
     166  static gchar *_global_title = NULL;
     167  
     168  static gboolean swap_a_and_b = FALSE;
     169  
     170  static GVariant *
     171  handle_get_property (GDBusConnection  *connection,
     172                       const gchar      *sender,
     173                       const gchar      *object_path,
     174                       const gchar      *interface_name,
     175                       const gchar      *property_name,
     176                       GError          **error,
     177                       gpointer          user_data)
     178  {
     179    GVariant *ret;
     180  
     181    ret = NULL;
     182    if (g_strcmp0 (property_name, "FluxCapicitorName") == 0)
     183      {
     184        ret = g_variant_new_string ("DeLorean");
     185      }
     186    else if (g_strcmp0 (property_name, "Title") == 0)
     187      {
     188        if (_global_title == NULL)
     189          _global_title = g_strdup ("Back To C!");
     190        ret = g_variant_new_string (_global_title);
     191      }
     192    else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
     193      {
     194        g_set_error (error,
     195                     G_IO_ERROR,
     196                     G_IO_ERROR_FAILED,
     197                     "Hello %s. I thought I said reading this property "
     198                     "always results in an error. kthxbye",
     199                     sender);
     200      }
     201    else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
     202      {
     203        ret = g_variant_new_string ("There's no home like home");
     204      }
     205    else if (g_strcmp0 (property_name, "Foo") == 0)
     206      {
     207        ret = g_variant_new_string (swap_a_and_b ? "Tock" : "Tick");
     208      }
     209    else if (g_strcmp0 (property_name, "Bar") == 0)
     210      {
     211        ret = g_variant_new_string (swap_a_and_b ? "Tick" : "Tock");
     212      }
     213  
     214    return ret;
     215  }
     216  
     217  static gboolean
     218  handle_set_property (GDBusConnection  *connection,
     219                       const gchar      *sender,
     220                       const gchar      *object_path,
     221                       const gchar      *interface_name,
     222                       const gchar      *property_name,
     223                       GVariant         *value,
     224                       GError          **error,
     225                       gpointer          user_data)
     226  {
     227    if (g_strcmp0 (property_name, "Title") == 0)
     228      {
     229        if (g_strcmp0 (_global_title, g_variant_get_string (value, NULL)) != 0)
     230          {
     231            GVariantBuilder *builder;
     232            GError *local_error;
     233  
     234            g_free (_global_title);
     235            _global_title = g_variant_dup_string (value, NULL);
     236  
     237            local_error = NULL;
     238            builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
     239            g_variant_builder_add (builder,
     240                                   "{sv}",
     241                                   "Title",
     242                                   g_variant_new_string (_global_title));
     243            g_dbus_connection_emit_signal (connection,
     244                                           NULL,
     245                                           object_path,
     246                                           "org.freedesktop.DBus.Properties",
     247                                           "PropertiesChanged",
     248                                           g_variant_new ("(sa{sv}as)",
     249                                                          interface_name,
     250                                                          builder,
     251                                                          NULL),
     252                                           &local_error);
     253            g_assert_no_error (local_error);
     254          }
     255      }
     256    else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
     257      {
     258        /* do nothing - they can't read it after all! */
     259      }
     260    else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
     261      {
     262        g_set_error (error,
     263                     G_IO_ERROR,
     264                     G_IO_ERROR_FAILED,
     265                     "Hello AGAIN %s. I thought I said writing this property "
     266                     "always results in an error. kthxbye",
     267                     sender);
     268      }
     269  
     270    return *error == NULL;
     271  }
     272  
     273  
     274  /* for now */
     275  static const GDBusInterfaceVTable interface_vtable =
     276  {
     277    handle_method_call,
     278    handle_get_property,
     279    handle_set_property,
     280    { 0 }
     281  };
     282  
     283  /* ---------------------------------------------------------------------------------------------------- */
     284  
     285  static gboolean
     286  on_timeout_cb (gpointer user_data)
     287  {
     288    GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
     289    GVariantBuilder *builder;
     290    GVariantBuilder *invalidated_builder;
     291    GError *error;
     292  
     293    swap_a_and_b = !swap_a_and_b;
     294  
     295    error = NULL;
     296    builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
     297    invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
     298    g_variant_builder_add (builder,
     299                           "{sv}",
     300                           "Foo",
     301                           g_variant_new_string (swap_a_and_b ? "Tock" : "Tick"));
     302    g_variant_builder_add (builder,
     303                           "{sv}",
     304                           "Bar",
     305                           g_variant_new_string (swap_a_and_b ? "Tick" : "Tock"));
     306    g_dbus_connection_emit_signal (connection,
     307                                   NULL,
     308                                   "/org/gtk/GDBus/TestObject",
     309                                   "org.freedesktop.DBus.Properties",
     310                                   "PropertiesChanged",
     311                                   g_variant_new ("(sa{sv}as)",
     312                                                  "org.gtk.GDBus.TestInterface",
     313                                                  builder,
     314                                                  invalidated_builder),
     315                                   &error);
     316    g_assert_no_error (error);
     317  
     318  
     319    return G_SOURCE_CONTINUE;
     320  }
     321  
     322  /* ---------------------------------------------------------------------------------------------------- */
     323  
     324  static void
     325  on_bus_acquired (GDBusConnection *connection,
     326                   const gchar     *name,
     327                   gpointer         user_data)
     328  {
     329    guint registration_id;
     330  
     331    registration_id = g_dbus_connection_register_object (connection,
     332                                                         "/org/gtk/GDBus/TestObject",
     333                                                         introspection_data->interfaces[0],
     334                                                         &interface_vtable,
     335                                                         NULL,  /* user_data */
     336                                                         NULL,  /* user_data_free_func */
     337                                                         NULL); /* GError** */
     338    g_assert (registration_id > 0);
     339  
     340    /* swap value of properties Foo and Bar every two seconds */
     341    g_timeout_add_seconds (2,
     342                           on_timeout_cb,
     343                           connection);
     344  }
     345  
     346  static void
     347  on_name_acquired (GDBusConnection *connection,
     348                    const gchar     *name,
     349                    gpointer         user_data)
     350  {
     351  }
     352  
     353  static void
     354  on_name_lost (GDBusConnection *connection,
     355                const gchar     *name,
     356                gpointer         user_data)
     357  {
     358    exit (1);
     359  }
     360  
     361  int
     362  main (int argc, char *argv[])
     363  {
     364    guint owner_id;
     365    GMainLoop *loop;
     366  
     367    /* We are lazy here - we don't want to manually provide
     368     * the introspection data structures - so we just build
     369     * them from XML.
     370     */
     371    introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
     372    g_assert (introspection_data != NULL);
     373  
     374    owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
     375                               "org.gtk.GDBus.TestServer",
     376                               G_BUS_NAME_OWNER_FLAGS_NONE,
     377                               on_bus_acquired,
     378                               on_name_acquired,
     379                               on_name_lost,
     380                               NULL,
     381                               NULL);
     382  
     383    loop = g_main_loop_new (NULL, FALSE);
     384    g_main_loop_run (loop);
     385  
     386    g_bus_unown_name (owner_id);
     387  
     388    g_dbus_node_info_unref (introspection_data);
     389  
     390    return 0;
     391  }