Home | History | Annotate | Download | only in tools
      1 /*
      2 ** Copyright 2009 The Android Open Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 /** socket testing  */
     18 
     19 #include <stdlib.h>
     20 #include <stdio.h>
     21 #include <errno.h>
     22 #include <sys/uio.h>
     23 #include <unistd.h>
     24 
     25 #include <fcntl.h>
     26 #include <pthread.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <errno.h>
     30 #include <unistd.h>
     31 #include <sys/socket.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/poll.h>
     34 #include <sys/un.h>
     35 #include <netinet/in.h>
     36 
     37 #include <bluetooth/bluetooth.h>
     38 #include <bluetooth/rfcomm.h>
     39 #include <bluetooth/sco.h>
     40 #include <bluetooth/l2cap.h>
     41 
     42 enum sock_type {
     43     UNIX = 0,
     44     RFCOMM,
     45     SCO,
     46     L2CAP,
     47     TCP,
     48 };
     49 
     50 struct thread_args {
     51     int fd;
     52     int type;
     53     int delay;
     54 };
     55 
     56 struct sockaddr_un  local_addr_un  = {AF_UNIX, "/data/foo"};
     57 struct sockaddr_rc  local_addr_rc  = {AF_BLUETOOTH, *BDADDR_ANY, 4};
     58 struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
     59 struct sockaddr_l2  local_addr_l2  = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
     60 struct sockaddr_in  local_addr_in  = {AF_INET, 9999, {0}, {0}};
     61 
     62 struct sockaddr_un  remote_addr_un  ;
     63 struct sockaddr_rc  remote_addr_rc  ;
     64 struct sockaddr_sco remote_addr_sco ;
     65 struct sockaddr_l2  remote_addr_l2  ;
     66 struct sockaddr_in  remote_addr_in  ;
     67 
     68 static void print_events(int events) {
     69     if (events & POLLIN) printf("POLLIN ");
     70     if (events & POLLPRI) printf("POLLPRI ");
     71     if (events & POLLOUT) printf("POLLOUT ");
     72     if (events & POLLERR) printf("POLLERR ");
     73     if (events & POLLHUP) printf("POLLHUP ");
     74     if (events & POLLNVAL) printf("POLLNVAL ");
     75     printf("\n");
     76 }
     77 
     78 static void print_fds(struct pollfd *ufds, nfds_t nfds) {
     79     unsigned int i;
     80     for (i=0; i<nfds; i++)
     81         printf("%d ", ufds[i].fd);
     82 }
     83 
     84 static int _socket(int type) {
     85     int ret;
     86     int family = -1;
     87     int typ = -1;
     88     int protocol = -1;
     89 
     90     switch (type) {
     91     case UNIX:
     92         family = PF_UNIX;
     93         typ = SOCK_STREAM;
     94         protocol = 0;
     95         break;
     96     case RFCOMM:
     97         family = PF_BLUETOOTH;
     98         typ = SOCK_STREAM;
     99         protocol = BTPROTO_RFCOMM;
    100         break;
    101     case SCO:
    102         family = PF_BLUETOOTH;
    103         typ = SOCK_SEQPACKET;
    104         protocol = BTPROTO_SCO;
    105         break;
    106     case L2CAP:
    107         family = PF_BLUETOOTH;
    108         typ = SOCK_SEQPACKET;
    109         protocol = BTPROTO_L2CAP;
    110         break;
    111     case TCP:
    112         family = PF_INET;
    113         typ = SOCK_STREAM;
    114         protocol = 0;
    115         break;
    116     }
    117 
    118     printf("%ld: socket()\n", pthread_self());
    119     ret = socket(family, typ, protocol);
    120     printf("%ld: socket() = %d\n", pthread_self(), ret);
    121     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    122 
    123     return ret;
    124 }
    125 
    126 static int _close(int fd, int type) {
    127     int ret;
    128 
    129     printf("%ld: close(%d)\n", pthread_self(), fd);
    130     ret = close(fd);
    131     printf("%ld: close(%d) = %d\n", pthread_self(), fd, ret);
    132     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    133 
    134     return ret;
    135 }
    136 
    137 static int _bind(int fd, int type) {
    138     int len = 0;
    139     int ret;
    140     struct sockaddr *addr = NULL;
    141 
    142     switch (type) {
    143     case UNIX:
    144         unlink(local_addr_un.sun_path);
    145         addr = (struct sockaddr *) &local_addr_un;
    146         len = sizeof(local_addr_un);
    147         break;
    148     case RFCOMM:
    149         addr = (struct sockaddr *) &local_addr_rc;
    150         len = sizeof(local_addr_rc);
    151         break;
    152     case SCO:
    153         addr = (struct sockaddr *) &local_addr_sco;
    154         len = sizeof(local_addr_sco);
    155         break;
    156     case L2CAP:
    157         addr = (struct sockaddr *) &local_addr_l2;
    158         len = sizeof(local_addr_l2);
    159         break;
    160     case TCP:
    161         addr = (struct sockaddr *) &local_addr_in;
    162         len = sizeof(local_addr_in);
    163         break;
    164     }
    165 
    166     printf("%ld: bind(%d)\n", pthread_self(), fd);
    167     ret = bind(fd, addr, len);
    168     printf("%ld: bind(%d) = %d\n", pthread_self(), fd, ret);
    169     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    170 
    171     return ret;
    172 }
    173 
    174 static int _listen(int fd, int type) {
    175     int ret;
    176 
    177     printf("%ld: listen(%d)\n", pthread_self(), fd);
    178     ret = listen(fd, 1);
    179     printf("%ld: listen(%d) = %d\n", pthread_self(), fd, ret);
    180     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    181 
    182     return ret;
    183 }
    184 
    185 static int _read(int fd) {
    186     int ret;
    187     char buf;
    188 
    189     printf("%ld: read(%d)\n", pthread_self(), fd);
    190     ret = read(fd, &buf, 1);
    191     printf("%ld: read(%d) = %d [%d]\n", pthread_self(), fd, ret, (int)buf);
    192     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    193 
    194     return ret;
    195 }
    196 
    197 
    198 static int _accept(int fd, int type) {
    199     int ret;
    200     int len;
    201     struct sockaddr *addr = NULL;
    202 
    203     switch (type) {
    204     case UNIX:
    205         addr = (struct sockaddr *) &remote_addr_un;
    206         len = sizeof(remote_addr_un);
    207         break;
    208     case RFCOMM:
    209         addr = (struct sockaddr *) &remote_addr_rc;
    210         len = sizeof(remote_addr_rc);
    211         break;
    212     case SCO:
    213         addr = (struct sockaddr *) &remote_addr_sco;
    214         len = sizeof(remote_addr_sco);
    215         break;
    216     case L2CAP:
    217         addr = (struct sockaddr *) &remote_addr_l2;
    218         len = sizeof(remote_addr_l2);
    219         break;
    220     case TCP:
    221         addr = (struct sockaddr *) &remote_addr_in;
    222         len = sizeof(remote_addr_in);
    223         break;
    224     }
    225 
    226     printf("%ld: accept(%d)\n", pthread_self(), fd);
    227     ret = accept(fd, addr, &len);
    228     printf("%ld: accept(%d) = %d\n", pthread_self(), fd, ret);
    229     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    230     else {
    231         printf("\tlen = %d\n", len);
    232     }
    233 
    234     return ret;
    235 }
    236 
    237 int get_bdaddr(const char *str, bdaddr_t *ba) {
    238     char *d = ((char *)ba) + 5, *endp;
    239     int i;
    240     for(i = 0; i < 6; i++) {
    241         *d-- = strtol(str, &endp, 16);
    242         if (*endp != ':' && i != 5) {
    243             memset(ba, 0, sizeof(bdaddr_t));
    244             return -1;
    245         }
    246         str = endp + 1;
    247     }
    248     return 0;
    249 }
    250 
    251 static int _connect(int fd, int type) {
    252     int ret;
    253     int len = 0;
    254     struct sockaddr *addr = NULL;
    255 
    256     switch (type) {
    257     case UNIX:
    258         addr = (struct sockaddr *) &local_addr_un;
    259         len = sizeof(local_addr_un);
    260         break;
    261     case RFCOMM:
    262         get_bdaddr("00:11:22:33:44:55", &local_addr_rc.rc_bdaddr);
    263         addr = (struct sockaddr *) &local_addr_rc;
    264         len = sizeof(local_addr_rc);
    265         break;
    266     case SCO:
    267         addr = (struct sockaddr *) &local_addr_sco;
    268         len = sizeof(local_addr_sco);
    269         break;
    270     case L2CAP:
    271         addr = (struct sockaddr *) &local_addr_l2;
    272         len = sizeof(local_addr_l2);
    273         break;
    274     case TCP:
    275         addr = (struct sockaddr *) &local_addr_in;
    276         len = sizeof(local_addr_in);
    277         break;
    278     }
    279 
    280     printf("%ld: connect(%d)\n", pthread_self(), fd);
    281     ret = connect(fd, addr, len);
    282     printf("%ld: connect(%d) = %d\n", pthread_self(), fd, ret);
    283     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    284 
    285     return ret;
    286 }
    287 
    288 static int _write(int fd, int type) {
    289     int ret;
    290     char buf = 69;
    291 
    292     printf("%ld: write(%d)\n", pthread_self(), fd);
    293     ret = write(fd, &buf, 1);
    294     printf("%ld: write(%d) = %d\n", pthread_self(), fd, ret);
    295     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    296 
    297     return ret;
    298 }
    299 
    300 static int _shutdown(int fd, int how) {
    301     int ret;
    302 
    303     printf("%ld: shutdown(%d)\n", pthread_self(), fd);
    304     ret = shutdown(fd, how);
    305     printf("%ld: shutdown(%d) = %d\n", pthread_self(), fd, ret);
    306     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    307 
    308     return ret;
    309 }
    310 
    311 static int _poll(struct pollfd *ufds, nfds_t nfds, int timeout) {
    312     int ret;
    313     unsigned int i;
    314 
    315     printf("%ld: poll(", pthread_self());
    316     print_fds(ufds, nfds);
    317     printf(")\n");
    318     ret = poll(ufds, nfds, timeout);
    319     printf("%ld: poll() = %d\n", pthread_self(), ret);
    320     if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
    321     if (ret > 0) {
    322         for (i=0; i<nfds; i++) {
    323             if (ufds[i].revents) {
    324                 printf("\tfd %d ", ufds[i].fd); print_events(ufds[i].revents);
    325             }
    326         }
    327     }
    328     return ret;
    329 }
    330 
    331 static void thread_delay_close(struct thread_args *args) {
    332     printf("%ld: START\n", pthread_self());
    333     sleep(args->delay);
    334     _close(args->fd, args->type);
    335     printf("%ld: END\n", pthread_self());
    336 }
    337 
    338 static void thread_poll(void *args) {
    339     int fd = (int)args;
    340     struct pollfd pfd;
    341     printf("%ld: START\n", pthread_self());
    342     pfd.fd = fd;
    343     pfd.events = 0;
    344     _poll(&pfd, 1, -1);
    345     printf("%ld: END\n", pthread_self());
    346 }
    347 
    348 static void thread_read(void *args) {
    349     int fd = (int)args;
    350     printf("%ld: START\n", pthread_self());
    351     _read(fd);
    352     printf("%ld: END\n", pthread_self());
    353 }
    354 
    355 static void thread_pollin(void *args) {
    356     int fd = (int)args;
    357     struct pollfd pfd;
    358     printf("%ld: START\n", pthread_self());
    359     pfd.fd = fd;
    360     pfd.events = POLLIN;
    361     _poll(&pfd, 1, -1);
    362     printf("%ld: END\n", pthread_self());
    363 }
    364 
    365 static void thread_shutdown(int fd) {
    366     printf("%ld: START\n", pthread_self());
    367     sleep(4);
    368     _shutdown(fd, SHUT_RDWR);
    369     printf("%ld: END\n", pthread_self());
    370 }
    371 
    372 static void thread_accept(struct thread_args *args) {
    373     printf("%ld: START\n", pthread_self());
    374     sleep(args->delay);
    375     _accept(args->fd, args->type);
    376     printf("%ld: END\n", pthread_self());
    377 }
    378 
    379 static void thread_connect(struct thread_args *args) {
    380     printf("%ld: START\n", pthread_self());
    381     sleep(args->delay);
    382     _connect(args->fd, args->type);
    383     printf("%ld: END\n", pthread_self());
    384 }
    385 
    386 static void thread_delay_close_write(struct thread_args *args) {
    387     printf("%ld: START\n", pthread_self());
    388     sleep(args->delay);
    389     _close(args->fd, args->type);
    390     sleep(args->delay);
    391     _write(args->fd, args->type);
    392     printf("%ld: END\n", pthread_self());
    393 }
    394 
    395 static void thread_accept_write(struct thread_args *args) {
    396     printf("%ld: START\n", pthread_self());
    397     sleep(args->delay);
    398     _accept(args->fd, args->type);
    399     sleep(args->delay);
    400     _write(args->fd, args->type);
    401     printf("%ld: END\n", pthread_self());
    402 }
    403 
    404 static void thread_delay_connect(struct thread_args *args) {
    405     printf("%ld: START\n", pthread_self());
    406     sleep(args->delay);
    407     args->fd = _socket(args->type);
    408     _connect(args->fd, args->type);
    409     printf("%ld: END\n", pthread_self());
    410 }
    411 
    412 static int do_accept_accept_accept(int type) {
    413     int fd;
    414 
    415     fd = _socket(type);
    416     if (fd < 0) goto error;
    417 
    418     if (_bind(fd, type) < 0) goto error;
    419 
    420     if (_listen(fd, type) < 0) goto error;
    421 
    422     while (1) {
    423         _accept(fd, type);
    424     }
    425 
    426     return 0;
    427 
    428 error:
    429     return -1;
    430 }
    431 
    432 static int do_accept_and_close(int type) {
    433     int fd;
    434     pthread_t thread;
    435     struct thread_args args = {-1, type, 1};
    436 
    437     fd = _socket(type);
    438     if (fd < 0) goto error;
    439 
    440     if (_bind(fd, type) < 0) goto error;
    441 
    442     if (_listen(fd, type) < 0) goto error;
    443 
    444     args.fd = fd;
    445     pthread_create(&thread, NULL, (void *)thread_delay_close, (void *)&args);
    446 
    447     _accept(fd, type);
    448 
    449     pthread_join(thread, NULL);
    450 
    451     return 0;
    452 
    453 error:
    454     return -1;
    455 }
    456 
    457 static int do_accept_shutdown(int type) {
    458     int fd;
    459     pthread_t thread;
    460     struct thread_args args = {-1, type, 0};
    461 
    462     fd = _socket(type);
    463     if (fd < 0) goto error;
    464 
    465     if (_bind(fd, type) < 0) goto error;
    466 
    467     if (_listen(fd, type) < 0) goto error;
    468 
    469     args.fd = fd;
    470     pthread_create(&thread, NULL, (void *)thread_accept, (void *)&args);
    471 
    472     sleep(4);
    473     _shutdown(fd, SHUT_RDWR);
    474 
    475     pthread_join(thread, NULL);
    476 
    477     _close(fd, type);
    478 
    479     return 0;
    480 
    481 error:
    482     return -1;
    483 }
    484 
    485 static int do_connect_shutdown(int type) {
    486     int fd;
    487     pthread_t thread;
    488     struct thread_args args = {-1, type, 0};
    489 
    490     fd = _socket(type);
    491     if (fd < 0) goto error;
    492 
    493     args.fd = fd;
    494     pthread_create(&thread, NULL, (void *)thread_connect, (void *)&args);
    495 
    496     sleep(4);
    497     _shutdown(fd, SHUT_RDWR);
    498 
    499     pthread_join(thread, NULL);
    500 
    501     _close(fd, type);
    502 
    503     return 0;
    504 
    505 error:
    506     return -1;
    507 }
    508 
    509 static int do_connectnb_shutdown(int type) {
    510     int fd;
    511     int flags;
    512     pthread_t thread;
    513     struct thread_args args = {-1, type, 0};
    514 
    515 
    516     fd = _socket(type);
    517     if (fd < 0) goto error;
    518 
    519     flags = fcntl(fd, F_GETFL);
    520     if (flags == -1)
    521         return -1;
    522     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
    523         return -1;
    524 
    525     _connect(fd, type);
    526 
    527     sleep(1);
    528     _shutdown(fd, SHUT_RDWR);
    529 
    530     sleep(2);
    531 
    532     _close(fd, type);
    533 
    534     return 0;
    535 
    536 error:
    537     return -1;
    538 }
    539 
    540 static int do_connectnb_close(int type) {
    541     int fd;
    542     pthread_t thread;
    543     struct thread_args args = {-1, type, 0};
    544     int flags;
    545 
    546     fd = _socket(type);
    547     if (fd < 0) goto error;
    548 
    549     flags = fcntl(fd, F_GETFL);
    550     if (flags == -1)
    551         return -1;
    552     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
    553         return -1;
    554 
    555     _connect(fd, type);
    556 
    557     sleep(2);
    558 
    559     _close(fd, type);
    560 
    561     return 0;
    562 
    563 error:
    564     return -1;
    565 }
    566 
    567 // accept in one thread. close then write in another
    568 static int do_accept_close_write(int type) {
    569     int fd;
    570     pthread_t thread;
    571     struct thread_args args = {-1, type, 1};
    572 
    573     fd = _socket(type);
    574     if (fd < 0) goto error;
    575 
    576     if (_bind(fd, type) < 0) goto error;
    577 
    578     if (_listen(fd, type) < 0) goto error;
    579 
    580     args.fd = fd;
    581     pthread_create(&thread, NULL, (void *)thread_delay_close_write, (void *)&args);
    582 
    583     _accept(fd, type);
    584 
    585     pthread_join(thread, NULL);
    586 
    587     return 0;
    588 
    589 error:
    590     return -1;
    591 }
    592 
    593 static int do_poll_poll_poll_shutdown(int type) {
    594     const int MAX_T = 32;
    595     int fd;
    596     pthread_t t[MAX_T];
    597     int i;
    598 
    599     fd = _socket(type);
    600 
    601     for (i=0; i<MAX_T; i++)
    602         pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
    603 
    604     sleep(1);
    605 
    606     _shutdown(fd, SHUT_RDWR);
    607 
    608     for (i=0; i<MAX_T; i++)
    609         pthread_join(t[i], NULL);
    610 
    611     _close(fd, type);
    612 
    613     return 0;
    614 }
    615 
    616 static int do_poll_poll_poll_close(int type) {
    617     const int MAX_T = 32;
    618     int fd;
    619     pthread_t t[MAX_T];
    620     int i;
    621 
    622     fd = _socket(type);
    623 
    624     for (i=0; i<MAX_T; i++)
    625         pthread_create(&t[i], NULL, (void *)thread_poll, (void *)fd);
    626 
    627     sleep(1);
    628 
    629     _close(fd, type);
    630 
    631     for (i=0; i<MAX_T; i++)
    632         pthread_join(t[i], NULL);
    633 
    634     return 0;
    635 }
    636 
    637 static int do_read_read_read_close(int type) {
    638     const int MAX_T = 32;
    639     int fd;
    640     pthread_t t[MAX_T];
    641     int i;
    642 
    643     fd = _socket(type);
    644 
    645     for (i=0; i<MAX_T; i++)
    646         pthread_create(&t[i], NULL, (void *)thread_read, (void *)fd);
    647 
    648     sleep(1);
    649 
    650     _close(fd, type);
    651 
    652     for (i=0; i<MAX_T; i++)
    653         pthread_join(t[i], NULL);
    654 
    655     return 0;
    656 }
    657 
    658 static int do_read_read_read_shutdown(int type) {
    659     const int MAX_T = 32;
    660     int fd;
    661     pthread_t t[MAX_T];
    662     int i;
    663 
    664     fd = _socket(type);
    665 
    666     for (i=0; i<MAX_T; i++)
    667         pthread_create(&t[i], NULL, (void *)thread_read, (void *)fd);
    668 
    669     sleep(1);
    670 
    671     _shutdown(fd, SHUT_RDWR);
    672 
    673     for (i=0; i<MAX_T; i++)
    674         pthread_join(t[i], NULL);
    675 
    676     _close(fd, type);
    677 
    678     return 0;
    679 }
    680 
    681 static int do_connected_read1_shutdown1(int type) {
    682     int fd1, fd2;
    683     pthread_t t1;
    684     pthread_t t2;
    685     struct thread_args a1 = {-1, type, 0};
    686     struct thread_args a2 = {-1, type, 2};
    687 
    688     fd1 = _socket(type);
    689     if (fd1 < 0) goto error;
    690 
    691     if (_bind(fd1, type) < 0) goto error;
    692 
    693     if (_listen(fd1, type) < 0) goto error;
    694 
    695     a1.fd = fd1;
    696     pthread_create(&t1, NULL, (void *)thread_accept_write, (void *)&a1);
    697 
    698     fd2 = _socket(type);
    699     if (_connect(fd2, type)) goto error;
    700 
    701     pthread_create(&t2, NULL, (void *)thread_shutdown, (void *)&fd2);
    702 
    703     while (1) if (_read(fd2)) break;
    704 
    705     pthread_join(t1, NULL);
    706     pthread_join(t2, NULL);
    707 
    708     return 0;
    709 
    710 error:
    711     return -1;
    712 }
    713 
    714 // accept in one thread, connect from two different threads
    715 static int do_accept_connect_connect(int type) {
    716     int fd;
    717     pthread_t t1;
    718     pthread_t t2;
    719     struct thread_args a1 = {-1, type, 1};
    720     struct thread_args a2 = {-1, type, 2};
    721 
    722     fd = _socket(type);
    723     if (fd < 0) goto error;
    724 
    725     if (_bind(fd, type) < 0) goto error;
    726 
    727     if (_listen(fd, type) < 0) goto error;
    728 
    729     pthread_create(&t1, NULL, (void *)thread_delay_connect, (void *)&a1);
    730     pthread_create(&t2, NULL, (void *)thread_delay_connect, (void *)&a2);
    731 
    732     _accept(fd, type);
    733 
    734     pthread_join(t1, NULL);
    735     pthread_join(t2, NULL);
    736 
    737     return 0;
    738 
    739 error:
    740     return -1;
    741 }
    742 
    743 struct {
    744     char *name;
    745     int (*ptr)(int);
    746 } action_table[]  = {
    747     {"accept_accept_accept", do_accept_accept_accept},
    748     {"accept_and_close", do_accept_and_close},
    749     {"accept_shutdown", do_accept_shutdown},
    750     {"connect_shutdown", do_connect_shutdown},
    751     {"connectnb_shutdown", do_connectnb_shutdown},
    752     {"connectnb_close", do_connectnb_close},
    753     {"accept_close_write", do_accept_close_write},
    754     {"accept_connect_connect", do_accept_connect_connect},
    755     {"poll_poll_poll_shutdown", do_poll_poll_poll_shutdown},
    756     {"poll_poll_poll_close", do_poll_poll_poll_close},
    757     {"read_read_read_shutdown", do_read_read_read_shutdown},
    758     {"read_read_read_close", do_read_read_read_close},
    759     {"connected_read1_shutdown1", do_connected_read1_shutdown1},
    760     {NULL, NULL},
    761 };
    762 
    763 struct {
    764     char *name;
    765     enum sock_type type;
    766 } type_table[]  = {
    767     {"unix", UNIX},
    768     {"rfcomm", RFCOMM},
    769     {"sco", SCO},
    770     {"l2cap", L2CAP},
    771     {"tcp", TCP},
    772     {NULL, -1},
    773 };
    774 
    775 static void usage() {
    776     int i;
    777 
    778     printf("socktest TYPE ACTION\n");
    779     printf("\nTYPE:\n");
    780     for (i = 0; type_table[i].name; i++) {
    781         printf("\t%s\n", type_table[i].name);
    782     }
    783     printf("\nACTION:\n");
    784     for (i = 0; action_table[i].name; i++) {
    785         printf("\t%s\n", action_table[i].name);
    786     }
    787 }
    788 
    789 int main(int argc, char **argv) {
    790     int i;
    791     int type = -1;
    792 
    793     if (argc != 3) {
    794         usage();
    795         return -1;
    796     }
    797     for (i = 0; type_table[i].name; i++) {
    798         if (!strcmp(argv[1], type_table[i].name)) {
    799             type = type_table[i].type;
    800             break;
    801         }
    802     }
    803     if (type == -1) {
    804         usage();
    805         return -1;
    806     }
    807     for (i = 0; action_table[i].name; i++) {
    808         if (!strcmp(argv[2], action_table[i].name)) {
    809             printf("TYPE = %s ACTION = %s\n", type_table[type].name,
    810                     action_table[i].name);
    811             return (*action_table[i].ptr)(type);
    812         }
    813     }
    814     usage();
    815     return -1;
    816 }
    817