gpt4 book ai didi

c - DBusWatch 和 DBusTimeout 示例

转载 作者:太空狗 更新时间:2023-10-29 16:40:04 41 4
gpt4 key购买 nike

我需要用C 编写一个应用程序,用于在dbus 消息队列上异步发送和读取消息。我已经读过,为此我应该使用连接提供的 DBusWatchDBusTimeout 对象,但我找不到如何在任何地方使用这些对象的示例......

目前我使用dbus_connection_read_write_dispatch为了做到这一点,但我读到它不推荐用于异步操作,所以我必须切换到创建我自己的 main loop 并使用它......

最接近我的问题的答案是:

http://lists.freedesktop.org/archives/dbus/2007-September/008555.html ,

建议查看 dbus-gmain.c 文件,我照做了,但我只发现有一个 dbus_connection_set_watch_functions 的调用和 dbus_connection_set_timeout_functions ,以其他函数作为参数 - 我应该覆盖这些函数吗?我应该按原样使用它们吗?

我根本不知道如何使用这些来读取和写入 dbus 消息队列...

任何想法都非常受欢迎......

最佳答案

这是我前一段时间写的东西。我删除了特定于应用程序的代码,您应该只在处理用于您的应用程序的 DBus 消息的地方添加您的代码片段,就应该这样。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <dbus/dbus.h>

struct dbus_ctx {
DBusConnection *conn;
struct event_base *evbase;
struct event dispatch_ev;
void *extra;
};

static void dispatch(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusConnection *c = ctx->conn;

logger(LOG_DEBUG "dispatching\n");

while (dbus_connection_get_dispatch_status(c) == DBUS_DISPATCH_DATA_REMAINS)
dbus_connection_dispatch(c);
}

static void handle_dispatch_status(DBusConnection *c,
DBusDispatchStatus status, void *data)
{
struct dbus_ctx *ctx = data;

logger(LOG_DEBUG "new dbus dispatch status: %d\n", status);

if (status == DBUS_DISPATCH_DATA_REMAINS) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 0,
};
event_add(&ctx->dispatch_ev, &tv);
}
}

static void handle_watch(int fd, short events, void *x)
{
struct dbus_ctx *ctx = x;
struct DBusWatch *watch = ctx->extra;

unsigned int flags = 0;
if (events & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (events & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
/*if (events & HUP)
flags |= DBUS_WATCH_HANGUP;
if (events & ERR)
flags |= DBUS_WATCH_ERROR;*/

logger(LOG_DEBUG "got dbus watch event fd=%d watch=%p ev=%d\n",
fd, watch, events);
if (dbus_watch_handle(watch, flags) == FALSE)
logger(LOG_ERROR "dbus_watch_handle() failed\n");

handle_dispatch_status(ctx->conn, DBUS_DISPATCH_DATA_REMAINS, ctx);
}

static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;

struct dbus_ctx *ctx = data;
ctx->extra = w;

int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
short cond = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
cond |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
cond |= EV_WRITE;

struct event *event = event_new(ctx->evbase, fd, cond, handle_watch, ctx);
if (!event)
return FALSE;

event_add(event, NULL);

dbus_watch_set_data(w, event, NULL);

logger(LOG_DEBUG "added dbus watch fd=%d watch=%p cond=%d\n", fd, w, cond);
return TRUE;
}

static void remove_watch(DBusWatch *w, void *data)
{
struct event *event = dbus_watch_get_data(w);

if (event)
event_free(event);

dbus_watch_set_data(w, NULL, NULL);

logger(LOG_DEBUG "removed dbus watch watch=%p\n", w);
}

static void toggle_watch(DBusWatch *w, void *data)
{
logger(LOG_DEBUG "toggling dbus watch watch=%p\n", w);

if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}

static void handle_timeout(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusTimeout *t = ctx->extra;

logger(LOG_DEBUG "got dbus handle timeout event %p\n", t);

dbus_timeout_handle(t);
}

static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
struct dbus_ctx *ctx = data;

if (!dbus_timeout_get_enabled(t))
return TRUE;

logger(LOG_DEBUG "adding timeout %p\n", t);

struct event *event = event_new(ctx->evbase, -1, EV_TIMEOUT|EV_PERSIST,
handle_timeout, t);
if (!event) {
logger(LOG_ERROR "failed to allocate new event for timeout\n");
return FALSE;
}

int ms = dbus_timeout_get_interval(t);
struct timeval tv = {
.tv_sec = ms / 1000,
.tv_usec = (ms % 1000) * 1000,
};
event_add(event, &tv);

dbus_timeout_set_data(t, event, NULL);

return TRUE;
}

