2013-11-20 10:24:18

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 00/19] Socket HAL

From: Andrei Emeltchenko <[email protected]>

This is initial code implementing socket HAL. OPP currently works with send/receive files. Probaly
other profiles works as well, not tested yet.

Changes:
* v6: Use watch_id to remove source and general cleanup
* v5: Changed uuid_to_chan table to profile table keeping information about profile like: channel, create_record,
svc_hint and sec_level.
* v4: Changed name rfslot -> rfsock following Johan's comment and other cosmetic changes, fixed one bug in SDP
record, use NULL instead of 0 for sdp functions.
* v3: Fixed coding style with write/send between file descriptors.
* v2: Following Marcel comments changed way copying between file descriptors works, added SDP record
for OPP and now it is possible to send files through GUI. Merged one patch with structures with actual user.
* v1: Rebased and use static src address, hal_fd removed from structure and closed after sent to framework,
added connect calls and SDP parsing, added cleanup_rfcomm function, minor fixes.
* RFC Initial

TODO:
* Use sec_level / check what to do with Android supplied security flags.
* Use splice() (requires bionic change first)

For tracking rfcomm sockets I use structure rfslot which has following
fields:
- real_sock - real RFCOMM socket
- fd - fd to communicate with Android framework

create_rfslot sets hal_fd which is fd passed to Android framework with CMSG

Andrei Emeltchenko (19):
android/socket: Add get RFCOMM default channel
android/socket: Handling rfcomm sockets
android/socket: Implement listen on RFCOMM socket
android/socket: Implement socket accepted event
android/socket: Implement Android RFCOMM stack events
android/socket: Implement RFCOMM events
android/socket: Send accept signal to Android framework
android/socket: Notify channel to Android framework
android/socket: Implement socket connect HAL method
android/socket: Parse SDP response and connect
android/socket: Implement HAL connect call
android/socket: Send RFCOMM channel to framework
android/socket: Send connect signal to Android framework
android/socket: Close file descriptor after sending
android/socket: Add SDP record for OPP profile
android/socket: Add MAS uuid to profile table
android/socket: Add SPP uuid to profile table
android/socket: Add PBAP SDP record
android/socket: Add SPP SDP record

android/socket.c | 797 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 793 insertions(+), 4 deletions(-)

--
1.7.10.4



2013-11-20 13:21:30

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCHv6 10/19] android/socket: Parse SDP response and connect

Hi Andrei,

On Wed, Nov 20, 2013, Andrei Emeltchenko wrote:
> Parse SDP response, find RFCOMM channel and connect.
> ---
> android/socket.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 63 insertions(+)

Patches 1-9 have been applied (I merged 2 and 3 to avoid the compilation
error reported earlier), but one issue here:

> + io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
> + BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
> + BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
> + BT_IO_OPT_CHANNEL, chan,
> + BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
> + BT_IO_OPT_INVALID);
> + if (!io) {
> + error("Failed connect: %s", gerr->message);
> + g_error_free(gerr);
> + goto fail;
> + }
> +
> + rfsock->real_sock = g_io_channel_unix_get_fd(io);
> + rfsock->channel = chan;
> + connections = g_list_append(connections, rfsock);
> + return;

Looks like you're leaking a reference for the GIOChannel since you don't
store it anywhere and return from the function without doing a
g_io_channel_unref().

Johan

2013-11-20 13:06:08

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCHv6 02/19] android/socket: Handling rfcomm sockets

Hi Andrei,

On Wed, Nov 20, 2013, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> Implement functions creating and destroying rfcomm_socket structures.
> ---
> android/socket.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 63 insertions(+), 1 deletion(-)

I've applied the first patch, but this one doesn't compile:

android/socket.c:81:13: error: ‘cleanup_rfsock’ defined but not used [-Werror=unused-function]
static void cleanup_rfsock(struct rfcomm_sock *rfsock)

Johan

2013-11-20 10:24:34

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 16/19] android/socket: Add MAS uuid to profile table

From: Andrei Emeltchenko <[email protected]>

---
android/socket.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 06b2906..07588d5 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -47,6 +47,7 @@

#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15
+#define MAS_DEFAULT_CHANNEL 16

