Diff between 84bc0d0e5718c6a9e427d4d3bf545bc0f41a37ee and a0d52c9ad0abe3d7b4f99ea855c8d7664bb3c3fd

Changed Files

File Additions Deletions Status
btio/btio.c +112 -18 modified
btio/btio.h +7 -17 modified

Full Patch

diff --git a/btio/btio.c b/btio/btio.c
index b3bbc4b..9d05cde 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -48,6 +48,14 @@
 
 #define DEFAULT_DEFER_TIMEOUT 30
 
+typedef enum {
+	BT_IO_L2CAP,
+	BT_IO_L2ERTM,
+	BT_IO_RFCOMM,
+	BT_IO_SCO,
+	BT_IO_INVALID,
+} BtIOType;
+
 struct set_opts {
 	bdaddr_t src;
 	bdaddr_t dst;
@@ -85,6 +93,64 @@ struct server {
 	GDestroyNotify destroy;
 };
 
+static BtIOType bt_io_get_type(GIOChannel *io, GError **gerr)
+{
+	int sk = g_io_channel_unix_get_fd(io);
+	int domain, type, proto, err;
+	socklen_t len;
+
+	domain = 0;
+	len = sizeof(domain);
+	err = getsockopt(sk, SOL_SOCKET, SO_DOMAIN, &domain, &len);
+	if (err < 0) {
+		ERROR_FAILED(gerr, "getsockopt(SO_DOMAIN)", errno);
+		return BT_IO_INVALID;
+	}
+
+	if (domain != AF_BLUETOOTH) {
+		g_set_error(gerr, BT_IO_ERROR, EINVAL,
+				"BtIO socket domain not AF_BLUETOOTH");
+		return BT_IO_INVALID;
+	}
+
+	proto = 0;
+	len = sizeof(proto);
+	err = getsockopt(sk, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
+	if (err < 0) {
+		ERROR_FAILED(gerr, "getsockopt(SO_PROTOCOL)", errno);
+		return BT_IO_INVALID;
+	}
+
+	switch (proto) {
+	case BTPROTO_RFCOMM:
+		return BT_IO_RFCOMM;
+	case BTPROTO_SCO:
+		return BT_IO_SCO;
+	}
+
+	type = 0;
+	len = sizeof(type);
+	err = getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len);
+	if (err < 0) {
+		ERROR_FAILED(gerr, "getsockopt(SO_TYPE)", errno);
+		return BT_IO_INVALID;
+	}
+
+	switch (proto) {
+	case BTPROTO_L2CAP:
+		switch (type) {
+		case SOCK_SEQPACKET:
+			return BT_IO_L2CAP;
+		case SOCK_STREAM:
+			return BT_IO_L2ERTM;
+		}
+	}
+
+	g_set_error(gerr, BT_IO_ERROR, EINVAL, "Unknown BtIO socket type");
+
+	return BT_IO_INVALID;
+}
+
 static void server_remove(struct server *server)
 {
 	if (server->destroy)
@@ -1179,11 +1245,11 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
 		return rfcomm_get(sock, err, opt1, args);
 	case BT_IO_SCO:
 		return sco_get(sock, err, opt1, args);
+	default:
+		g_set_error(err, BT_IO_ERROR, EINVAL,
+				"Unknown BtIO type %d", type);
+		return FALSE;
 	}
-
-	g_set_error(err, BT_IO_ERROR, EINVAL,
-			"Unknown BtIO type %d", type);
-	return FALSE;
 }
 
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
@@ -1216,13 +1282,13 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
 	return TRUE;
 }
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-							BtIOOption opt1, ...)
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
 	va_list args;
 	gboolean ret;
 	struct set_opts opts;
 	int sock;
+	BtIOType type;
 
 	va_start(args, opt1);
 	ret = parse_set_opts(&opts, err, opt1, args);
@@ -1231,6 +1297,10 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
 	if (!ret)
 		return ret;
 
