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