OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / system / bluetooth / tools / sock_shutdown_test.c
diff --git a/system/bluetooth/tools/sock_shutdown_test.c b/system/bluetooth/tools/sock_shutdown_test.c
new file mode 100644 (file)
index 0000000..29f6b59
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+** 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.
+*/
+
+/** testing behavior of shutdown() */
+
+#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/poll.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;
+    int delay;
+};
+
+struct sockaddr_un  local_addr_un  = {AF_UNIX, "/tmp/foo"};
+struct sockaddr_rc  local_addr_rc  = {AF_BLUETOOTH, *BDADDR_ANY, 4};
+struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
+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 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 _shutdown(int fd, int how) {
+    int ret;
+
+    printf("%d: shutdown(%d)\n", gettid(), fd);
+    ret = shutdown(fd, how);
+    printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret);
+    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
+
+    return ret;
+}
+
+static void thread_accept(struct thread_args *args) {
+    printf("%d: START\n", gettid());
+    sleep(args->delay);
+    _accept(args->fd, args->type);
+    printf("%d: END\n", gettid());
+}
+
+static int do_accept_shutdown(int type) {
+    int fd;
+    pthread_t thread;
+    struct thread_args args = {-1, type, 0};
+
+    fd = _socket(type);
+    if (fd < 0) goto error;
+
+    if (_bind(fd, type) < 0) goto error;
+
+    if (_listen(fd, type) < 0) goto error;
+
+    args.fd = fd;
+    pthread_create(&thread, NULL, (void *)thread_accept, (void *)&args);
+
+    sleep(2);
+    _shutdown(fd, SHUT_RDWR);
+
+    pthread_join(thread, NULL);
+
+    _close(fd);
+
+    return 0;
+
+error:
+    return -1;
+}
+
+struct {
+    char *name;
+    int (*ptr)(int);
+} action_table[]  = {
+    {"accept_shutdown", do_accept_shutdown},
+    {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("sock_shutdown_test 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;
+}