From: Andrei Emeltchenko <[email protected]>
Since Android calls allows directly connect to specified channel numbers
refactor code which makes connect to function and reuse it from both
places. This allows to test connect without parsing SDP.
Andrei Emeltchenko (3):
android/socket: Refactor connect to allow directly connect to rfcomm
android/socket: Connect directly to RFCOMM chan is uuid is zero
android/tester: Test that connect call returns channel number
android/android-tester.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
android/socket.c | 103 ++++++++++++++++++++++++-----------------
2 files changed, 179 insertions(+), 41 deletions(-)
--
1.8.3.2
Hi Andrei,
On Thu, Dec 19, 2013, Andrei Emeltchenko wrote:
> Since Socket HAL allows us to specify RFCOMM channel number and directly
> connect refactor send function to allow connect directly is uuid is zero
> and channel number is specified.
> ---
> android/socket.c | 71 +++++++++++++++++++++++++++++++-------------------------
> 1 file changed, 39 insertions(+), 32 deletions(-)
All three patches have been applied. Thanks.
Johan
From: Andrei Emeltchenko <[email protected]>
Since Socket HAL allows us to specify RFCOMM channel number and directly
connect refactor send function to allow connect directly is uuid is zero
and channel number is specified.
---
android/socket.c | 71 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 39 insertions(+), 32 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index cee4b6e..656222e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -838,13 +838,47 @@ fail:
cleanup_rfsock(rfsock);
}
-static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+static bool do_connect(struct rfcomm_sock *rfsock, int chan)
{
- struct rfcomm_sock *rfsock = data;
BtIOSecLevel sec_level = BT_IO_SEC_MEDIUM;
+ GIOChannel *io;
GError *gerr = NULL;
+
+ if (rfsock->profile)
+ sec_level = rfsock->profile->sec_level;
+
+ 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, sec_level,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("Failed connect: %s", gerr->message);
+ g_error_free(gerr);
+ return false;
+ }
+
+ g_io_channel_set_close_on_unref(io, FALSE);
+ g_io_channel_unref(io);
+
+ if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ error("Error sending RFCOMM channel");
+ return false;
+ }
+
+ rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock_set_buffer(rfsock);
+ rfsock->channel = chan;
+ connections = g_list_append(connections, rfsock);
+
+ return true;
+}
+
+static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ struct rfcomm_sock *rfsock = data;
sdp_list_t *list;
- GIOChannel *io;
int chan;
DBG("");
@@ -885,36 +919,9 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
DBG("Got RFCOMM channel %d", chan);
- if (rfsock->profile)
- sec_level = rfsock->profile->sec_level;
-
- 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, sec_level,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("Failed connect: %s", gerr->message);
- g_error_free(gerr);
- 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_set_buffer(rfsock);
- rfsock->channel = chan;
- connections = g_list_append(connections, rfsock);
-
- g_io_channel_unref(io);
-
- return;
+ if (do_connect(rfsock, chan))
+ return;
fail:
- connections = g_list_remove(connections, rfsock);
cleanup_rfsock(rfsock);
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Check uuid and connect to specified RFCOMM channel directly if uuid is
zeroed.
---
android/socket.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 656222e..94a44fc 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -929,6 +929,7 @@ static void handle_connect(const void *buf, uint16_t len)
{
const struct hal_cmd_sock_connect *cmd = buf;
struct rfcomm_sock *rfsock;
+ static uint8_t zero_uuid[16];
uuid_t uuid;
int hal_fd = -1;
@@ -940,17 +941,21 @@ static void handle_connect(const void *buf, uint16_t len)
android2bdaddr(cmd->bdaddr, &rfsock->dst);
- memset(&uuid, 0, sizeof(uuid));
- uuid.type = SDP_UUID128;
- memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
+ if (!memcmp(cmd->uuid, zero_uuid, sizeof(zero_uuid))) {
+ if (!do_connect(rfsock, cmd->channel))
+ goto failed;
+ } else {
+ memset(&uuid, 0, sizeof(uuid));
+ uuid.type = SDP_UUID128;
+ memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
- rfsock->profile = get_profile_by_uuid(cmd->uuid);
+ rfsock->profile = get_profile_by_uuid(cmd->uuid);
- if (bt_search_service(&adapter_addr, &rfsock->dst, &uuid,
+ if (bt_search_service(&adapter_addr, &rfsock->dst, &uuid,
sdp_search_cb, rfsock, NULL) < 0) {
- error("Failed to search SDP records");
- cleanup_rfsock(rfsock);
- goto failed;
+ error("Failed to search SDP records");
+ goto failed;
+ }
}
ipc_send_rsp_full(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT, 0, NULL,
@@ -962,6 +967,9 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT,
HAL_STATUS_FAILED);
+ if (rfsock)
+ cleanup_rfsock(rfsock);
+
if (hal_fd >= 0)
close(hal_fd);
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
The test connects to emulated bthost and read channel number
---
android/android-tester.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/android/android-tester.c b/android/android-tester.c
index 55fa702..8a2861e 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -1080,6 +1080,27 @@ static void setup_socket_interface(const void *test_data)
tester_setup_complete();
}
+static void setup_socket_interface_enabled(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const void *sock;
+ bt_status_t status;
+
+ setup(data);
+
+ sock = data->if_bluetooth->get_profile_interface(BT_PROFILE_SOCKETS_ID);
+ if (!sock) {
+ tester_setup_failed();
+ return;
+ }
+
+ data->if_sock = sock;
+
+ status = data->if_bluetooth->enable();
+ if (status != BT_STATUS_SUCCESS)
+ tester_setup_failed();
+}
+
static void test_generic_listen(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -1148,6 +1169,97 @@ clean:
close(sock_fd);
}
+static gboolean socket_chan_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ int sock_fd = g_io_channel_unix_get_fd(io);
+ struct test_data *data = tester_get_data();
+ const struct socket_data *test = data->test_data;
+ int channel, len;
+
+ tester_print("%s", __func__);
+
+ if (cond & G_IO_HUP) {
+ tester_warn("Socket %d hang up", sock_fd);
+ goto failed;
+ }
+
+ if (cond & (G_IO_ERR | G_IO_NVAL)) {
+ tester_warn("Socket error: sock %d cond %d", sock_fd, cond);
+ goto failed;
+ }
+
+ if (test->test_channel) {
+ len = read(sock_fd, &channel, sizeof(channel));
+ if (len != sizeof(channel) || channel != test->channel)
+ goto failed;
+
+ tester_print("read correct channel: %d", channel);
+ tester_test_passed();
+ return FALSE;
+ }
+
+failed:
+ tester_test_failed();
+ return FALSE;
+}
+
+static void test_socket_real_connect(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct socket_data *test = data->test_data;
+ struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+ const uint8_t *client_bdaddr;
+ bt_bdaddr_t emu_bdaddr;
+ bt_status_t status;
+ int sock_fd = -1;
+
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+ if (!client_bdaddr) {
+ tester_warn("No client bdaddr");
+ tester_test_failed();
+ return;
+ }
+
+ bdaddr2android((bdaddr_t *) client_bdaddr, &emu_bdaddr);
+
+ bthost_set_server_psm(bthost, 0x0003);
+
+ status = data->if_sock->connect(&emu_bdaddr, test->sock_type,
+ test->service_uuid, test->channel,
+ &sock_fd, test->flags);
+ if (status != test->expected_status) {
+ tester_test_failed();
+ goto clean;
+ }
+
+ /* Check that file descriptor is valid */
+ if (status == BT_STATUS_SUCCESS && fcntl(sock_fd, F_GETFD) == -1) {
+ tester_test_failed();
+ return;
+ }
+
+ tester_print("status %d sock_fd %d", status, sock_fd);
+
+ if (status == BT_STATUS_SUCCESS) {
+ GIOChannel *io;
+
+ io = g_io_channel_unix_new(sock_fd);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ socket_chan_cb, NULL);
+
+ g_io_channel_unref(io);
+ }
+
+ return;
+
+clean:
+ if (sock_fd >= 0)
+ close(sock_fd);
+}
+
#define test_bredrle(name, data, test_setup, test, test_teardown) \
do { \
struct test_data *user; \
@@ -1267,5 +1379,10 @@ int main(int argc, char *argv[])
&btsock_inv_param_bdaddr,
setup_socket_interface, test_generic_connect, teardown);
+ test_bredrle("Socket Connect - Check returned chan",
+ &btsock_success_check_chan,
+ setup_socket_interface_enabled,
+ test_socket_real_connect, teardown);
+
return tester_run();
}
--
1.8.3.2
Hi Andrei,
On Wed, Dec 18, 2013, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> Check uuid and connect to specified channel number directly.
> ---
> android/socket.c | 32 +++++++++++++++++++++++---------
> 1 file changed, 23 insertions(+), 9 deletions(-)
Please fix the commit message: capital UUID, s/is/if/ and
s/chan/channel/ in the subject.
> +static bool is_empty(const uint8_t *uuid)
> +{
> + static uint8_t zero_uuid[16];
> +
> + return memcmp(uuid, zero_uuid, sizeof(zero_uuid)) == 0;
> +}
> +
> static void handle_connect(const void *buf, uint16_t len)
> {
> const struct hal_cmd_sock_connect *cmd = buf;
> - struct rfcomm_sock *rfsock;
> + struct rfcomm_sock *rfsock = NULL;
Firstly this rfsock = NULL seems completely unrelated to this patch, and
secondly it's not even needed. Please remove it.
> uuid_t uuid;
> int hal_fd = -1;
>
> @@ -940,17 +947,21 @@ static void handle_connect(const void *buf, uint16_t len)
>
> android2bdaddr(cmd->bdaddr, &rfsock->dst);
>
> - memset(&uuid, 0, sizeof(uuid));
> - uuid.type = SDP_UUID128;
> - memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
> + if (is_empty(cmd->uuid)) {
> + if (!do_connect(rfsock, cmd->channel))
> + goto failed;
If this is_empty function was really needed it should at least be called
uuid_is_empty to make it clear what it's for. However, since it's a
one-line function and you've only got a single place needing it, I'd
just declare a static const uint8_t zero_uuuid[16] in handle_connect()
and do the memcmp directly there.
Johan
From: Andrei Emeltchenko <[email protected]>
Check uuid and connect to specified channel number directly.
---
android/socket.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 656222e..7bc5b0b 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -925,10 +925,17 @@ fail:
cleanup_rfsock(rfsock);
}
+static bool is_empty(const uint8_t *uuid)
+{
+ static uint8_t zero_uuid[16];
+
+ return memcmp(uuid, zero_uuid, sizeof(zero_uuid)) == 0;
+}
+
static void handle_connect(const void *buf, uint16_t len)
{
const struct hal_cmd_sock_connect *cmd = buf;
- struct rfcomm_sock *rfsock;
+ struct rfcomm_sock *rfsock = NULL;
uuid_t uuid;
int hal_fd = -1;
@@ -940,17 +947,21 @@ static void handle_connect(const void *buf, uint16_t len)
android2bdaddr(cmd->bdaddr, &rfsock->dst);
- memset(&uuid, 0, sizeof(uuid));
- uuid.type = SDP_UUID128;
- memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
+ if (is_empty(cmd->uuid)) {
+ if (!do_connect(rfsock, cmd->channel))
+ goto failed;
+ } else {
+ memset(&uuid, 0, sizeof(uuid));
+ uuid.type = SDP_UUID128;
+ memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
- rfsock->profile = get_profile_by_uuid(cmd->uuid);
+ rfsock->profile = get_profile_by_uuid(cmd->uuid);
- if (bt_search_service(&adapter_addr, &rfsock->dst, &uuid,
+ if (bt_search_service(&adapter_addr, &rfsock->dst, &uuid,
sdp_search_cb, rfsock, NULL) < 0) {
- error("Failed to search SDP records");
- cleanup_rfsock(rfsock);
- goto failed;
+ error("Failed to search SDP records");
+ goto failed;
+ }
}
ipc_send_rsp_full(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT, 0, NULL,
@@ -962,6 +973,9 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT,
HAL_STATUS_FAILED);
+ if (rfsock)
+ cleanup_rfsock(rfsock);
+
if (hal_fd >= 0)
close(hal_fd);
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Since Socket HAL allows us to specify RFCOMM channel number and directly
connect refactor send function to allow connect directly is uuid is zero
and channel number is specified.
---
android/socket.c | 71 +++++++++++++++++++++++++++++++-------------------------
1 file changed, 39 insertions(+), 32 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index cee4b6e..656222e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -838,13 +838,47 @@ fail:
cleanup_rfsock(rfsock);
}
-static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+static bool do_connect(struct rfcomm_sock *rfsock, int chan)
{
- struct rfcomm_sock *rfsock = data;
BtIOSecLevel sec_level = BT_IO_SEC_MEDIUM;
+ GIOChannel *io;
GError *gerr = NULL;
+
+ if (rfsock->profile)
+ sec_level = rfsock->profile->sec_level;
+
+ 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, sec_level,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("Failed connect: %s", gerr->message);
+ g_error_free(gerr);
+ return false;
+ }
+
+ g_io_channel_set_close_on_unref(io, FALSE);
+ g_io_channel_unref(io);
+
+ if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ error("Error sending RFCOMM channel");
+ return false;
+ }
+
+ rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock_set_buffer(rfsock);
+ rfsock->channel = chan;
+ connections = g_list_append(connections, rfsock);
+
+ return true;
+}
+
+static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ struct rfcomm_sock *rfsock = data;
sdp_list_t *list;
- GIOChannel *io;
int chan;
DBG("");
@@ -885,36 +919,9 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
DBG("Got RFCOMM channel %d", chan);
- if (rfsock->profile)
- sec_level = rfsock->profile->sec_level;
-
- 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, sec_level,
- BT_IO_OPT_INVALID);
- if (!io) {
- error("Failed connect: %s", gerr->message);
- g_error_free(gerr);
- 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_set_buffer(rfsock);
- rfsock->channel = chan;
- connections = g_list_append(connections, rfsock);
-
- g_io_channel_unref(io);
-
- return;
+ if (do_connect(rfsock, chan))
+ return;
fail:
- connections = g_list_remove(connections, rfsock);
cleanup_rfsock(rfsock);
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
The test connects to emulated bthost and read channel number
---
android/android-tester.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/android/android-tester.c b/android/android-tester.c
index 55fa702..8a2861e 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -1080,6 +1080,27 @@ static void setup_socket_interface(const void *test_data)
tester_setup_complete();
}
+static void setup_socket_interface_enabled(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const void *sock;
+ bt_status_t status;
+
+ setup(data);
+
+ sock = data->if_bluetooth->get_profile_interface(BT_PROFILE_SOCKETS_ID);
+ if (!sock) {
+ tester_setup_failed();
+ return;
+ }
+
+ data->if_sock = sock;
+
+ status = data->if_bluetooth->enable();
+ if (status != BT_STATUS_SUCCESS)
+ tester_setup_failed();
+}
+
static void test_generic_listen(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -1148,6 +1169,97 @@ clean:
close(sock_fd);
}
+static gboolean socket_chan_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ int sock_fd = g_io_channel_unix_get_fd(io);
+ struct test_data *data = tester_get_data();
+ const struct socket_data *test = data->test_data;
+ int channel, len;
+
+ tester_print("%s", __func__);
+
+ if (cond & G_IO_HUP) {
+ tester_warn("Socket %d hang up", sock_fd);
+ goto failed;
+ }
+
+ if (cond & (G_IO_ERR | G_IO_NVAL)) {
+ tester_warn("Socket error: sock %d cond %d", sock_fd, cond);
+ goto failed;
+ }
+
+ if (test->test_channel) {
+ len = read(sock_fd, &channel, sizeof(channel));
+ if (len != sizeof(channel) || channel != test->channel)
+ goto failed;
+
+ tester_print("read correct channel: %d", channel);
+ tester_test_passed();
+ return FALSE;
+ }
+
+failed:
+ tester_test_failed();
+ return FALSE;
+}
+
+static void test_socket_real_connect(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct socket_data *test = data->test_data;
+ struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+ const uint8_t *client_bdaddr;
+ bt_bdaddr_t emu_bdaddr;
+ bt_status_t status;
+ int sock_fd = -1;
+
+ client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+ if (!client_bdaddr) {
+ tester_warn("No client bdaddr");
+ tester_test_failed();
+ return;
+ }
+
+ bdaddr2android((bdaddr_t *) client_bdaddr, &emu_bdaddr);
+
+ bthost_set_server_psm(bthost, 0x0003);
+
+ status = data->if_sock->connect(&emu_bdaddr, test->sock_type,
+ test->service_uuid, test->channel,
+ &sock_fd, test->flags);
+ if (status != test->expected_status) {
+ tester_test_failed();
+ goto clean;
+ }
+
+ /* Check that file descriptor is valid */
+ if (status == BT_STATUS_SUCCESS && fcntl(sock_fd, F_GETFD) == -1) {
+ tester_test_failed();
+ return;
+ }
+
+ tester_print("status %d sock_fd %d", status, sock_fd);
+
+ if (status == BT_STATUS_SUCCESS) {
+ GIOChannel *io;
+
+ io = g_io_channel_unix_new(sock_fd);
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ socket_chan_cb, NULL);
+
+ g_io_channel_unref(io);
+ }
+
+ return;
+
+clean:
+ if (sock_fd >= 0)
+ close(sock_fd);
+}
+
#define test_bredrle(name, data, test_setup, test, test_teardown) \
do { \
struct test_data *user; \
@@ -1267,5 +1379,10 @@ int main(int argc, char *argv[])
&btsock_inv_param_bdaddr,
setup_socket_interface, test_generic_connect, teardown);
+ test_bredrle("Socket Connect - Check returned chan",
+ &btsock_success_check_chan,
+ setup_socket_interface_enabled,
+ test_socket_real_connect, teardown);
+
return tester_run();
}
--
1.8.3.2