/* Use Object Transfer for all services */
#define SVC_HINT_OBEX 0x10
@@ -202,6 +203,12 @@ static struct profile_info {
.channel = OPP_DEFAULT_CHANNEL,
.svc_hint = SVC_HINT_OBEX,
.create_record = create_opp_record
+ }, {
+ .uuid = {
+ 0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ },
+ .channel = MAS_DEFAULT_CHANNEL
}
};

--
1.7.10.4


2013-11-20 10:24:31

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 13/19] android/socket: Send connect signal to Android framework

From: Andrei Emeltchenko <[email protected]>

Android framework expects connect signal to be sent when
remote device is connected.
---
android/socket.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 1d16bc7..d8e922d 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -424,6 +424,33 @@ static int handle_listen(void *buf)
return hal_fd;
}

+static bool sock_send_connect(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr)
+{
+ struct hal_sock_connect_signal cmd;
+ int len;
+
+ DBG("");
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.size = sizeof(cmd);
+ bdaddr2android(bdaddr, cmd.bdaddr);
+ cmd.channel = rfsock->channel;
+ cmd.status = 0;
+
+ len = write(rfsock->fd, &cmd, sizeof(cmd));
+ if (len < 0) {
+ error("%s", strerror(errno));
+ return false;
+ }
+
+ if (len != sizeof(cmd)) {
+ error("Error sending connect signal");
+ false;
+ }
+
+ return true;
+}
+
static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
@@ -456,6 +483,9 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
rfsock->fd, rfsock->real_sock, rfsock->channel,
g_io_channel_unix_get_fd(io));

+ if (!sock_send_connect(rfsock, &dst))
+ goto fail;
+
/* Handle events from Android */
cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
io_stack = g_io_channel_unix_new(rfsock->fd);
--
1.7.10.4


2013-11-20 10:24:36

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 18/19] android/socket: Add PBAP SDP record

From: Andrei Emeltchenko <[email protected]>

This adds SDP service record like shown below:

Service Name: OBEX Phonebook Access Server
Service RecHandle: 0x10002
Service Class ID List:
"Phonebook Access - PSE" (0x112f)
Protocol Descriptor List:
"RFCOMM" (0x0003)
Channel: 15
"OBEX" (0x0008)
Profile Descriptor List:
"Phonebook Access" (0x1130)
Version: 0x0100
---
android/socket.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 32b2db6..a71c51c 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -183,6 +183,67 @@ static sdp_record_t *create_opp_record(uint8_t chan)
return record;
}

+static sdp_record_t *create_pbap_record(uint8_t chan)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, pbap_uuid, rfcomm_uuid, obex_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel;
+ uint8_t formats[] = { 0x01 };
+ uint8_t dtd = SDP_UINT8;
+ sdp_data_t *sflist;
+ sdp_record_t *record;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ record->handle = sdp_next_handle();
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&pbap_uuid, PBAP_PSE_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &pbap_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[0] = sdp_list_append(NULL, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[0] = sdp_list_append(proto[0], channel);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[1] = sdp_list_append(NULL, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sflist = sdp_data_alloc(dtd, formats);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
+
+ sdp_set_info_attr(record, "OBEX Phonebook Access Server", NULL, NULL);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(pfseq, NULL);
+ sdp_list_free(root, NULL);
+ sdp_list_free(svclass_id, NULL);
+ sdp_list_free(aproto, NULL);
+
+ return record;
+}
+
static struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -195,7 +256,9 @@ static struct profile_info {
0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = PBAP_DEFAULT_CHANNEL
+ .channel = PBAP_DEFAULT_CHANNEL,
+ .svc_hint = SVC_HINT_OBEX,
+ .create_record = create_pbap_record
}, {
.uuid = {
0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
--
1.7.10.4


2013-11-20 10:24:35

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 17/19] android/socket: Add SPP uuid to profile table

From: Andrei Emeltchenko <[email protected]>

---
android/socket.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 07588d5..32b2db6 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -45,6 +45,7 @@
#include "utils.h"
#include "socket.h"

+#define SPP_DEFAULT_CHANNEL 3
#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15
#define MAS_DEFAULT_CHANNEL 16
@@ -209,7 +210,13 @@ static struct profile_info {
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
.channel = MAS_DEFAULT_CHANNEL
- }
+ }, {
+ .uuid = {
+ 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ },
+ .channel = SPP_DEFAULT_CHANNEL
+ },
};

