• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
print_events(int events)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 
print_fds(struct pollfd * ufds,nfds_t nfds)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 
_socket(int type)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 
_close(int fd,int type)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 
_bind(int fd,int type)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 
_listen(int fd,int type)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 
_read(int fd)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 
_accept(int fd,int type)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 
get_bdaddr(const char * str,bdaddr_t * ba)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 
_connect(int fd,int type)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 
_write(int fd,int type)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 
_shutdown(int fd,int how)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 
_poll(struct pollfd * ufds,nfds_t nfds,int timeout)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 
thread_delay_close(struct thread_args * args)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 
thread_poll(void * args)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 
thread_read(void * args)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 
thread_pollin(void * args)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 
thread_shutdown(int fd)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 
thread_accept(struct thread_args * args)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 
thread_connect(struct thread_args * args)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 
thread_delay_close_write(struct thread_args * args)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 
thread_accept_write(struct thread_args * args)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 
thread_delay_connect(struct thread_args * args)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 
do_accept_accept_accept(int type)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 
do_accept_and_close(int type)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 
do_accept_shutdown(int type)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 
do_connect_shutdown(int type)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 
do_connectnb_shutdown(int type)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 
do_connectnb_close(int type)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
do_accept_close_write(int type)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 
do_poll_poll_poll_shutdown(int type)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 
do_poll_poll_poll_close(int type)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 
do_read_read_read_close(int type)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 
do_read_read_read_shutdown(int type)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 
do_connected_read1_shutdown1(int type)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
do_accept_connect_connect(int type)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 
usage()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 
main(int argc,char ** argv)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