1/* 2 * Copyright (C) 2015 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#include <stdio.h> 18#include <errno.h> 19#include <stdbool.h> 20#include <string.h> 21#include <stdlib.h> 22#include <unistd.h> 23#include <getopt.h> 24 25#include <trusty/tipc.h> 26 27#define TIPC_DEFAULT_DEVNAME "/dev/trusty-ipc-dev0" 28 29static const char *dev_name = NULL; 30static const char *test_name = NULL; 31 32static const char *uuid_name = "com.android.ipc-unittest.srv.uuid"; 33static const char *echo_name = "com.android.ipc-unittest.srv.echo"; 34static const char *ta_only_name = "com.android.ipc-unittest.srv.ta_only"; 35static const char *ns_only_name = "com.android.ipc-unittest.srv.ns_only"; 36static const char *datasink_name = "com.android.ipc-unittest.srv.datasink"; 37static const char *closer1_name = "com.android.ipc-unittest.srv.closer1"; 38static const char *closer2_name = "com.android.ipc-unittest.srv.closer2"; 39static const char *closer3_name = "com.android.ipc-unittest.srv.closer3"; 40static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl"; 41 42static const char *_sopts = "hsvD:t:r:m:b:"; 43static const struct option _lopts[] = { 44 {"help", no_argument, 0, 'h'}, 45 {"silent", no_argument, 0, 's'}, 46 {"variable",no_argument, 0, 'v'}, 47 {"dev", required_argument, 0, 'D'}, 48 {"repeat", required_argument, 0, 'r'}, 49 {"burst", required_argument, 0, 'b'}, 50 {"msgsize", required_argument, 0, 'm'}, 51 {0, 0, 0, 0} 52}; 53 54static const char *usage = 55"Usage: %s [options]\n" 56"\n" 57"options:\n" 58" -h, --help prints this message and exit\n" 59" -D, --dev name device name\n" 60" -t, --test name test to run\n" 61" -r, --repeat cnt repeat count\n" 62" -m, --msgsize size max message size\n" 63" -v, --variable variable message size\n" 64" -s, --silent silent\n" 65"\n" 66; 67 68static const char *usage_long = 69"\n" 70"The following tests are available:\n" 71" connect - connect to datasink service\n" 72" connect_foo - connect to non existing service\n" 73" burst_write - send messages to datasink service\n" 74" echo - send/receive messages to echo service\n" 75" select - test select call\n" 76" blocked_read - test blocked read\n" 77" closer1 - connection closed by remote (test1)\n" 78" closer2 - connection closed by remote (test2)\n" 79" closer3 - connection closed by remote (test3)\n" 80" ta2ta-ipc - execute TA to TA unittest\n" 81" dev-uuid - print device uuid\n" 82" ta-access - test ta-access flags\n" 83"\n" 84; 85 86static uint opt_repeat = 1; 87static uint opt_msgsize = 32; 88static uint opt_msgburst = 32; 89static bool opt_variable = false; 90static bool opt_silent = false; 91 92static void print_usage_and_exit(const char *prog, int code, bool verbose) 93{ 94 fprintf (stderr, usage, prog); 95 if (verbose) 96 fprintf (stderr, usage_long); 97 exit(code); 98} 99 100static void parse_options(int argc, char **argv) 101{ 102 int c; 103 int oidx = 0; 104 105 while (1) 106 { 107 c = getopt_long (argc, argv, _sopts, _lopts, &oidx); 108 if (c == -1) 109 break; /* done */ 110 111 switch (c) { 112 113 case 'D': 114 dev_name = strdup(optarg); 115 break; 116 117 case 't': 118 test_name = strdup(optarg); 119 break; 120 121 case 'v': 122 opt_variable = true; 123 break; 124 125 case 'r': 126 opt_repeat = atoi(optarg); 127 break; 128 129 case 'm': 130 opt_msgsize = atoi(optarg); 131 break; 132 133 case 'b': 134 opt_msgburst = atoi(optarg); 135 break; 136 137 case 's': 138 opt_silent = true; 139 break; 140 141 case 'h': 142 print_usage_and_exit(argv[0], EXIT_SUCCESS, true); 143 break; 144 145 default: 146 print_usage_and_exit(argv[0], EXIT_FAILURE, false); 147 } 148 } 149} 150 151static int connect_test(uint repeat) 152{ 153 uint i; 154 int echo_fd; 155 int dsink_fd; 156 157 if (!opt_silent) { 158 printf("%s: repeat = %u\n", __func__, repeat); 159 } 160 161 for (i = 0; i < repeat; i++) { 162 echo_fd = tipc_connect(dev_name, echo_name); 163 if (echo_fd < 0) { 164 fprintf(stderr, "Failed to connect to '%s' service\n", 165 "echo"); 166 } 167 dsink_fd = tipc_connect(dev_name, datasink_name); 168 if (dsink_fd < 0) { 169 fprintf(stderr, "Failed to connect to '%s' service\n", 170 "datasink"); 171 } 172 173 if (echo_fd >= 0) { 174 tipc_close(echo_fd); 175 } 176 if (dsink_fd >= 0) { 177 tipc_close(dsink_fd); 178 } 179 } 180 181 if (!opt_silent) { 182 printf("%s: done\n", __func__); 183 } 184 185 return 0; 186} 187 188static int connect_foo(uint repeat) 189{ 190 uint i; 191 int fd; 192 193 if (!opt_silent) { 194 printf("%s: repeat = %u\n", __func__, repeat); 195 } 196 197 for (i = 0; i < repeat; i++) { 198 fd = tipc_connect(dev_name, "foo"); 199 if (fd >= 0) { 200 fprintf(stderr, "succeeded to connect to '%s' service\n", 201 "foo"); 202 tipc_close(fd); 203 } 204 } 205 206 if (!opt_silent) { 207 printf("%s: done\n", __func__); 208 } 209 210 return 0; 211} 212 213 214static int closer1_test(uint repeat) 215{ 216 uint i; 217 int fd; 218 219 if (!opt_silent) { 220 printf("%s: repeat = %u\n", __func__, repeat); 221 } 222 223 for (i = 0; i < repeat; i++) { 224 fd = tipc_connect(dev_name, closer1_name); 225 if (fd < 0) { 226 fprintf(stderr, "Failed to connect to '%s' service\n", 227 "closer1"); 228 continue; 229 } 230 if (!opt_silent) { 231 printf("%s: connected\n", __func__); 232 } 233 tipc_close(fd); 234 } 235 236 if (!opt_silent) { 237 printf("%s: done\n", __func__); 238 } 239 240 return 0; 241} 242 243static int closer2_test(uint repeat) 244{ 245 uint i; 246 int fd; 247 248 if (!opt_silent) { 249 printf("%s: repeat = %u\n", __func__, repeat); 250 } 251 252 for (i = 0; i < repeat; i++) { 253 fd = tipc_connect(dev_name, closer2_name); 254 if (fd < 0) { 255 if (!opt_silent) { 256 printf("failed to connect to '%s' service\n", "closer2"); 257 } 258 } else { 259 /* this should always fail */ 260 fprintf(stderr, "connected to '%s' service\n", "closer2"); 261 tipc_close(fd); 262 } 263 } 264 265 if (!opt_silent) { 266 printf("%s: done\n", __func__); 267 } 268 269 return 0; 270} 271 272static int closer3_test(uint repeat) 273{ 274 uint i, j; 275 ssize_t rc; 276 int fd[4]; 277 char buf[64]; 278 279 if (!opt_silent) { 280 printf("%s: repeat = %u\n", __func__, repeat); 281 } 282 283 for (i = 0; i < repeat; i++) { 284 285 /* open 4 connections to closer3 service */ 286 for (j = 0; j < 4; j++) { 287 fd[j] = tipc_connect(dev_name, closer3_name); 288 if (fd[j] < 0) { 289 fprintf(stderr, "fd[%d]: failed to connect to '%s' service\n", j, "closer3"); 290 } else { 291 if (!opt_silent) { 292 printf("%s: fd[%d]=%d: connected\n", __func__, j, fd[j]); 293 } 294 memset(buf, i + j, sizeof(buf)); 295 rc = write(fd[j], buf, sizeof(buf)); 296 if (rc != sizeof(buf)) { 297 if (!opt_silent) { 298 printf("%s: fd[%d]=%d: write returned = %zd\n", 299 __func__, j, fd[j], rc); 300 } 301 perror("closer3_test: write"); 302 } 303 } 304 } 305 306 /* sleep a bit */ 307 sleep(1); 308 309 /* It is expected that they will be closed by remote */ 310 for (j = 0; j < 4; j++) { 311 if (fd[j] < 0) 312 continue; 313 rc = write(fd[j], buf, sizeof(buf)); 314 if (rc != sizeof(buf)) { 315 if (!opt_silent) { 316 printf("%s: fd[%d]=%d: write returned = %zd\n", 317 __func__, j, fd[j], rc); 318 } 319 perror("closer3_test: write"); 320 } 321 } 322 323 /* then they have to be closed by remote */ 324 for (j = 0; j < 4; j++) { 325 if (fd[j] >= 0) { 326 tipc_close(fd[j]); 327 } 328 } 329 } 330 331 if (!opt_silent) { 332 printf("%s: done\n", __func__); 333 } 334 335 return 0; 336} 337 338 339static int echo_test(uint repeat, uint msgsz, bool var) 340{ 341 uint i; 342 ssize_t rc; 343 size_t msg_len; 344 int echo_fd =-1; 345 char tx_buf[msgsz]; 346 char rx_buf[msgsz]; 347 348 if (!opt_silent) { 349 printf("%s: repeat %u: msgsz %u: variable %s\n", 350 __func__, repeat, msgsz, var ? "true" : "false"); 351 } 352 353 echo_fd = tipc_connect(dev_name, echo_name); 354 if (echo_fd < 0) { 355 fprintf(stderr, "Failed to connect to service\n"); 356 return echo_fd; 357 } 358 359 for (i = 0; i < repeat; i++) { 360 361 msg_len = msgsz; 362 if (opt_variable && msgsz) { 363 msg_len = rand() % msgsz; 364 } 365 366 memset(tx_buf, i + 1, msg_len); 367 368 rc = write(echo_fd, tx_buf, msg_len); 369 if ((size_t)rc != msg_len) { 370 perror("echo_test: write"); 371 break; 372 } 373 374 rc = read(echo_fd, rx_buf, msg_len); 375 if (rc < 0) { 376 perror("echo_test: read"); 377 break; 378 } 379 380 if ((size_t)rc != msg_len) { 381 fprintf(stderr, "data truncated (%zu vs. %zu)\n", 382 rc, msg_len); 383 continue; 384 } 385 386 if (memcmp(tx_buf, rx_buf, (size_t) rc)) { 387 fprintf(stderr, "data mismatch\n"); 388 continue; 389 } 390 } 391 392 tipc_close(echo_fd); 393 394 if (!opt_silent) { 395 printf("%s: done\n",__func__); 396 } 397 398 return 0; 399} 400 401static int burst_write_test(uint repeat, uint msgburst, uint msgsz, bool var) 402{ 403 int fd; 404 uint i, j; 405 ssize_t rc; 406 size_t msg_len; 407 char tx_buf[msgsz]; 408 409 if (!opt_silent) { 410 printf("%s: repeat %u: burst %u: msgsz %u: variable %s\n", 411 __func__, repeat, msgburst, msgsz, 412 var ? "true" : "false"); 413 } 414 415 for (i = 0; i < repeat; i++) { 416 417 fd = tipc_connect(dev_name, datasink_name); 418 if (fd < 0) { 419 fprintf(stderr, "Failed to connect to '%s' service\n", 420 "datasink"); 421 break; 422 } 423 424 for (j = 0; j < msgburst; j++) { 425 msg_len = msgsz; 426 if (var && msgsz) { 427 msg_len = rand() % msgsz; 428 } 429 430 memset(tx_buf, i + 1, msg_len); 431 rc = write(fd, tx_buf, msg_len); 432 if ((size_t)rc != msg_len) { 433 perror("burst_test: write"); 434 break; 435 } 436 } 437 438 tipc_close(fd); 439 } 440 441 if (!opt_silent) { 442 printf("%s: done\n",__func__); 443 } 444 445 return 0; 446} 447 448 449static int _wait_for_msg(int fd, uint msgsz, int timeout) 450{ 451 int rc; 452 fd_set rfds; 453 uint msgcnt = 0; 454 char rx_buf[msgsz]; 455 struct timeval tv; 456 457 if (!opt_silent) { 458 printf("waiting (%d) for msg\n", timeout); 459 } 460 461 FD_ZERO(&rfds); 462 FD_SET(fd, &rfds); 463 464 tv.tv_sec = timeout; 465 tv.tv_usec = 0; 466 467 for(;;) { 468 rc = select(fd+1, &rfds, NULL, NULL, &tv); 469 470 if (rc == 0) { 471 if (!opt_silent) { 472 printf("select timedout\n"); 473 } 474 break; 475 } 476 477 if (rc == -1) { 478 perror("select_test: select"); 479 return rc; 480 } 481 482 rc = read(fd, rx_buf, sizeof(rx_buf)); 483 if (rc < 0) { 484 perror("select_test: read"); 485 return rc; 486 } else { 487 if (rc > 0) { 488 msgcnt++; 489 } 490 } 491 } 492 493 if (!opt_silent) { 494 printf("got %u messages\n", msgcnt); 495 } 496 497 return 0; 498} 499 500 501static int select_test(uint repeat, uint msgburst, uint msgsz) 502{ 503 int fd; 504 uint i, j; 505 ssize_t rc; 506 char tx_buf[msgsz]; 507 508 if (!opt_silent) { 509 printf("%s: repeat %u\n", __func__, repeat); 510 } 511 512 fd = tipc_connect(dev_name, echo_name); 513 if (fd < 0) { 514 fprintf(stderr, "Failed to connect to '%s' service\n", 515 "echo"); 516 return fd; 517 } 518 519 for (i = 0; i < repeat; i++) { 520 521 _wait_for_msg(fd, msgsz, 1); 522 523 if (!opt_silent) { 524 printf("sending burst: %u msg\n", msgburst); 525 } 526 527 for (j = 0; j < msgburst; j++) { 528 memset(tx_buf, i + j, msgsz); 529 rc = write(fd, tx_buf, msgsz); 530 if ((size_t)rc != msgsz) { 531 perror("burst_test: write"); 532 break; 533 } 534 } 535 } 536 537 tipc_close(fd); 538 539 if (!opt_silent) { 540 printf("%s: done\n",__func__); 541 } 542 543 return 0; 544} 545 546static int blocked_read_test(uint repeat) 547{ 548 int fd; 549 uint i; 550 ssize_t rc; 551 char rx_buf[512]; 552 553 if (!opt_silent) { 554 printf("%s: repeat %u\n", __func__, repeat); 555 } 556 557 fd = tipc_connect(dev_name, echo_name); 558 if (fd < 0) { 559 fprintf(stderr, "Failed to connect to '%s' service\n", 560 "echo"); 561 return fd; 562 } 563 564 for (i = 0; i < repeat; i++) { 565 rc = read(fd, rx_buf, sizeof(rx_buf)); 566 if (rc < 0) { 567 perror("select_test: read"); 568 break; 569 } else { 570 if (!opt_silent) { 571 printf("got %zd bytes\n", rc); 572 } 573 } 574 } 575 576 tipc_close(fd); 577 578 if (!opt_silent) { 579 printf("%s: done\n",__func__); 580 } 581 582 return 0; 583} 584 585static int ta2ta_ipc_test(void) 586{ 587 int fd; 588 char rx_buf[64]; 589 590 if (!opt_silent) { 591 printf("%s:\n", __func__); 592 } 593 594 fd = tipc_connect(dev_name, main_ctrl_name); 595 if (fd < 0) { 596 fprintf(stderr, "Failed to connect to '%s' service\n", 597 "main_ctrl"); 598 return fd; 599 } 600 601 /* wait for test to complete */ 602 (void) read(fd, rx_buf, sizeof(rx_buf)); 603 604 tipc_close(fd); 605 606 return 0; 607} 608 609typedef struct uuid 610{ 611 uint32_t time_low; 612 uint16_t time_mid; 613 uint16_t time_hi_and_version; 614 uint8_t clock_seq_and_node[8]; 615} uuid_t; 616 617static void print_uuid(const char *dev, uuid_t *uuid) 618{ 619 printf("%s:", dev); 620 printf("uuid: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", 621 uuid->time_low, 622 uuid->time_mid, 623 uuid->time_hi_and_version, 624 uuid->clock_seq_and_node[0], 625 uuid->clock_seq_and_node[1], 626 uuid->clock_seq_and_node[2], 627 uuid->clock_seq_and_node[3], 628 uuid->clock_seq_and_node[4], 629 uuid->clock_seq_and_node[5], 630 uuid->clock_seq_and_node[6], 631 uuid->clock_seq_and_node[7] 632 ); 633} 634 635static int dev_uuid_test(void) 636{ 637 int fd; 638 ssize_t rc; 639 uuid_t uuid; 640 641 fd = tipc_connect(dev_name, uuid_name); 642 if (fd < 0) { 643 fprintf(stderr, "Failed to connect to '%s' service\n", 644 "uuid"); 645 return fd; 646 } 647 648 /* wait for test to complete */ 649 rc = read(fd, &uuid, sizeof(uuid)); 650 if (rc < 0) { 651 perror("dev_uuid_test: read"); 652 } else if (rc != sizeof(uuid)) { 653 fprintf(stderr, "unexpected uuid size (%d vs. %d)\n", 654 (int)rc, (int)sizeof(uuid)); 655 } else { 656 print_uuid(dev_name, &uuid); 657 } 658 659 tipc_close(fd); 660 661 return 0; 662} 663 664static int ta_access_test(void) 665{ 666 int fd; 667 668 if (!opt_silent) { 669 printf("%s:\n", __func__); 670 } 671 672 fd = tipc_connect(dev_name, ta_only_name); 673 if (fd >= 0) { 674 fprintf(stderr, "Succeed to connect to '%s' service\n", 675 "ta_only"); 676 tipc_close(fd); 677 } 678 679 fd = tipc_connect(dev_name, ns_only_name); 680 if (fd < 0) { 681 fprintf(stderr, "Failed to connect to '%s' service\n", 682 "ns_only"); 683 return fd; 684 } 685 tipc_close(fd); 686 687 if (!opt_silent) { 688 printf("%s: done\n",__func__); 689 } 690 691 return 0; 692} 693 694 695int main(int argc, char **argv) 696{ 697 int rc = 0; 698 699 if (argc <= 1) { 700 print_usage_and_exit(argv[0], EXIT_FAILURE, false); 701 } 702 703 parse_options(argc, argv); 704 705 if (!dev_name) { 706 dev_name = TIPC_DEFAULT_DEVNAME; 707 } 708 709 if (!test_name) { 710 fprintf(stderr, "need a Test to run\n"); 711 print_usage_and_exit(argv[0], EXIT_FAILURE, true); 712 } 713 714 if (strcmp(test_name, "connect") == 0) { 715 rc = connect_test(opt_repeat); 716 } else if (strcmp(test_name, "connect_foo") == 0) { 717 rc = connect_foo(opt_repeat); 718 } else if (strcmp(test_name, "burst_write") == 0) { 719 rc = burst_write_test(opt_repeat, opt_msgburst, opt_msgsize, opt_variable); 720 } else if (strcmp(test_name, "select") == 0) { 721 rc = select_test(opt_repeat, opt_msgburst, opt_msgsize); 722 } else if (strcmp(test_name, "blocked_read") == 0) { 723 rc = blocked_read_test(opt_repeat); 724 } else if (strcmp(test_name, "closer1") == 0) { 725 rc = closer1_test(opt_repeat); 726 } else if (strcmp(test_name, "closer2") == 0) { 727 rc = closer2_test(opt_repeat); 728 } else if (strcmp(test_name, "closer3") == 0) { 729 rc = closer3_test(opt_repeat); 730 } else if (strcmp(test_name, "echo") == 0) { 731 rc = echo_test(opt_repeat, opt_msgsize, opt_variable); 732 } else if(strcmp(test_name, "ta2ta-ipc") == 0) { 733 rc = ta2ta_ipc_test(); 734 } else if (strcmp(test_name, "dev-uuid") == 0) { 735 rc = dev_uuid_test(); 736 } else if (strcmp(test_name, "ta-access") == 0) { 737 rc = ta_access_test(); 738 } else { 739 fprintf(stderr, "Unrecognized test name '%s'\n", test_name); 740 print_usage_and_exit(argv[0], EXIT_FAILURE, true); 741 } 742 743 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 744} 745