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