static uint32_t sdp_service_register(struct profile_info *profile)
--
1.7.10.4


2013-11-20 10:24:29

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 11/19] android/socket: Implement HAL connect call

From: Andrei Emeltchenko <[email protected]>

HAL connect uses similar event handlers like listen call.
---
android/socket.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index a5b28b7..e188c3f 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -426,6 +426,53 @@ static int handle_listen(void *buf)

static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
+ struct rfcomm_sock *rfsock = user_data;
+ GIOChannel *io_stack;
+ GError *gerr = NULL;
+ bdaddr_t dst;
+ char address[18];
+ int chan = -1;
+ guint id;
+ GIOCondition cond;
+
+ if (err) {
+ error("%s", err->message);
+ goto fail;
+ }
+
+ bt_io_get(io, &gerr,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ goto fail;
+ }
+
+ ba2str(&dst, address);
+ DBG("Connected to %s rfsock %p chan %d", address, rfsock, chan);
+
+ DBG("rfsock: fd %d real_sock %d chan %u sock %d",
+ rfsock->fd, rfsock->real_sock, rfsock->channel,
+ g_io_channel_unix_get_fd(io));
+
+ /* Handle events from Android */
+ cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+ io_stack = g_io_channel_unix_new(rfsock->fd);
+ id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock);
+ g_io_channel_unref(io_stack);
+
+ rfsock->stack_watch = id;
+
+ /* Handle rfcomm events */
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ id = g_io_add_watch(io, cond, sock_rfcomm_event_cb, rfsock);
+
+ rfsock->rfcomm_watch = id;
+
+ return;
+fail:
+ cleanup_rfsock(rfsock);
}

static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
--
1.7.10.4


2013-11-20 10:24:20

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 02/19] android/socket: Handling rfcomm sockets

From: Andrei Emeltchenko <[email protected]>

Implement functions creating and destroying rfcomm_socket structures.
---
android/socket.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index d4c7674..e19b2aa 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"
@@ -43,6 +44,61 @@

static bdaddr_t adapter_addr;

+/* Simple list of RFCOMM server sockets */
+GList *servers = NULL;
+
+/* Simple list of RFCOMM connected sockets */
+GList *connections = NULL;
+
+struct rfcomm_sock {
+ int fd; /* descriptor for communication with Java framework */
+ int real_sock; /* real RFCOMM socket */
+ int channel; /* RFCOMM channel */
+
+ guint rfcomm_watch;
+ guint stack_watch;
+};
+
+static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
+{
+ int fds[2] = {-1, -1};
+ struct rfcomm_sock *rfsock;
+
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
+ error("socketpair(): %s", strerror(errno));
+ *hal_fd = -1;
+ return NULL;
+ }
+
+ rfsock = g_new0(struct rfcomm_sock, 1);
+ rfsock->fd = fds[0];
+ *hal_fd = fds[1];
+ rfsock->real_sock = sock;
+
+ return rfsock;
+}
+
+static void cleanup_rfsock(struct rfcomm_sock *rfsock)
+{
+ DBG("rfsock: %p fd %d real_sock %d chan %u",
+ rfsock, rfsock->fd, rfsock->real_sock, rfsock->channel);
+
+ if (rfsock->fd > 0)
+ close(rfsock->fd);
+ if (rfsock->real_sock > 0)
+ close(rfsock->real_sock);
+
+ if (rfsock->rfcomm_watch > 0)
+ if (!g_source_remove(rfsock->rfcomm_watch))
+ error("rfcomm_watch source was not found");
+
+ if (rfsock->stack_watch > 0)
+ if (!g_source_remove(rfsock->stack_watch))
+ error("stack_watch source was not found");
+
+ g_free(rfsock);
+}
+
static struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -81,6 +137,8 @@ static int handle_listen(void *buf)
{
struct hal_cmd_sock_listen *cmd = buf;
struct profile_info *profile;
+ struct rfcomm_sock *rfsock;
+ int hal_fd;
int chan;

DBG("");
@@ -93,7 +151,11 @@ static int handle_listen(void *buf)

DBG("rfcomm channel %d", chan);

- return -1;
+ rfsock = create_rfsock(-1, &hal_fd);
+ if (!rfsock)
+ return -1;
+
+ return hal_fd;
}

static int handle_connect(void *buf)
--
1.7.10.4


