C DBus:当名称从总线中消失时观察

C DBus:当名称从总线中消失时观察,c,dbus,C,Dbus,我正在使用低级dbusc库实现该服务。StatusNotifierWatcher规范要求观察者可以知道“StatusNotifierItem实例何时从总线上消失”,以便发送StatusNotifierItemUnregistered信号 示例实现: #include <stdio.h> #include <stdlib.h> #include <dbus/dbus.h> DBusConnection *conn = NULL; void item_unre

我正在使用低级dbusc库实现该服务。StatusNotifierWatcher规范要求观察者可以知道“StatusNotifierItem实例何时从总线上消失”,以便发送
StatusNotifierItemUnregistered
信号

示例实现:

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

DBusConnection *conn = NULL;

void item_unregistered_signal(const char *name) {
    DBusMessage *signal = dbus_message_new_signal(
            "/org/freedesktop/StatusNotifierWatcher",
            "org.freedesktop.StatusNotifierWatcher",
            "StatusNotifierItemUnregistered");
    dbus_message_append_args(signal,
            DBUS_TYPE_STRING, &name,
            DBUS_TYPE_INVALID);
    dbus_connection_send(conn, signal, NULL);
    dbus_message_unref(signal);
}

void watch_name(const char *name, void(*cb)(const char *)) {
    // Not sure how to impliment
}

dbus_bool_t register_item(DBusConnection *connection, DBusMessage *message, void *_data) {
    DBusError error;
    char *name;

    if (!dbus_message_get_args(message, &error,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_INVALID)) {
        fprintf(stderr, "Error parsing method args: %s\n", error.message);
        return FALSE;
    }

    watch_name(name, item_unregistered_signal);
    return TRUE;
}

static void check_and_abort(DBusError *error) {
    if (dbus_error_is_set(error)) {
        fprintf(stderr, "dbus_err: %s\n", error->message);
        exit(EXIT_FAILURE);
    }
}

int main() {
    DBusError error;
    dbus_error_init(&error);
    conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
    check_and_abort(&error);

    dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
            DBUS_NAME_FLAG_REPLACE_EXISTING,
            &error);
    check_and_abort(&error);

    dbus_connection_add_filter(conn, register_item, NULL, free);

    while(1) {
        dbus_connection_read_write_dispatch(conn, 1000);
    }
}
#包括
#包括
#包括
DBusConnection*conn=NULL;
无效项\u未注册\u信号(常量字符*名称){
dbus消息*信号=dbus\u消息\u新信号(
“/org/freedesktop/StatusNotifierWatcher”,
“org.freedesktop.StatusNotifierWatcher”,
“注册状态”);
dbus_消息_附加_参数(信号,
DBUS_类型_字符串和名称,
DBUS_类型_无效);
dbus_连接_发送(连接,信号,空);
dbus_消息_unref(信号);
}
void watch_name(常量字符*名称,void(*cb)(常量字符*){
//不知道如何实现
}
dbus bool\u t寄存器项(DBusConnection*连接、DBusMessage*消息、void*\u数据){
DBusError错误;
字符*名称;
如果(!dbus_message_get_args)(消息,&错误,
DBUS_类型_字符串和名称,
DBUS_类型_无效){
fprintf(stderr,“错误解析方法参数:%s\n”,错误消息);
返回FALSE;
}
监视名称(名称、项目、未注册信号);
返回TRUE;
}
静态无效检查和中止(DBusError*错误){
如果(dbus_错误_已设置(错误)){
fprintf(标准,“数据库错误:%s\n”,错误->消息);
退出(退出失败);
}
}
int main(){
DBusError错误;
dbus_error_init(&error);
conn=dbus\u-bus\u-get(dbus\u-bus\u会话,&错误);
检查和中止(&error);
dbus_总线_请求_名称(conn,“org.freedesktop.StatusNotifierWatcher”,
DBUS_名称_标志_替换_现有,
&误差);
检查和中止(&error);
dbus\u连接\u添加\u过滤器(连接,寄存器\u项,空,自由);
而(1){
dbus连接读写调度(conn,1000);
}
}

如果我有一个DBus服务的知名名称,我如何知道该名称何时从总线上消失?

好吧,我找到了这个答案,我将为未来需要使用libdbus的可怜人发布一个答案

org.freedesktop.DBus
在任何DBus名称更改时发送
NameOwnerChanged
信号。可以使用此信号跟踪项是否已消失,因为NewOwner参数是空字符串。 此函数可以执行以下操作:

static DBusHandlerResult signal_handler(DBusConnection *connection,
        DBusMessage *message, void *_usr_data) {

    if (dbus_message_is_signal(message, "org.freedesktop.DBus",
            "NameOwnerChanged")) {
        const char *name;
        const char *old_owner;
        const char *new_owner;

        if (!dbus_message_get_args(message, NULL,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &old_owner,
                DBUS_TYPE_STRING, &new_owner,
                DBUS_TYPE_INVALID)) {
            fprintf(stderr, "Error getting OwnerChanged args");
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
        if (strcmp(name, "") != 0) {
            // Name not lost, just swapped owners
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
        name_lost(name);
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
还需要添加一个匹配项,以便使用此信号调用您的程序。我在
main()


对于那些使用(推荐)而不是libdbus(不推荐)的用户,等价物是。

libdbus不会贬值,只是在大多数情况下不推荐使用。事实上,它可能比任何其他库都更符合dbus规范。不过,感谢您的添加,很好地澄清了更高级别的库具有方便这些功能;dbus的油嘴滑舌是非常不受欢迎的。libdbus没有被弃用,但不鼓励使用它。sd总线通常被认为是低级别D总线使用的更好的选择。我会修改我的答案。被谁普遍接受?我已经使用libdbus-1两周了,发现它是最轻的DBus实现。此外,libdbus-1是最容易理解的。sd dbus有更多的依赖性,有些系统甚至没有systemd,D-Bus维护人员“普遍接受”。sd总线确实是systemd的一部分,所以如果您不能依赖systemd,它不是一个选项,对吗。libdbus-1没有sd总线那么方便的API,它的线程模型定义不清,并且很难正确使用wrt内存管理。请参阅Lennart关于sd总线为什么没有与systemd分离的想法。
dbus_bus_add_match(conn, 
        "type='signal',\
        sender='org.freedesktop.DBus',\
        interface='org.freedesktop.DBus',\
        member='NameOwnerChanged'",
        &error);
check_and_abort(&error);

dbus_connection_add_filter(conn, signal_handler, NULL, free);