From: Andrei Emeltchenko <[email protected]>
This is initial code implementing socket HAL. Receiving files
through OPP currently working somehow.
For tracking rfcomm sockets I use structure rfslot which has following
fields:
- real_sock - real RFCOMM socket
- fd - fd to communicate with Android framework
- hal_fd - fd passed to Android framework with CMSG
Andrei Emeltchenko (9):
android/hal-sock: Add debug flag printing
android: Avoid unneeded includes
android/ahl-sock: Add connect signal to socket
android/hal-sock: Initial listen handle
android/hal-sock: Implement socket accepted event
android/hal-sock: Implement Android RFCOMM stack events
android/hal-sock: Implement RFCOMM events
android/hal-sock: Implement accept signal over Android fd
android/hal-sock: Write channel to Android fd
android/adapter.h | 2 +
android/hal-msg.h | 2 +
android/hal-sock.c | 8 +-
android/hidhost.c | 1 -
android/socket.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++-
android/socket.h | 7 ++
6 files changed, 277 insertions(+), 7 deletions(-)
--
1.7.10.4
Hi Johan,
On Wed, Nov 13, 2013 at 02:15:37PM +0200, Johan Hedberg wrote:
> > +struct rfcomm_slot {
> > + int fd;
> > + int hal_fd;
> > + int real_sock;
> > + uint32_t channel;
> > +};
>
> You should really have comments here for what each struct member is used
> for (you have this info in your cover letter but it should also be part
> of the code). Why do you keep hal_fd here? Shouldn't we close it on our
> side as soon as we've handed it over to the HAL?
Basically hal_fd is needed until it is passed to the Android framework.
Do you want it to be like this:
int hal_fd;
rfslot = create_rfslot(&hal_fd, int sock);
send(hal_fd);
close(hal_fd);
Best regards
Andrei Emeltchenko
Hi Andrei,
On Wed, Nov 13, 2013, Andrei Emeltchenko wrote:
> > A table would probably make more sense here. What about the SDP records
> > that need to be registered? Also, I'd stick to the assigned numbers from
> > our doc/assigned-numbers.txt.
>
> If I use table then we need a loop here.
Correct.
> So shall we change default Android assigned number to ours? Some devices
> assume that numbers and we would have worse interoperability.
A device which hard-codes a remote RFCOMM channel and never does an SDP
lookup wouldn't be able to pass qualification or interoperate with any
device that doesn't have the same hard-coded channel. So I really doubt
such devices exist on the market, unless you can provide some proof.
Johan
Hi Johan,
On Wed, Nov 13, 2013 at 02:15:37PM +0200, Johan Hedberg wrote:
> Hi Andrei,
>
> On Mon, Nov 11, 2013, Andrei Emeltchenko wrote:
> > Handle HAL socket listen call. Create RFCOMM socket and wait for events.
> > ---
> > android/socket.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
> > 1 file changed, 92 insertions(+), 2 deletions(-)
> >
> > diff --git a/android/socket.c b/android/socket.c
> > index c283c5f..80cb39e 100644
> > --- a/android/socket.c
> > +++ b/android/socket.c
> > @@ -27,22 +27,112 @@
> >
> > #include <glib.h>
> > #include <stdbool.h>
> > +#include <errno.h>
> >
> > #include "lib/bluetooth.h"
> > +#include "btio/btio.h"
> > #include "log.h"
> > #include "hal-msg.h"
> > #include "hal-ipc.h"
> > #include "ipc.h"
> > +#include "adapter.h"
> > #include "socket.h"
> >
> > +/* Simple list of RFCOMM server sockets */
> > +GList *rfcomm_srv_list = NULL;
> > +/* Simple list of RFCOMM accepted sockets */
> > +GList *rfcomm_accepted_list = NULL;
>
> What are these lists needed for? When/how will their items be freed?
> How about calling them "servers" and "connections"?
I will add code freeing those.
>
> > +struct rfcomm_slot {
> > + int fd;
> > + int hal_fd;
> > + int real_sock;
> > + uint32_t channel;
> > +};
>
> You should really have comments here for what each struct member is used
> for (you have this info in your cover letter but it should also be part
> of the code). Why do you keep hal_fd here? Shouldn't we close it on our
> side as soon as we've handed it over to the HAL? Why do you use uint32_t
> for the channel? RFCOMM channels are uint8_t and have a range of 1-31.
I will change it to int since we need to write int to Android framework.
>
> > +static struct rfcomm_slot *create_rfslot(int sock)
> > {
> > - DBG("Not implemented");
> > + int fds[2] = {-1, -1};
> > + struct rfcomm_slot *rfslot;
> > +
> > + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
> > + error("socketpair(): %s", strerror(errno));
> > + return NULL;
> > + }
> > +
> > + rfslot = g_malloc0(sizeof(*rfslot));
> > + rfslot->fd = fds[0];
> > + rfslot->hal_fd = fds[1];
> > + rfslot->real_sock = sock;
> > +
> > + return rfslot;
> > +}
> > +
> > +static const uint8_t UUID_PBAP[] = {
> > + 0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
> > + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> > +};
> > +#define RFCOMM_CHAN_PBAP 19
> > +
> > +static const uint8_t UUID_OPP[] = {
> > + 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
> > + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> > +};
> > +#define RFCOMM_CHAN_OPP 12
>
> A table would probably make more sense here. What about the SDP records
> that need to be registered? Also, I'd stick to the assigned numbers from
> our doc/assigned-numbers.txt.
If I use table then we need a loop here.
So shall we change default Android assigned number to ours? Some devices
assume that numbers and we would have worse interoperability.
Best regards
Andrei Emeltchenko
>
> > +static int handle_listen(void *buf)
> > +{
> > + struct hal_cmd_sock_listen *cmd = buf;
> > + const bdaddr_t *src = bt_adapter_get_address();
> > + struct rfcomm_slot *rfslot;
> > + GIOChannel *io;
> > + GError *err = NULL;
> > + int ch;
> > +
> > + DBG("");
> > +
> > + ch = get_rfcomm_chan(cmd->uuid);
> > + if (ch < 0)
> > + return -1;
> > +
> > + DBG("rfcomm channel %u", ch);
> > +
> > + rfslot = create_rfslot(-1);
> > +
> > + io = bt_io_listen(connect_cb, NULL, rfslot, NULL, &err,
> > + BT_IO_OPT_SOURCE_BDADDR, src,
> > + BT_IO_OPT_CHANNEL, ch,
> > + BT_IO_OPT_INVALID);
>
> Might make sense to pass a proper GDestroyNotify callback here so that
> once you finally implement proper freeing of data it can be done in a
> clean way.
>
> Johan
Hi Andrei,
On Mon, Nov 11, 2013, Andrei Emeltchenko wrote:
> Handle HAL socket listen call. Create RFCOMM socket and wait for events.
> ---
> android/socket.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 92 insertions(+), 2 deletions(-)
>
> diff --git a/android/socket.c b/android/socket.c
> index c283c5f..80cb39e 100644
> --- a/android/socket.c
> +++ b/android/socket.c
> @@ -27,22 +27,112 @@
>
> #include <glib.h>
> #include <stdbool.h>
> +#include <errno.h>
>
> #include "lib/bluetooth.h"
> +#include "btio/btio.h"
> #include "log.h"
> #include "hal-msg.h"
> #include "hal-ipc.h"
> #include "ipc.h"
> +#include "adapter.h"
> #include "socket.h"
>
> +/* Simple list of RFCOMM server sockets */
> +GList *rfcomm_srv_list = NULL;
> +/* Simple list of RFCOMM accepted sockets */
> +GList *rfcomm_accepted_list = NULL;
What are these lists needed for? When/how will their items be freed?
How about calling them "servers" and "connections"?
> +struct rfcomm_slot {
> + int fd;
> + int hal_fd;
> + int real_sock;
> + uint32_t channel;
> +};
You should really have comments here for what each struct member is used
for (you have this info in your cover letter but it should also be part
of the code). Why do you keep hal_fd here? Shouldn't we close it on our
side as soon as we've handed it over to the HAL? Why do you use uint32_t
for the channel? RFCOMM channels are uint8_t and have a range of 1-31.
> +static struct rfcomm_slot *create_rfslot(int sock)
> {
> - DBG("Not implemented");
> + int fds[2] = {-1, -1};
> + struct rfcomm_slot *rfslot;
> +
> + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
> + error("socketpair(): %s", strerror(errno));
> + return NULL;
> + }
> +
> + rfslot = g_malloc0(sizeof(*rfslot));
> + rfslot->fd = fds[0];
> + rfslot->hal_fd = fds[1];
> + rfslot->real_sock = sock;
> +
> + return rfslot;
> +}
> +
> +static const uint8_t UUID_PBAP[] = {
> + 0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
> + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> +};
> +#define RFCOMM_CHAN_PBAP 19
> +
> +static const uint8_t UUID_OPP[] = {
> + 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
> + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> +};
> +#define RFCOMM_CHAN_OPP 12
A table would probably make more sense here. What about the SDP records
that need to be registered? Also, I'd stick to the assigned numbers from
our doc/assigned-numbers.txt.
> +static int handle_listen(void *buf)
> +{
> + struct hal_cmd_sock_listen *cmd = buf;
> + const bdaddr_t *src = bt_adapter_get_address();
> + struct rfcomm_slot *rfslot;
> + GIOChannel *io;
> + GError *err = NULL;
> + int ch;
> +
> + DBG("");
> +
> + ch = get_rfcomm_chan(cmd->uuid);
> + if (ch < 0)
> + return -1;
> +
> + DBG("rfcomm channel %u", ch);
> +
> + rfslot = create_rfslot(-1);
> +
> + io = bt_io_listen(connect_cb, NULL, rfslot, NULL, &err,
> + BT_IO_OPT_SOURCE_BDADDR, src,
> + BT_IO_OPT_CHANNEL, ch,
> + BT_IO_OPT_INVALID);
Might make sense to pass a proper GDestroyNotify callback here so that
once you finally implement proper freeing of data it can be done in a
clean way.
Johan
Hi Andrei,
On 11 November 2013 15:03, Andrei Emeltchenko
<[email protected]> wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> Handle HAL socket listen call. Create RFCOMM socket and wait for events.
> ---
> android/socket.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 92 insertions(+), 2 deletions(-)
>
> diff --git a/android/socket.c b/android/socket.c
> index c283c5f..80cb39e 100644
> --- a/android/socket.c
> +++ b/android/socket.c
> @@ -27,22 +27,112 @@
>
> #include <glib.h>
> #include <stdbool.h>
> +#include <errno.h>
>
> #include "lib/bluetooth.h"
> +#include "btio/btio.h"
> #include "log.h"
> #include "hal-msg.h"
> #include "hal-ipc.h"
> #include "ipc.h"
> +#include "adapter.h"
> #include "socket.h"
>
> +/* Simple list of RFCOMM server sockets */
> +GList *rfcomm_srv_list = NULL;
> +/* Simple list of RFCOMM accepted sockets */
> +GList *rfcomm_accepted_list = NULL;
>
> -static int handle_listen(void *buf)
> +struct rfcomm_slot {
> + int fd;
> + int hal_fd;
> + int real_sock;
> + uint32_t channel;
> +};
> +
> +static struct rfcomm_slot *create_rfslot(int sock)
> {
> - DBG("Not implemented");
> + int fds[2] = {-1, -1};
> + struct rfcomm_slot *rfslot;
> +
> + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
> + error("socketpair(): %s", strerror(errno));
> + return NULL;
> + }
> +
> + rfslot = g_malloc0(sizeof(*rfslot));
> + rfslot->fd = fds[0];
> + rfslot->hal_fd = fds[1];
> + rfslot->real_sock = sock;
> +
> + return rfslot;
> +}
> +
> +static const uint8_t UUID_PBAP[] = {
> + 0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
> + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> +};
> +#define RFCOMM_CHAN_PBAP 19
> +
> +static const uint8_t UUID_OPP[] = {
> + 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
> + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> +};
> +#define RFCOMM_CHAN_OPP 12
> +
> +static int get_rfcomm_chan(const uint8_t *uuid)
> +{
> + if (!memcmp(UUID_PBAP, uuid, sizeof(UUID_PBAP)))
> + return RFCOMM_CHAN_PBAP;
> +
> + if (!memcmp(UUID_OPP, uuid, sizeof(UUID_OPP)))
> + return RFCOMM_CHAN_OPP;
>
> return -1;
> }
>
> +static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
> +{
> +}
> +
> +static int handle_listen(void *buf)
> +{
> + struct hal_cmd_sock_listen *cmd = buf;
> + const bdaddr_t *src = bt_adapter_get_address();
> + struct rfcomm_slot *rfslot;
> + GIOChannel *io;
> + GError *err = NULL;
> + int ch;
> +
> + DBG("");
> +
> + ch = get_rfcomm_chan(cmd->uuid);
> + if (ch < 0)
> + return -1;
> +
> + DBG("rfcomm channel %u", ch);
> +
> + rfslot = create_rfslot(-1);
> +
> + io = bt_io_listen(connect_cb, NULL, rfslot, NULL, &err,
> + BT_IO_OPT_SOURCE_BDADDR, src,
> + BT_IO_OPT_CHANNEL, ch,
> + BT_IO_OPT_INVALID);
> + if (!io) {
> + error("Failed listen: %s", err->message);
shouldn't we free rfslot in case of error?
> + g_error_free(err);
> + return -1;
> + }
> +
> + rfslot->real_sock = g_io_channel_unix_get_fd(io);
> + rfcomm_srv_list = g_list_append(rfcomm_srv_list, rfslot);
> +
> + DBG("real_sock %d fd %d hal_fd %d",
> + rfslot->real_sock, rfslot->fd, rfslot->hal_fd);
> +
> + return rfslot->hal_fd;
> +}
> +
> static int handle_connect(void *buf)
> {
> DBG("Not implemented");
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Best regards
Marcin
From: Andrei Emeltchenko <[email protected]>
---
android/socket.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 20f4e38..0188646 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -27,6 +27,7 @@
#include <glib.h>
#include <stdbool.h>
+#include <unistd.h>
#include <errno.h>
#include "lib/bluetooth.h"
@@ -292,6 +293,10 @@ static int handle_listen(void *buf)
rfslot->real_sock = g_io_channel_unix_get_fd(io);
rfcomm_srv_list = g_list_append(rfcomm_srv_list, rfslot);
+ /* TODO: Check this */
+ if (write(rfslot->fd, &ch, sizeof(ch)) < 0)
+ return -1;
+
DBG("real_sock %d fd %d hal_fd %d",
rfslot->real_sock, rfslot->fd, rfslot->hal_fd);
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
Handle HAL socket listen call. Create RFCOMM socket and wait for events.
---
android/socket.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index c283c5f..80cb39e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -27,22 +27,112 @@
#include <glib.h>
#include <stdbool.h>
+#include <errno.h>
#include "lib/bluetooth.h"
+#include "btio/btio.h"
#include "log.h"
#include "hal-msg.h"
#include "hal-ipc.h"
#include "ipc.h"
+#include "adapter.h"
#include "socket.h"
+/* Simple list of RFCOMM server sockets */
+GList *rfcomm_srv_list = NULL;
+/* Simple list of RFCOMM accepted sockets */
+GList *rfcomm_accepted_list = NULL;
-static int handle_listen(void *buf)
+struct rfcomm_slot {
+ int fd;
+ int hal_fd;
+ int real_sock;
+ uint32_t channel;
+};
+
+static struct rfcomm_slot *create_rfslot(int sock)
{
- DBG("Not implemented");
+ int fds[2] = {-1, -1};
+ struct rfcomm_slot *rfslot;
+
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
+ error("socketpair(): %s", strerror(errno));
+ return NULL;
+ }
+
+ rfslot = g_malloc0(sizeof(*rfslot));
+ rfslot->fd = fds[0];
+ rfslot->hal_fd = fds[1];
+ rfslot->real_sock = sock;
+
+ return rfslot;
+}
+
+static const uint8_t UUID_PBAP[] = {
+ 0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+};
+#define RFCOMM_CHAN_PBAP 19
+
+static const uint8_t UUID_OPP[] = {
+ 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+};
+#define RFCOMM_CHAN_OPP 12
+
+static int get_rfcomm_chan(const uint8_t *uuid)
+{
+ if (!memcmp(UUID_PBAP, uuid, sizeof(UUID_PBAP)))
+ return RFCOMM_CHAN_PBAP;
+
+ if (!memcmp(UUID_OPP, uuid, sizeof(UUID_OPP)))
+ return RFCOMM_CHAN_OPP;
return -1;
}
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+}
+
+static int handle_listen(void *buf)
+{
+ struct hal_cmd_sock_listen *cmd = buf;
+ const bdaddr_t *src = bt_adapter_get_address();
+ struct rfcomm_slot *rfslot;
+ GIOChannel *io;
+ GError *err = NULL;
+ int ch;
+
+ DBG("");
+
+ ch = get_rfcomm_chan(cmd->uuid);
+ if (ch < 0)
+ return -1;
+
+ DBG("rfcomm channel %u", ch);
+
+ rfslot = create_rfslot(-1);
+
+ io = bt_io_listen(connect_cb, NULL, rfslot, NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR, src,
+ BT_IO_OPT_CHANNEL, ch,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("Failed listen: %s", err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ rfslot->real_sock = g_io_channel_unix_get_fd(io);
+ rfcomm_srv_list = g_list_append(rfcomm_srv_list, rfslot);
+
+ DBG("real_sock %d fd %d hal_fd %d",
+ rfslot->real_sock, rfslot->fd, rfslot->hal_fd);
+
+ return rfslot->hal_fd;
+}
+
static int handle_connect(void *buf)
{
DBG("Not implemented");
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
Handle events from Android framework. Write everything to real RFCOMM
socket.
---
android/socket.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 0ee53ba..dfad9da 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -94,6 +94,35 @@ static int get_rfcomm_chan(const uint8_t *uuid)
static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
+ struct rfcomm_slot *rfslot = data;
+ unsigned char buf[1024] = { 0 };
+ int len;
+
+ DBG("rfslot: fd %d hal_fd %d real_sock %d chan %u sock %d",
+ rfslot->fd, rfslot->hal_fd, rfslot->real_sock, rfslot->channel,
+ g_io_channel_unix_get_fd(io));
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Socket error: sock %d cond %d",
+ g_io_channel_unix_get_fd(io), cond);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ return FALSE;
+ }
+
+ /* FIXME check fd vs sock(io) */
+ len = recv(rfslot->fd, buf, sizeof(buf), 0);
+ if (len <= 0) {
+ error("recv(): %s", strerror(errno));
+ return FALSE;
+ }
+
+ DBG("read %d bytes write to %d", len, rfslot->real_sock);
+
+ if (send(rfslot->real_sock, buf, len, 0) < 0) {
+ error("send(): %s", strerror(errno));
+ return FALSE;
+ }
+
return TRUE;
}
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
Connect signal is used to pass information to framework that socket
is accepted.
---
android/hal-msg.h | 2 ++
android/socket.h | 7 +++++++
2 files changed, 9 insertions(+)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index 569c8ea..68cc8ed 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -232,6 +232,8 @@ struct hal_cmd_sock_connect {
uint8_t flags;
} __attribute__((packed));
+/* Bluetooth Hidhost HAL api */
+
#define HAL_OP_HIDHOST_CONNECT 0x01
struct hal_cmd_hidhost_connect {
uint8_t bdaddr[6];
diff --git a/android/socket.h b/android/socket.h
index 7aa5574..ba56c9b 100644
--- a/android/socket.h
+++ b/android/socket.h
@@ -21,6 +21,13 @@
*
*/
+struct hal_sock_connect_signal {
+ short size;
+ uint8_t bdaddr[6];
+ int channel;
+ int status;
+} __attribute__((packed));
+
void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len);
bool bt_socket_register(int sk, const bdaddr_t *addr);
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
Copy data from RFCOMM socket to Android framework.
---
android/socket.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index dfad9da..a962cdc 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -129,6 +129,35 @@ static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
+ struct rfcomm_slot *rfslot = data;
+ unsigned char buf[1024] = { 0 };
+ int len;
+
+ DBG("rfslot: fd %d hal_fd %d real_sock %d chan %u sock %d",
+ rfslot->fd, rfslot->hal_fd, rfslot->real_sock, rfslot->channel,
+ g_io_channel_unix_get_fd(io));
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Socket error: sock %d cond %d",
+ g_io_channel_unix_get_fd(io), cond);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ return FALSE;
+ }
+
+ /* FIXME check real_sock vs sock(io) */
+ len = recv(rfslot->real_sock, buf, sizeof(buf), 0);
+ if (len <= 0) {
+ error("recv(): %s sock %d", strerror(errno), rfslot->real_sock);
+ return FALSE;
+ }
+
+ DBG("read %d bytes, write to fd %d", len, rfslot->fd);
+
+ if (send(rfslot->fd, buf, len, MSG_DONTWAIT) < 0) {
+ error("send(): %s sock %d", strerror(errno), rfslot->fd);
+ return FALSE;
+ }
+
return TRUE;
}
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
When we get accepted event we create rfcomm slot and start listening
for events from Android framework and from RFCOMM real socket.
---
android/socket.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 80cb39e..0ee53ba 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -91,8 +91,58 @@ static int get_rfcomm_chan(const uint8_t *uuid)
return -1;
}
+static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ return TRUE;
+}
+
+static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ return TRUE;
+}
+
static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
+ struct rfcomm_slot *rfslot = user_data;
+ struct rfcomm_slot *rfslot_acc;
+ GIOChannel *io_stack;
+ bdaddr_t dst;
+ char address[18];
+ int sock_acc;
+
+ bt_io_get(io, &err,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ return;
+ }
+
+ ba2str(&dst, address);
+ DBG("Incoming connection from %s rfslot %p", address, rfslot);
+
+ DBG("rfslot: fd %d hal_fd %d real_sock %d chan %u sock %d",
+ rfslot->fd, rfslot->hal_fd, rfslot->real_sock, rfslot->channel,
+ g_io_channel_unix_get_fd(io));
+
+ sock_acc = g_io_channel_unix_get_fd(io);
+ rfslot_acc = create_rfslot(sock_acc);
+ rfcomm_accepted_list = g_list_append(rfcomm_accepted_list, rfslot_acc);
+
+ /* Handle events from Android */
+ io_stack = g_io_channel_unix_new(rfslot_acc->fd);
+ g_io_add_watch(io_stack, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ sock_stack_event_cb, rfslot_acc);
+ g_io_channel_unref(io_stack);
+
+ /* Handle rfcomm events */
+ g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ sock_rfcomm_event_cb, rfslot_acc);
+
+ DBG("rfslot %p rfslot_acc %p", rfslot, rfslot_acc);
}
static int handle_listen(void *buf)
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
Declare struct mgmt in adapter.h. This avoids including mgmt.h in
every file using adapter functions like socket and hid.
---
android/adapter.h | 2 ++
android/hidhost.c | 1 -
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/adapter.h b/android/adapter.h
index c62b859..3bda9d9 100644
--- a/android/adapter.h
+++ b/android/adapter.h
@@ -23,6 +23,8 @@
typedef void (*bt_adapter_ready)(int err);
+struct mgmt;
+
void bt_adapter_init(uint16_t index, struct mgmt *mgmt_if,
bt_adapter_ready cb);
diff --git a/android/hidhost.c b/android/hidhost.c
index 683938f..8c3e9f6 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -38,7 +38,6 @@
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
#include "lib/uuid.h"
-#include "src/shared/mgmt.h"
#include "src/sdp-client.h"
#include "src/glib-helper.h"
#include "profiles/input/uhid_copy.h"
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
Android expects to get accept signal over file descriptor which was
set during listen HAL call.
---
android/socket.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index a962cdc..20f4e38 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -36,6 +36,7 @@
#include "hal-ipc.h"
#include "ipc.h"
#include "adapter.h"
+#include "utils.h"
#include "socket.h"
/* Simple list of RFCOMM server sockets */
@@ -68,6 +69,45 @@ static struct rfcomm_slot *create_rfslot(int sock)
return rfslot;
}
+static int bt_sock_send_fd(int sock_fd, const void *buf, int len, int send_fd)
+{
+ ssize_t ret;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iv;
+ char msgbuf[CMSG_SPACE(1)];
+
+ DBG("len %d sock_fd %d send_fd %d", len, sock_fd, send_fd);
+
+ if (sock_fd == -1 || send_fd == -1)
+ return -1;
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.msg_control = msgbuf;
+ msg.msg_controllen = sizeof(msgbuf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
+ memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
+
+ iv.iov_base = (unsigned char *) buf;
+ iv.iov_len = len;
+
+ msg.msg_iov = &iv;
+ msg.msg_iovlen = 1;
+
+ ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL);
+ if (ret < 0) {
+ error("sendmsg(): sock_fd %d send_fd %d: %s",
+ sock_fd, send_fd, strerror(errno));
+ return ret;
+ }
+
+ return ret;
+}
+
static const uint8_t UUID_PBAP[] = {
0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
@@ -161,6 +201,21 @@ static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
return TRUE;
}
+static void socket_send_accept(struct rfcomm_slot *rfslot, bdaddr_t *bdaddr,
+ int fd_accepted)
+{
+ struct hal_sock_connect_signal cmd;
+
+ DBG("");
+
+ cmd.size = sizeof(cmd);
+ bdaddr2android(bdaddr, cmd.bdaddr);
+ cmd.channel = rfslot->channel;
+ cmd.status = 0;
+
+ bt_sock_send_fd(rfslot->fd, &cmd, sizeof(cmd), fd_accepted);
+}
+
static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_slot *rfslot = user_data;
@@ -190,6 +245,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
rfslot_acc = create_rfslot(sock_acc);
rfcomm_accepted_list = g_list_append(rfcomm_accepted_list, rfslot_acc);
+ socket_send_accept(rfslot, &dst, rfslot_acc->hal_fd);
+
/* Handle events from Android */
io_stack = g_io_channel_unix_new(rfslot_acc->fd);
g_io_add_watch(io_stack, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
--
1.7.10.4
From: Andrei Emeltchenko <[email protected]>
---
android/hal-sock.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/android/hal-sock.c b/android/hal-sock.c
index b7bc88e..eafa451 100644
--- a/android/hal-sock.c
+++ b/android/hal-sock.c
@@ -55,8 +55,8 @@ static bt_status_t sock_listen(btsock_type_t type, const char *service_name,
return BT_STATUS_PARM_INVALID;
}
- DBG("uuid %s chan %d sock %p type %d service_name %s",
- btuuid2str(uuid), chan, sock, type, service_name);
+ DBG("uuid %s chan %d sock %p type %d service_name %s flags 0x%02x",
+ btuuid2str(uuid), chan, sock, type, service_name, flags);
switch (type) {
case BTSOCK_RFCOMM:
@@ -82,8 +82,8 @@ static bt_status_t sock_connect(const bt_bdaddr_t *bdaddr, btsock_type_t type,
return BT_STATUS_PARM_INVALID;
}
- DBG("uuid %s chan %d sock %p type %d", btuuid2str(uuid), chan, sock,
- type);
+ DBG("uuid %s chan %d sock %p type %d flags 0x%02x",
+ btuuid2str(uuid), chan, sock, type, flags);
if (type != BTSOCK_RFCOMM) {
error("Socket type %u not supported", type);
--
1.7.10.4
Hi Luiz,
On Monday 11 November 2013 15:20:21 Luiz Augusto von Dentz wrote:
> Hi Andrei,
>
> On Mon, Nov 11, 2013 at 2:37 PM, Andrei Emeltchenko
>
> <[email protected]> wrote:
> > From: Andrei Emeltchenko <[email protected]>
> >
> > Declare struct mgmt in adapter.h. This avoids including mgmt.h in
> > every file using adapter functions like socket and hid.
> > ---
> >
> > android/adapter.h | 2 ++
> > android/hidhost.c | 1 -
> > 2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/android/adapter.h b/android/adapter.h
> > index c62b859..3bda9d9 100644
> > --- a/android/adapter.h
> > +++ b/android/adapter.h
> > @@ -23,6 +23,8 @@
> >
> > typedef void (*bt_adapter_ready)(int err);
> >
> > +struct mgmt;
> > +
> >
> > void bt_adapter_init(uint16_t index, struct mgmt *mgmt_if,
> >
> > bt_adapter_ready
> > cb);
> >
> > diff --git a/android/hidhost.c b/android/hidhost.c
> > index 683938f..8c3e9f6 100644
> > --- a/android/hidhost.c
> > +++ b/android/hidhost.c
> > @@ -38,7 +38,6 @@
> >
> > #include "lib/sdp.h"
> > #include "lib/sdp_lib.h"
> > #include "lib/uuid.h"
> >
> > -#include "src/shared/mgmt.h"
> >
> > #include "src/sdp-client.h"
> > #include "src/glib-helper.h"
> > #include "profiles/input/uhid_copy.h"
> >
> > --
> > 1.7.10.4
>
> Well it looks like we need to find a proper place for the mgmt
> interaction, or then perhaps pass the fd and use mgmt_new on adapter
> but that seems to require some work as it does create a different mgmt
> objects with different queues which I don't think is safe to use.
I've some patches that try to address this issue. Should be able to send them
soon.
--
Szymon K. Janc
[email protected]
Hi Andrei,
On Mon, Nov 11, 2013 at 2:37 PM, Andrei Emeltchenko
<[email protected]> wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> Declare struct mgmt in adapter.h. This avoids including mgmt.h in
> every file using adapter functions like socket and hid.
> ---
> android/adapter.h | 2 ++
> android/hidhost.c | 1 -
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/android/adapter.h b/android/adapter.h
> index c62b859..3bda9d9 100644
> --- a/android/adapter.h
> +++ b/android/adapter.h
> @@ -23,6 +23,8 @@
>
> typedef void (*bt_adapter_ready)(int err);
>
> +struct mgmt;
> +
> void bt_adapter_init(uint16_t index, struct mgmt *mgmt_if,
> bt_adapter_ready cb);
>
> diff --git a/android/hidhost.c b/android/hidhost.c
> index 683938f..8c3e9f6 100644
> --- a/android/hidhost.c
> +++ b/android/hidhost.c
> @@ -38,7 +38,6 @@
> #include "lib/sdp.h"
> #include "lib/sdp_lib.h"
> #include "lib/uuid.h"
> -#include "src/shared/mgmt.h"
> #include "src/sdp-client.h"
> #include "src/glib-helper.h"
> #include "profiles/input/uhid_copy.h"
> --
> 1.7.10.4
Well it looks like we need to find a proper place for the mgmt
interaction, or then perhaps pass the fd and use mgmt_new on adapter
but that seems to require some work as it does create a different mgmt
objects with different queues which I don't think is safe to use.
--
Luiz Augusto von Dentz