2013-11-20 10:24:21

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 03/19] android/socket: Implement listen on RFCOMM socket

From: Andrei Emeltchenko <[email protected]>

Handle HAL socket listen call. Create RFCOMM socket and wait for events.
---
android/socket.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index e19b2aa..b8d96f9 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -133,11 +133,17 @@ static struct profile_info *get_profile_by_uuid(const uint8_t *uuid)
return NULL;
}

+static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+}
+
static int handle_listen(void *buf)
{
struct hal_cmd_sock_listen *cmd = buf;
struct profile_info *profile;
struct rfcomm_sock *rfsock;
+ GIOChannel *io;
+ GError *err = NULL;
int hal_fd;
int chan;

@@ -155,6 +161,27 @@ static int handle_listen(void *buf)
if (!rfsock)
return -1;

+ io = bt_io_listen(accept_cb, NULL, rfsock, NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_CHANNEL, chan,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("Failed listen: %s", err->message);
+ g_error_free(err);
+ cleanup_rfsock(rfsock);
+ return -1;
+ }
+
+ rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ servers = g_list_append(servers, rfsock);
+
+ /* TODO: Add server watch */
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_unref(io);
+
+ DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
+ hal_fd);
+
return hal_fd;
}

--
1.7.10.4


2013-11-20 10:24:33

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 15/19] android/socket: Add SDP record for OPP profile

From: Andrei Emeltchenko <[email protected]>

This adds SDP record for OPP shown below:

Service Name: OBEX Object Push
Service RecHandle: 0x10002
Service Class ID List:
"OBEX Object Push" (0x1105)
Protocol Descriptor List:
"RFCOMM" (0x0003)
Channel: 9
"OBEX" (0x0008)
Profile Descriptor List:
"OBEX Object Push" (0x1105)
Version: 0x0100
---
android/socket.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 5862c9c..06b2906 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -35,7 +35,9 @@
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
#include "src/sdp-client.h"
+#include "src/sdpd.h"

+#include "bluetooth.h"
#include "log.h"
#include "hal-msg.h"
#include "hal-ipc.h"
@@ -46,6 +48,9 @@
#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15

+/* Use Object Transfer for all services */
+#define SVC_HINT_OBEX 0x10
+
static bdaddr_t adapter_addr;

/* Simple list of RFCOMM server sockets */
@@ -63,6 +68,7 @@ struct rfcomm_sock {
guint stack_watch;

bdaddr_t dst;
+ uint32_t service_handle;
};

static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
@@ -102,9 +108,79 @@ static void cleanup_rfsock(struct rfcomm_sock *rfsock)
if (!g_source_remove(rfsock->stack_watch))
error("stack_watch source was not found");

+ if (rfsock->service_handle)
+ bt_adapter_remove_record(rfsock->service_handle);
+
g_free(rfsock);
}

+static sdp_record_t *create_opp_record(uint8_t chan)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, opush_uuid, rfcomm_uuid, obex_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+ void *dtds[sizeof(formats)], *values[sizeof(formats)];
+ unsigned int i;
+ uint8_t dtd = SDP_UINT8;
+ sdp_data_t *sflist;
+ sdp_data_t *channel;
+ sdp_record_t *record;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ record->handle = sdp_next_handle();
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &opush_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[0] = sdp_list_append(NULL, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[0] = sdp_list_append(proto[0], channel);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[1] = sdp_list_append(NULL, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ for (i = 0; i < sizeof(formats); i++) {
+ dtds[i] = &dtd;
+ values[i] = &formats[i];
+ }
+ sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
+
+ sdp_set_info_attr(record, "OBEX Object Push", NULL, NULL);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(proto[1], NULL);
+ sdp_list_free(apseq, NULL);
+ sdp_list_free(pfseq, NULL);
+ sdp_list_free(aproto, NULL);
+ sdp_list_free(root, NULL);
+ sdp_list_free(svclass_id, NULL);
+
+ return record;
+}
+
static struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -123,10 +199,29 @@ static struct profile_info {
0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = OPP_DEFAULT_CHANNEL
+ .channel = OPP_DEFAULT_CHANNEL,
+ .svc_hint = SVC_HINT_OBEX,
+ .create_record = create_opp_record
}
};

