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