📄 dbus.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <stdint.h>#include <glib.h>#include <dbus/dbus.h>#ifdef NEED_DBUS_WATCH_GET_UNIX_FD#define dbus_watch_get_unix_fd dbus_watch_get_fd#endif#ifdef HAVE_DBUS_GLIB#include <dbus/dbus-glib-lowlevel.h>#endif#include "dbus.h"#include "logging.h"#define DISPATCH_TIMEOUT 0static int name_listener_initialized = 0;static GSList *name_listeners = NULL;#ifndef HAVE_DBUS_GLIBtypedef struct { uint32_t id; DBusTimeout *timeout;} timeout_handler_t;struct watch_info { guint watch_id; GIOChannel *io; DBusConnection *conn;};struct server_info { guint watch_id; GIOChannel *io; DBusServer *server;};#endifstruct disconnect_data { void (*disconnect_cb)(void *); void *user_data;};struct name_callback { name_cb_t func; void *user_data;};struct name_data { DBusConnection *connection; char *name; GSList *callbacks;};static struct name_data *name_data_find(DBusConnection *connection, const char *name){ GSList *current; for (current = name_listeners; current != NULL; current = current->next) { struct name_data *data = current->data; if (name == NULL && data->name == NULL) { if (connection == data->connection) return data; } else { if (strcmp(name, data->name) == 0) return data; } } return NULL;}static struct name_callback *name_callback_find(GSList *callbacks, name_cb_t func, void *user_data){ GSList *current; for (current = callbacks; current != NULL; current = current->next) { struct name_callback *cb = current->data; if (cb->func == func && cb->user_data == user_data) return cb; } return NULL;}static void name_data_call_and_free(struct name_data *data){ GSList *l; for (l = data->callbacks; l != NULL; l = l->next) { struct name_callback *cb = l->data; if (cb->func) cb->func(data->name, cb->user_data); g_free(cb); } g_slist_free(data->callbacks); g_free(data->name); g_free(data);}static void name_data_free(struct name_data *data){ GSList *l; for (l = data->callbacks; l != NULL; l = l->next) g_free(l->data); g_slist_free(data->callbacks); g_free(data->name); g_free(data);}static int name_data_add(DBusConnection *connection, const char *name, name_cb_t func, void *user_data){ int first = 1; struct name_data *data = NULL; struct name_callback *cb = NULL; cb = g_new(struct name_callback, 1); cb->func = func; cb->user_data = user_data; data = name_data_find(connection, name); if (data) { first = 0; goto done; } data = g_new0(struct name_data, 1); data->connection = connection; data->name = g_strdup(name); name_listeners = g_slist_append(name_listeners, data);done: data->callbacks = g_slist_append(data->callbacks, cb); return first;}static void name_data_remove(DBusConnection *connection, const char *name, name_cb_t func, void *user_data){ struct name_data *data; struct name_callback *cb = NULL; data = name_data_find(connection, name); if (!data) return; cb = name_callback_find(data->callbacks, func, user_data); if (cb) { data->callbacks = g_slist_remove(data->callbacks, cb); g_free(cb); } if (!data->callbacks) { name_listeners = g_slist_remove(name_listeners, data); name_data_free(data); }}static gboolean add_match(DBusConnection *connection, const char *name){ DBusError err; char match_string[128]; snprintf(match_string, sizeof(match_string), "interface=%s,member=NameOwnerChanged,arg0=%s", DBUS_INTERFACE_DBUS, name); dbus_error_init(&err); dbus_bus_add_match(connection, match_string, &err); if (dbus_error_is_set(&err)) { error("Adding match rule \"%s\" failed: %s", match_string, err.message); dbus_error_free(&err); return FALSE; } return TRUE;}static gboolean remove_match(DBusConnection *connection, const char *name){ DBusError err; char match_string[128]; snprintf(match_string, sizeof(match_string), "interface=%s,member=NameOwnerChanged,arg0=%s", DBUS_INTERFACE_DBUS, name); dbus_error_init(&err); dbus_bus_remove_match(connection, match_string, &err); if (dbus_error_is_set(&err)) { error("Removing owner match rule for %s failed: %s", name, err.message); dbus_error_free(&err); return FALSE; } return TRUE;}static DBusHandlerResult name_exit_filter(DBusConnection *connection, DBusMessage *message, void *user_data){ GSList *l; struct name_data *data; char *name, *old, *new; if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) { error("Invalid arguments for NameOwnerChanged signal"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* We are not interested of service creations */ if (*new != '\0') return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; data = name_data_find(connection, name); if (!data) { error("Got NameOwnerChanged signal for %s which has no listeners", name); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } for (l = data->callbacks; l != NULL; l = l->next) { struct name_callback *cb = l->data; cb->func(name, cb->user_data); } name_listeners = g_slist_remove(name_listeners, data); name_data_free(data); remove_match(connection, name); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;}int name_listener_add(DBusConnection *connection, const char *name, name_cb_t func, void *user_data){ int first; if (!name_listener_initialized) { if (!dbus_connection_add_filter(connection, name_exit_filter, NULL, NULL)) { error("dbus_connection_add_filter() failed"); return -1; } name_listener_initialized = 1; } first = name_data_add(connection, name, func, user_data); /* The filter is already added if this is not the first callback * registration for the name */ if (!first) return 0; if (name) { debug("name_listener_add(%s)", name); if (!add_match(connection, name)) { name_data_remove(connection, name, func, user_data); return -1; } } return 0;}int name_listener_remove(DBusConnection *connection, const char *name, name_cb_t func, void *user_data){ struct name_data *data; struct name_callback *cb; data = name_data_find(connection, name); if (!data) { error("remove_name_listener: no listener for %s", name); return -1; } cb = name_callback_find(data->callbacks, func, user_data); if (!cb) { error("No matching callback found for %s", name); return -1; } data->callbacks = g_slist_remove(data->callbacks, cb); g_free(cb); /* Don't remove the filter if other callbacks exist */ if (data->callbacks) return 0; if (name) { debug("name_listener_remove(%s)", name); if (!remove_match(connection, name)) return -1; } name_data_remove(connection, name, func, user_data); return 0;}int name_listener_indicate_disconnect(DBusConnection *connection){ struct name_data *data; data = name_data_find(connection, NULL); if (!data) { error("name_listener_indicate_disconnect: no listener found"); return -1; } debug("name_listener_indicate_disconnect"); name_data_call_and_free(data); return 0;}dbus_bool_t dbus_bus_get_unix_process_id(DBusConnection *conn, const char *name, unsigned long *pid){ DBusMessage *msg, *reply; DBusError err; dbus_uint32_t pid_arg; msg = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetConnectionUnixProcessID"); if (!msg) { error("Unable to allocate new message"); return FALSE; } if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { error("Unable to append arguments to message"); dbus_message_unref(msg); return FALSE; } dbus_error_init(&err); reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); if (dbus_error_is_set(&err)) { error("Sending GetConnectionUnixProcessID failed: %s", err.message); dbus_error_free(&err); dbus_message_unref(msg); return FALSE; } dbus_error_init(&err); dbus_message_get_args(reply, &err, DBUS_TYPE_UINT32, &pid_arg, DBUS_TYPE_INVALID); if (dbus_error_is_set(&err)) { error("Getting GetConnectionUnixProcessID args failed: %s", err.message); dbus_error_free(&err); dbus_message_unref(msg); dbus_message_unref(reply); return FALSE; } *pid = (unsigned long) pid_arg; dbus_message_unref(msg); dbus_message_unref(reply); return TRUE;}static DBusHandlerResult disconnect_filter(DBusConnection *conn, DBusMessage *msg, void *data){ struct disconnect_data *dc_data = data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -