简体   繁体   English

如何获取g_dbus_connection_signal_subscribe函数来告诉我有关预先存在的对象/接口的信息?

[英]How can I get the g_dbus_connection_signal_subscribe function to tell me about pre-existing objects/interfaces?

The function g_dbus_connection_signal_subscribe works great for telling me when new DBus objects appear (or vanish) with InterfacesAdded signal (or InterfacesRemoved signal). 函数g_dbus_connection_signal_subscribe非常适合告诉我新的DBus对象何时出现(或消失)InterfacesAdded信号(或InterfacesRemoved信号)。 But I need for to know about pre-existing objects/interfaces. 但我需要知道预先存在的对象/接口。

I wrote the following piece of C code to provide callbacks when DBus objects are added/removed from the bus. 我写了下面的一段C代码,以便在从总线添加/删除DBus对象时提供回调。 Error-checking omitted for simplicity. 为简单起见,省略了错误检查。

#include <stdio.h>
#include <stdlib.h>
#include <gio/gio.h>

static void signal_cb(GDBusConnection *connection,
        const gchar *sender_name,const gchar *object_path,
        const gchar *interface_name,const gchar *signal_name,
        GVariant *parameters,gpointer user_data)
{
    printf("%s: %s.%s %s\n",object_path,interface_name,signal_name,
        g_variant_print(parameters,TRUE));
}

int main(int argc,char *argv[])
{
GDBusConnection *c;
GMainLoop *loop;
int filter_id;

    c = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL,&err);
    loop = g_main_loop_new(NULL,0);
    filter_id = g_dbus_connection_signal_subscribe(c,
        "org.bluez",NULL,NULL,NULL,NULL,
        G_DBUS_SIGNAL_FLAGS_NONE,signal_cb,NULL,NULL);   
    g_main_loop_run (loop);
    g_main_loop_unref (loop);

    exit(0);
}

So what I'm trying to do is keep track of all the DBus objects that exist under the org.bluez branch of the tree. 所以我要做的是跟踪树的org.bluez分支下存在的所有DBus对象。 (These represent pluggable Bluetooth controllers and the devices that are discovered by each controller). (这些代表可插拔蓝牙控制器和每个控制器发现的设备)。 I need to know about DBus objects that were already there before my program started, and I need to know about new objects that appear after my program starts. 我需要知道在程序启动之前已经存在的DBus对象,我需要知道程序启动后出现的新对象。

My code above tells me about new objects, but nothing about the objects that are already there. 我上面的代码告诉我有关新对象的信息,但没有关于已存在的对象的信息。 Is there a way in the gdbus API to get an "InterfacesCreated" signal for objects that already exist? gdbus API中是否有一种方法可以为已存在的对象获取“InterfacesCreated”信号? I suppose could read the entire DBus object hierarchy and then subscribe to changes, but that leads to race conditions where if an object appears between the time I read the object hierarchy and the time I subscribe, then I would miss those objects.... 我想可以读取整个DBus对象层次结构,然后订阅更改,但这会导致竞争条件,如果在我读取对象层次结构和我订阅的时间之间出现一个对象,那么我会想念那些对象....

What's the best-practice way to accomplish this with the gdbus API? 使用gdbus API实现此目的的最佳实践方法是什么?

In case anyone happens upon this, as Parthiban noted, the solution (for D-Bus services which implement the org.freedesktop.DBus.ObjectManager interface, such as BlueZ) is to call the GetManagedObjects method. 如果有人发生这种情况,正如Parthiban所指出的那样,解决方案(对于实现org.freedesktop.DBus.ObjectManager接口的D-Bus服务,例如BlueZ)就是调用GetManagedObjects方法。 This is extremely painful to code in C with GDBus since it requires detailed understanding of GVariant typing; 使用GDBus在C语言中进行编码非常痛苦,因为它需要详细了解GVariant类型; see the documentation . 文档 Also check out the docs on GVariant data type strings. 另请查看有关GVariant数据类型字符串的文档 But here's how it's done: 但这是如何完成的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#include <gio/gio.h>


