socktest.c revision 3f61fb90d08d4848a7d7dd24180c2b95ebd60bfc
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 <pthread.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <unistd.h>
30#include <sys/socket.h>
31#include <sys/ioctl.h>
32#include <sys/un.h>
33#include <netinet/in.h>
34
35#include <bluetooth/bluetooth.h>
36#include <bluetooth/rfcomm.h>
37#include <bluetooth/sco.h>
38#include <bluetooth/l2cap.h>
39
40enum sock_type {
41    UNIX = 0,
42    RFCOMM,
43    SCO,
44    L2CAP,
45    TCP,
46};
47
48struct thread_args {
49    int fd;
50    int type;
51    int delay;
52};
53
54struct sockaddr_un  local_addr_un  = {AF_UNIX, "/data/foo"};
55struct sockaddr_rc  local_addr_rc  = {AF_BLUETOOTH, *BDADDR_ANY, 4};
56struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
57struct sockaddr_l2  local_addr_l2  = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
58struct sockaddr_in  local_addr_in  = {AF_INET, 9999, {0}, {0}};
59
60struct sockaddr_un  remote_addr_un  ;
61struct sockaddr_rc  remote_addr_rc  ;
62struct sockaddr_sco remote_addr_sco ;
63struct sockaddr_l2  remote_addr_l2  ;
64struct sockaddr_in  remote_addr_in  ;
65
66static int _socket(int type) {
67    int ret;
68    int family = -1;
69    int typ = -1;
70    int protocol = -1;
71
72    switch (type) {
73    case UNIX:
74        family = PF_UNIX;
75        typ = SOCK_STREAM;
76        protocol = 0;
77        break;
78    case RFCOMM:
79        family = PF_BLUETOOTH;
80        typ = SOCK_STREAM;
81        protocol = BTPROTO_RFCOMM;
82        break;
83    case SCO:
84        family = PF_BLUETOOTH;
85        typ = SOCK_SEQPACKET;
86        protocol = BTPROTO_SCO;
87        break;
88    case L2CAP:
89        family = PF_BLUETOOTH;
90        typ = SOCK_SEQPACKET;
91        protocol = BTPROTO_L2CAP;
92        break;
93    case TCP:
94        family = PF_INET;
95        typ = SOCK_STREAM;
96        protocol = 0;
97        break;
98    }
99
100    printf("%d: socket()\n", gettid());
101    ret = socket(family, typ, protocol);
102    printf("%d: socket() = %d\n", gettid(), ret);
103    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
104
105    return ret;
106}
107
108static int _close(int fd, int type) {
109    int ret;
110
111    printf("%d: close(%d)\n", gettid(), fd);
112    ret = close(fd);
113    printf("%d: close(%d) = %d\n", gettid(), fd, ret);
114    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
115
116    return ret;
117}
118
119static int _bind(int fd, int type) {
120    int len = 0;
121    int ret;
122    struct sockaddr *addr = NULL;
123
124    switch (type) {
125    case UNIX:
126        unlink(local_addr_un.sun_path);
127        addr = (struct sockaddr *) &local_addr_un;
128        len = sizeof(local_addr_un);
129        break;
130    case RFCOMM:
131        addr = (struct sockaddr *) &local_addr_rc;
132        len = sizeof(local_addr_rc);
133        break;
134    case SCO:
135        addr = (struct sockaddr *) &local_addr_sco;
136        len = sizeof(local_addr_sco);
137        break;
138    case L2CAP:
139        addr = (struct sockaddr *) &local_addr_l2;
140        len = sizeof(local_addr_l2);
141        break;
142    case TCP:
143        addr = (struct sockaddr *) &local_addr_in;
144        len = sizeof(local_addr_in);
145        break;
146    }
147
148    printf("%d: bind(%d)\n", gettid(), fd);
149    ret = bind(fd, addr, len);
150    printf("%d: bind(%d) = %d\n", gettid(), fd, ret);
151    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
152
153    return ret;
154}
155
156static int _listen(int fd, int type) {
157    int ret;
158
159    printf("%d: listen(%d)\n", gettid(), fd);
160    ret = listen(fd, 1);
161    printf("%d: listen(%d) = %d\n", gettid(), fd, ret);
162    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
163
164    return ret;
165}
166
167static int _accept(int fd, int type) {
168    int ret;
169    int len;
170    struct sockaddr *addr = NULL;
171
172    switch (type) {
173    case UNIX:
174        addr = (struct sockaddr *) &remote_addr_un;
175        len = sizeof(remote_addr_un);
176        break;
177    case RFCOMM:
178        addr = (struct sockaddr *) &remote_addr_rc;
179        len = sizeof(remote_addr_rc);
180        break;
181    case SCO:
182        addr = (struct sockaddr *) &remote_addr_sco;
183        len = sizeof(remote_addr_sco);
184        break;
185    case L2CAP:
186        addr = (struct sockaddr *) &remote_addr_l2;
187        len = sizeof(remote_addr_l2);
188        break;
189    case TCP:
190        addr = (struct sockaddr *) &remote_addr_in;
191        len = sizeof(remote_addr_in);
192        break;
193    }
194
195    printf("%d: accept(%d)\n", gettid(), fd);
196    ret = accept(fd, addr, &len);
197    printf("%d: accept(%d) = %d\n", gettid(), fd, ret);
198    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
199    else {
200        printf("\tlen = %d\n", len);
201    }
202
203    return ret;
204}
205
206static int _connect(int fd, int type) {
207    int ret;
208    int len = 0;
209    struct sockaddr *addr = NULL;
210
211    switch (type) {
212    case UNIX:
213        addr = (struct sockaddr *) &local_addr_un;
214        len = sizeof(local_addr_un);
215        break;
216    case RFCOMM:
217        addr = (struct sockaddr *) &local_addr_rc;
218        len = sizeof(local_addr_rc);
219        break;
220    case SCO:
221        addr = (struct sockaddr *) &local_addr_sco;
222        len = sizeof(local_addr_sco);
223        break;
224    case L2CAP:
225        addr = (struct sockaddr *) &local_addr_l2;
226        len = sizeof(local_addr_l2);
227        break;
228    case TCP:
229        addr = (struct sockaddr *) &local_addr_in;
230        len = sizeof(local_addr_in);
231        break;
232    }
233
234    printf("%d: connect(%d)\n", gettid(), fd);
235    ret = connect(fd, addr, len);
236    printf("%d: connect(%d) = %d\n", gettid(), fd, ret);
237    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
238
239    return ret;
240}
241
242static int _write(int fd, int type) {
243    int ret;
244    char buf = 0;
245
246    printf("%d: write(%d)\n", gettid(), fd);
247    ret = write(fd, &buf, 1);
248    printf("%d: connect(%d) = %d\n", gettid(), fd, ret);
249    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
250
251    return ret;
252}
253
254static void thread_delay_close(struct thread_args *args) {
255    printf("%d: START\n", gettid());
256    sleep(args->delay);
257    _close(args->fd, args->type);
258    printf("%d: END\n", gettid());
259}
260
261static void thread_delay_close_write(struct thread_args *args) {
262    printf("%d: START\n", gettid());
263    sleep(args->delay);
264    _close(args->fd, args->type);
265    sleep(args->delay);
266    _write(args->fd, args->type);
267    printf("%d: END\n", gettid());
268}
269
270static void thread_delay_connect(struct thread_args *args) {
271    printf("%d: START\n", gettid());
272    sleep(args->delay);
273    args->fd = _socket(args->type);
274    _connect(args->fd, args->type);
275    printf("%d: END\n", gettid());
276}
277
278static int do_accept_accept_accept(int type) {
279    int fd;
280
281    fd = _socket(type);
282    if (fd < 0) goto error;
283
284    if (_bind(fd, type) < 0) goto error;
285
286    if (_listen(fd, type) < 0) goto error;
287
288    while (1) {
289        _accept(fd, type);
290    }
291
292    return 0;
293
294error:
295    return -1;
296}
297
298static int do_accept_and_close(int type) {
299    int fd;
300    pthread_t thread;
301    struct thread_args args = {-1, type, 1};
302
303    fd = _socket(type);
304    if (fd < 0) goto error;
305
306    if (_bind(fd, type) < 0) goto error;
307
308    if (_listen(fd, type) < 0) goto error;
309
310    args.fd = fd;
311    pthread_create(&thread, NULL, (void *)thread_delay_close, (void *)&args);
312
313    _accept(fd, type);
314
315    pthread_join(thread, NULL);
316
317    return 0;
318
319error:
320    return -1;
321}
322
323// accept in one thread. close then write in another
324static int do_accept_close_write(int type) {
325    int fd;
326    pthread_t thread;
327    struct thread_args args = {-1, type, 1};
328
329    fd = _socket(type);
330    if (fd < 0) goto error;
331
332    if (_bind(fd, type) < 0) goto error;
333
334    if (_listen(fd, type) < 0) goto error;
335
336    args.fd = fd;
337    pthread_create(&thread, NULL, (void *)thread_delay_close_write, (void *)&args);
338
339    _accept(fd, type);
340
341    pthread_join(thread, NULL);
342
343    return 0;
344
345error:
346    return -1;
347}
348
349static int do_poll_poll_shutdown(int type) {
350#if 0
351    int fd;
352    struct thread_args a1 = {-1, type, 1};
353    struct thread_args a2 = {-1, type, 2};
354
355    fd = _socket(type);
356
357    pthread_create(&t1, NULL, (void *)thread_poll, (void *)fd[0]);
358    pthread_create(&t2, NULL, (void *)thread_poll, (void *)fd[0]);
359
360    sleep(1);
361
362    _shutdown(fd[1], SHUT_RDWR);
363
364    pthread_join(t1, NULL);
365    pthread_join(t2, NULL);
366#endif
367    return 0;
368}
369
370// accept in one thread, connect from two different threads
371static int do_accept_connect_connect(int type) {
372    int fd;
373    pthread_t t1;
374    pthread_t t2;
375    struct thread_args a1 = {-1, type, 1};
376    struct thread_args a2 = {-1, type, 2};
377
378    fd = _socket(type);
379    if (fd < 0) goto error;
380
381    if (_bind(fd, type) < 0) goto error;
382
383    if (_listen(fd, type) < 0) goto error;
384
385    pthread_create(&t1, NULL, (void *)thread_delay_connect, (void *)&a1);
386    pthread_create(&t2, NULL, (void *)thread_delay_connect, (void *)&a2);
387
388    _accept(fd, type);
389
390    pthread_join(t1, NULL);
391    pthread_join(t2, NULL);
392
393    return 0;
394
395error:
396    return -1;
397}
398
399struct {
400    char *name;
401    int (*ptr)(int);
402} action_table[]  = {
403    {"accept_accept_accept", do_accept_accept_accept},
404    {"accept_and_close", do_accept_and_close},
405    {"accept_close_write", do_accept_close_write},
406    {"accept_connect_connect", do_accept_connect_connect},
407    {NULL, NULL},
408};
409
410struct {
411    char *name;
412    enum sock_type type;
413} type_table[]  = {
414    {"unix", UNIX},
415    {"rfcomm", RFCOMM},
416    {"sco", SCO},
417    {"l2cap", L2CAP},
418    {"tcp", TCP},
419    {NULL, -1},
420};
421
422static void usage() {
423    int i;
424
425    printf("socktest TYPE ACTION\n");
426    printf("\nTYPE:\n");
427    for (i = 0; type_table[i].name; i++) {
428        printf("\t%s\n", type_table[i].name);
429    }
430    printf("\nACTION:\n");
431    for (i = 0; action_table[i].name; i++) {
432        printf("\t%s\n", action_table[i].name);
433    }
434}
435
436int main(int argc, char **argv) {
437    int i;
438    int type = -1;
439
440    if (argc != 3) {
441        usage();
442        return -1;
443    }
444    for (i = 0; type_table[i].name; i++) {
445        if (!strcmp(argv[1], type_table[i].name)) {
446            type = type_table[i].type;
447            break;
448        }
449    }
450    if (type == -1) {
451        usage();
452        return -1;
453    }
454    for (i = 0; action_table[i].name; i++) {
455        if (!strcmp(argv[2], action_table[i].name)) {
456            printf("TYPE = %s ACTION = %s\n", type_table[type].name,
457                    action_table[i].name);
458            return (*action_table[i].ptr)(type);
459        }
460    }
461    usage();
462    return -1;
463}
464