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

📄 glib-helper.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 <errno.h>#include <fcntl.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/rfcomm.h>#include <bluetooth/l2cap.h>#include <bluetooth/sco.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <glib.h>#include "glib-helper.h"typedef int (*resolver_t) (int fd, char *src, char *dst);typedef BtIOError (*connect_t) (BtIO *io, BtIOFunc func);typedef BtIOError (*listen_t) (BtIO *io, BtIOFunc func);int set_nonblocking(int fd){	long arg;	arg = fcntl(fd, F_GETFL);	if (arg < 0)		return -errno;	/* Return if already nonblocking */	if (arg & O_NONBLOCK)		return 0;	arg |= O_NONBLOCK;	if (fcntl(fd, F_SETFL, arg) < 0)		return -errno;	return 0;}struct io_context {	int			fd;	GIOChannel		*io;	BtIOFunc		func;	bt_io_callback_t	cb;	resolver_t		resolver;	gpointer		user_data;};struct bt_io {	char			src[18];	char			dst[18];	guint32			flags;	guint8			channel;	guint16			psm;	guint16			mtu;	BtIOTransport		type;	connect_t		connect;	listen_t		listen;	struct io_context	*io_ctxt;	int			refcount;};struct search_context {	bdaddr_t		src;	bdaddr_t		dst;	sdp_session_t		*session;	bt_callback_t		cb;	bt_destroy_t		destroy;	gpointer		user_data;	uuid_t			uuid;};static GSList *context_list = NULL;static void search_context_cleanup(struct search_context *ctxt){	context_list = g_slist_remove(context_list, ctxt);	if (ctxt->destroy)		ctxt->destroy(ctxt->user_data);	g_free(ctxt);}static void search_completed_cb(uint8_t type, uint16_t status,			uint8_t *rsp, size_t size, void *user_data){	struct search_context *ctxt = user_data;	sdp_list_t *recs = NULL;	int scanned, seqlen = 0, bytesleft = size;	uint8_t dataType;	int err = 0;	if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {		err = -EPROTO;		goto done;	}	scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);	if (!scanned || !seqlen)		goto done;	rsp += scanned;	bytesleft -= scanned;	do {		sdp_record_t *rec;		int recsize;		recsize = 0;		rec = sdp_extract_pdu(rsp, bytesleft, &recsize);		if (!rec)			break;		if (!recsize) {			sdp_record_free(rec);			break;		}		scanned += recsize;		rsp += recsize;		bytesleft -= recsize;		recs = sdp_list_append(recs, rec);	} while (scanned < size && bytesleft > 0);done:	sdp_close(ctxt->session);	if (ctxt->cb)		ctxt->cb(recs, err, ctxt->user_data);	search_context_cleanup(ctxt);}static gboolean search_process_cb(GIOChannel *chan,			GIOCondition cond, void *user_data){	struct search_context *ctxt = user_data;	int err = 0;	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {		err = EIO;		goto failed;	}	if (sdp_process(ctxt->session) < 0)		goto failed;	return TRUE;failed:	if (err) {		sdp_close(ctxt->session);		if (ctxt->cb)			ctxt->cb(NULL, err, ctxt->user_data);		search_context_cleanup(ctxt);	}	return FALSE;}static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data){	struct search_context *ctxt = user_data;	sdp_list_t *search, *attrids;	uint32_t range = 0x0000ffff;	socklen_t len;	int sk, err = 0;	sk = g_io_channel_unix_get_fd(chan);	len = sizeof(err);	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {		err = errno;		goto failed;	}	if (err != 0)		goto failed;	if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {		err = EIO;		goto failed;	}	search = sdp_list_append(NULL, &ctxt->uuid);	attrids = sdp_list_append(NULL, &range);	if (sdp_service_search_attr_async(ctxt->session,				search, SDP_ATTR_REQ_RANGE, attrids) < 0) {		sdp_list_free(attrids, NULL);		sdp_list_free(search, NULL);		err = EIO;		goto failed;	}	sdp_list_free(attrids, NULL);	sdp_list_free(search, NULL);	/* Set callback responsible for update the internal SDP transaction */	g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,			search_process_cb, ctxt);	return FALSE;failed:	sdp_close(ctxt->session);	if (ctxt->cb)		ctxt->cb(NULL, -err, ctxt->user_data);	search_context_cleanup(ctxt);	return FALSE;}static int create_search_context(struct search_context **ctxt,				const bdaddr_t *src, const bdaddr_t *dst,				uuid_t *uuid){	sdp_session_t *s;	GIOChannel *chan;	if (!ctxt)		return -EINVAL;	s = sdp_connect(src, dst, SDP_NON_BLOCKING);	if (!s)		return -errno;	*ctxt = g_try_malloc0(sizeof(struct search_context));	if (!*ctxt) {		sdp_close(s);		return -ENOMEM;	}	bacpy(&(*ctxt)->src, src);	bacpy(&(*ctxt)->dst, dst);	(*ctxt)->session = s;	(*ctxt)->uuid = *uuid;	chan = g_io_channel_unix_new(sdp_get_socket(s));	g_io_add_watch(chan, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,			connect_watch, *ctxt);	g_io_channel_unref(chan);	return 0;}int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,			uuid_t *uuid, bt_callback_t cb, void *user_data,			bt_destroy_t destroy){	struct search_context *ctxt = NULL;	int err;	if (!cb)		return -EINVAL;	err = create_search_context(&ctxt, src, dst, uuid);	if (err < 0)		return err;	ctxt->cb	= cb;	ctxt->destroy	= destroy;	ctxt->user_data	= user_data;	context_list = g_slist_append(context_list, ctxt);	return 0;}int bt_discover_services(const bdaddr_t *src, const bdaddr_t *dst,		bt_callback_t cb, void *user_data, bt_destroy_t destroy){	uuid_t uuid;	sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);	return bt_search_service(src, dst, &uuid, cb, user_data, destroy);}static int find_by_bdaddr(const void *data, const void *user_data){	const struct search_context *ctxt = data, *search = user_data;	return (bacmp(&ctxt->dst, &search->dst) &&					bacmp(&ctxt->src, &search->src));}int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst){	struct search_context search, *ctxt;	GSList *match;	memset(&search, 0, sizeof(search));	bacpy(&search.src, src);	bacpy(&search.dst, dst);	/* Ongoing SDP Discovery */	match = g_slist_find_custom(context_list, &search, find_by_bdaddr);	if (!match)		return -ENODATA;	ctxt = match->data;	if (!ctxt->session)		return -ENOTCONN;	close(ctxt->session->sock);	return 0;}char *bt_uuid2string(uuid_t *uuid){	gchar *str;	uuid_t uuid128;	unsigned int data0;	unsigned short data1;	unsigned short data2;	unsigned short data3;	unsigned int data4;	unsigned short data5;	if (!uuid)		return NULL;	switch (uuid->type) {	case SDP_UUID16:		sdp_uuid16_to_uuid128(&uuid128, uuid);		break;	case SDP_UUID32:		sdp_uuid32_to_uuid128(&uuid128, uuid);		break;	case SDP_UUID128:		memcpy(&uuid128, uuid, sizeof(uuid_t));		break;	default:		/* Type of UUID unknown */		return NULL;	}	memcpy(&data0, &uuid128.value.uuid128.data[0], 4);	memcpy(&data1, &uuid128.value.uuid128.data[4], 2);	memcpy(&data2, &uuid128.value.uuid128.data[6], 2);	memcpy(&data3, &uuid128.value.uuid128.data[8], 2);	memcpy(&data4, &uuid128.value.uuid128.data[10], 4);	memcpy(&data5, &uuid128.value.uuid128.data[14], 2);	str = g_try_malloc0(MAX_LEN_UUID_STR);	if (!str)		return NULL;	sprintf(str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",			g_ntohl(data0), g_ntohs(data1),			g_ntohs(data2), g_ntohs(data3),			g_ntohl(data4), g_ntohs(data5));	return str;}static struct {	const char	*name;	uint16_t	class;} bt_services[] = {	{ "vcp",	VIDEO_CONF_SVCLASS_ID		},	{ "pbap",	PBAP_SVCLASS_ID			},	{ "sap",	SAP_SVCLASS_ID			},	{ "ftp",	OBEX_FILETRANS_SVCLASS_ID	},	{ "bpp",	BASIC_PRINTING_SVCLASS_ID	},	{ "bip",	IMAGING_SVCLASS_ID		},	{ "synch",	IRMC_SYNC_SVCLASS_ID		},	{ "dun",	DIALUP_NET_SVCLASS_ID		},	{ "opp",	OBEX_OBJPUSH_SVCLASS_ID		},	{ "fax",	FAX_SVCLASS_ID			},	{ "spp",	SERIAL_PORT_SVCLASS_ID		},	{ "hsp",	HEADSET_SVCLASS_ID		},	{ "hfp",	HANDSFREE_SVCLASS_ID		},	{ }};uint16_t bt_string2class(const char *pattern){	int i;	for (i = 0; bt_services[i].name; i++) {		if (strcasecmp(bt_services[i].name, pattern) == 0)			return bt_services[i].class;	}	return 0;}int bt_string2uuid(uuid_t *uuid, const char *string){	uint32_t data0, data4;	uint16_t data1, data2, data3, data5;	if (strlen(string) == 36 &&			string[8] == '-' &&			string[13] == '-' &&			string[18] == '-' &&			string[23] == '-' &&			sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",				&data0, &data1, &data2, &data3, &data4, &data5) == 6) {		uint8_t val[16];		data0 = g_htonl(data0);		data1 = g_htons(data1);		data2 = g_htons(data2);		data3 = g_htons(data3);		data4 = g_htonl(data4);		data5 = g_htons(data5);		memcpy(&val[0], &data0, 4);		memcpy(&val[4], &data1, 2);		memcpy(&val[6], &data2, 2);		memcpy(&val[8], &data3, 2);		memcpy(&val[10], &data4, 4);		memcpy(&val[14], &data5, 2);		sdp_uuid128_create(uuid, val);		return 0;	} else {		uint16_t class = bt_string2class(string);		if (class) {			sdp_uuid16_create(uuid, class);			return 0;		}	}	return -1;}gchar *bt_list2string(GSList *list){	GSList *l;	gchar *str, *tmp;	if (!list)		return NULL;	str = g_strdup((const gchar *) list->data);	for (l = list->next; l; l = l->next) {		tmp = g_strconcat(str, " " , (const gchar *) l->data, NULL);		g_free(str);		str = tmp;	}	return str;}GSList *bt_string2list(const gchar *str){	GSList *l = NULL;	gchar **uuids;	int i = 0;	if (!str)		return NULL;	/* FIXME: eglib doesn't support g_strsplit */	uuids = g_strsplit(str, " ", 0);	if (!uuids)		return NULL;	while (uuids[i]) {		l = g_slist_append(l, uuids[i]);		i++;	}	g_free(uuids);	return l;}static inline int resolve_names(int fd, struct sockaddr *host,			struct sockaddr *peer, socklen_t len){	int err;	socklen_t namelen;	namelen = len;	memset(host, 0, len);	err = getsockname(fd, host, &namelen);	if (err < 0)		return err;	namelen = len;	memset(peer, 0, len);	err = getpeername(fd, peer, &namelen);	if (err < 0)		return err;	return 0;}static int rfcomm_resolver(int fd, char *src, char *dst){	struct sockaddr_rc host, peer;	socklen_t len;	int err;	len = sizeof(host);	err = resolve_names(fd, (struct sockaddr *) &host,			(struct sockaddr *) &peer, len);	if (err < 0)		return err;	ba2str(&host.rc_bdaddr, src);	ba2str(&peer.rc_bdaddr, dst);	return 0;}static int l2cap_resolver(int fd, char *src, char *dst){	struct sockaddr_l2 host, peer;	socklen_t len;	int err;	len = sizeof(host);	err = resolve_names(fd, (struct sockaddr *) &host,			(struct sockaddr *) &peer, len);	if (err < 0)		return err;	ba2str(&host.l2_bdaddr, src);	ba2str(&peer.l2_bdaddr, dst);	return 0;}static int sco_resolver(int fd, char *src, char *dst){	struct sockaddr_sco host, peer;	socklen_t len;	int err;	len = sizeof(host);	err = resolve_names(fd, (struct sockaddr *) &host,			(struct sockaddr *) &peer, len);	if (err < 0)		return err;	ba2str(&host.sco_bdaddr, src);	ba2str(&peer.sco_bdaddr, dst);	return 0;}static gboolean listen_cb(GIOChannel *chan, GIOCondition cond,		gpointer user_data){	BtIO *io = user_data;	struct io_context *io_ctxt = io->io_ctxt;	int fd, err = 0;	GIOChannel *gio;	struct sockaddr addr;	socklen_t len;	bdaddr_t src, dst;	if (cond & G_IO_NVAL)		return FALSE;	if (cond & (G_IO_HUP | G_IO_ERR)) {		g_io_channel_close(chan);		g_io_channel_unref(chan);		g_free(io_ctxt);		return FALSE;	}	len = sizeof(addr);	memset(&addr, 0, len);	fd = accept(io_ctxt->fd, &addr, &len);	if (fd < 0)		goto drop;	if (io_ctxt->resolver) {		err = io_ctxt->resolver(fd, io->src, io->dst);		if (err < 0) {			close(fd);			goto drop;		}	}	gio = g_io_channel_unix_new(fd);	if (!gio)		err = -ENOMEM;	if (io_ctxt->func)		io_ctxt->func(io, err, gio, io_ctxt->user_data);	if (io_ctxt->cb) {		str2ba(io->src, &src);		str2ba(io->dst, &dst);		io_ctxt->cb(gio, err, &src, &dst, io_ctxt->user_data);	}	return TRUE;drop:	if (io_ctxt->func)		io_ctxt->func(io, -errno, NULL, io_ctxt->user_data);	if (io_ctxt->cb)		io_ctxt->cb(NULL, err, NULL, NULL, io_ctxt->user_data);	return TRUE;}static int transport_listen(BtIO *io){	struct io_context *io_ctxt = io->io_ctxt;	int err;

⌨️ 快捷键说明

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