diff options
author | Nick Pelly <npelly@google.com> | 2009-05-11 14:22:20 -0700 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2009-05-11 14:24:41 -0700 |
commit | b88063b946e2c8f349e69c7db0a631088f991fc4 (patch) | |
tree | 4352f4f56c8d4e4867b3d0a10ef1bb507892bbde /bluedroid | |
parent | 565816179ce7b754db55a2ab3e9ef877dca2f69b (diff) | |
download | bluetooth-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.mk | 17 | ||||
-rw-r--r-- | bluedroid/socktest.c | 394 |
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; +} |