+static uint32_t sdp_service_register(struct profile_info *profile)
+{
+ sdp_record_t *record;
+
+ record = profile->create_record(profile->channel);
+ if (!record)
+ return 0;
+
+ if (bt_adapter_add_record(record, profile->svc_hint) < 0) {
+ error("Failed to register on SDP record");
+ sdp_record_free(record);
+ return 0;
+ }
+
+ return record->handle;
+}
+
static int bt_sock_send_fd(int sock_fd, const void *buf, int len, int send_fd)
{
ssize_t ret;
@@ -421,6 +516,8 @@ static int handle_listen(void *buf)
return -1;
}

+ rfsock->service_handle = sdp_service_register(profile);
+
return hal_fd;
}

--
1.7.10.4


2013-11-20 10:24:37

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 19/19] android/socket: Add SPP SDP record

From: Andrei Emeltchenko <[email protected]>

---
android/socket.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index a71c51c..15aa77d 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -237,9 +237,69 @@ static sdp_record_t *create_pbap_record(uint8_t chan)
sdp_list_free(proto[1], NULL);
sdp_list_free(apseq, NULL);
sdp_list_free(pfseq, NULL);
+ sdp_list_free(aproto, NULL);
sdp_list_free(root, NULL);
sdp_list_free(svclass_id, NULL);
+
+ return record;
+}
+
+static sdp_record_t *create_spp_record(uint8_t chan)
+{
+ sdp_list_t *svclass_id, *apseq, *profiles, *root;
+ uuid_t root_uuid, sp_uuid, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[1];
+ sdp_data_t *channel;
+ sdp_record_t *record;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ record->handle = sdp_next_handle();
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(NULL, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
+ svclass_id = sdp_list_append(NULL, &sp_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
+ profile.version = 0x0100;
+ profiles = sdp_list_append(NULL, &profile);
+ sdp_set_profile_descs(record, profiles);
+
+ sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+ proto[0] = sdp_list_append(NULL, &rfcomm);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[0] = sdp_list_append(proto[0], channel);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_add_lang_attr(record);
+
+ sdp_set_info_attr(record, "Serial Port", "BlueZ", "COM Port");
+
+ sdp_set_url_attr(record, "http://www.bluez.org/",
+ "http://www.bluez.org/", "http://www.bluez.org/");
+
+ sdp_set_service_id(record, sp_uuid);
+ sdp_set_service_ttl(record, 0xffff);
+ sdp_set_service_avail(record, 0xff);
+ sdp_set_record_state(record, 0x00001234);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], NULL);
+ sdp_list_free(apseq, NULL);
sdp_list_free(aproto, NULL);
+ sdp_list_free(root, NULL);
+ sdp_list_free(svclass_id, NULL);
+ sdp_list_free(profiles, NULL);

return record;
}
@@ -278,7 +338,9 @@ static struct profile_info {
0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = SPP_DEFAULT_CHANNEL
+ .channel = SPP_DEFAULT_CHANNEL,
+ .svc_hint = 0,
+ .create_record = create_spp_record
},
};

--
1.7.10.4


2013-11-20 10:24:32

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 14/19] android/socket: Close file descriptor after sending

From: Andrei Emeltchenko <[email protected]>

---
android/socket.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index d8e922d..5862c9c 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -613,6 +613,7 @@ void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
break;

ipc_send(sk, HAL_SERVICE_ID_SOCK, opcode, 0, NULL, fd);
+ close(fd);
return;
case HAL_OP_SOCK_CONNECT:
fd = handle_connect(buf);
@@ -620,6 +621,7 @@ void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
break;

ipc_send(sk, HAL_SERVICE_ID_SOCK, opcode, 0, NULL, fd);
+ close(fd);
return;
default:
DBG("Unhandled command, opcode 0x%x", opcode);
--
1.7.10.4


2013-11-20 10:24:27

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 09/19] android/socket: Implement socket connect HAL method

From: Andrei Emeltchenko <[email protected]>

First step is to query remote device for RFCOMM channel.
---
android/socket.c | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 90561dc..1815367 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -33,6 +33,9 @@
#include "lib/bluetooth.h"
#include "btio/btio.h"
#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "src/sdp-client.h"
+
#include "log.h"
#include "hal-msg.h"
#include "hal-ipc.h"
@@ -58,6 +61,8 @@ struct rfcomm_sock {

guint rfcomm_watch;
guint stack_watch;
+
+ bdaddr_t dst;
};