+	type = bt_io_get_type(io, err);
+	if (type == BT_IO_INVALID)
+		return FALSE;
+
 	sock = g_io_channel_unix_get_fd(io);
 
 	switch (type) {
@@ -1243,18 +1313,23 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
 		return rfcomm_set(sock, opts.sec_level, opts.master, err);
 	case BT_IO_SCO:
 		return sco_set(sock, opts.mtu, err);
+	default:
+		g_set_error(err, BT_IO_ERROR, EINVAL,
+				"Unknown BtIO type %d", type);
+		return FALSE;
 	}
 
-	g_set_error(err, BT_IO_ERROR, EINVAL,
-			"Unknown BtIO type %d", type);
-	return FALSE;
 }
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-							BtIOOption opt1, ...)
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
 	va_list args;
 	gboolean ret;
+	BtIOType type;
+
+	type = bt_io_get_type(io, err);
+	if (type == BT_IO_INVALID)
+		return FALSE;
 
 	va_start(args, opt1);
 	ret = get_valist(io, type, err, opt1, args);
@@ -1340,15 +1415,30 @@ failed:
 	return NULL;
 }
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
-				gpointer user_data, GDestroyNotify destroy,
-				GError **gerr, BtIOOption opt1, ...)
+static BtIOType get_opts_type(struct set_opts *opts)
+{
+	if (opts->channel)
+		return BT_IO_RFCOMM;
+
+	if (opts->mode)
+		return BT_IO_L2ERTM;
+
+	if (opts->psm || opts->cid)
+		return BT_IO_L2CAP;
+
+	return BT_IO_SCO;
+}
+
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+				GDestroyNotify destroy, GError **gerr,
+				BtIOOption opt1, ...)
 {
 	GIOChannel *io;
 	va_list args;
 	struct set_opts opts;
 	int err, sock;
 	gboolean ret;
+	BtIOType type;
 
 	va_start(args, opt1);
 	ret = parse_set_opts(&opts, gerr, opt1, args);
@@ -1357,6 +1447,8 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
 	if (ret == FALSE)
 		return NULL;
 
+	type = get_opts_type(&opts);
+
 	io = create_io(type, FALSE, &opts, gerr);
 	if (io == NULL)
 		return NULL;
@@ -1392,16 +1484,16 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
 	return io;
 }
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-				BtIOConfirm confirm, gpointer user_data,
-				GDestroyNotify destroy, GError **err,
-				BtIOOption opt1, ...)
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
+				gpointer user_data, GDestroyNotify destroy,
+				GError **err, BtIOOption opt1, ...)
 {
 	GIOChannel *io;
 	va_list args;
 	struct set_opts opts;
 	int sock;
 	gboolean ret;
+	BtIOType type;
 
 	va_start(args, opt1);
 	ret = parse_set_opts(&opts, err, opt1, args);
@@ -1410,6 +1502,8 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
 	if (ret == FALSE)
 		return NULL;
 
+	type = get_opts_type(&opts);
+
 	io = create_io(type, TRUE, &opts, err);
 	if (io == NULL)
 		return NULL;
diff --git a/btio/btio.h b/btio/btio.h
index bb35025..a6ff5a2 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -31,13 +31,6 @@
 GQuark bt_io_error_quark(void);
 
 typedef enum {
-	BT_IO_L2CAP,
-	BT_IO_L2ERTM,
-	BT_IO_RFCOMM,
-	BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
 	BT_IO_OPT_INVALID = 0,
 	BT_IO_OPT_SOURCE,
 	BT_IO_OPT_SOURCE_BDADDR,
@@ -85,19 +78,16 @@ typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
 					GDestroyNotify destroy, GError **err);
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-						BtIOOption opt1, ...);
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...);
+
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...);
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-						BtIOOption opt1, ...);
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+				GDestroyNotify destroy, GError **gerr,
+				BtIOOption opt1, ...);
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
 				gpointer user_data, GDestroyNotify destroy,
 				GError **err, BtIOOption opt1, ...);
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-				BtIOConfirm confirm, gpointer user_data,
-				GDestroyNotify destroy, GError **err,
-				BtIOOption opt1, ...);
-
 #endif