• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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