summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/glib-helper.c481
-rw-r--r--common/glib-helper.h37
2 files changed, 396 insertions, 122 deletions
diff --git a/common/glib-helper.c b/common/glib-helper.c
index 0d7c6d60..c0355dba 100644
--- a/common/glib-helper.c
+++ b/common/glib-helper.c
@@ -43,7 +43,9 @@
#include "glib-helper.h"
-typedef int (*resolver_t) (int fd, bdaddr_t *src, bdaddr_t *dst);
+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)
{
@@ -67,11 +69,26 @@ int set_nonblocking(int fd)
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;
@@ -426,7 +443,7 @@ static inline int resolve_names(int fd, struct sockaddr *host,
return 0;
}
-static int rfcomm_resolver(int fd, bdaddr_t *src, bdaddr_t *dst)
+static int rfcomm_resolver(int fd, char *src, char *dst)
{
struct sockaddr_rc host, peer;
socklen_t len;
@@ -438,13 +455,13 @@ static int rfcomm_resolver(int fd, bdaddr_t *src, bdaddr_t *dst)
if (err < 0)
return err;
- bacpy(src, &host.rc_bdaddr);
- bacpy(dst, &peer.rc_bdaddr);
+ ba2str(&host.rc_bdaddr, src);
+ ba2str(&peer.rc_bdaddr, dst);
return 0;
}
-static int l2cap_resolver(int fd, bdaddr_t *src, bdaddr_t *dst)
+static int l2cap_resolver(int fd, char *src, char *dst)
{
struct sockaddr_l2 host, peer;
socklen_t len;
@@ -456,13 +473,13 @@ static int l2cap_resolver(int fd, bdaddr_t *src, bdaddr_t *dst)
if (err < 0)
return err;
- bacpy(src, &host.l2_bdaddr);
- bacpy(dst, &peer.l2_bdaddr);
+ ba2str(&host.l2_bdaddr, src);
+ ba2str(&peer.l2_bdaddr, dst);
return 0;
}
-static int sco_resolver(int fd, bdaddr_t *src, bdaddr_t *dst)
+static int sco_resolver(int fd, char *src, char *dst)
{
struct sockaddr_sco host, peer;
socklen_t len;
@@ -474,17 +491,19 @@ static int sco_resolver(int fd, bdaddr_t *src, bdaddr_t *dst)
if (err < 0)
return err;
- bacpy(src, &host.sco_bdaddr);
- bacpy(dst, &peer.sco_bdaddr);
+ ba2str(&host.sco_bdaddr, src);
+ ba2str(&peer.sco_bdaddr, dst);
return 0;
}
static gboolean listen_cb(GIOChannel *chan, GIOCondition cond,
- struct io_context *io_ctxt)
+ gpointer user_data)
{
+ BtIO *io = user_data;
+ struct io_context *io_ctxt = io->io_ctxt;
int fd, err = 0;
- GIOChannel *io;
+ GIOChannel *gio;
struct sockaddr addr;
socklen_t len;
bdaddr_t src, dst;
@@ -506,34 +525,42 @@ static gboolean listen_cb(GIOChannel *chan, GIOCondition cond,
goto drop;
if (io_ctxt->resolver) {
- err = io_ctxt->resolver(fd, &src, &dst);
+ err = io_ctxt->resolver(fd, io->src, io->dst);
if (err < 0) {
close(fd);
goto drop;
}
}
- io = g_io_channel_unix_new(fd);
- if (!io)
+ gio = g_io_channel_unix_new(fd);
+ if (!gio)
err = -ENOMEM;
- if (io_ctxt->cb)
- io_ctxt->cb(io, err, &src, &dst, io_ctxt->user_data);
+ 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, -errno, NULL, NULL, io_ctxt->user_data);
+ io_ctxt->cb(NULL, err, NULL, NULL, io_ctxt->user_data);
return TRUE;
}
-static int transport_listen(struct io_context *io_ctxt)
+static int transport_listen(BtIO *io)
{
+ struct io_context *io_ctxt = io->io_ctxt;
int err;
- err = listen(io_ctxt->fd, 1);
+ err = listen(io_ctxt->fd, 5);
if (err < 0)
return -errno;
@@ -542,14 +569,16 @@ static int transport_listen(struct io_context *io_ctxt)
return -ENOMEM;
g_io_add_watch(io_ctxt->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) listen_cb, io_ctxt);
+ (GIOFunc) listen_cb, io);
return 0;
}
-static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
- struct io_context *io_ctxt)
+static gboolean connect_cb(GIOChannel *gio, GIOCondition cond,
+ gpointer user_data)
{
+ BtIO *io = user_data;
+ struct io_context *io_ctxt = io->io_ctxt;
int err = 0, ret;
socklen_t len;
bdaddr_t src, dst;
@@ -569,7 +598,7 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
}
if (io_ctxt->resolver) {
- err = io_ctxt->resolver(io_ctxt->fd, &src, &dst);
+ err = io_ctxt->resolver(io_ctxt->fd, io->src, io->dst);
if (err < 0)
goto done;
}
@@ -577,8 +606,13 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
io_ctxt->io = NULL;
done:
- if (io_ctxt->cb)
- io_ctxt->cb(io, err, &src, &dst, io_ctxt->user_data);
+ 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);
+ }
if (io_ctxt->io) {
g_io_channel_close(io_ctxt->io);
g_io_channel_unref(io_ctxt->io);
@@ -588,9 +622,10 @@ done:
return FALSE;
}
-static int transport_connect(struct io_context *io_ctxt, struct sockaddr *addr,
- socklen_t addrlen)
+static int transport_connect(BtIO *io, struct sockaddr *addr,
+ socklen_t addrlen)
{
+ struct io_context *io_ctxt = io->io_ctxt;
int err;
io_ctxt->io = g_io_channel_unix_new(io_ctxt->fd);
@@ -606,51 +641,54 @@ static int transport_connect(struct io_context *io_ctxt, struct sockaddr *addr,
return -errno;
g_io_add_watch(io_ctxt->io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) connect_cb, io_ctxt);
+ (GIOFunc) connect_cb, io);
return 0;
}
-static int sco_connect(struct io_context *io_ctxt, const bdaddr_t *src,
- const bdaddr_t *dst)
+static BtIOError sco_connect(BtIO *io, BtIOFunc func)
{
+ struct io_context *io_ctxt = io->io_ctxt;
struct sockaddr_sco addr;
int sk, err;
+ io_ctxt->func = func;
+
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
if (sk < 0)
return -errno;
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, src);
+ str2ba(io->src, &addr.sco_bdaddr);
err = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0) {
close(sk);
- return -errno;
+ return BT_IO_FAILED;
}
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, dst);
+ str2ba(io->dst, &addr.sco_bdaddr);
- err = transport_connect(io_ctxt, (struct sockaddr *) &addr,
+ err = transport_connect(io, (struct sockaddr *) &addr,
sizeof(addr));
if (err < 0) {
close(sk);
- return err;
+ return BT_IO_FAILED;
}
- return 0;
+ return BT_IO_SUCCESS;
}
-static int l2cap_bind(struct io_context *io_ctxt, const bdaddr_t *src,
+static int l2cap_bind(struct io_context *io_ctxt, const char *address,
uint16_t psm, uint16_t mtu, uint32_t flags,
struct sockaddr_l2 *addr)
{
int err;
struct l2cap_options l2o;
+ struct sockaddr_l2 l2a;
io_ctxt->fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (io_ctxt->fd < 0)
@@ -676,7 +714,7 @@ static int l2cap_bind(struct io_context *io_ctxt, const bdaddr_t *src,
memset(addr, 0, sizeof(*addr));
addr->l2_family = AF_BLUETOOTH;
- bacpy(&addr->l2_bdaddr, src);
+ str2ba(address, &l2a.l2_bdaddr);
addr->l2_psm = htobs(psm);
err = bind(io_ctxt->fd, (struct sockaddr *) addr, sizeof(*addr));
@@ -688,60 +726,63 @@ static int l2cap_bind(struct io_context *io_ctxt, const bdaddr_t *src,
return 0;
}
-static int l2cap_listen(struct io_context *io_ctxt, const bdaddr_t *src,
- uint16_t psm, uint16_t mtu, uint32_t flags)
+static BtIOError l2cap_listen(BtIO *io, BtIOFunc func)
{
+ struct io_context *io_ctxt = io->io_ctxt;
struct sockaddr_l2 addr;
- int err;
+ BtIOError err;
- err = l2cap_bind(io_ctxt, src, psm, mtu, flags, &addr);
+ io_ctxt->func = func;
+
+ err = l2cap_bind(io_ctxt, io->src, io->psm, io->mtu, io->flags, &addr);
if (err < 0)
return err;
- err = transport_listen(io_ctxt);
+ err = transport_listen(io);
if (err < 0) {
close(io_ctxt->fd);
return err;
}
- return 0;
+ return BT_IO_SUCCESS;
}
-static int l2cap_connect(struct io_context *io_ctxt, const bdaddr_t *src,
- const bdaddr_t *dst, uint16_t psm,
- uint16_t mtu)
+static BtIOError l2cap_connect(BtIO *io, BtIOFunc func)
{
+ struct io_context *io_ctxt = io->io_ctxt;
struct sockaddr_l2 l2a;
- int err;
+ BtIOError err;
+
+ io_ctxt->func = func;
- err = l2cap_bind(io_ctxt, src, 0, mtu, 0, &l2a);
+ err = l2cap_bind(io_ctxt, io->src, 0, io->mtu, 0, &l2a);
if (err < 0)
return err;
memset(&l2a, 0, sizeof(l2a));
l2a.l2_family = AF_BLUETOOTH;
- bacpy(&l2a.l2_bdaddr, dst);
- l2a.l2_psm = htobs(psm);
+ str2ba(io->dst, &l2a.l2_bdaddr);
+ l2a.l2_psm = htobs(io->psm);
- err = transport_connect(io_ctxt, (struct sockaddr *) &l2a,
+ err = transport_connect(io, (struct sockaddr *) &l2a,
sizeof(l2a));
if (err < 0) {
close(io_ctxt->fd);
return err;
}
- return 0;
+ return BT_IO_SUCCESS;
}
-static int rfcomm_bind(struct io_context *io_ctxt, const bdaddr_t *src,
+static BtIOError rfcomm_bind(struct io_context *io_ctxt, const char *address,
uint8_t channel, uint32_t flags,
struct sockaddr_rc *addr)
{
- int err;
+ BtIOError err;
io_ctxt->fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
if (io_ctxt->fd < 0)
- return -errno;
+ return BT_IO_FAILED;
if (flags) {
int opt = flags;
@@ -749,36 +790,38 @@ static int rfcomm_bind(struct io_context *io_ctxt, const bdaddr_t *src,
sizeof(opt));
if (err < 0) {
close(io_ctxt->fd);
- return -errno;
+ return BT_IO_FAILED;
}
}
memset(addr, 0, sizeof(*addr));
addr->rc_family = AF_BLUETOOTH;
- bacpy(&addr->rc_bdaddr, src);
+ str2ba(address, &addr->rc_bdaddr);
addr->rc_channel = channel;
err = bind(io_ctxt->fd, (struct sockaddr *) addr, sizeof(*addr));
if (err < 0) {
close(io_ctxt->fd);
- return -errno;
+ return BT_IO_FAILED;
}
- return 0;
+ return BT_IO_SUCCESS;
}
-static int rfcomm_listen(struct io_context *io_ctxt, const bdaddr_t *src,
- uint8_t *channel, uint32_t flags)
+static BtIOError rfcomm_listen(BtIO *io, BtIOFunc func)
{
+ struct io_context *io_ctxt = io->io_ctxt;
struct sockaddr_rc addr;
socklen_t sa_len;
- int err;
+ BtIOError err;
+
+ io_ctxt->func = func;
- err = rfcomm_bind(io_ctxt, src, *channel, flags, &addr);
+ err = rfcomm_bind(io_ctxt, io->src, io->channel, io->flags, &addr);
if (err < 0)
return err;
- err = transport_listen(io_ctxt);
+ err = transport_listen(io);
if (err < 0) {
close(io_ctxt->fd);
return err;
@@ -792,44 +835,47 @@ static int rfcomm_listen(struct io_context *io_ctxt, const bdaddr_t *src,
return err;
}
- *channel = addr.rc_channel;
+ io->channel = addr.rc_channel;
- return 0;
+ return BT_IO_SUCCESS;
}
-static int rfcomm_connect(struct io_context *io_ctxt, const bdaddr_t *src,
- const bdaddr_t *dst, uint8_t channel)
+static BtIOError rfcomm_connect(BtIO *io, BtIOFunc func)
{
+ struct io_context *io_ctxt = io->io_ctxt;
struct sockaddr_rc addr;
- int err;
+ BtIOError err;
+
+ io_ctxt->func = func;
- err = rfcomm_bind(io_ctxt, src, 0, 0, &addr);
+ err = rfcomm_bind(io_ctxt, io->src, 0, 0, &addr);
if (err < 0)
return err;
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, dst);
- addr.rc_channel = channel;
+ str2ba(io->dst, &addr.rc_bdaddr);
+ addr.rc_channel = io->channel;
- err = transport_connect(io_ctxt, (struct sockaddr *) &addr,
+ err = transport_connect(io, (struct sockaddr *) &addr,
sizeof(addr));
if (err < 0) {
close(io_ctxt->fd);
return err;
}
- return 0;
+ return BT_IO_SUCCESS;
}
-static int create_io_context(struct io_context **io_ctxt, gpointer cb,
- gpointer resolver, gpointer user_data)
+static int create_io_context(struct io_context **io_ctxt, BtIOFunc func,
+ gpointer cb, gpointer resolver, gpointer user_data)
{
*io_ctxt = g_try_malloc0(sizeof(struct search_context));
if (!*io_ctxt)
return -ENOMEM;
(*io_ctxt)->cb = cb;
+ (*io_ctxt)->func = func;
(*io_ctxt)->resolver = resolver;
(*io_ctxt)->user_data = user_data;
@@ -848,20 +894,26 @@ static void io_context_cleanup(struct io_context *io_ctxt)
GIOChannel *rfcomm_listen_internal(const bdaddr_t *src, uint8_t *channel,
uint32_t flags, bt_io_callback_t cb, void *user_data)
{
- struct io_context *io_ctxt;
- int err;
+ BtIO *io;
+ BtIOError err;
- err = create_io_context(&io_ctxt, cb, rfcomm_resolver, user_data);
- if (err < 0)
+ io = bt_io_create(BT_RFCOMM, user_data, NULL);
+ if (!io)
return NULL;
- err = rfcomm_listen(io_ctxt, src, channel, flags);
- if (err < 0) {
- io_context_cleanup(io_ctxt);
+ ba2str(src, io->src);
+ io->channel = *channel;
+ io->flags = flags;
+ io->io_ctxt->cb = cb;
+ err = bt_io_listen(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
return NULL;
}
- return io_ctxt->io;
+ *channel = io->channel;
+
+ return io->io_ctxt->io;
}
GIOChannel *bt_rfcomm_listen_allocate(const bdaddr_t *src, uint8_t *channel,
@@ -882,22 +934,27 @@ GIOChannel *bt_rfcomm_listen(const bdaddr_t *src, uint8_t channel,
return NULL;
return rfcomm_listen_internal(src, &channel, flags, cb, user_data);
+
}
int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
uint8_t channel, bt_io_callback_t cb, void *user_data)
{
- struct io_context *io_ctxt;
- int err;
-
- err = create_io_context(&io_ctxt, cb, rfcomm_resolver, user_data);
- if (err < 0)
- return err;
+ BtIO *io;
+ BtIOError err;
- err = rfcomm_connect(io_ctxt, src, dst, channel);
- if (err < 0) {
- io_context_cleanup(io_ctxt);
- return err;
+ io = bt_io_create(BT_RFCOMM, user_data, NULL);
+ if (!io)
+ return -1;
+
+ ba2str(src, io->src);
+ ba2str(dst, io->dst);
+ io->channel = channel;
+ io->io_ctxt->cb = cb;
+ err = bt_io_connect(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return -1;
}
return 0;
@@ -906,37 +963,47 @@ int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
GIOChannel *bt_l2cap_listen(const bdaddr_t *src, uint16_t psm, uint16_t mtu,
uint32_t flags, bt_io_callback_t cb, void *user_data)
{
- struct io_context *io_ctxt;
- int err;
+ BtIO *io;
+ BtIOError err;
- err = create_io_context(&io_ctxt, cb, l2cap_resolver, user_data);
- if (err < 0)
+ io = bt_io_create(BT_L2CAP, user_data, NULL);
+ if (!io)
return NULL;
- err = l2cap_listen(io_ctxt, src, psm, mtu, flags);
- if (err < 0) {
- io_context_cleanup(io_ctxt);
+ ba2str(src, io->src);
+ io->psm = psm;
+ io->mtu = mtu;
+ io->flags = flags;
+ io->io_ctxt->cb = cb;
+ err = bt_io_listen(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
return NULL;
}
- return io_ctxt->io;
+ return io->io_ctxt->io;
}
int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst,
uint16_t psm, uint16_t mtu, bt_io_callback_t cb,
void *user_data)
{
- struct io_context *io_ctxt;
- int err;
+ BtIO *io;
+ BtIOError err;
- err = create_io_context(&io_ctxt, cb, l2cap_resolver, user_data);
- if (err < 0)
- return err;
-
- err = l2cap_connect(io_ctxt, src, dst, psm, mtu);
- if (err < 0) {
- io_context_cleanup(io_ctxt);
- return err;
+ io = bt_io_create(BT_L2CAP, user_data, NULL);
+ if (!io)
+ return -1;
+
+ ba2str(src, io->src);
+ ba2str(dst, io->dst);
+ io->psm = psm;
+ io->mtu = mtu;
+ io->io_ctxt->cb = cb;
+ err = bt_io_connect(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return -1;
}
return 0;
@@ -945,18 +1012,188 @@ int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst,
int bt_sco_connect(const bdaddr_t *src, const bdaddr_t *dst,
bt_io_callback_t cb, void *user_data)
{
- struct io_context *io_ctxt;
+ BtIO *io;
+ BtIOError err;
+
+ io = bt_io_create(BT_SCO, user_data, NULL);
+ if (!io)
+ return -1;
+
+ ba2str(src, io->src);
+ ba2str(dst, io->dst);
+ io->io_ctxt->cb = cb;
+ err = bt_io_connect(io, NULL, NULL);
+ if (err != BT_IO_SUCCESS) {
+ bt_io_unref(io);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Experiemental bt_io API */
+
+BtIO *bt_io_create(BtIOTransport type, gpointer user_data, GDestroyNotify notify)
+{
+ BtIO *io;
int err;
- err = create_io_context(&io_ctxt, cb, sco_resolver, user_data);
- if (err < 0)
- return err;
+ io = g_new0(BtIO, 1);
+ if (!io)
+ return NULL;
+
+ io->refcount = 1;
+
+ switch (type) {
+ case BT_L2CAP:
+ err = create_io_context(&io->io_ctxt, NULL, NULL,
+ l2cap_resolver, user_data);
+ io->connect = l2cap_connect;
+ io->listen = l2cap_listen;
+ break;
+ case BT_RFCOMM:
+ err = create_io_context(&io->io_ctxt, NULL, NULL,
+ rfcomm_resolver, user_data);
+ io->connect = rfcomm_connect;
+ io->listen = rfcomm_listen;
+ break;
+ case BT_SCO:
+ err = create_io_context(&io->io_ctxt, NULL, NULL,
+ sco_resolver, user_data);
+ io->connect = sco_connect;
+ break;
+ default:
+ return NULL;
+ }
- err = sco_connect(io_ctxt, src, dst);
if (err < 0) {
- io_context_cleanup(io_ctxt);
- return err;
+ bt_io_unref(io);
+ return NULL;
}
- return 0;
+ return io;
+}
+
+BtIO *bt_io_ref(BtIO *io)
+{
+ io->refcount++;
+
+ return io;
+}
+
+void bt_io_unref(BtIO *io)
+{
+ io->refcount--;
+
+ if (io->refcount)
+ return;
+
+ io_context_cleanup(io->io_ctxt);
+ g_free(io);
+}
+
+gboolean bt_io_set_source(BtIO *io, const char *address)
+{
+ if (strlen(address) != sizeof(io->src))
+ return FALSE;
+
+ memcpy(io->src, address, sizeof(io->src));
+
+ return TRUE;
+}
+
+const char *bt_io_get_source(BtIO *io)
+{
+ return io->src;
+}
+
+gboolean bt_io_set_destination(BtIO *io, const char *address)
+{
+ if (strlen(address) != sizeof(io->dst))
+ return FALSE;
+
+ memcpy(io->dst, address, sizeof(io->dst));
+
+ return TRUE;
+}
+
+const char *bt_io_get_destination(BtIO *io)
+{
+ return io->dst;
+}
+
+gboolean bt_io_set_flags(BtIO *io, guint32 flags)
+{
+ io->flags = flags;
+
+ return TRUE;
+}
+
+guint32 bt_io_get_flags(BtIO *io)
+{
+ return io->flags;
+}
+
+gboolean bt_io_set_channel(BtIO *io, guint8 channel)
+{
+ if (io->type != BT_RFCOMM)
+ return FALSE;
+
+ io->channel = channel;
+
+ return TRUE;
+}
+
+guint8 bt_io_get_channel(BtIO *io)
+{
+ return io->channel;
+}
+
+gboolean bt_io_set_psm(BtIO *io, guint16 psm)
+{
+ if (io->type != BT_L2CAP)
+ return FALSE;
+
+ io->psm = psm;
+
+ return TRUE;
+}
+guint16 bt_io_get_psm(BtIO *io)
+{
+ return io->psm;
+}
+
+gboolean bt_io_set_mtu(BtIO *io, guint16 mtu)
+{
+ io->mtu = mtu;
+
+ return TRUE;
+}
+
+guint16 bt_io_get_mtu(BtIO *io)
+{
+ return io->mtu;
+}
+
+BtIOError bt_io_connect(BtIO *io, const char *uuid, BtIOFunc func)
+{
+ if (!io->connect)
+ return BT_IO_FAILED;
+
+ return io->connect(io, func);
+}
+
+BtIOError bt_io_listen(BtIO *io, const char *uuid, BtIOFunc func)
+{
+ if (!io->listen)
+ return BT_IO_FAILED;
+
+ return io->listen(io, func);
+}
+
+BtIOError bt_io_shutdown(BtIO *io)
+{
+ io_context_cleanup(io->io_ctxt);
+
+ return BT_IO_SUCCESS;
}
diff --git a/common/glib-helper.h b/common/glib-helper.h
index 8d346b49..458d5c88 100644
--- a/common/glib-helper.h
+++ b/common/glib-helper.h
@@ -54,3 +54,40 @@ int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst,
void *user_data);
int bt_sco_connect(const bdaddr_t *src, const bdaddr_t *dst,
bt_io_callback_t cb, void *user_data);
+
+/* Experiemental bt_io API */
+
+typedef struct bt_io BtIO;
+
+typedef enum {
+ BT_L2CAP,
+ BT_RFCOMM,
+ BT_SCO
+} BtIOTransport;
+
+typedef enum {
+ BT_IO_SUCCESS,
+ BT_IO_FAILED
+} BtIOError;
+
+typedef void (*BtIOFunc) (BtIO *io, BtIOError err, GIOChannel *chan,
+ gpointer user_data);
+
+BtIO *bt_io_create(BtIOTransport type, gpointer user_data, GDestroyNotify notify);
+BtIO *bt_io_ref(BtIO *io);
+void bt_io_unref(BtIO *io);
+gboolean bt_io_set_source(BtIO *io, const char *address);
+const char *bt_io_get_source(BtIO *io);
+gboolean bt_io_set_destination(BtIO *io, const char *address);
+const char *bt_io_get_destination(BtIO *io);
+gboolean bt_io_set_flags(BtIO *io, guint32 flags);
+guint32 bt_io_get_flags(BtIO *io);
+gboolean bt_io_set_channel(BtIO *io, guint8 channel);
+guint8 bt_io_get_channel(BtIO *io);
+gboolean bt_io_set_psm(BtIO *io, guint16 psm);
+guint16 bt_io_get_psm(BtIO *io);
+gboolean bt_io_set_mtu(BtIO *io, guint16 mtu);
+guint16 bt_io_get_mtu(BtIO *io);
+BtIOError bt_io_connect(BtIO *io, const char *uuid, BtIOFunc func);
+BtIOError bt_io_listen(BtIO *io, const char *uuid, BtIOFunc func);
+BtIOError bt_io_shutdown(BtIO *io);