static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
@@ -419,11 +424,37 @@ static int handle_listen(void *buf)
return hal_fd;
}

+static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ DBG("");
+}
+
static int handle_connect(void *buf)
{
- DBG("Not implemented");
+ struct hal_cmd_sock_connect *cmd = buf;
+ struct rfcomm_sock *rfsock;
+ bdaddr_t dst;
+ uuid_t uuid;
+ int hal_fd = -1;

- return -1;
+ DBG("");
+
+ android2bdaddr(cmd->bdaddr, &dst);
+ rfsock = create_rfsock(-1, &hal_fd);
+ bacpy(&rfsock->dst, &dst);
+
+ memset(&uuid, 0, sizeof(uuid));
+ uuid.type = SDP_UUID128;
+ memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
+
+ if (bt_search_service(&adapter_addr, &dst, &uuid, sdp_search_cb, rfsock,
+ NULL) < 0) {
+ error("Failed to search SDP records");
+ cleanup_rfsock(rfsock);
+ return -1;
+ }
+
+ return hal_fd;
}

void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
--
1.7.10.4


2013-11-20 10:24:30

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 12/19] android/socket: Send RFCOMM channel to framework

From: Andrei Emeltchenko <[email protected]>

Framework expects channel to be send.
---
android/socket.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index e188c3f..1d16bc7 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -530,6 +530,11 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
goto fail;
}

+ if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ error("Error sending RFCOMM channel");
+ goto fail;
+ }
+
rfsock->real_sock = g_io_channel_unix_get_fd(io);
rfsock->channel = chan;
connections = g_list_append(connections, rfsock);
--
1.7.10.4


2013-11-20 10:24:25

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 07/19] android/socket: Send accept signal to Android framework

From: Andrei Emeltchenko <[email protected]>

Android expects to get accept signal over file descriptor which was
set during listen HAL call.
---
android/socket.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 3e738a4..5901d45 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -37,6 +37,7 @@
#include "hal-msg.h"
#include "hal-ipc.h"
#include "ipc.h"
+#include "utils.h"
#include "socket.h"

#define OPP_DEFAULT_CHANNEL 9
@@ -121,6 +122,45 @@ static struct profile_info {
}
};

+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 struct profile_info *get_profile_by_uuid(const uint8_t *uuid)
{
unsigned int i;
@@ -240,6 +280,28 @@ fail:
return FALSE;
}

+static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
+ int fd_accepted)
+{
+ struct hal_sock_connect_signal cmd;
+ int len;
+
+ DBG("");
+
+ cmd.size = sizeof(cmd);
+ bdaddr2android(bdaddr, cmd.bdaddr);
+ cmd.channel = rfsock->channel;
+ cmd.status = 0;
+
+ len = bt_sock_send_fd(rfsock->fd, &cmd, sizeof(cmd), fd_accepted);
+ if (len != sizeof(cmd)) {
+ error("Error sending accept signal");
+ return false;
+ }
+
+ return true;
+}
+
static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
@@ -279,6 +341,11 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
rfsock->fd, rfsock->real_sock, rfsock->channel,
sock_acc);

+ if (!sock_send_accept(rfsock, &dst, hal_fd)) {
+ cleanup_rfsock(rfsock_acc);
+ return;
+ }
+
/* Handle events from Android */
cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
io_stack = g_io_channel_unix_new(rfsock_acc->fd);
--
1.7.10.4


2013-11-20 10:24:28

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 10/19] android/socket: Parse SDP response and connect

From: Andrei Emeltchenko <[email protected]>

Parse SDP response, find RFCOMM channel and connect.
---
android/socket.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 1815367..a5b28b7 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -424,9 +424,72 @@ static int handle_listen(void *buf)
return hal_fd;
}

