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

📄 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 <ctype.h>#include <dirent.h>#include <errno.h>#include <stdlib.h>#include <unistd.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/hidp.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <glib.h>#include <dbus/dbus.h>#include "dbus.h"#include "dbus-helper.h"#include "logging.h"#include "textfile.h"#include "device.h"#include "server.h"#include "error.h"#include "manager.h"#include "storage.h"static const char *pnp_uuid	= "00001200-0000-1000-8000-00805f9b34fb";static const char *hid_uuid	= "00001124-0000-1000-8000-00805f9b34fb";static const char *headset_uuid	= "00001108-0000-1000-8000-00805f9b34fb";struct pending_req {	char		*adapter_path;	/* Local adapter D-Bus path */	bdaddr_t	src;		/* Local adapter BT address */	bdaddr_t	dst;		/* Peer BT address */	DBusConnection	*conn;	DBusMessage	*msg;	sdp_record_t	*pnp_rec;	sdp_record_t	*hid_rec;	int		ctrl_sock;};static GSList *device_paths = NULL;	/* Input registered paths */static DBusConnection *connection = NULL;static struct pending_req *pending_req_new(DBusConnection *conn,			DBusMessage *msg, bdaddr_t *src, bdaddr_t *dst){	char adapter[18], adapter_path[32];	struct pending_req *pr;	int dev_id;	pr = g_try_new0(struct pending_req, 1);	if (!pr)		return NULL;	ba2str(src, adapter);	dev_id = hci_devid(adapter);	snprintf(adapter_path, 32, "/org/bluez/hci%d", dev_id);	pr->adapter_path = g_strdup(adapter_path);	bacpy(&pr->src, src);	bacpy(&pr->dst, dst);	pr->conn = dbus_connection_ref(conn);	pr->msg = dbus_message_ref(msg);	return pr;}static void pending_req_free(struct pending_req *pr){	if (!pr)		return;	if (pr->adapter_path)		g_free(pr->adapter_path);	if (pr->conn)		dbus_connection_unref(pr->conn);	if (pr->msg)		dbus_message_unref(pr->msg);	if (pr->pnp_rec)		sdp_record_free(pr->pnp_rec);	if (pr->hid_rec)		sdp_record_free(pr->hid_rec);	g_free(pr);}static int get_record(struct pending_req *pr, uint32_t handle,					DBusPendingCallNotifyFunction cb){	DBusMessage *msg;	DBusPendingCall *pending;	char addr[18];	const char *paddr = addr;	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,			"org.bluez.Adapter", "GetRemoteServiceRecord");	if (!msg)		return -1;	ba2str(&pr->dst, addr);	dbus_message_append_args(msg,			DBUS_TYPE_STRING, &paddr,			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_pending_call_unref(pending);	dbus_message_unref(msg);	return 0;}static int get_handles(struct pending_req *pr, const char *uuid,					DBusPendingCallNotifyFunction cb){	DBusMessage *msg;	DBusPendingCall *pending;	char addr[18];	const char *paddr = addr;	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,			"org.bluez.Adapter", "GetRemoteServiceHandles");	if (!msg)		return -1;	ba2str(&pr->dst, addr);	dbus_message_append_args(msg,			DBUS_TYPE_STRING, &paddr,			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_pending_call_unref(pending);	dbus_message_unref(msg);	return 0;}static void epox_endian_quirk(unsigned char *data, int size){	/* USAGE_PAGE (Keyboard)	05 07	 * USAGE_MINIMUM (0)		19 00	 * USAGE_MAXIMUM (65280)	2A 00 FF   <= must be FF 00	 * LOGICAL_MINIMUM (0)		15 00	 * LOGICAL_MAXIMUM (65280)	26 00 FF   <= must be FF 00	 */	unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,						0x15, 0x00, 0x26, 0x00, 0xff };	int i;	if (!data)		return;	for (i = 0; i < size - sizeof(pattern); i++) {		if (!memcmp(data + i, pattern, sizeof(pattern))) {			data[i + 5] = 0xff;			data[i + 6] = 0x00;			data[i + 10] = 0xff;			data[i + 11] = 0x00;		}	}}static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req){	sdp_data_t *pdlist, *pdlist2;	uint8_t attr_val;	pdlist = sdp_data_get(rec, 0x0101);	pdlist2 = sdp_data_get(rec, 0x0102);	if (pdlist) {		if (pdlist2) {			if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {				strncpy(req->name, pdlist2->val.str, 127);				strcat(req->name, " ");			}			strncat(req->name, pdlist->val.str, 127 - strlen(req->name));		} else			strncpy(req->name, pdlist->val.str, 127);	} else {		pdlist2 = sdp_data_get(rec, 0x0100);		if (pdlist2)			strncpy(req->name, pdlist2->val.str, 127); 	}	pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);	req->parser = pdlist ? pdlist->val.uint16 : 0x0100;	pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);	req->subclass = pdlist ? pdlist->val.uint8 : 0;	pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);	req->country = pdlist ? pdlist->val.uint8 : 0;	pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);	attr_val = pdlist ? pdlist->val.uint8 : 0;	if (attr_val)		req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);	pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);	attr_val = pdlist ? pdlist->val.uint8 : 0;	if (attr_val)		req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);	pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);	if (pdlist) {		pdlist = pdlist->val.dataseq;		pdlist = pdlist->val.dataseq;		pdlist = pdlist->next;		req->rd_data = g_try_malloc0(pdlist->unitSize);		if (req->rd_data) {			memcpy(req->rd_data, (unsigned char *) pdlist->val.str,								pdlist->unitSize);			req->rd_size = pdlist->unitSize;			epox_endian_quirk(req->rd_data, req->rd_size);		}	}}static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req){	sdp_data_t *pdlist;	pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);	req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;	pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);	req->product = pdlist ? pdlist->val.uint16 : 0x0000;	pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);	req->version = pdlist ? pdlist->val.uint16 : 0x0000;}static gboolean interrupt_connect_cb(GIOChannel *chan,			GIOCondition cond, struct pending_req *pr){	struct hidp_connadd_req hidp;	DBusMessage *reply;	const char *path;	int isk, ret, err;	socklen_t len;	memset(&hidp, 0, sizeof(hidp));	isk = g_io_channel_unix_get_fd(chan);	if (cond & G_IO_NVAL) {		err = EHOSTDOWN;		isk = -1;		goto failed;	}	if (cond & (G_IO_HUP | G_IO_ERR)) {		err = EHOSTDOWN;		error("Hangup or error on HIDP interrupt socket");		goto failed;	}	len = sizeof(ret);	if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {		err = errno;		error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err);		goto failed;	}	if (ret != 0) {		err = ret;		error("connect(): %s (%d)", strerror(ret), ret);		goto failed;	}	extract_hid_record(pr->hid_rec, &hidp);	if (pr->pnp_rec)		extract_pnp_record(pr->pnp_rec, &hidp);	store_device_info(&pr->src, &pr->dst, &hidp);	if (input_device_register(pr->conn, &pr->src,					&pr->dst, &hidp, &path) < 0) {		error_failed(pr->conn, pr->msg, "path registration failed");		goto cleanup;	}	dbus_connection_emit_signal(pr->conn, INPUT_PATH,			INPUT_MANAGER_INTERFACE, "DeviceCreated",			DBUS_TYPE_STRING, &path,			DBUS_TYPE_INVALID);	device_paths = g_slist_append(device_paths, g_strdup(path));	/* Replying to the requestor */	reply = dbus_message_new_method_return(pr->msg);	dbus_message_append_args(reply,				DBUS_TYPE_STRING, &path,				DBUS_TYPE_INVALID);	send_message_and_unref(pr->conn, reply);	goto cleanup;failed:	error_connection_attempt_failed(pr->conn, pr->msg, err);cleanup:	if (isk >= 0)		close(isk);	close(pr->ctrl_sock);	pending_req_free(pr);	if (hidp.rd_data)		g_free(hidp.rd_data);	return FALSE;}static gboolean control_connect_cb(GIOChannel *chan,			GIOCondition cond, struct pending_req *pr){	int ret, csk, err;	socklen_t len;	csk = g_io_channel_unix_get_fd(chan);	if (cond & G_IO_NVAL) {		err = EHOSTDOWN;		csk = -1;		goto failed;	}	if (cond & (G_IO_HUP | G_IO_ERR)) {		err = EHOSTDOWN;		error("Hangup or error on HIDP control socket");		goto failed;	}	/* Set HID control channel */	pr->ctrl_sock = csk;	len = sizeof(ret);	if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {		err = errno;		error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err);		goto failed;	}	if (ret != 0) {		err = ret;		error("connect(): %s (%d)", strerror(ret), ret);		goto failed;	}	/* Connect to the HID interrupt channel */	if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR,			(GIOFunc) interrupt_connect_cb, pr) < 0) {		err = errno;		error("L2CAP connect failed:%s (%d)", strerror(errno), errno);		goto failed;	}	return FALSE;failed:	if (csk >= 0)		close(csk);	error_connection_attempt_failed(pr->conn, pr->msg, err);	pending_req_free(pr);	return FALSE;}static void create_bonding_reply(DBusPendingCall *call, void *data){	DBusMessage *reply = dbus_pending_call_steal_reply(call);	struct pending_req *pr = data;	DBusError derr;	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		error("CreateBonding failed: %s(%s)",					derr.name, derr.message);		error_failed(pr->conn, pr->msg, "Authentication failed (CreateBonding)");		dbus_error_free(&derr);		dbus_message_unref(reply);		pending_req_free(pr);		return;	}	dbus_message_unref(reply);	if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL,				(GIOFunc) control_connect_cb, pr) < 0) {		int err = errno;		error_connection_attempt_failed(pr->conn, pr->msg, err);		error("L2CAP connect failed:%s (%d)", strerror(err), err);		pending_req_free(pr);	}}static void finish_sdp_transaction(bdaddr_t *dba){	char address[18], *addr_ptr = address;	DBusMessage *msg, *reply;	DBusError derr;	ba2str(dba, address);	msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",						"org.bluez.Adapter",						"FinishRemoteServiceTransaction");	if (!msg) {		error("Unable to allocate new method call");		return;	}	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(connection, msg,								-1, &derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) {		error("FinishRemoteServiceTransaction(%s) failed: %s",				address, derr.message);		dbus_error_free(&derr);		return;	}	dbus_message_unref(reply);}static int create_bonding(struct pending_req *pr){	DBusPendingCall *pending;	DBusMessage *msg;	char address[18], *addr_ptr = address;	msg = dbus_message_new_method_call("org.bluez", pr->adapter_path,					   "org.bluez.Adapter", "CreateBonding");	if (!msg) {		error("Unable to allocate new method call");		return -1;	}	ba2str(&pr->dst, address);	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, 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, create_bonding_reply, pr, NULL);	dbus_pending_call_unref(pending);	dbus_message_unref(msg);	return 0;}static void hid_record_reply(DBusPendingCall *call, void *data){	DBusMessage *reply = dbus_pending_call_steal_reply(call);	struct pending_req *pr = data;	DBusError derr;	uint8_t *rec_bin;	int len, scanned;	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		/* FIXME : to not try to be clever about		   hcid error but forward as is to the user */		if (dbus_error_has_name(&derr,			"org.bluez.Error.ConnectionAttemptFailed"))			error_connection_attempt_failed(pr->conn, 					pr->msg, EIO);		else			error_not_supported(pr->conn, pr->msg);		error("GetRemoteServiceRecord failed: %s(%s)",					derr.name, derr.message);		goto fail;	}	finish_sdp_transaction(&pr->dst);	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 HID service record length");		goto fail;	}	pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned);	if (!pr->hid_rec) {		error_not_supported(pr->conn, pr->msg);		goto fail;	}	dbus_message_unref(reply);	if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) {		sdp_data_t *d;		/* Pairing mandatory for keyboard and combo */		d = sdp_data_get(pr->hid_rec, SDP_ATTR_HID_DEVICE_SUBCLASS);		if (d && (d->val.uint8 & 0x40) &&				!has_bonding(&pr->src, &pr->dst)) {			if (create_bonding(pr) < 0) {				error_failed(pr->conn, pr->msg,					"Unable to initialize bonding process");				goto fail;			}			/* Wait bonding reply */			return;		}		/* Otherwise proceede L2CAP connection */	}	/* No encryption or link key already exists -- connect control channel */	if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL,				(GIOFunc) control_connect_cb, pr) < 0) {		int err = errno;		error("L2CAP connect failed:%s (%d)", strerror(err), err);		error_connection_attempt_failed(pr->conn, pr->msg, err);		goto fail;	}	/* Wait L2CAP connect */	return;fail:	dbus_error_free(&derr);	pending_req_free(pr);	dbus_message_unref(reply);}static void hid_handle_reply(DBusPendingCall *call, void *data){	DBusMessage *reply = dbus_pending_call_steal_reply(call);	struct pending_req *pr = data;	uint32_t *phandle;	DBusError derr;	int len;

⌨️ 快捷键说明

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