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/** testing behavior of shutdown() */
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/poll.h>
33#include <sys/un.h>
34#include <netinet/in.h>
35
36#include <bluetooth/bluetooth.h>
37#include <bluetooth/rfcomm.h>
38#include <bluetooth/sco.h>
39#include <bluetooth/l2cap.h>
40
41enum sock_type {
42    UNIX = 0,
43    RFCOMM,
44    SCO,
45    L2CAP,
46    TCP,
47};
48
49struct thread_args {
50    int fd;
51    int type;
52    int delay;
53};
54
55struct sockaddr_un  local_addr_un  = {AF_UNIX, "/tmp/foo"};
56struct sockaddr_rc  local_addr_rc  = {AF_BLUETOOTH, *BDADDR_ANY, 4};
57struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
58struct sockaddr_l2  local_addr_l2  = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
59struct sockaddr_in  local_addr_in  = {AF_INET, 9999, {0}, {0}};
60
61struct sockaddr_un  remote_addr_un  ;
62struct sockaddr_rc  remote_addr_rc  ;
63struct sockaddr_sco remote_addr_sco ;
64struct sockaddr_l2  remote_addr_l2  ;
65struct sockaddr_in  remote_addr_in  ;
66
67static int _socket(int type) {
68    int ret;
69    int family = -1;
70    int typ = -1;
71    int protocol = -1;
72
73    switch (type) {
74    case UNIX:
75        family = PF_UNIX;
76        typ = SOCK_STREAM;
77        protocol = 0;
78        break;
79    case RFCOMM:
80        family = PF_BLUETOOTH;
81        typ = SOCK_STREAM;
82        protocol = BTPROTO_RFCOMM;
83        break;
84    case SCO:
85        family = PF_BLUETOOTH;
86        typ = SOCK_SEQPACKET;
87        protocol = BTPROTO_SCO;
88        break;
89    case L2CAP:
90        family = PF_BLUETOOTH;
91        typ = SOCK_SEQPACKET;
92        protocol = BTPROTO_L2CAP;
93        break;
94    case TCP:
95        family = PF_INET;
96        typ = SOCK_STREAM;
97        protocol = 0;
98        break;
99    }
100
101    printf("%d: socket()\n", gettid());
102    ret = socket(family, typ, protocol);
103    printf("%d: socket() = %d\n", gettid(), ret);
104    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
105
106    return ret;
107}
108
109static int _close(int fd) {
110    int ret;
111
112    printf("%d: close(%d)\n", gettid(), fd);
113    ret = close(fd);
114    printf("%d: close(%d) = %d\n", gettid(), fd, ret);
115    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
116
117    return ret;
118}
119
120static int _bind(int fd, int type) {
121    int len = 0;
122    int ret;
123    struct sockaddr *addr = NULL;
124
125    switch (type) {
126    case UNIX:
127        unlink(local_addr_un.sun_path);
128        addr = (struct sockaddr *) &local_addr_un;
129        len = sizeof(local_addr_un);
130        break;
131    case RFCOMM:
132        addr = (struct sockaddr *) &local_addr_rc;
133        len = sizeof(local_addr_rc);
134        break;
135    case SCO:
136        addr = (struct sockaddr *) &local_addr_sco;
137        len = sizeof(local_addr_sco);
138        break;
139    case L2CAP:
140        addr = (struct sockaddr *) &local_addr_l2;
141        len = sizeof(local_addr_l2);
142        break;
143    case TCP:
144        addr = (struct sockaddr *) &local_addr_in;
145        len = sizeof(local_addr_in);
146        break;
147    }
148
149    printf("%d: bind(%d)\n", gettid(), fd);
150    ret = bind(fd, addr, len);
151    printf("%d: bind(%d) = %d\n", gettid(), fd, ret);
152    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
153
154    return ret;
155}
156
157static int _listen(int fd, int type) {
158    int ret;
159
160    printf("%d: listen(%d)\n", gettid(), fd);
161    ret = listen(fd, 1);
162    printf("%d: listen(%d) = %d\n", gettid(), fd, ret);
163    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
164
165    return ret;
166}
167
168static int _accept(int fd, int type) {
169    int ret;
170    int len;
171    struct sockaddr *addr = NULL;
172
173    switch (type) {
174    case UNIX:
175        addr = (struct sockaddr *) &remote_addr_un;
176        len = sizeof(remote_addr_un);
177        break;
178    case RFCOMM:
179        addr = (struct sockaddr *) &remote_addr_rc;
180        len = sizeof(remote_addr_rc);
181        break;
182    case SCO:
183        addr = (struct sockaddr *) &remote_addr_sco;
184        len = sizeof(remote_addr_sco);
185        break;
186    case L2CAP:
187        addr = (struct sockaddr *) &remote_addr_l2;
188        len = sizeof(remote_addr_l2);
189        break;
190    case TCP:
191        addr = (struct sockaddr *) &remote_addr_in;
192        len = sizeof(remote_addr_in);
193        break;
194    }
195
196    printf("%d: accept(%d)\n", gettid(), fd);
197    ret = accept(fd, addr, &len);
198    printf("%d: accept(%d) = %d\n", gettid(), fd, ret);
199    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
200    else {
201        printf("\tlen = %d\n", len);
202    }
203
204    return ret;
205}
206
207static int _shutdown(int fd, int how) {
208    int ret;
209
210    printf("%d: shutdown(%d)\n", gettid(), fd);
211    ret = shutdown(fd, how);
212    printf("%d: shutdown(%d) = %d\n", gettid(), fd, ret);
213    if (ret < 0) printf("\terr %d (%s)\n", errno, strerror(errno));
214
215    return ret;
216}
217
218static void thread_accept(struct thread_args *args) {
219    printf("%d: START\n", gettid());
220    sleep(args->delay);
221    _accept(args->fd, args->type);
222    printf("%d: END\n", gettid());
223}
224
225static int do_accept_shutdown(int type) {
226    int fd;
227    pthread_t thread;
228    struct thread_args args = {-1, type, 0};
229
230    fd = _socket(type);
231    if (fd < 0) goto error;
232
233    if (_bind(fd, type) < 0) goto error;
234
235    if (_listen(fd, type) < 0) goto error;
236
237    args.fd = fd;
238    pthread_create(&thread, NULL, (void *)thread_accept, (void *)&args);
239
240    sleep(2);
241    _shutdown(fd, SHUT_RDWR);
242
243    pthread_join(thread, NULL);
244
245    _close(fd);
246
247    return 0;
248
249error:
250    return -1;
251}
252
253struct {
254    char *name;
255    int (*ptr)(int);
256} action_table[]  = {
257    {"accept_shutdown", do_accept_shutdown},
258    {NULL, NULL},
259};
260
261struct {
262    char *name;
263    enum sock_type type;
264} type_table[]  = {
265    {"unix", UNIX},
266    {"rfcomm", RFCOMM},
267    {"sco", SCO},
268    {"l2cap", L2CAP},
269    {"tcp", TCP},
270    {NULL, -1},
271};
272
273static void usage() {
274    int i;
275
276    printf("sock_shutdown_test TYPE ACTION\n");
277    printf("\nTYPE:\n");
278    for (i = 0; type_table[i].name; i++) {
279        printf("\t%s\n", type_table[i].name);
280    }
281    printf("\nACTION:\n");
282    for (i = 0; action_table[i].name; i++) {
283        printf("\t%s\n", action_table[i].name);
284    }
285}
286
287int main(int argc, char **argv) {
288    int i;
289    int type = -1;
290
291    if (argc != 3) {
292        usage();
293        return -1;
294    }
295    for (i = 0; type_table[i].name; i++) {
296        if (!strcmp(argv[1], type_table[i].name)) {
297            type = type_table[i].type;
298            break;
299        }
300    }
301    if (type == -1) {
302        usage();
303        return -1;
304    }
305    for (i = 0; action_table[i].name; i++) {
306        if (!strcmp(argv[2], action_table[i].name)) {
307            printf("TYPE = %s ACTION = %s\n", type_table[type].name,
308                    action_table[i].name);
309            return (*action_table[i].ptr)(type);
310        }
311    }
312    usage();
313    return -1;
314}
315