+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+}
+
static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
{
+ struct rfcomm_sock *rfsock = data;
+ GError *gerr = NULL;
+ sdp_list_t *list;
+ GIOChannel *io;
+ int chan;
+
DBG("");
+
+ if (err < 0) {
+ error("Unable to get SDP record: %s", strerror(-err));
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error("No SDP records found");
+ goto fail;
+ }
+
+ for (list = recs; list != NULL; list = list->next) {
+ sdp_record_t *rec = list->data;
+ sdp_list_t *protos;
+
+ if (sdp_get_access_protos(rec, &protos) < 0) {
+ error("Unable to get proto list");
+ goto fail;
+ }
+
+ chan = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
+ NULL);
+ sdp_list_free(protos, NULL);
+ }
+
+ if (chan <= 0) {
+ error("Could not get RFCOMM channel %d", chan);
+ goto fail;
+ }
+
+ DBG("Got RFCOMM channel %d", chan);
+
+ io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
+ BT_IO_OPT_CHANNEL, chan,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("Failed connect: %s", gerr->message);
+ g_error_free(gerr);
+ goto fail;
+ }
+
+ rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock->channel = chan;
+ connections = g_list_append(connections, rfsock);
+ return;
+
+fail:
+ cleanup_rfsock(rfsock);
}

static int handle_connect(void *buf)
--
1.7.10.4


2013-11-20 10:24:23

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 05/19] android/socket: Implement Android RFCOMM stack events

From: Andrei Emeltchenko <[email protected]>

Handle events from Android framework. Write everything to real RFCOMM
socket. Consider splice() in the future.
---
android/socket.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 48afd4b..49b7413 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -133,10 +133,69 @@ static struct profile_info *get_profile_by_uuid(const uint8_t *uuid)
return NULL;
}

+static int try_write_all(int fd, unsigned char *buf, int len)
+{
+ int sent = 0;
+
+ while (len > 0) {
+ int written;
+
+ written = write(fd, buf, len);
+ if (written < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+
+ if (!written)
+ return 0;
+
+ len -= written; buf += written; sent += written;
+ }
+
+ return sent;
+}
+
static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
+ struct rfcomm_sock *rfsock = data;
+ unsigned char buf[1024];
+ int len, sent;
+
+ DBG("rfsock: fd %d real_sock %d chan %u sock %d",
+ rfsock->fd, rfsock->real_sock, rfsock->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);
+ goto fail;
+ }
+
+ len = read(rfsock->fd, buf, sizeof(buf));
+ if (len <= 0) {
+ error("read(): %s", strerror(errno));
+ /* Read again */
+ return TRUE;
+ }
+
+ DBG("read %d bytes write to %d", len, rfsock->real_sock);
+
+ sent = try_write_all(rfsock->real_sock, buf, len);
+ if (sent < 0) {
+ error("write(): %s", strerror(errno));
+ goto fail;
+ }
+
+ DBG("Written %d bytes", sent);
+
return TRUE;
+fail:
+ connections = g_list_remove(connections, rfsock);
+ cleanup_rfsock(rfsock);
+
+ return FALSE;
}

static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
--
1.7.10.4


2013-11-20 10:24:19

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 01/19] android/socket: Add get RFCOMM default channel

From: Andrei Emeltchenko <[email protected]>

RFCOMM default channel is the same like in other BlueZ code, it is
defined in src/profile.c
---
android/socket.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 04bb7d1..d4c7674 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -27,19 +27,71 @@

#include <glib.h>
#include <stdbool.h>
+#include <errno.h>

#include "lib/bluetooth.h"
+#include "btio/btio.h"
+#include "lib/sdp.h"
#include "log.h"
#include "hal-msg.h"
#include "hal-ipc.h"
#include "ipc.h"
#include "socket.h"

+#define OPP_DEFAULT_CHANNEL 9
+#define PBAP_DEFAULT_CHANNEL 15
+
static bdaddr_t adapter_addr;

+static struct profile_info {
+ uint8_t uuid[16];
+ uint8_t channel;
+ uint8_t svc_hint;
+ BtIOSecLevel sec_level;
+ sdp_record_t * (*create_record)(uint8_t chan);
+} profiles[] = {
+ {
+ .uuid = {
+ 0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ },
+ .channel = PBAP_DEFAULT_CHANNEL
+ }, {
+ .uuid = {
+ 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ },
+ .channel = OPP_DEFAULT_CHANNEL
+ }
+};
+
+static struct profile_info *get_profile_by_uuid(const uint8_t *uuid)
+{
+ unsigned int i;
+
+ for (i = 0; i < G_N_ELEMENTS(profiles); i++) {
+ if (!memcmp(profiles[i].uuid, uuid, 16))
+ return &profiles[i];
+ }
+
+ return NULL;
+}
+
static int handle_listen(void *buf)
{
- DBG("Not implemented");
+ struct hal_cmd_sock_listen *cmd = buf;
+ struct profile_info *profile;
+ int chan;
+
+ DBG("");
+
+ profile = get_profile_by_uuid(cmd->uuid);
+ if (!profile)
+ return -1;
+
+ chan = profile->channel;
+
+ DBG("rfcomm channel %d", chan);

return -1;
}
--
1.7.10.4


