diff options
| author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2008-05-12 21:21:47 +0000 | 
|---|---|---|
| committer | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2008-05-12 21:21:47 +0000 | 
| commit | eac653286a4619a0b28614cdde1506997e5d6023 (patch) | |
| tree | 39e47d27560b6bf34d8ed4b232aa245fb22ca642 | |
| parent | 788878d89291688a06d2bb067fa9d5c82c4ad050 (diff) | |
introduce bt_rfcomm_listen.
| -rw-r--r-- | common/glib-helper.c | 134 | ||||
| -rw-r--r-- | common/glib-helper.h | 2 | 
2 files changed, 128 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)  { diff --git a/common/glib-helper.h b/common/glib-helper.h index 7a312005..71ed67b8 100644 --- a/common/glib-helper.h +++ b/common/glib-helper.h @@ -38,6 +38,8 @@ gchar *bt_uuid2string(uuid_t *uuid);  gchar *bt_list2string(GSList *list);  GSList *bt_string2list(const gchar *str); +GIOChannel *bt_rfcomm_listen(const bdaddr_t *src, uint8_t channel, +			uint32_t flags, bt_io_callback_t cb, void *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);  int bt_l2cap_connect(const bdaddr_t *src, const bdaddr_t *dst, | 
