(root)/
glib-2.79.0/
gio/
tests/
gdbus-example-subtree.c
       1  #include <gio/gio.h>
       2  #include <stdlib.h>
       3  #include <string.h>
       4  
       5  /* ---------------------------------------------------------------------------------------------------- */
       6  
       7  static GDBusNodeInfo *introspection_data = NULL;
       8  static GDBusInterfaceInfo *manager_interface_info = NULL;
       9  static GDBusInterfaceInfo *block_interface_info = NULL;
      10  static GDBusInterfaceInfo *partition_interface_info = NULL;
      11  
      12  /* Introspection data for the service we are exporting */
      13  static const gchar introspection_xml[] =
      14    "<node>"
      15    "  <interface name='org.gtk.GDBus.Example.Manager'>"
      16    "    <method name='Hello'>"
      17    "      <arg type='s' name='greeting' direction='in'/>"
      18    "      <arg type='s' name='response' direction='out'/>"
      19    "    </method>"
      20    "  </interface>"
      21    "  <interface name='org.gtk.GDBus.Example.Block'>"
      22    "    <method name='Hello'>"
      23    "      <arg type='s' name='greeting' direction='in'/>"
      24    "      <arg type='s' name='response' direction='out'/>"
      25    "    </method>"
      26    "    <property type='i' name='Major' access='read'/>"
      27    "    <property type='i' name='Minor' access='read'/>"
      28    "    <property type='s' name='Notes' access='readwrite'/>"
      29    "  </interface>"
      30    "  <interface name='org.gtk.GDBus.Example.Partition'>"
      31    "    <method name='Hello'>"
      32    "      <arg type='s' name='greeting' direction='in'/>"
      33    "      <arg type='s' name='response' direction='out'/>"
      34    "    </method>"
      35    "    <property type='i' name='PartitionNumber' access='read'/>"
      36    "    <property type='s' name='Notes' access='readwrite'/>"
      37    "  </interface>"
      38    "</node>";
      39  
      40  /* ---------------------------------------------------------------------------------------------------- */
      41  
      42  static void
      43  manager_method_call (GDBusConnection       *connection,
      44                       const gchar           *sender,
      45                       const gchar           *object_path,
      46                       const gchar           *interface_name,
      47                       const gchar           *method_name,
      48                       GVariant              *parameters,
      49                       GDBusMethodInvocation *invocation,
      50                       gpointer               user_data)
      51  {
      52    const gchar *greeting;
      53    gchar *response;
      54  
      55    g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Manager");
      56    g_assert_cmpstr (method_name, ==, "Hello");
      57  
      58    g_variant_get (parameters, "(&s)", &greeting);
      59  
      60    response = g_strdup_printf ("Method %s.%s with user_data '%s' on object path %s called with arg '%s'",
      61                                interface_name,
      62                                method_name,
      63                                (const gchar *) user_data,
      64                                object_path,
      65                                greeting);
      66    g_dbus_method_invocation_return_value (invocation,
      67                                           g_variant_new ("(s)", response));
      68    g_free (response);
      69  }
      70  
      71  const GDBusInterfaceVTable manager_vtable =
      72  {
      73    manager_method_call,
      74    NULL,                 /* get_property */
      75    NULL,                 /* set_property */
      76    { 0 }
      77  };
      78  
      79  /* ---------------------------------------------------------------------------------------------------- */
      80  
      81  static void
      82  block_method_call (GDBusConnection       *connection,
      83                     const gchar           *sender,
      84                     const gchar           *object_path,
      85                     const gchar           *interface_name,
      86                     const gchar           *method_name,
      87                     GVariant              *parameters,
      88                     GDBusMethodInvocation *invocation,
      89                     gpointer               user_data)
      90  {
      91    g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Block");
      92  
      93    if (g_strcmp0 (method_name, "Hello") == 0)
      94      {
      95        const gchar *greeting;
      96        gchar *response;
      97  
      98        g_variant_get (parameters, "(&s)", &greeting);
      99  
     100        response = g_strdup_printf ("Method %s.%s with user_data '%s' on object path %s called with arg '%s'",
     101                                    interface_name,
     102                                    method_name,
     103                                    (const gchar *) user_data,
     104                                    object_path,
     105                                    greeting);
     106        g_dbus_method_invocation_return_value (invocation,
     107                                               g_variant_new ("(s)", response));
     108        g_free (response);
     109      }
     110    else if (g_strcmp0 (method_name, "DoStuff") == 0)
     111      {
     112        g_dbus_method_invocation_return_dbus_error (invocation,
     113                                                    "org.gtk.GDBus.TestSubtree.Error.Failed",
     114                                                    "This method intentionally always fails");
     115      }
     116    else
     117      {
     118        g_assert_not_reached ();
     119      }
     120  }
     121  
     122  static GVariant *
     123  block_get_property (GDBusConnection  *connection,
     124                      const gchar      *sender,
     125                      const gchar      *object_path,
     126                      const gchar      *interface_name,
     127                      const gchar      *property_name,
     128                      GError          **error,
     129                      gpointer          user_data)
     130  {
     131    GVariant *ret;
     132    const gchar *node;
     133    gint major;
     134    gint minor;
     135  
     136    node = strrchr (object_path, '/') + 1;
     137    if (g_str_has_prefix (node, "sda"))
     138      major = 8;
     139    else
     140      major = 9;
     141    if (strlen (node) == 4)
     142      minor = node[3] - '0';
     143    else
     144      minor = 0;
     145  
     146    ret = NULL;
     147    if (g_strcmp0 (property_name, "Major") == 0)
     148      {
     149        ret = g_variant_new_int32 (major);
     150      }
     151    else if (g_strcmp0 (property_name, "Minor") == 0)
     152      {
     153        ret = g_variant_new_int32 (minor);
     154      }
     155    else if (g_strcmp0 (property_name, "Notes") == 0)
     156      {
     157        g_set_error (error,
     158                     G_IO_ERROR,
     159                     G_IO_ERROR_FAILED,
     160                     "Hello %s. I thought I said reading this property "
     161                     "always results in an error. kthxbye",
     162                     sender);
     163      }
     164    else
     165      {
     166        g_assert_not_reached ();
     167      }
     168  
     169    return ret;
     170  }
     171  
     172  static gboolean
     173  block_set_property (GDBusConnection  *connection,
     174                      const gchar      *sender,
     175                      const gchar      *object_path,
     176                      const gchar      *interface_name,
     177                      const gchar      *property_name,
     178                      GVariant         *value,
     179                      GError          **error,
     180                      gpointer          user_data)
     181  {
     182    /* TODO */
     183    g_assert_not_reached ();
     184  }
     185  
     186  const GDBusInterfaceVTable block_vtable =
     187  {
     188    block_method_call,
     189    block_get_property,
     190    block_set_property,
     191    { 0 }
     192  };
     193  
     194  /* ---------------------------------------------------------------------------------------------------- */
     195  
     196  static void
     197  partition_method_call (GDBusConnection       *connection,
     198                         const gchar           *sender,
     199                         const gchar           *object_path,
     200                         const gchar           *interface_name,
     201                         const gchar           *method_name,
     202                         GVariant              *parameters,
     203                         GDBusMethodInvocation *invocation,
     204                         gpointer               user_data)
     205  {
     206    const gchar *greeting;
     207    gchar *response;
     208  
     209    g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.Example.Partition");
     210    g_assert_cmpstr (method_name, ==, "Hello");
     211  
     212    g_variant_get (parameters, "(&s)", &greeting);
     213  
     214    response = g_strdup_printf ("Method %s.%s with user_data '%s' on object path %s called with arg '%s'",
     215                                interface_name,
     216                                method_name,
     217                                (const gchar *) user_data,
     218                                object_path,
     219                                greeting);
     220    g_dbus_method_invocation_return_value (invocation,
     221                                           g_variant_new ("(s)", response));
     222    g_free (response);
     223  }
     224  
     225  const GDBusInterfaceVTable partition_vtable =
     226  {
     227    partition_method_call,
     228    NULL,
     229    NULL,
     230    { 0 }
     231  };
     232  
     233  /* ---------------------------------------------------------------------------------------------------- */
     234  
     235  static gchar **
     236  subtree_enumerate (GDBusConnection       *connection,
     237                     const gchar           *sender,
     238                     const gchar           *object_path,
     239                     gpointer               user_data)
     240  {
     241    gchar **nodes;
     242    GPtrArray *p;
     243  
     244    p = g_ptr_array_new ();
     245    g_ptr_array_add (p, g_strdup ("sda"));
     246    g_ptr_array_add (p, g_strdup ("sda1"));
     247    g_ptr_array_add (p, g_strdup ("sda2"));
     248    g_ptr_array_add (p, g_strdup ("sda3"));
     249    g_ptr_array_add (p, g_strdup ("sdb"));
     250    g_ptr_array_add (p, g_strdup ("sdb1"));
     251    g_ptr_array_add (p, g_strdup ("sdc"));
     252    g_ptr_array_add (p, g_strdup ("sdc1"));
     253    g_ptr_array_add (p, NULL);
     254    nodes = (gchar **) g_ptr_array_free (p, FALSE);
     255  
     256    return nodes;
     257  }
     258  
     259  static GDBusInterfaceInfo **
     260  subtree_introspect (GDBusConnection       *connection,
     261                      const gchar           *sender,
     262                      const gchar           *object_path,
     263                      const gchar           *node,
     264                      gpointer               user_data)
     265  {
     266    GPtrArray *p;
     267  
     268    p = g_ptr_array_new ();
     269    if (node == NULL)
     270      {
     271        g_ptr_array_add (p, g_dbus_interface_info_ref (manager_interface_info));
     272      }
     273    else
     274      {
     275        g_ptr_array_add (p, g_dbus_interface_info_ref (block_interface_info));
     276        if (strlen (node) == 4)
     277          g_ptr_array_add (p,
     278                           g_dbus_interface_info_ref (partition_interface_info));
     279      }
     280  
     281    g_ptr_array_add (p, NULL);
     282  
     283    return (GDBusInterfaceInfo **) g_ptr_array_free (p, FALSE);
     284  }
     285  
     286  static const GDBusInterfaceVTable *
     287  subtree_dispatch (GDBusConnection             *connection,
     288                    const gchar                 *sender,
     289                    const gchar                 *object_path,
     290                    const gchar                 *interface_name,
     291                    const gchar                 *node,
     292                    gpointer                    *out_user_data,
     293                    gpointer                     user_data)
     294  {
     295    const GDBusInterfaceVTable *vtable_to_return;
     296    gpointer user_data_to_return;
     297  
     298    if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Manager") == 0)
     299      {
     300        user_data_to_return = "The Root";
     301        vtable_to_return = &manager_vtable;
     302      }
     303    else
     304      {
     305        if (strlen (node) == 4)
     306          user_data_to_return = "A partition";
     307        else
     308          user_data_to_return = "A block device";
     309  
     310        if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Block") == 0)
     311          vtable_to_return = &block_vtable;
     312        else if (g_strcmp0 (interface_name, "org.gtk.GDBus.Example.Partition") == 0)
     313          vtable_to_return = &partition_vtable;
     314        else
     315          g_assert_not_reached ();
     316      }
     317  
     318    *out_user_data = user_data_to_return;
     319  
     320    return vtable_to_return;
     321  }
     322  
     323  const GDBusSubtreeVTable subtree_vtable =
     324  {
     325    subtree_enumerate,
     326    subtree_introspect,
     327    subtree_dispatch,
     328    { 0 }
     329  };
     330  
     331  /* ---------------------------------------------------------------------------------------------------- */
     332  
     333  static void
     334  on_bus_acquired (GDBusConnection *connection,
     335                   const gchar     *name,
     336                   gpointer         user_data)
     337  {
     338    guint registration_id;
     339  
     340    registration_id = g_dbus_connection_register_subtree (connection,
     341                                                          "/org/gtk/GDBus/TestSubtree/Devices",
     342                                                          &subtree_vtable,
     343                                                          G_DBUS_SUBTREE_FLAGS_NONE,
     344                                                          NULL,  /* user_data */
     345                                                          NULL,  /* user_data_free_func */
     346                                                          NULL); /* GError** */
     347    g_assert (registration_id > 0);
     348  }
     349  
     350  static void
     351  on_name_acquired (GDBusConnection *connection,
     352                    const gchar     *name,
     353                    gpointer         user_data)
     354  {
     355  }
     356  
     357  static void
     358  on_name_lost (GDBusConnection *connection,
     359                const gchar     *name,
     360                gpointer         user_data)
     361  {
     362    exit (1);
     363  }
     364  
     365  int
     366  main (int argc, char *argv[])
     367  {
     368    guint owner_id;
     369    GMainLoop *loop;
     370  
     371    /* We are lazy here - we don't want to manually provide
     372     * the introspection data structures - so we just build
     373     * them from XML.
     374     */
     375    introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
     376    g_assert (introspection_data != NULL);
     377  
     378    manager_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Manager");
     379    block_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Block");
     380    partition_interface_info = g_dbus_node_info_lookup_interface (introspection_data, "org.gtk.GDBus.Example.Partition");
     381    g_assert (manager_interface_info != NULL);
     382    g_assert (block_interface_info != NULL);
     383    g_assert (partition_interface_info != NULL);
     384  
     385    owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
     386                               "org.gtk.GDBus.TestSubtree",
     387                               G_BUS_NAME_OWNER_FLAGS_NONE,
     388                               on_bus_acquired,
     389                               on_name_acquired,
     390                               on_name_lost,
     391                               NULL,
     392                               NULL);
     393  
     394    loop = g_main_loop_new (NULL, FALSE);
     395    g_main_loop_run (loop);
     396  
     397    g_bus_unown_name (owner_id);
     398  
     399    g_dbus_node_info_unref (introspection_data);
     400  
     401    return 0;
     402  }