summaryrefslogtreecommitdiff
path: root/bluedroid
diff options
context:
space:
mode:
authorNick Pelly <npelly@google.com>2009-05-11 14:22:20 -0700
committerNick Pelly <npelly@google.com>2009-05-11 14:24:41 -0700
commitb88063b946e2c8f349e69c7db0a631088f991fc4 (patch)
tree4352f4f56c8d4e4867b3d0a10ef1bb507892bbde /bluedroid
parent565816179ce7b754db55a2ab3e9ef877dca2f69b (diff)
downloadbluetooth-b88063b946e2c8f349e69c7db0a631088f991fc4.tar.gz
Add utility for testing native code sockets.
Signed-off-by: Nick Pelly <npelly@google.com>
Diffstat (limited to 'bluedroid')
-rw-r--r--bluedroid/Android.mk17
-rw-r--r--bluedroid/socktest.c394
2 files changed, 411 insertions, 0 deletions
diff --git a/bluedroid/Android.mk b/bluedroid/Android.mk
index b4f8a39..f771f98 100644
--- a/bluedroid/Android.mk
+++ b/bluedroid/Android.mk
@@ -38,3 +38,20 @@ LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := bttest
include $(BUILD_EXECUTABLE)
+
+#
+# socktest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := socktest.c
+
+LOCAL_C_INCLUDES := \
+ system/bluetooth/bluez-clean-headers
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := socktest
+
+include $(BUILD_EXECUTABLE)
diff --git a/bluedroid/socktest.c b/bluedroid/socktest.c
new file mode 100644
index 0000000..1c22c68
--- /dev/null
+++ b/bluedroid/socktest.c
@@ -0,0 +1,394 @@
+/*
+** Copyright 2009 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+/** socket testing */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sco.h>
+#include <bluetooth/l2cap.h>
+
+enum sock_type {
+ UNIX = 0,
+ RFCOMM,
+ SCO,
+ L2CAP,
+ TCP,
+};
+
+struct thread_args {
+ int fd;
+ int type;
+};
+
+struct sockaddr_un local_addr_un = {AF_UNIX, "/data/foo"};
+struct sockaddr_rc local_addr_rc = {AF_BLUETOOTH, *BDADDR_ANY, 1};
+struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_ANY};
+struct sockaddr_l2 local_addr_l2 = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
+struct sockaddr_in local_addr_in = {AF_INET, 9999, {0}, {0}};
+
+struct sockaddr_un remote_addr_un ;
+struct sockaddr_rc remote_addr_rc ;
+struct sockaddr_sco remote_addr_sco ;
+struct sockaddr_l2 remote_addr_l2 ;
+struct sockaddr_in remote_addr_in ;
+
+static int _socket(int type) {
+ int ret;
+ int family = -1;
+ int typ = -1;
+ int protocol = -1;
+
+ switch (type) {
+ case UNIX:
+ family = PF_UNIX;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ case RFCOMM:
+ family = PF_BLUETOOTH;
+ typ = SOCK_STREAM;
+ protocol = BTPROTO_RFCOMM;
+ break;
+ case SCO:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_SCO;
+ break;
+ case L2CAP:
+ family = PF_BLUETOOTH;
+ typ = SOCK_SEQPACKET;
+ protocol = BTPROTO_L2CAP;
+ break;
+ case TCP:
+ family = PF_INET;
+ typ = SOCK_STREAM;
+ protocol = 0;
+ break;
+ }
+
+ printf("%d: socket()\n", gettid());
+ ret = socket(family, typ, protocol);
+ printf("%d: socket() = %d\n", gettid(), ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _close(int fd, int type) {
+ int ret;
+
+ printf("%d: close(%d)\n", gettid(), fd);
+ ret = close(fd);
+ printf("%d: close(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _bind(int fd, int type) {
+ int len = 0;
+ int ret;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ unlink(local_addr_un.sun_path);
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%d: bind(%d)\n", gettid(), fd);
+ ret = bind(fd, addr, len);
+ printf("%d: bind(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _listen(int fd, int type) {
+ int ret;
+
+ printf("%d: listen(%d)\n", gettid(), fd);
+ ret = listen(fd, 1);
+ printf("%d: listen(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _accept(int fd, int type) {
+ int ret;
+ int len;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &remote_addr_un;
+ len = sizeof(remote_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &remote_addr_rc;
+ len = sizeof(remote_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &remote_addr_sco;
+ len = sizeof(remote_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &remote_addr_l2;
+ len = sizeof(remote_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &remote_addr_in;
+ len = sizeof(remote_addr_in);
+ break;
+ }
+
+ printf("%d: accept(%d)\n", gettid(), fd);
+ ret = accept(fd, addr, &len);
+ printf("%d: accept(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+ else {
+ printf("\tlen = %d\n", len);
+ }
+
+ return ret;
+}
+
+static int _connect(int fd, int type) {
+ int ret;
+ int len;
+ struct sockaddr *addr = NULL;
+
+ switch (type) {
+ case UNIX:
+ addr = (struct sockaddr *) &local_addr_un;
+ len = sizeof(local_addr_un);
+ break;
+ case RFCOMM:
+ addr = (struct sockaddr *) &local_addr_rc;
+ len = sizeof(local_addr_rc);
+ break;
+ case SCO:
+ addr = (struct sockaddr *) &local_addr_sco;
+ len = sizeof(local_addr_sco);
+ break;
+ case L2CAP:
+ addr = (struct sockaddr *) &local_addr_l2;
+ len = sizeof(local_addr_l2);
+ break;
+ case TCP:
+ addr = (struct sockaddr *) &local_addr_in;
+ len = sizeof(local_addr_in);
+ break;
+ }
+
+ printf("%d: connect(%d)\n", gettid(), fd);
+ ret = connect(fd, addr, len);
+ printf("%d: connect(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static int _write(int fd, int type) {
+ int ret;
+ char buf = 0;
+
+ printf("%d: write(%d)\n", gettid(), fd);
+ ret = write(fd, &buf, 1);
+ printf("%d: connect(%d) = %d\n", gettid(), fd, ret);
+ if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+ return ret;
+}
+
+static void thread_delay_close(void *args) {
+ int fd = ((struct thread_args *)args)->fd;
+ int type = ((struct thread_args *)args)->type;
+ free(args);
+
+ printf("%d: START\n", gettid());
+ sleep(1);
+ _close(fd, type);
+ printf("%d: END\n", gettid());
+}
+
+static void thread_delay_close_write(void *args) {
+ int fd = ((struct thread_args *)args)->fd;
+ int type = ((struct thread_args *)args)->type;
+ free(args);
+
+ printf("%d: START\n", gettid());
+ sleep(1);
+ _close(fd, type);
+ sleep(1);
+ _write(fd, type);
+ printf("%d: END\n", gettid());
+}
+
+static int do_accept_and_close(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args *args;
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args = malloc(sizeof(struct thread_args));
+ args->fd = fd;
+ args->type = type;
+ pthread_create(&thread, NULL, (void *)thread_delay_close, args);
+
+ _accept(fd, type);
+
+ pthread_join(thread, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+// accept in one thread. close then write in another
+static int do_accept_close_write(int type) {
+ int fd;
+ pthread_t thread;
+ struct thread_args *args;
+
+ fd = _socket(type);
+ if (fd < 0) goto error;
+
+ if (_bind(fd, type) < 0) goto error;
+
+ if (_listen(fd, type) < 0) goto error;
+
+ args = malloc(sizeof(struct thread_args));
+ args->fd = fd;
+ args->type = type;
+ pthread_create(&thread, NULL, (void *)thread_delay_close_write, args);
+
+ _accept(fd, type);
+
+ pthread_join(thread, NULL);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+struct {
+ char *name;
+ int (*ptr)(int);
+} action_table[] = {
+ {"accept_and_close", do_accept_and_close},
+ {"accept_close_write", do_accept_close_write},
+ {NULL, NULL},
+};
+
+struct {
+ char *name;
+ enum sock_type type;
+} type_table[] = {
+ {"unix", UNIX},
+ {"rfcomm", RFCOMM},
+ {"sco", SCO},
+ {"l2cap", L2CAP},
+ {"tcp", TCP},
+ {NULL, -1},
+};
+
+static void usage() {
+ int i;
+
+ printf("socktest TYPE ACTION\n");
+ printf("\nTYPE:\n");
+ for (i = 0; type_table[i].name; i++) {
+ printf("\t%s\n", type_table[i].name);
+ }
+ printf("\nACTION:\n");
+ for (i = 0; action_table[i].name; i++) {
+ printf("\t%s\n", action_table[i].name);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i;
+ int type = -1;
+
+ if (argc != 3) {
+ usage();
+ return -1;
+ }
+ for (i = 0; type_table[i].name; i++) {
+ if (!strcmp(argv[1], type_table[i].name)) {
+ type = type_table[i].type;
+ break;
+ }
+ }
+ if (type == -1) {
+ usage();
+ return -1;
+ }
+ for (i = 0; action_table[i].name; i++) {
+ if (!strcmp(argv[2], action_table[i].name)) {
+ printf("TYPE = %s ACTION = %s\n", type_table[type].name,
+ action_table[i].name);
+ return (*action_table[i].ptr)(type);
+ }
+ }
+ usage();
+ return -1;
+}