static void remove_timeout(DBusTimeout *t, void *data)
{
struct event *event = dbus_timeout_get_data(t);

logger(LOG_DEBUG "removing timeout %p\n", t);

event_free(event);

dbus_timeout_set_data(t, NULL, NULL);
}

static void toggle_timeout(DBusTimeout *t, void *data)
{
logger(LOG_DEBUG "toggling timeout %p\n", t);

if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}

static DBusHandlerResult handle_nameownerchanged(DBusMessage *message,
void *data)
{
struct dbus_ctx *ctx = data;
char *name, *old, *new;
if (dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID) == FALSE) {
logger(LOG_ERROR "spurious NameOwnerChanged signal\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
logger(LOG_DEBUG "dbus NameOwnerChanged %s -> %s\n", old, new);

if (new[0] != '\0')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

/* XXX handle disconnecting clients */

return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

static DBusHandlerResult msg_filter(DBusConnection *connection,
DBusMessage *message, void *data)
{
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
"NameOwnerChanged"))
return handle_nameownerchanged(message, data);

logger(LOG_DEBUG "got dbus message %d %s -> %s %s/%s/%s %s\n",
dbus_message_get_type(message),
dbus_message_get_sender(message),
dbus_message_get_destination(message),
dbus_message_get_path(message),
dbus_message_get_interface(message),
dbus_message_get_member(message),
dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR ?
dbus_message_get_error_name(message) : "");

return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

static void unregister_func(DBusConnection *connection, void *data)
{
}

static DBusHandlerResult message_func(DBusConnection *connection,
DBusMessage *message, void *data)
{
struct dbus_ctx *ctx = data;

logger(LOG_DEBUG "got dbus message sent to %s %s %s\n",
dbus_message_get_destination(message),
dbus_message_get_interface(message),
dbus_message_get_path(message));

/* XXX handle DBus message */

return DBUS_HANDLER_RESULT_HANDLED;
}

static DBusObjectPathVTable dbus_vtable = {
.unregister_function = unregister_func,
.message_function = message_func,
};

struct dbus_ctx *dbus_init(struct event_base *eb)
{
DBusConnection *conn = NULL;
struct dbus_ctx *ctx = calloc(1, sizeof(struct dbus_ctx));
if (!ctx) {
logger_perror("can't allocate dbus_ctx\n");
goto out;
}

conn = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
if (conn == NULL) {
logger(LOG_ERROR "failed to get bus\n");
goto out;
}

dbus_connection_set_exit_on_disconnect(conn, FALSE);

ctx->conn = conn;
ctx->evbase = eb;
event_assign(&ctx->dispatch_ev, eb, -1, EV_TIMEOUT, dispatch, ctx);

if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_watch_functions() failed\n");
goto out;
}

if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_timeout_functions() failed\n");
goto out;
}

if (dbus_connection_add_filter(conn, msg_filter, ctx, NULL) == FALSE) {
logger(LOG_ERROR "dbus_connection_add_filter() failed\n");
goto out;
}

dbus_connection_set_dispatch_status_function(conn, handle_dispatch_status,
ctx, NULL);

char match[256];
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='NameOwnerChanged'",
DBUS_INTERFACE_DBUS);
DBusError error;
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
"NameOwnerChanged", error.message);
dbus_error_free(&error);
goto out;
}

snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='%s'",
GNP_IPC_INTERFACE, GNP_IPC_SIGNAL_DELIVER_SA);
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
GNP_IPC_SIGNAL_DELIVER_SA, error.message);
dbus_error_free(&error);
goto out;
}

if (dbus_connection_register_object_path(conn, GNP_IPC_PATH, &dbus_vtable,
ctx) != TRUE) {
logger(LOG_ERROR "failed to register object path\n");
goto out;
}

return ctx;

out:
if (conn) {
dbus_connection_close(conn);
dbus_connection_unref(conn);
}
if (ctx)
free(ctx);
return NULL;
}

void dbus_close(struct dbus_ctx *ctx)
{
if (ctx && ctx->conn) {
dbus_connection_flush(ctx->conn);
dbus_connection_close(ctx->conn);
dbus_connection_unref(ctx->conn);
event_del(&ctx->dispatch_ev);
}
if (ctx)
free(ctx);
}

关于c - DBusWatch 和 DBusTimeout 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9378593/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com