⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbus-service.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  BlueZ - Bluetooth protocol stack for Linux * *  Copyright (C) 2006-2007  Nokia Corporation *  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 <unistd.h>#include <stdlib.h>#include <dirent.h>#include <signal.h>#include <ctype.h>#include <sys/types.h>#include <sys/wait.h>#include <bluetooth/sdp.h>#include <glib.h>#include <dbus/dbus.h>#include "dbus.h"#include "dbus-helper.h"#include "hcid.h"#include "notify.h"#include "server.h"#include "dbus-common.h"#include "dbus-error.h"#include "error.h"#include "manager.h"#include "adapter.h"#include "dbus-service.h"#include "dbus-hci.h"#define SERVICE_INTERFACE "org.bluez.Service"#define STARTUP_TIMEOUT (10 * 1000) /* 10 seconds */#define SHUTDOWN_TIMEOUT (2 * 1000) /* 2 seconds */#define SERVICE_SUFFIX ".service"#define SERVICE_GROUP "Bluetooth Service"#define NAME_MATCH "interface=" DBUS_INTERFACE_DBUS ",member=NameOwnerChanged"static GSList *services = NULL;static GSList *removed = NULL;static void service_free(struct service *service){	if (!service)		return;	if (service->action)		dbus_message_unref(service->action);	g_free(service->bus_name);	g_free(service->filename);	g_free(service->object_path);	g_free(service->name);	g_free(service->descr);	g_free(service->ident);	g_free(service);}static void service_exit(const char *name, struct service *service){	DBusConnection *conn = get_dbus_connection();	debug("Service owner exited: %s", name);	dbus_connection_emit_signal(conn, service->object_path,					SERVICE_INTERFACE, "Stopped",					DBUS_TYPE_INVALID);	if (service->action) {		DBusMessage *reply;		reply = dbus_message_new_method_return(service->action);		send_message_and_unref(conn, reply);		dbus_message_unref(service->action);		service->action = NULL;	}	g_free(service->bus_name);	service->bus_name = NULL;}static DBusHandlerResult get_info(DBusConnection *conn,					DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	DBusMessageIter iter;	DBusMessageIter dict;	dbus_bool_t running;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_iter_init_append(reply, &iter);	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);	dbus_message_iter_append_dict_entry(&dict, "identifier",			DBUS_TYPE_STRING, &service->ident);	dbus_message_iter_append_dict_entry(&dict, "name",			DBUS_TYPE_STRING, &service->name);	dbus_message_iter_append_dict_entry(&dict, "description",			DBUS_TYPE_STRING, &service->descr);	running = (service->external || service->bus_name) ? TRUE : FALSE;	dbus_message_iter_append_dict_entry(&dict, "running",			DBUS_TYPE_BOOLEAN, &running);	dbus_message_iter_close_container(&iter, &dict);	return send_message_and_unref(conn, reply);}static DBusHandlerResult get_identifier(DBusConnection *conn,					DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	const char *identifier = "";	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	if (service->ident)		identifier = service->ident;	dbus_message_append_args(reply,			DBUS_TYPE_STRING, &identifier,			DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult get_name(DBusConnection *conn,					DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	const char *name = "";	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	if (service->name)		name = service->name;	dbus_message_append_args(reply,			DBUS_TYPE_STRING, &name,			DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult get_description(DBusConnection *conn,						DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	const char *description = "";	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	if (service->descr)		description = service->descr;	dbus_message_append_args(reply,			DBUS_TYPE_STRING, &description,			DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult get_bus_name(DBusConnection *conn,						DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	if (!service->bus_name)		return error_not_available(conn, msg);	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_append_args(reply,			DBUS_TYPE_STRING, &service->bus_name,			DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static void service_setup(gpointer data){	/* struct service *service = data; */}static DBusHandlerResult service_filter(DBusConnection *conn,					DBusMessage *msg, void *data){	DBusError err;	struct service *service = data;	const char *name, *old, *new;	unsigned long pid;	if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;	if (!dbus_message_get_args(msg, 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;	}	if (*new == '\0' || *old != '\0' || *new != ':')		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;	if (!dbus_bus_get_unix_process_id(conn, new, &pid)) {		error("Could not get PID of %s", new);		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;	}	if ((GPid) pid != service->pid)		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;	debug("Child PID %d got the unique bus name %s", service->pid, new);	service->bus_name = g_strdup(new);	dbus_error_init(&err);	dbus_bus_remove_match(conn, NAME_MATCH, &err);	if (dbus_error_is_set(&err)) {		error("Remove match \"%s\" failed: %s" NAME_MATCH, err.message);		dbus_error_free(&err);	}	dbus_connection_remove_filter(conn, service_filter, service);	if (service->action) {		msg = dbus_message_new_method_return(service->action);		if (msg) {			if (dbus_message_is_method_call(service->action, MANAGER_INTERFACE,							"ActivateService"))				dbus_message_append_args(msg, DBUS_TYPE_STRING, &new,							DBUS_TYPE_INVALID);			send_message_and_unref(conn, msg);		}		dbus_message_unref(service->action);		service->action = NULL;	}	if (service->startup_timer) {		g_source_remove(service->startup_timer);		service->startup_timer = 0;	} else		debug("service_filter: timeout was already removed!");	name_listener_add(conn, new, (name_cb_t) service_exit, service);	dbus_connection_emit_signal(conn, service->object_path,					SERVICE_INTERFACE, "Started",					DBUS_TYPE_INVALID);	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;}static void abort_startup(struct service *service, DBusConnection *conn, int ecode){	DBusError err;	if (conn) {		dbus_error_init(&err);		dbus_bus_remove_match(conn, NAME_MATCH, &err);		if (dbus_error_is_set(&err)) {			error("Remove match \"%s\" failed: %s" NAME_MATCH, err.message);		dbus_error_free(&err);		}		dbus_connection_remove_filter(conn, service_filter, service);	}	g_source_remove(service->startup_timer);	service->startup_timer = 0;	if (service->action) {		if (conn)			error_failed_errno(conn, service->action, ecode);		dbus_message_unref(service->action);		service->action = NULL;	}	if (service->pid > 0 && kill(service->pid, SIGKILL) < 0)		error("kill(%d, SIGKILL): %s (%d)", service->pid,				strerror(errno), errno);}static void service_died(GPid pid, gint status, gpointer data){	struct service *service = data;	if (WIFEXITED(status))		debug("%s (%s) exited with status %d", service->name,				service->ident, WEXITSTATUS(status));	else		debug("%s (%s) was killed by signal %d", service->name,				service->ident, WTERMSIG(status));	g_spawn_close_pid(pid);	service->pid = 0;	if (service->startup_timer)		abort_startup(service, get_dbus_connection(), ECANCELED);	if (service->shutdown_timer) {		g_source_remove(service->shutdown_timer);		service->shutdown_timer = 0;	}	if (g_slist_find(removed, service)) {		removed = g_slist_remove(removed, service);		service_free(service);	}}static gboolean service_shutdown_timeout(gpointer data){	struct service *service = data;	if (service->pid > 0) {		debug("SIGKILL for \"%s\" (PID %d) since it didn't exit yet",			service->name, service->pid);		if (kill(service->pid, SIGKILL) < 0)			error("kill(%d, SIGKILL): %s (%d)", service->pid,						strerror(errno), errno);	}	service->shutdown_timer = 0;	return FALSE;}static void stop_service(struct service *service, gboolean remove){	if (service->pid > 0 && kill(service->pid, SIGTERM) < 0)		error("kill(%d, SIGTERM): %s (%d)", service->pid,				strerror(errno), errno);	service->shutdown_timer = g_timeout_add(SHUTDOWN_TIMEOUT,						service_shutdown_timeout,						service);	if (remove) {		services = g_slist_remove(services, service);		removed = g_slist_append(removed, service);	}}static gboolean service_startup_timeout(gpointer data){	struct service *service = data;	debug("Killing \"%s\" (PID %d) because it did not connect to D-Bus in time",			service->name, service->pid);	abort_startup(service, get_dbus_connection(), ETIME);	return FALSE;}int service_start(struct service *service, DBusConnection *conn){	DBusError derr;	char *addr, *argv[2], *envp[2], command[PATH_MAX], address[256];	if (!dbus_connection_add_filter(conn, service_filter, service, NULL)) {		error("Unable to add signal filter");		return -1;	}	dbus_error_init(&derr);	dbus_bus_add_match(conn, NAME_MATCH, &derr);	if (dbus_error_is_set(&derr)) {		error("Add match \"%s\" failed: %s", derr.message);		dbus_error_free(&derr);		dbus_connection_remove_filter(conn, service_filter, service);		return -1;	}	snprintf(command, sizeof(command) - 1, "%s/bluetoothd-service-%s",						SERVICEDIR, service->ident);	argv[0] = command;	argv[1] = NULL;	addr = get_local_server_address();	snprintf(address, sizeof(address) - 1, "BLUETOOTHD_ADDRESS=%s", addr);	envp[0] = address;	envp[1] = NULL;	dbus_free(addr);	if (!g_spawn_async(SERVICEDIR, argv, envp, G_SPAWN_DO_NOT_REAP_CHILD,				service_setup, service, &service->pid, NULL)) {		error("Unable to execute %s", argv[0]);		dbus_connection_remove_filter(conn, service_filter, service);		dbus_bus_remove_match(conn, NAME_MATCH, NULL);		return -1;	}	g_child_watch_add(service->pid, service_died, service);	debug("%s executed with PID %d", argv[0], service->pid);	service->startup_timer = g_timeout_add(STARTUP_TIMEOUT,						service_startup_timeout,						service);	return 0;}static DBusHandlerResult start(DBusConnection *conn,				DBusMessage *msg, void *data){	struct service *service = data;	if (service->external || service->pid)		return error_failed_errno(conn, msg, EALREADY);	if (service_start(service, conn) < 0)		return error_failed_errno(conn, msg, ENOEXEC);	service->action = dbus_message_ref(msg);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult stop(DBusConnection *conn,				DBusMessage *msg, void *data){	struct service *service  = data;	if (service->external || !service->bus_name)		return error_failed_errno(conn, msg, EPERM);	stop_service(service, FALSE);	service->action = dbus_message_ref(msg);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult is_running(DBusConnection *conn,					DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	dbus_bool_t running;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	running = (service->external || service->bus_name) ? TRUE : FALSE;	dbus_message_append_args(reply,			DBUS_TYPE_BOOLEAN, &running,			DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult is_external(DBusConnection *conn,					DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_append_args(reply,			DBUS_TYPE_BOOLEAN, &service->external,			DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult set_trusted(DBusConnection *conn,					DBusMessage *msg, void *data){	struct service *service = data;	DBusMessage *reply;	const char *address;	if (!dbus_message_get_args(msg, NULL,			DBUS_TYPE_STRING, &address,			DBUS_TYPE_INVALID))		return error_invalid_arguments(conn, msg, NULL);	if (check_address(address) < 0)		return error_invalid_arguments(conn, msg, NULL);	reply = dbus_message_new_method_return(msg);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -