Is there a way to check for listening clients in DBus?
Is it even possible to do? I'm using gdbus.
Background
I'm creating service which interfaces with serial ports and I want to implicitly open serial ports if someone is listening and automatically close it if last client disconnects. I could do it with open/close methods but there is risk that one client closes connection when other is still listening.
Another solution to my problem would be connection counting, but there is also risk that client forgets to close port or crashes.
Do you have any other idea how to implement this?
My code (shortened)
Based on: https://github.com/bratsche/glib/blob/master/gio/tests/gdbus-example-server.c
#include <gio/gio.h>
#include <stdlib.h>
#ifdef G_OS_UNIX
#include <unistd.h>
#endif
/* ---------------------------------------------------------------------------------------------------- */
static GDBusNodeInfo *introspection_data = NULL;
/* Introspection data for the service we are exporting */
static const gchar introspection_xml[] =
"<node>"
" <interface name='info.skorepa.serial.port'>"
" <signal name='DataRecieved'>"
" <arg type='ay' name='data'/>"
" </signal>"
" </interface>"
"</node>";
/* ---------------------------------------------------------------------------------------------------- */
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)
{
// nothing - signal only
}
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)
{
// nothing - signal only
}
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)
{
// nothing - no properties
}
/* for now */
static const GDBusInterfaceVTable interface_vtable =
{
handle_method_call,
handle_get_property,
handle_set_property
};
/* ---------------------------------------------------------------------------------------------------- */
// Here I emit signal - for now I just emit every 2 seconds
static gboolean
on_timeout_cb (gpointer user_data)
{
GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
GVariantBuilder *builder;
GVariantBuilder *invalidated_builder;
GError *error;
error = NULL;
printf("Constructing array\n");
builder = g_variant_builder_new (G_VARIANT_TYPE ("ay"));
printf("Adding 65\n");
g_variant_builder_add (builder,
"y",
65);
printf("Adding 66\n");
g_variant_builder_add (builder,
"y",
66);
printf("Emitting signal\n");
g_dbus_connection_emit_signal (connection,
NULL,
"/info/skorepa/TestObject",
"info.skorepa.serial.port",
"DataRecieved",
g_variant_new ("(ay)",
builder),
&error);
printf("Checking for errors\n");
g_assert_no_error (error);
return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
guint registration_id;
registration_id = g_dbus_connection_register_object (connection,
"/info/skorepa/TestObject",
introspection_data->interfaces[0],
&interface_vtable,
NULL, /* user_data */
NULL, /* user_data_free_func */
NULL); /* GError** */
g_assert (registration_id > 0);
/* swap value of properties Foo and Bar every two seconds */
g_timeout_add_seconds (2,
on_timeout_cb,
connection);
}
static void
on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
exit (1);
}
int
main (int argc, char *argv[])
{
guint owner_id;
GMainLoop *loop;
g_type_init ();
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
g_assert (introspection_data != NULL);
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
"info.skorepa.serial",
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL,
NULL);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_bus_unown_name (owner_id);
g_dbus_node_info_unref (introspection_data);
return 0;
}
Compiled using:
gcc signal-sample.c `pkg-config --cflags --libs glib-2.0 gio-2.0` -o test
Thank you