/* The GVariant must be of type "a{sa{sv}}" (array of interfaces, where each */
/* interface has an array of properties). */
/* This type what DBus provides with InterfacesAdded signal and is also */
/* part of the return value from the GetManagedObjects method. */
static void proc_interface_var(const gchar *objpath,GVariant *iflist)
{
GVariantIter *iter,*iter2;
gchar *ifname,*propname,*proptext;
GVariant *propvalue;

    g_variant_get(iflist,"a{sa{sv}}",&iter);
    while (g_variant_iter_loop(iter,"{sa{sv}}",&ifname,&iter2)) {
        if (strcmp(ifname,"org.bluez.Adatper1") != 0 &&
                                    strcmp(ifname,"org.bluez.Device1") != 0) {
            /* we only care about the Adatper1 and Device1 interfaces */
            continue;
        } /* if */
        printf("Interface %s added to object %s\n",ifname,objpath);
        while (g_variant_iter_loop(iter2,"{sv}",&propname,&propvalue)) {
            proptext = g_variant_print(propvalue,0);
            printf("\t%s=%s\n",propname,proptext);
            g_free(proptext);
        } /* while */
    } /* while */
    return;
} /* proc_interface_var */


/* The GVariant must be of type "a{sv}" (an array of properties). */
static void proc_property_var(const gchar *objpath,
                                        gchar *ifname,GVariant *proplist)
{
GVariantIter *iter;
gchar *propname,*proptext;
GVariant *propvalue;

    g_variant_get(proplist,"a{sv}",&iter);
    while (g_variant_iter_loop(iter,"{sv}",&propname,&propvalue)) {
        proptext = g_variant_print(propvalue,0);
        printf("\tProperty changed on object %s interface %s: %s=%s\n",
            objpath,ifname,propname,proptext);
        g_free(proptext);
    } /* while */
    return;
} /* proc_property_var */


static void signal_cb(GDBusConnection *c,
            const gchar *sender_name,const gchar *object_path,
            const gchar *interface_name,const gchar *signal_name,
            GVariant *parameters,gpointer user_data)
{
char fullsignal[200];
gchar *s,*objpath,*ifname,*propname,*proptext;
GVariant *ifvar,*propvalue;
GVariantIter *iter,*iter2;

    snprintf(fullsignal,200,"%s.%s",interface_name,signal_name);
    if (strcmp(fullsignal,
                "org.freedesktop.DBus.ObjectManager.InterfacesAdded") == 0) {
        g_variant_get(parameters,"(o*)",&objpath,&ifvar);
        proc_interface_var(objpath,ifvar);
    } else if (strcmp(fullsignal,
                "org.freedesktop.DBus.Properties.PropertiesChanged") == 0) {
        g_variant_get(parameters,"(s*as)",&ifname,&propvalue,&iter2);
        proc_property_var(object_path,ifname,propvalue);
        while (g_variant_iter_loop(iter2,"s",&propname)) {
            printf("\tProperty changed on object %s interface %s: "
                "%s is nil\n",object_path,ifname,propname);
        } /* while */
    } else {
        printf("Ignoring unsupported signal for object %s, "
            "signal=%s.%s, param type=%s\n",
            object_path,interface_name,signal_name,
            g_variant_get_type_string(parameters));
        s = g_variant_print(parameters,TRUE);
        printf("Unsupported signal: parameters %s\n",s);
        g_free(s);
    } /* else */

    return;
} /* signal_cb */


static void bt_discover(GDBusConnection *c,const char *ctlname,int on_off)
{
GError *err=NULL;
GVariant *result;
const char *method;
char ctlpath[80];

    snprintf(ctlpath,80,"/org/bluez/%s",ctlname);
    method = on_off ? "StartDiscovery" : "StopDiscovery";
    result = g_dbus_connection_call_sync(c,"org.bluez",ctlpath,
        "org.bluez.Adapter1",method,NULL,
        G_VARIANT_TYPE("()"),       /* return-type */
        G_DBUS_CALL_FLAGS_NONE,5000,NULL,&err);
    if (result==NULL) {
        if (err) fprintf(stderr,"g_dbus_connection_call error: %s\n",   
            err->message);
        exit(1);
    } /* if */
    g_variant_unref(result);
    return;
} /* bt_discover */


