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

📄 manager.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  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 <errno.h>#include <ctype.h>#include <dirent.h>#include <sys/stat.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/bnep.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <glib.h>#include "dbus.h"#include "dbus-helper.h"#include "logging.h"#include "textfile.h"#define NETWORK_MANAGER_INTERFACE "org.bluez.network.Manager"#include "error.h"#include "bridge.h"#include "manager.h"#include "common.h"#define MAX_NAME_SIZE	256struct pending_reply {	DBusConnection	*conn;	DBusMessage	*msg;	bdaddr_t	src;		/* Source address */	bdaddr_t	dst;		/* Destination address */	char		*addr;		/* Destination address */	char		*path;		/* D-Bus object path */	char		*adapter_path;	/* Default adapter path */	uint16_t	id;		/* Role */};static struct network_conf *conf = NULL;/* Network service configuration */static GSList *server_paths	= NULL;	/* Network registered servers paths */static GSList *connection_paths	= NULL;	/* Network registered connections paths */static int default_index = -1;		/* Network default connection path index */static int net_uid = 0;			/* Network objects identifier */static DBusConnection *connection = NULL;static void pending_reply_free(struct pending_reply *pr){	if (pr->addr)		g_free(pr->addr);	if (pr->path)		g_free(pr->path);	if (pr->adapter_path)		g_free(pr->adapter_path);	if (pr->msg)		dbus_message_unref(pr->msg);	if (pr->conn)		dbus_connection_unref(pr->conn);}static DBusHandlerResult create_path(DBusConnection *conn,					DBusMessage *msg, const char *path,					const char *sname){	DBusMessage *reply;	/* emit signal when it is a new path */	if (sname) {		dbus_connection_emit_signal(conn, NETWORK_PATH,						NETWORK_MANAGER_INTERFACE,						sname, DBUS_TYPE_STRING, &path,						DBUS_TYPE_INVALID);	}	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,					DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult list_paths(DBusConnection *conn, DBusMessage *msg,					GSList *list){	DBusMessage *reply;	DBusMessageIter iter;	DBusMessageIter array_iter;	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_TYPE_STRING_AS_STRING, &array_iter);	for (; list; list = list->next) {		dbus_message_iter_append_basic(&array_iter,						DBUS_TYPE_STRING,						&list->data);	}	dbus_message_iter_close_container(&iter, &array_iter);	return send_message_and_unref(conn, reply);}static const char * last_connection_used(DBusConnection *conn){	const char *path = NULL;	GSList *l;	int i;	for (i = g_slist_length (connection_paths) -1; i > -1; i--) {		path = g_slist_nth_data (connection_paths, i);		if (connection_is_connected(path))			break;	}	/* No connection connected fallback to last connection */	if (i == -1) {		l = g_slist_last(connection_paths);		path = l->data;	}	return path;}static DBusHandlerResult remove_path(DBusConnection *conn,					DBusMessage *msg, GSList **list,					const char *sname){	const char *path;	DBusMessage *reply;	DBusError derr;	GSList *l;	dbus_error_init(&derr);	if (!dbus_message_get_args(msg, &derr,				DBUS_TYPE_STRING, &path,				DBUS_TYPE_INVALID)) {		error_invalid_arguments(conn, msg, derr.message);		dbus_error_free(&derr);		return DBUS_HANDLER_RESULT_HANDLED;	}	l = g_slist_find_custom(*list, path, (GCompareFunc) strcmp);	if (!l)		return error_does_not_exist(conn, msg, "Path doesn't exist");	/* Remove references from the storage */	if (*list == connection_paths) {		if (connection_has_pending(path))			return error_failed(conn, msg, "Connection is Busy");		connection_remove_stored(path);		/* Reset default connection */		if (l == g_slist_nth(*list, default_index)) {			const char *dpath;			dpath = last_connection_used(conn);			connection_store(dpath, TRUE);		}	}	g_free(l->data);	*list = g_slist_remove(*list, l->data);	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	if (!dbus_connection_destroy_object_path(conn, path))		error("Network path unregister failed");	dbus_connection_emit_signal(conn, NETWORK_PATH,					NETWORK_MANAGER_INTERFACE,					sname, DBUS_TYPE_STRING, &path,					DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static void pan_record_reply(DBusPendingCall *call, void *data){	struct pending_reply *pr = data;	DBusMessage *reply = dbus_pending_call_steal_reply(call);	DBusError derr;	int len, scanned;	uint8_t *rec_bin;	sdp_data_t *d;	sdp_record_t *rec = NULL;	char name[MAX_NAME_SIZE], *desc = NULL;	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		/* FIXME: forward error as is */		if (dbus_error_has_name(&derr,				"org.bluez.Error.ConnectionAttemptFailed"))			error_connection_attempt_failed(pr->conn, pr->msg, 					EINVAL);		else			error_not_supported(pr->conn, pr->msg);		error("GetRemoteServiceRecord failed: %s(%s)", derr.name,			derr.message);		goto fail;	}	if (!dbus_message_get_args(reply, &derr,				DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len,				DBUS_TYPE_INVALID)) {		error_not_supported(pr->conn, pr->msg);		error("%s: %s", derr.name, derr.message);		goto fail;	}	if (len == 0) {		error_not_supported(pr->conn, pr->msg);		error("Invalid PAN service record length");		goto fail;	}	rec = sdp_extract_pdu(rec_bin, &scanned);	/* Concat remote name and service name */	memset(name, 0, MAX_NAME_SIZE);	if (read_remote_name(&pr->src, &pr->dst, name, MAX_NAME_SIZE) < 0)		len = 0;	else		len = strlen(name);	d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);	if (d) {		snprintf(name + len, MAX_NAME_SIZE - len,			len ? " (%.*s)" : "%.*s", d->unitSize, d->val.str);	}	/* Extract service description from record */	d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY);	if (d) {		desc = g_new0(char, d->unitSize);		snprintf(desc, d->unitSize, "%.*s",				d->unitSize, d->val.str);	}	if (connection_register(pr->path, &pr->src, &pr->dst, pr->id, name,				desc) < 0) {		error_failed(pr->conn, pr->msg, "D-Bus path registration failed");		goto fail;	}	connection_store(pr->path, FALSE);	connection_paths = g_slist_append(connection_paths, g_strdup(pr->path));	create_path(pr->conn, pr->msg, pr->path, "ConnectionCreated");fail:	if (desc)		g_free(desc);	sdp_record_free(rec);	dbus_error_free(&derr);	pending_reply_free(pr);	dbus_message_unref(reply);}static int get_record(struct pending_reply *pr, uint32_t handle,					DBusPendingCallNotifyFunction cb){	DBusMessage *msg;	DBusPendingCall *pending;	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,			"org.bluez.Adapter", "GetRemoteServiceRecord");	if (!msg)		return -1;	dbus_message_append_args(msg,			DBUS_TYPE_STRING, &pr->addr,			DBUS_TYPE_UINT32, &handle,			DBUS_TYPE_INVALID);	if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {		error("Can't send D-Bus message.");		dbus_message_unref(msg);		return -1;	}	dbus_pending_call_set_notify(pending, cb, pr, NULL);	dbus_message_unref(msg);	dbus_pending_call_unref(pending);	return 0;}static void pan_handle_reply(DBusPendingCall *call, void *data){	struct pending_reply *pr = data;	DBusMessage *reply = dbus_pending_call_steal_reply(call);	DBusError derr;	uint32_t *phandle;	int len;	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		/* FIXME : forward error as is */		if (dbus_error_has_name(&derr,				"org.bluez.Error.ConnectionAttemptFailed"))			error_connection_attempt_failed(pr->conn, pr->msg,					EINVAL);		else			error_not_supported(pr->conn, pr->msg);		error("GetRemoteServiceHandles: %s(%s)", derr.name,				derr.message);		goto fail;	}	if (!dbus_message_get_args(reply, &derr,				DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle,				&len, DBUS_TYPE_INVALID)) {		error_not_supported(pr->conn, pr->msg);		error("%s: %s", derr.name, derr.message);		goto fail;	}	if (!len) {		error_not_supported(pr->conn, pr->msg);		goto fail;	}	if (get_record(pr, *phandle, pan_record_reply) < 0) {		error_not_supported(pr->conn, pr->msg);		goto fail;	}	dbus_message_unref(reply);	return;fail:	dbus_error_free(&derr);	pending_reply_free(pr);}static int get_handles(struct pending_reply *pr,			DBusPendingCallNotifyFunction cb){	DBusMessage *msg;	DBusPendingCall *pending;	const char *uuid;	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,			"org.bluez.Adapter", "GetRemoteServiceHandles");	if (!msg)		return -1;	uuid = bnep_uuid(pr->id);	dbus_message_append_args(msg,			DBUS_TYPE_STRING, &pr->addr,			DBUS_TYPE_STRING, &uuid,			DBUS_TYPE_INVALID);	if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) {		error("Can't send D-Bus message.");		dbus_message_unref(msg);		return -1;	}	dbus_pending_call_set_notify(pending, cb, pr, NULL);	dbus_message_unref(msg);	dbus_pending_call_unref(pending);	return 0;}static DBusHandlerResult list_servers(DBusConnection *conn, DBusMessage *msg,					void *data){	return list_paths(conn, msg, server_paths);}static DBusHandlerResult find_server(DBusConnection *conn,						DBusMessage *msg, void *data){	DBusError derr;	const char *pattern;	const char *path;	GSList *list;	DBusMessage *reply;	dbus_error_init(&derr);	if (!dbus_message_get_args(msg, &derr,				DBUS_TYPE_STRING, &pattern,				DBUS_TYPE_INVALID)) {		error_invalid_arguments(conn, msg, derr.message);		dbus_error_free(&derr);		return DBUS_HANDLER_RESULT_HANDLED;	}	for (list = server_paths; list; list = list->next) {		path = (const char *) list->data;		if (server_find_data(path, pattern) == 0)			break;	}	if (list == NULL) {		error_does_not_exist(conn, msg, "No such server");		return DBUS_HANDLER_RESULT_HANDLED;	}	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,					DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult list_connections(DBusConnection *conn,						DBusMessage *msg, void *data){	return list_paths(conn, msg, connection_paths);}static GSList * find_connection_pattern(DBusConnection *conn,					const char *pattern){	const char *path;	GSList *list;	if (pattern == NULL)		return NULL;	for (list = connection_paths; list; list = list->next) {		path = (const char *) list->data;		if (connection_find_data(path, pattern) == 0)			break;	}	return list;}static DBusHandlerResult find_connection(DBusConnection *conn,						DBusMessage *msg, void *data){	DBusError derr;	const char *pattern;	const char *path;	GSList *list;	DBusMessage *reply;	dbus_error_init(&derr);	if (!dbus_message_get_args(msg, &derr,				DBUS_TYPE_STRING, &pattern,				DBUS_TYPE_INVALID)) {		error_invalid_arguments(conn, msg, derr.message);		dbus_error_free(&derr);		return DBUS_HANDLER_RESULT_HANDLED;	}	list = find_connection_pattern(conn, pattern);	if (list == NULL) {		error_does_not_exist(conn, msg, "No such connection");		return DBUS_HANDLER_RESULT_HANDLED;	}	path = list->data;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,					DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}char *find_adapter(DBusConnection *conn, bdaddr_t *src){	DBusMessage *msg, *reply;	DBusError derr;	char address[18], *addr_ptr = address;	char *path, *ret;	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Manager",						"FindAdapter");	if (!msg) {		error("Unable to allocate new method call");		return NULL;	}	ba2str(src, address);	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,				 DBUS_TYPE_INVALID);	dbus_error_init(&derr);	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1,								&derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr) ||				dbus_set_error_from_message(&derr, reply)) {		error("FindAdapter(%s) failed: %s", address, derr.message);		dbus_error_free(&derr);		return NULL;	}	dbus_error_init(&derr);	dbus_message_get_args(reply, &derr,				DBUS_TYPE_STRING, &path,				DBUS_TYPE_INVALID);	if (dbus_error_is_set(&derr)) {		error("Unable to get message args");		dbus_message_unref(reply);

⌨️ 快捷键说明

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