0
votes

I'm learning how to use D-Bus on C with GLib. So far I've created a D-Bus service which calls my application, and I get a response after using the 'dbus-send' command. I have two files, one with the D-Bus code and one with the functions to call. The 'test_method_start' function lets us know that it has been called successfully, and creates a new thread. The second funtion tells us that we are stopping, and exits the thread.

I'm obviously missing something out, because I'm not seeing the result of the function calls. Can anyone tell me where I'm going wrong? I'm referring to the example here.

Here's the code snippets:

File1.c:

void test_method_start()
{
    printf("Test method started\n")``;
    //syslog(LOG_NOTICE, "Test method started\n");
    if (!(pthread_create(&socketServerThread, NULL, 
       socketServerLoop, &socketServerParam)))
    {
        printf("Socket Server thread created successfully\n");
    }
    else
        fprintf(stderr, "Error creating Socket Server thread\n");
    pthread_exit(NULL);
}

void test_method_stop()
{
    printf("Test method ended\n");
    pthread_exit(NULL);
}

File2.c:

/*
* dbusClient
*/

/** Headers **/

#include "dbusClient.h"
#include <glib.h>
#include <gio/gio.h>
#include <gio/gioerror.h>
#include <gio/gdbuserror.h>
#include <stdlib.h>
#include <stdio.h>


/** Function Predeclarations    **/

/** Globals **/

/**  The service name on the bus. **/
static const gchar service[] = "org.test.DBusClient";

/** The object we publish on the bus.   **/
static const gchar object_path[] = "/org/test/DBusObject";

/** Introspection data for the one object, in the internal form.    **/
static GDBusNodeInfo *introspection_data = NULL;

/** Introspection data for the one object in XML form   **/

static const gchar introspection_xml[] =
            "<node>"
            "  <interface name='org.test.DBusClientInterface'>"
            "    <method name='test_method_start'>"
            "      <arg type='s' name='message' direction='in'/>"
            "      <arg type='s' name='response' direction='out'/>"
            "    </method>"
            "    <method name='test_method_stop'>"
            "      <arg type='s' name='message' direction='in'/>"
            "      <arg type='s' name='response' direction='out'/>"
            "    </method>"
            "  </interface>"
            "</node>";


/** Object Callbacks    **/

/*  Handle a request for a property */

static GVariant *handle_get_property (GDBusConnection  *connection,
                     const gchar      *sender,
                     const gchar      *object_path,
                     const gchar      *interface_name,
                     const gchar      *property_name,
                     GError          **error,
                     gpointer          user_data)
{
    printf("handle_get_property\n");
/*  Print an optional log message   */
#ifdef VERBOSE
  fprintf (stderr, "[server 0] "
  "handle_get_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n",
  connection, sender, object_path, interface_name, property_name,
           user_data);
#endif

/*  We currently don't have any properties, 
so this should be an error. */
g_set_error (error,
               G_IO_ERROR,
               G_IO_ERROR_FAILED,
               "[server 0] Invalid property '%s'",
               property_name);
// And we're done
return NULL;

} // handle_get_property

/*  Handle a call to a method   */
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)
{
    printf("handle_method_call\n");
#ifdef VERBOSE
  gchar *paramstr = g_variant_print (parameters, TRUE);
  fprintf (stderr, "[server 0] "
"handle_method_call (%p,\"%s\",\"%s\",\"%s\",\"%s",
\"\",invocation),%p)\n",
          connection, sender, object_path, interface_name, method_name,
           paramstr, user_data);
  g_free (paramstr);
#endif

/*  Default: No such method */

    if (g_strcmp0 (method_name, "test_method_start") == 0)
    {
        const gchar *greeting;

        g_variant_get (parameters, "(&s)", &greeting);

        if (g_strcmp0 (greeting, "Return Unregistered") == 0)
        {
            g_dbus_method_invocation_return_error (invocation,
                   G_IO_ERROR,
                   G_IO_ERROR_FAILED_HANDLED,
                   "As requested, here's a GError not registered 
                   (G_IO_ERROR_FAILED_HANDLED)");
        }
        else if (g_strcmp0 (greeting, "Return Registered") == 0)
        {
            g_dbus_method_invocation_return_error (invocation,
                   G_DBUS_ERROR,
                   G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
            "As requested, here's a GError that is 
             registered
             (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
        }
        else if (g_strcmp0 (greeting, "Return Raw") == 0)
        {
            g_dbus_method_invocation_return_dbus_error (invocation,
            "org.gtk.GDBus.SomeErrorName",
            "As requested, here's a raw D-Bus error");
        }
        else
        {
            gchar *response;
            response = g_strdup_printf ("You greeted me with '%s'. 
            Thanks!", greeting);
            g_dbus_method_invocation_return_value 
            (invocation,               
            g_variant_new ("(s)", response));
            g_free (response);
        }
      }
      else if (g_strcmp0 (method_name, "test_method_stop") == 0)
      {
          const gchar *greeting;

          g_variant_get (parameters, "(&s)", &greeting);

          if (g_strcmp0 (greeting, "Return Unregistered") == 0)
          {
              g_dbus_method_invocation_return_error (invocation,
              G_IO_ERROR,
              G_IO_ERROR_FAILED_HANDLED,
              "As requested, here's a GError not registered 
              (G_IO_ERROR_FAILED_HANDLED)");
          }
          else if (g_strcmp0 (greeting, "Return Registered") == 0)
          {
              g_dbus_method_invocation_return_error (invocation,
              G_DBUS_ERROR,
              G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
              "As requested, here's a GError that is registered 
              (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
          }
          else if (g_strcmp0 (greeting, "Return Raw") == 0)
          {
              g_dbus_method_invocation_return_dbus_error (invocation,
              "org.gtk.GDBus.SomeErrorName",
              "As requested, here's a raw D-Bus error");
          }
          else
          {
              gchar *response;
             response = g_strdup_printf ("You greeted me with 
             '%s'.Thanks!", greeting);
              g_dbus_method_invocation_return_value (invocation,
                        g_variant_new ("(s)", response));
                        g_free (response);
          }
      }
      else
      {
          g_dbus_method_invocation_return_error (invocation,
                                   G_IO_ERROR,
                                   G_IO_ERROR_INVALID_ARGUMENT,
                                   "[server 0] Invalid method: '%s'",
                                          method_name);
      }
} // handle_method_call

/*  Handle a request to set a property. */
static gboolean handle_set_property (GDBusConnection  *connection,
                     const gchar      *sender,
                     const gchar      *object_path,
                     const gchar      *interface_name,
                     const gchar      *property_name,
                     GVariant         *value,
                     GError          **error,
                     gpointer          user_data)
{
    printf("handle_set_property\n");
/*  Print an optional log message   */
#ifdef VERBOSE
  gchar *valstr = g_variant_print (value, TRUE);
  fprintf (stderr, "[server 0] "
           "handle_set_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",
           \"%s\",(error),%p)\n",
           connection, sender, object_path, 
           interface_name, property_name,
           valstr, user_data);
  g_free (valstr);
#endif

  g_set_error (error,
               G_IO_ERROR,
               G_IO_ERROR_FAILED,
               "[server 0] No such property: '%s'",
               property_name);
  return 0;
} // handle_set_property


/** Bus Callbacks   **/

/*  When the bus gets acquired...   */
static void on_bus_acquired (GDBusConnection *connection,
                 const gchar     *name,
                 gpointer        user_data)
{
    printf("on_bus_acquired\n");
  static GDBusInterfaceVTable interface_vtable =
    {
      handle_method_call,
      handle_get_property,
      handle_set_property
    };

  guint registration_id;
//  GError *error = NULL;

  // An optional notification
#ifdef VERBOSE
  fprintf (stderr, "[server 0] on_bus_acquired (%p, \"%s\", %p)\n",
           connection, name, user_data);
#endif

  registration_id = g_dbus_connection_register_object (connection,
                             object_path,
                             introspection_data->interfaces[0],
                             &interface_vtable,
                             NULL,    // Optional user data
                             NULL,    // Func. for freeing user data
                             NULL); // GError

  // Check to see whether or not the call succeeded.
  printf("g_assert registration_id = %d\n", registration_id);
  g_assert (registration_id > 0);

} // on_bus_acquired

static void on_name_acquired (GDBusConnection *connection,
                  const gchar     *name,
                  gpointer         user_data)
{

// An optional notification
#ifdef VERBOSE
  fprintf (stderr, "[server 0] on_name_acquired (%p, \"%s\", %p)\n",
           connection, name, user_data);
#endif
} // on_name_acquired

static void on_name_lost (GDBusConnection *connection,
              const gchar     *name,
              gpointer         user_data)
{

// An optional notification
#ifdef VERBOSE
  fprintf (stderr, "[server 0] on_name_lost (%p, \"%s\", %p)\n",
           connection, name, user_data);
#endif
  // Things seem to have gone badly wrong, so give up
  exit (1);
} // on_name_lost



/** Main    **/

void *dbusLoop(void *dbusParam)
{
  guint owner_id;
  GMainLoop *loop;
  printf("Reached dbusLoop\n");

  // Build an internal representation of the interface
  printf("Register the object\n");
  introspection_data = g_dbus_node_info_new_for_xml     
  (introspection_xml, NULL);
  g_assert (introspection_data != NULL);

  // Request the name on the bus
  owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
                             service,
                             G_BUS_NAME_OWNER_FLAGS_NONE,
                             on_bus_acquired,
                             on_name_acquired,
                             on_name_lost,
                             NULL,
                             NULL);

  // Start the main loop
  printf("Start the loop\n");
  loop = g_main_loop_new (NULL, FALSE);
  g_main_loop_run (loop);

  // Tell the bus that we're done with the name
  printf("Release the owner_id\n");
  g_bus_unown_name (owner_id);

  // Clean up after ourselves

  g_dbus_node_info_unref (introspection_data);

  //Exit and join main thread
    pthread_exit(NULL);
} // main

My command line statement is:

dbus-send --session --print-reply --type=method_call --dest=org.test.DBusClient /org/test/DBusObject org.test.DBusClientInterface.test_method_start string:"Hello"

and the response is:

method return sender=:1.364 -> dest=:1.376 reply_serial=2 string "You greeted me with 'Hello'. Thanks!"

What should I be doing now to get "test_method_start" to run?

Thanks for any help.

1

1 Answers

1
votes

You should not be calling pthread_exit on a thread you didn't start. test_method_start is called by a thread created by someone else.

How do you expect test_method_start to be called when you never call it anywhere or take its address? There is no magic to DBUS; you have to call it from handle_method_call if you want it to be called. You seem to have the code to check if the method name is "test_method_start", so you would call it inside that if.