summaryrefslogtreecommitdiffstats
path: root/common/glib-helper.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-05-12 21:21:47 +0000
committerLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2008-05-12 21:21:47 +0000
commiteac653286a4619a0b28614cdde1506997e5d6023 (patch)
tree39e47d27560b6bf34d8ed4b232aa245fb22ca642 /common/glib-helper.c
parent788878d89291688a06d2bb067fa9d5c82c4ad050 (diff)
introduce bt_rfcomm_listen.
Diffstat (limited to 'common/glib-helper.c')
-rw-r--r--common/glib-helper.c134
1 files changed, 126 insertions, 8 deletions
diff --git a/common/glib-helper.c b/common/glib-helper.c
index 36228d45..1eafbb98 100644
--- a/common/glib-helper.c
+++ b/common/glib-helper.c
@@ -365,6 +365,63 @@ GSList *bt_string2list(const gchar *str)
return l;
}
+static gboolean listen_cb(GIOChannel *chan, GIOCondition cond,
+ struct io_context *io_ctxt)
+{
+ int srv_sk, cli_sk, err = 0, ret;
+ GIOChannel *io;
+ socklen_t len;
+ struct sockaddr_rc addr;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ len = sizeof(ret);
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_close(chan);
+ g_io_channel_unref(chan);
+ g_free(io_ctxt);
+ return FALSE;
+ }
+
+ srv_sk = g_io_channel_unix_get_fd(chan);
+
+ len = sizeof(struct sockaddr_rc);
+ cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &len);
+ if (cli_sk < 0) {
+ if (io_ctxt->cb)
+ io_ctxt->cb(NULL, -errno, io_ctxt->user_data);
+ return TRUE;
+ }
+
+ io = g_io_channel_unix_new(cli_sk);
+ if (!io)
+ err = -ENOMEM;
+
+ if (io_ctxt->cb)
+ io_ctxt->cb(io, err, io_ctxt->user_data);
+
+ return TRUE;
+}
+
+static int transport_listen(struct io_context *io_ctxt, int fd)
+{
+ int err;
+
+ err = listen(fd, 1);
+ if (err < 0)
+ return -errno;
+
+ io_ctxt->io = g_io_channel_unix_new(fd);
+ if (!io_ctxt->io)
+ 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);
+
+ return 0;
+}
+
static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
struct io_context *io_ctxt)
{
@@ -504,26 +561,68 @@ static int l2cap_connect(struct io_context *io_ctxt, const bdaddr_t *src,
return 0;
}
-static int rfcomm_connect(struct io_context *io_ctxt, const bdaddr_t *src,
- const bdaddr_t *dst, uint8_t channel)
+static int rfcomm_bind(struct io_context *io_ctxt, const bdaddr_t *src,
+ uint8_t channel, uint32_t flags,
+ struct sockaddr_rc *addr)
{
- struct sockaddr_rc addr;
- int sk, err;
+ int sk, err, opt;
sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
if (sk < 0)
return -errno;
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, src);
+ if (flags) {
+ opt = flags;
+ err = setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt));
+ if (err < 0) {
+ close(sk);
+ return -errno;
+ }
+ }
- err = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
+ memset(addr, 0, sizeof(*addr));
+ addr->rc_family = AF_BLUETOOTH;
+ bacpy(&addr->rc_bdaddr, src);
+ addr->rc_channel = channel;
+
+ err = bind(sk, (struct sockaddr *) addr, sizeof(*addr));
if (err < 0) {
close(sk);
return -errno;
}
+ return sk;
+}
+
+static int rfcomm_listen(struct io_context *io_ctxt, const bdaddr_t *src,
+ uint8_t channel, uint32_t flags)
+{
+ struct sockaddr_rc addr;
+ int sk, err;
+
+ sk = rfcomm_bind(io_ctxt, src, channel, flags, &addr);
+ if (sk < 0)
+ return sk;
+
+ err = transport_listen(io_ctxt, sk);
+ if (err < 0) {
+ close(sk);
+ return err;
+ }
+
+ return 0;
+}
+
+static int rfcomm_connect(struct io_context *io_ctxt, const bdaddr_t *src,
+ const bdaddr_t *dst, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+ int sk, err;
+
+ sk = rfcomm_bind(io_ctxt, src, 0, 0, &addr);
+ if (sk < 0)
+ return sk;
+
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, dst);
@@ -561,6 +660,25 @@ static void io_context_cleanup(struct io_context *io_ctxt)
g_free(io_ctxt);
}
+GIOChannel *bt_rfcomm_listen(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;
+
+ err = create_io_context(&io_ctxt, cb, user_data);
+ if (err < 0)
+ return NULL;
+
+ err = rfcomm_listen(io_ctxt, src, channel, flags);
+ if (err < 0) {
+ io_context_cleanup(io_ctxt);
+ return NULL;
+ }
+
+ return io_ctxt->io;
+}
+
int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
uint8_t channel, bt_io_callback_t cb, void *user_data)
{