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

📄 manager.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  BlueZ - Bluetooth protocol stack for Linux * *  Copyright (C) 2004-2008  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 <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/param.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/un.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <bluetooth/rfcomm.h>#include <glib.h>#include <gdbus.h>#include "../src/dbus-common.h"#include "adapter.h"#include "device.h"#include "driver.h"#include "logging.h"#include "textfile.h"#include "error.h"#include "port.h"#include "storage.h"#include "manager.h"#include "sdpd.h"#include "glib-helper.h"#define SERIAL_PORT_NAME	"spp"#define SERIAL_PORT_UUID	"00001101-0000-1000-8000-00805F9B34FB"#define DIALUP_NET_NAME		"dun"#define DIALUP_NET_UUID		"00001103-0000-1000-8000-00805F9B34FB"#define SERIAL_PROXY_INTERFACE	"org.bluez.serial.Proxy"#define BUF_SIZE		1024typedef enum {	TTY_PROXY,	UNIX_SOCKET_PROXY,	TCP_SOCKET_PROXY,	UNKNOWN_PROXY_TYPE = 0xFF} proxy_type_t;struct proxy {	bdaddr_t	src;	bdaddr_t	dst;	char		*uuid128;	/* UUID 128 */	char		*address;	/* TTY or Unix socket name */	char		*path;		/* D-Bus path */	short int	port;		/* TCP port */	proxy_type_t	type;		/* TTY or Unix socket */	struct termios  sys_ti;		/* Default TTY setting */	struct termios  proxy_ti;	/* Proxy TTY settings */	uint8_t		channel;	/* RFCOMM channel */	uint32_t	record_id;	/* Service record id */	GIOChannel	*io;		/* Server listen */	guint		rfcomm_watch;	/* RFCOMM watch: Remote */	guint		local_watch;	/* Local watch: TTY or Unix socket */};static DBusConnection *connection = NULL;static GSList *proxies = NULL;static int sk_counter = 0;static void disable_proxy(struct proxy *prx){	if (prx->rfcomm_watch) {		g_source_remove(prx->rfcomm_watch);		prx->rfcomm_watch = 0;	}	if (prx->local_watch) {		g_source_remove(prx->local_watch);		prx->local_watch = 0;	}	remove_record_from_server(prx->record_id);	prx->record_id = 0;	g_io_channel_unref(prx->io);	prx->io = NULL;}static void proxy_free(struct proxy *prx){	g_free(prx->address);	g_free(prx->uuid128);	g_free(prx);}static inline DBusMessage *does_not_exist(DBusMessage *msg,					const char *description){	return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist",				description);}static inline DBusMessage *invalid_arguments(DBusMessage *msg,					const char *description){	return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",				description);}static inline DBusMessage *failed(DBusMessage *msg, const char *description){	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",				description);}static void add_lang_attr(sdp_record_t *r){	sdp_lang_attr_t base_lang;	sdp_list_t *langs = 0;	/* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */	base_lang.code_ISO639 = (0x65 << 8) | 0x6e;	base_lang.encoding = 106;	base_lang.base_offset = SDP_PRIMARY_LANG_BASE;	langs = sdp_list_append(0, &base_lang);	sdp_set_lang_attr(r, langs);	sdp_list_free(langs, 0);}static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel){	sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;	uuid_t uuid, root_uuid, l2cap, rfcomm;	sdp_profile_desc_t profile;	sdp_record_t *record;	sdp_data_t *ch;	record = sdp_record_alloc();	if (!record)		return NULL;	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);	root = sdp_list_append(NULL, &root_uuid);	sdp_set_browse_groups(record, root);	sdp_list_free(root, NULL);	bt_string2uuid(&uuid, uuid128);	svclass_id = sdp_list_append(NULL, &uuid);	sdp_set_service_classes(record, svclass_id);	sdp_list_free(svclass_id, NULL);	sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);	profile.version = 0x0100;	profiles = sdp_list_append(NULL, &profile);	sdp_set_profile_descs(record, profiles);	sdp_list_free(profiles, NULL);	sdp_uuid16_create(&l2cap, L2CAP_UUID);	proto[0] = sdp_list_append(NULL, &l2cap);	apseq = sdp_list_append(NULL, proto[0]);	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);	proto[1] = sdp_list_append(NULL, &rfcomm);	ch = sdp_data_alloc(SDP_UINT8, &channel);	proto[1] = sdp_list_append(proto[1], ch);	apseq = sdp_list_append(apseq, proto[1]);	aproto = sdp_list_append(NULL, apseq);	sdp_set_access_protos(record, aproto);	add_lang_attr(record);	sdp_set_info_attr(record, "Port Proxy Entity",				NULL, "Port Proxy Entity");	sdp_data_free(ch);	sdp_list_free(proto[0], NULL);	sdp_list_free(proto[1], NULL);	sdp_list_free(apseq, NULL);	sdp_list_free(aproto, NULL);	return record;}static GIOError channel_write(GIOChannel *chan, char *buf, size_t size){	GIOError err = G_IO_ERROR_NONE;	gsize wbytes, written;	wbytes = written = 0;	while (wbytes < size) {		err = g_io_channel_write(chan,				buf + wbytes,				size - wbytes,				&written);		if (err != G_IO_ERROR_NONE)			return err;		wbytes += written;	}	return err;}static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data){	char buf[BUF_SIZE];	GIOChannel *dest = data;	GIOError err;	size_t rbytes;	if (cond & G_IO_NVAL)		return FALSE;	if (cond & (G_IO_HUP | G_IO_ERR)) {		/* Try forward remaining data */		do {			rbytes = 0;			err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes);			if (err != G_IO_ERROR_NONE || rbytes == 0)				break;			err = channel_write(dest, buf, rbytes);		} while (err == G_IO_ERROR_NONE);		g_io_channel_close(dest);		return FALSE;	}	rbytes = 0;	err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes);	if (err != G_IO_ERROR_NONE)		return FALSE;	err = channel_write(dest, buf, rbytes);	if (err != G_IO_ERROR_NONE)		return FALSE;	return TRUE;}static inline int unix_socket_connect(const char *address){	struct sockaddr_un addr;	int err, sk;	memset(&addr, 0, sizeof(addr));	addr.sun_family = PF_UNIX;	if (strncmp("x00", address, 3) == 0) {		/*		 * Abstract namespace: first byte NULL, x00		 * must be removed from the original address.		 */		strcpy(addr.sun_path + 1, address + 3);	} else {		/* Filesystem address */		strcpy(addr.sun_path, address);	}	/* Unix socket */	sk = socket(AF_UNIX, SOCK_STREAM, 0);	if (sk < 0) {		err = errno;		error("Unix socket(%s) create failed: %s(%d)",				address, strerror(err), err);		return -err;	}	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {		err = errno;		error("Unix socket(%s) connect failed: %s(%d)",				address, strerror(err), err);		close(sk);		errno = err;		return -err;	}	return sk;}static int tcp_socket_connect(const char *address){	struct sockaddr_in addr;	int err, sk;	unsigned short int port;	memset(&addr, 0, sizeof(addr));	if (strncmp(address, "localhost", 9) != 0) {		error("Address should have the form localhost:port.");		return -1;	}	port = atoi(strchr(address, ':') + 1);	if (port <= 0) {		error("Invalid port '%d'.", port);		return -1;	}	addr.sin_family = AF_INET;	addr.sin_addr.s_addr = inet_addr("127.0.0.1");	addr.sin_port = htons(port);	sk = socket(PF_INET, SOCK_STREAM, 0);	if (sk < 0) {		err = errno;		error("TCP socket(%s) create failed %s(%d)", address,							strerror(err), err);		return -err;	}	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {		err = errno;		error("TCP socket(%s) connect failed: %s(%d)",						address, strerror(err), err);		close(sk);		errno = err;		return -err;	}	return sk;}static inline int tty_open(const char *tty, struct termios *ti){	int err, sk;	sk = open(tty, O_RDWR | O_NOCTTY);	if (sk < 0) {		err = errno;		error("Can't open TTY %s: %s(%d)", tty, strerror(err), err);		return -err;	}	if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {		err = errno;		error("Can't change serial settings: %s(%d)",				strerror(err), err);		close(sk);		errno = err;		return -err;	}	return sk;}static void connect_event_cb(GIOChannel *chan, int err, const bdaddr_t *src,				const bdaddr_t *dst, gpointer data){	struct proxy *prx = data;	GIOChannel *io;	int sk;	if (err < 0) {		error("accept: %s (%d)", strerror(-err), -err);		return;	}	bacpy(&prx->dst, dst);	switch (prx->type) {	case UNIX_SOCKET_PROXY:		sk = unix_socket_connect(prx->address);		break;	case TTY_PROXY:		sk = tty_open(prx->address, &prx->proxy_ti);		break;	case TCP_SOCKET_PROXY:		sk = tcp_socket_connect(prx->address);		break;	default:		sk = -1;	}	if (sk < 0) {		g_io_channel_unref(chan);		return;	}	g_io_channel_set_close_on_unref(chan, TRUE);	io = g_io_channel_unix_new(sk);	g_io_channel_set_close_on_unref(io, TRUE);	prx->rfcomm_watch = g_io_add_watch(chan,				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,				forward_data, io);	prx->local_watch = g_io_add_watch(io,				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,				forward_data, chan);	g_io_channel_unref(chan);	g_io_channel_unref(io);	return;}static DBusMessage *proxy_enable(DBusConnection *conn,				DBusMessage *msg, void *data){	struct proxy *prx = data;	sdp_record_t *record;	if (prx->io)		return failed(msg, "Already enabled");	/* Listen */	prx->io = bt_rfcomm_listen_allocate(&prx->src, &prx->channel, 0,				connect_event_cb, prx);	if (!prx->io) {		const char *strerr = strerror(errno);		error("RFCOMM listen socket failed: %s(%d)", strerr, errno);		return failed(msg, strerr);	}	g_io_channel_set_close_on_unref(prx->io, TRUE);	record = proxy_record_new(prx->uuid128, prx->channel);	if (!record) {		g_io_channel_unref(prx->io);		return failed(msg, "Unable to allocate new service record");	}	if (add_record_to_server(&prx->src, record) < 0) {		sdp_record_free(record);		g_io_channel_unref(prx->io);		return failed(msg, "Service registration failed");	}	prx->record_id = record->handle;	return dbus_message_new_method_return(msg);}static DBusMessage *proxy_disable(DBusConnection *conn,				DBusMessage *msg, void *data){	struct proxy *prx = data;	if (!prx->io)		return failed(msg, "Not enabled");	/* Remove the watches and unregister the record */	disable_proxy(prx);	return dbus_message_new_method_return(msg);}static DBusMessage *proxy_get_info(DBusConnection *conn,				DBusMessage *msg, void *data){	struct proxy *prx = data;	DBusMessage *reply;	DBusMessageIter iter, dict;	dbus_bool_t boolean;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	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, "uuid",			DBUS_TYPE_STRING, &prx->uuid128);	dbus_message_iter_append_dict_entry(&dict, "address",			DBUS_TYPE_STRING, &prx->address);	if (prx->channel)		dbus_message_iter_append_dict_entry(&dict, "channel",				DBUS_TYPE_BYTE, &prx->channel);	boolean = (prx->io ? TRUE : FALSE);	dbus_message_iter_append_dict_entry(&dict, "enabled",			DBUS_TYPE_BOOLEAN, &boolean);	boolean = (prx->rfcomm_watch ? TRUE : FALSE);	dbus_message_iter_append_dict_entry(&dict, "connected",			DBUS_TYPE_BOOLEAN, &boolean);	/* If connected: append the remote address */	if (boolean) {		char bda[18];		const char *pstr = bda;		ba2str(&prx->dst, bda);		dbus_message_iter_append_dict_entry(&dict, "address",				DBUS_TYPE_STRING, &pstr);	}	dbus_message_iter_close_container(&iter, &dict);	return reply;}static struct {	const char	*str;	speed_t		speed;} supported_speed[]  = {	{"50",		B50	},	{"300",		B300	},	{"600",		B600	},	{"1200",	B1200	},	{"1800",	B1800	},	{"2400",	B2400	},	{"4800",	B4800	},	{"9600",	B9600	},	{"19200",	B19200	},	{"38400",	B38400	},	{"57600",	B57600	},	{"115200",	B115200	},	{ NULL,		B0	}};static speed_t str2speed(const char *str, speed_t *speed){	int i;	for (i = 0; supported_speed[i].str; i++) {		if (strcmp(supported_speed[i].str, str) != 0)			continue;		if (speed)			*speed = supported_speed[i].speed;		return supported_speed[i].speed;	}	return B0;}static int set_parity(const char *str, tcflag_t *ctrl){	if (strcasecmp("even", str) == 0) {		*ctrl |= PARENB;		*ctrl &= ~PARODD;	} else if (strcasecmp("odd", str) == 0) {		*ctrl |= PARENB;		*ctrl |= PARODD;	} else if (strcasecmp("mark", str) == 0)		*ctrl |= PARENB;	else if ((strcasecmp("none", str) == 0) ||			(strcasecmp("space", str) == 0))		*ctrl &= ~PARENB;	else		return -1;	return 0;}static int set_databits(uint8_t databits, tcflag_t *ctrl){	if (databits < 5 || databits > 8)		return -EINVAL;	*ctrl &= ~CSIZE;	switch (databits) {	case 5:		*ctrl |= CS5;		break;	case 6:		*ctrl |= CS6;

⌨️ 快捷键说明

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