static void *receive_dbus_signals(void *arg)
{
GMainLoop *loop;

    printf("Receiving DBus signals...\n");
    loop = g_main_loop_new(NULL,0);
    g_main_loop_run(loop);
    g_main_loop_unref(loop);
    return NULL;
} /* receive_dbus_signals */


int main(int argc,char *argv[])
{
GError *err=NULL;
GVariant *result,*ifvar;
GVariantIter *iter;
GDBusConnection *c;
GDBusNodeInfo *node;
gchar *objpath;
pthread_t handle;
int filter_id;

    if ((c = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL,&err)) == NULL) {
        if (err) fprintf(stderr,"g_bus_get error: %s\n",err->message);
        exit(1);
    } /* if */

    filter_id = g_dbus_connection_signal_subscribe(c,
        "org.bluez",NULL,NULL,NULL,NULL,
        G_DBUS_SIGNAL_FLAGS_NONE,signal_cb,NULL,NULL);
    if (pthread_create(&handle,NULL,receive_dbus_signals,NULL) != 0) {
        fprintf(stderr,"Failed to create DBus listen thread\n");
        exit(1);
    } /* if */

    result = g_dbus_connection_call_sync(c,"org.bluez","/",
        "org.freedesktop.DBus.ObjectManager","GetManagedObjects",NULL,
        G_VARIANT_TYPE("(a{oa{sa{sv}}})"),      /* return-type */
        G_DBUS_CALL_FLAGS_NONE,5000,NULL,&err);
    if (result==NULL) {
        if (err) fprintf(stderr,"g_dbus_connection_call error: %s\n",   
            err->message);
        exit(1);
    } /* if */

    g_variant_get(result,"(a{oa{sa{sv}}})",&iter);
    /* below we replace 'a{sa{sv}}' with '*' to get it as a GVariant */
    while (g_variant_iter_loop(iter,"{o*}",&objpath,&ifvar)) {
        proc_interface_var(objpath,ifvar);
    } /* while */
    g_variant_unref(result);

    bt_discover(c,"hci0",1);
    sleep(5);
    bt_discover(c,"hci0",0);
    sleep(5);

    exit(0);
}

For D-Bus services which don't implement the org.freedesktop.DBus.ObjectManager interface, you need to use D-Bus introspection and parse the introspection XML to find the paths of the existing object nodes. 对于实现org.freedesktop.DBus.ObjectManager接口的D-Bus服务,您需要使用D-Bus内省并解析内省XML以查找现有对象节点的路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以使用预先存在的函数或代码来计算POSIX程序中的TCP段校验和 - Is there a pre-existing function or code I can use to compute a TCP segment checksum in a POSIX program 如何判断一个库是否是用 -g 编译的? - How can I tell if a library was compiled with -g? 开始预先存在的项目 - Starting work on a Pre-existing Project 谁能检查程序并告诉我如何才能获得正确的输出? - can anyone check the program and tell me how can i get the correct output? 为什么C语言允许用户创建与已有库function同名的宏? - Why does C language allow users to create Macros whose name are the same as a pre-existing library function? 我怎样才能让GDB告诉我哪个地址导致了段错? - How can I get GDB to tell me what address caused a segfault? 谁能告诉我它是如何得到寄存器DS的值的 - Who can tell me that how could it get the value of register DS 我怎样才能让gcc警告我“int i = i;” - How can I get gcc to warn me about “int i = i;” 如何获得有关C语言中函数调用者的信息? - How can I get information about a caller of a function in C? 如何指示gcc像g ++一样警告我有关无效函数指针转换的信息? - How to instruct gcc to warn me about invalid function pointer conversion just as g++ would do?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM