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
29 static const char *dev_name = NULL;
30 static const char *test_name = NULL;
31
32 static const char *uuid_name = "com.android.ipc-unittest.srv.uuid";
33 static const char *echo_name = "com.android.ipc-unittest.srv.echo";
34 static const char *ta_only_name = "com.android.ipc-unittest.srv.ta_only";
35 static const char *ns_only_name = "com.android.ipc-unittest.srv.ns_only";
36 static const char *datasink_name = "com.android.ipc-unittest.srv.datasink";
37 static const char *closer1_name = "com.android.ipc-unittest.srv.closer1";
38 static const char *closer2_name = "com.android.ipc-unittest.srv.closer2";
39 static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
40 static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
41
42 static const char *_sopts = "hsvD:t:r:m:b:";
43 static 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
54 static 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
68 static 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
86 static uint opt_repeat = 1;
87 static uint opt_msgsize = 32;
88 static uint opt_msgburst = 32;
89 static bool opt_variable = false;
90 static bool opt_silent = false;
91
print_usage_and_exit(const char * prog,int code,bool verbose)92 static 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
parse_options(int argc,char ** argv)100 static 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
connect_test(uint repeat)151 static 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
connect_foo(uint repeat)188 static 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
closer1_test(uint repeat)214 static 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
closer2_test(uint repeat)243 static 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
closer3_test(uint repeat)272 static 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
echo_test(uint repeat,uint msgsz,bool var)339 static 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
burst_write_test(uint repeat,uint msgburst,uint msgsz,bool var)401 static 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
_wait_for_msg(int fd,uint msgsz,int timeout)449 static 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
select_test(uint repeat,uint msgburst,uint msgsz)501 static 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
blocked_read_test(uint repeat)546 static 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
ta2ta_ipc_test(void)585 static 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
609 typedef 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
print_uuid(const char * dev,uuid_t * uuid)617 static 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
dev_uuid_test(void)635 static 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
ta_access_test(void)664 static 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
main(int argc,char ** argv)695 int 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