2013-11-20 10:24:26

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 08/19] android/socket: Notify channel to Android framework

From: Andrei Emeltchenko <[email protected]>

Android framework expects to receive channel number as int.
---
android/socket.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 5901d45..90561dc 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -410,6 +410,12 @@ static int handle_listen(void *buf)
DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
hal_fd);

+ if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ error("Error sending RFCOMM channel");
+ cleanup_rfsock(rfsock);
+ return -1;
+ }
+
return hal_fd;
}

--
1.7.10.4


2013-11-20 10:24:22

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 04/19] android/socket: Implement socket accepted event

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 | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index b8d96f9..48afd4b 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -133,8 +133,74 @@ static struct profile_info *get_profile_by_uuid(const uint8_t *uuid)
return NULL;
}

+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 accept_cb(GIOChannel *io, GError *err, gpointer user_data)
{
+ struct rfcomm_sock *rfsock = user_data;
+ struct rfcomm_sock *rfsock_acc;
+ GIOChannel *io_stack;
+ GError *gerr = NULL;
+ bdaddr_t dst;
+ char address[18];
+ int sock_acc;
+ int hal_fd;
+ guint id;
+ GIOCondition cond;
+
+ if (err) {
+ error("%s", err->message);
+ return;
+ }
+
+ bt_io_get(io, &gerr,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ return;
+ }
+
+ ba2str(&dst, address);
+ DBG("Incoming connection from %s rfsock %p", address, rfsock);
+
+ sock_acc = g_io_channel_unix_get_fd(io);
+ rfsock_acc = create_rfsock(sock_acc, &hal_fd);
+ connections = g_list_append(connections, rfsock_acc);
+
+ DBG("rfsock: fd %d real_sock %d chan %u sock %d",
+ rfsock->fd, rfsock->real_sock, rfsock->channel,
+ sock_acc);
+
+ /* Handle events from Android */
+ cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+ io_stack = g_io_channel_unix_new(rfsock_acc->fd);
+ id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock_acc);
+ g_io_channel_unref(io_stack);
+
+ rfsock_acc->stack_watch = id;
+
+ /* Handle rfcomm events */
+ cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+ id = g_io_add_watch(io, cond, sock_rfcomm_event_cb, rfsock_acc);
+
+ rfsock_acc->rfcomm_watch = id;
+
+ DBG("rfsock %p rfsock_acc %p stack_watch %d rfcomm_watch %d",
+ rfsock, rfsock_acc, rfsock_acc->stack_watch,
+ rfsock_acc->rfcomm_watch);
}

static int handle_listen(void *buf)
--
1.7.10.4


2013-11-20 10:24:24

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv6 06/19] android/socket: Implement RFCOMM events

From: Andrei Emeltchenko <[email protected]>

Copy data from RFCOMM socket to Android framework. Consider splice
in the future.
---
android/socket.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 49b7413..3e738a4 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -201,7 +201,43 @@ fail:
static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
+ struct rfcomm_sock *rfsock = data;
+ unsigned char buf[1024];
+ int len, sent;
+
+ DBG("rfsock: fd %d real_sock %d chan %u sock %d",
+ rfsock->fd, rfsock->real_sock, rfsock->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);
+ goto fail;
+ }
+
+ len = read(rfsock->real_sock, buf, sizeof(buf));
+ if (len <= 0) {
+ error("read(): %s", strerror(errno));
+ /* Read again */
+ return TRUE;
+ }
+
+ DBG("read %d bytes, write to fd %d", len, rfsock->fd);
+
+ sent = try_write_all(rfsock->fd, buf, len);
+ if (sent < 0) {
+ error("write(): %s", strerror(errno));
+ goto fail;
+ }
+
+ DBG("Written %d bytes", sent);
+
return TRUE;
+fail:
+ connections = g_list_remove(connections, rfsock);
+ cleanup_rfsock(rfsock);
+
+ return FALSE;
}

static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
--
1.7.10.4