summaryrefslogtreecommitdiffstats
path: root/common/glib-helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/glib-helper.c')
-rw-r--r--common/glib-helper.c139
1 files changed, 99 insertions, 40 deletions
diff --git a/common/glib-helper.c b/common/glib-helper.c
index e314d9e9..23271fa2 100644
--- a/common/glib-helper.c
+++ b/common/glib-helper.c
@@ -26,6 +26,7 @@
#endif
#include <errno.h>
+#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
@@ -34,6 +35,7 @@
#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>
@@ -379,6 +381,61 @@ done:
return FALSE;
}
+static int transport_connect(struct io_context *io_ctxt, int fd,
+ struct sockaddr *addr, socklen_t addrlen)
+{
+ int err;
+
+ io_ctxt->io = g_io_channel_unix_new(fd);
+ if (!io_ctxt->io)
+ return -ENOMEM;
+
+ err = g_io_channel_set_flags(io_ctxt->io, G_IO_FLAG_NONBLOCK, NULL);
+ if (err != G_IO_STATUS_NORMAL)
+ return -EPERM;
+
+ err = connect(fd, addr, addrlen);
+ if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ 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);
+
+ return 0;
+}
+
+static int sco_connect(struct io_context *io_ctxt, const bdaddr_t *src,
+ const bdaddr_t *dst)
+{
+ struct sockaddr_sco addr;
+ int sk, err;
+
+ 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);
+
+ err = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0)
+ return -errno;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, dst);
+
+ err = transport_connect(io_ctxt, sk, (struct sockaddr *) &addr,
+ sizeof(addr));
+ if (err < 0) {
+ close(sk);
+ return err;
+ }
+
+ return 0;
+}
+
static int l2cap_connect(struct io_context *io_ctxt, const bdaddr_t *src,
const bdaddr_t *dst, uint16_t psm)
{
@@ -389,34 +446,25 @@ static int l2cap_connect(struct io_context *io_ctxt, const bdaddr_t *src,
if (sk < 0)
return -errno;
- io_ctxt->io = g_io_channel_unix_new(sk);
- if (!io_ctxt->io)
- return -ENOMEM;
-
memset(&l2a, 0, sizeof(l2a));
l2a.l2_family = AF_BLUETOOTH;
bacpy(&l2a.l2_bdaddr, src);
err = bind(sk, (struct sockaddr *) &l2a, sizeof(l2a));
if (err < 0)
- return err;
-
- if (g_io_channel_set_flags(io_ctxt->io, G_IO_FLAG_NONBLOCK, NULL) !=
- G_IO_STATUS_NORMAL)
- return -EPERM;
+ return -errno;
memset(&l2a, 0, sizeof(l2a));
l2a.l2_family = AF_BLUETOOTH;
bacpy(&l2a.l2_bdaddr, dst);
l2a.l2_psm = htobs(psm);
- err = connect(sk, (struct sockaddr *) &l2a, sizeof(l2a));
-
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ err = transport_connect(io_ctxt, sk, (struct sockaddr *) &l2a,
+ sizeof(l2a));
+ if (err < 0) {
+ close(sk);
return err;
-
- g_io_add_watch(io_ctxt->io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) connect_cb, io_ctxt);
+ }
return 0;
}
@@ -431,34 +479,25 @@ static int rfcomm_connect(struct io_context *io_ctxt, const bdaddr_t *src,
if (sk < 0)
return -errno;
- io_ctxt->io = g_io_channel_unix_new(sk);
- if (!io_ctxt->io)
- return -ENOMEM;
-
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, src);
err = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0)
- return err;
-
- if (g_io_channel_set_flags(io_ctxt->io, G_IO_FLAG_NONBLOCK, NULL) !=
- G_IO_STATUS_NORMAL)
- return -EPERM;
+ return -errno;
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, dst);
addr.rc_channel = channel;
- err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
-
- if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+ err = transport_connect(io_ctxt, sk, (struct sockaddr *) &addr,
+ sizeof(addr));
+ if (err < 0) {
+ close(sk);
return err;
-
- g_io_add_watch(io_ctxt->io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) connect_cb, io_ctxt);
+ }
return 0;
}
@@ -476,6 +515,15 @@ static int create_io_context(struct io_context **io_ctxt, bt_io_callback_t cb,
return 0;
}
+static void io_context_cleanup(struct io_context *io_ctxt)
+{
+ if (io_ctxt->io) {
+ g_io_channel_close(io_ctxt->io);
+ g_io_channel_unref(io_ctxt->io);
+ }
+ g_free(io_ctxt);
+}
+
int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
sdp_record_t *record, bt_io_callback_t cb,
void *user_data)
@@ -503,11 +551,7 @@ int bt_rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst,
err = rfcomm_connect(io_ctxt, src, dst, channel);
if (err < 0) {
- if (io_ctxt->io) {
- g_io_channel_close(io_ctxt->io);
- g_io_channel_unref(io_ctxt->io);
- }
- g_free(io_ctxt);
+ io_context_cleanup(io_ctxt);
return err;
}
@@ -526,11 +570,26 @@ int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst,
err = l2cap_connect(io_ctxt, src, dst, psm);
if (err < 0) {
- if (io_ctxt->io) {
- g_io_channel_close(io_ctxt->io);
- g_io_channel_unref(io_ctxt->io);
- }
- g_free(io_ctxt);
+ io_context_cleanup(io_ctxt);
+ return err;
+ }
+
+ return 0;
+}
+
+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;
+ int err;
+
+ err = create_io_context(&io_ctxt, cb, user_data);
+ if (err < 0)
+ return err;
+
+ err = sco_connect(io_ctxt, src, dst);
+ if (err < 0) {
+ io_context_cleanup(io_ctxt);
return err;
}