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
41 enum sock_type {
42 UNIX = 0,
43 RFCOMM,
44 SCO,
45 L2CAP,
46 TCP,
47 };
48
49 struct thread_args {
50 int fd;
51 int type;
52 int delay;
53 };
54
55 struct sockaddr_un local_addr_un = {AF_UNIX, "/tmp/foo"};
56 struct sockaddr_rc local_addr_rc = {AF_BLUETOOTH, *BDADDR_ANY, 4};
57 struct sockaddr_sco local_addr_sco = {AF_BLUETOOTH, *BDADDR_LOCAL};
58 struct sockaddr_l2 local_addr_l2 = {AF_BLUETOOTH, htobs(0x1001), *BDADDR_ANY, 0};
59 struct sockaddr_in local_addr_in = {AF_INET, 9999, {0}, {0}};
60
61 struct sockaddr_un remote_addr_un ;
62 struct sockaddr_rc remote_addr_rc ;
63 struct sockaddr_sco remote_addr_sco ;
64 struct sockaddr_l2 remote_addr_l2 ;
65 struct sockaddr_in remote_addr_in ;
66
_socket(int type)67 static 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
_close(int fd)109 static 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
_bind(int fd,int type)120 static 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
_listen(int fd,int type)157 static 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
_accept(int fd,int type)168 static 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
_shutdown(int fd,int how)207 static 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
thread_accept(struct thread_args * args)218 static 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
do_accept_shutdown(int type)225 static 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
249 error:
250 return -1;
251 }
252
253 struct {
254 char *name;
255 int (*ptr)(int);
256 } action_table[] = {
257 {"accept_shutdown", do_accept_shutdown},
258 {NULL, NULL},
259 };
260
261 struct {
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
usage()273 static 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
main(int argc,char ** argv)287 int 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