Home | History | Annotate | Download | only in tipc-test
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    588 static int ta2ta_ipc_test(void)
    589 {
    590 	int fd;
    591 	char rx_buf[64];
    592 
    593 	if (!opt_silent) {
    594 		printf("%s:\n", __func__);
    595 	}
    596 
    597 	fd = tipc_connect(dev_name, main_ctrl_name);
    598 	if (fd < 0) {
    599 		fprintf(stderr, "Failed to connect to '%s' service\n",
    600 			"main_ctrl");
    601 		return fd;
    602 	}
    603 
    604 	/* wait for test to complete */
    605 	(void) read(fd, rx_buf, sizeof(rx_buf));
    606 
    607 	tipc_close(fd);
    608 
    609 	return 0;
    610 }
    611 
    612 typedef struct uuid
    613 {
    614 	uint32_t time_low;
    615 	uint16_t time_mid;
    616 	uint16_t time_hi_and_version;
    617 	uint8_t clock_seq_and_node[8];
    618 } uuid_t;
    619 
    620 static void print_uuid(const char *dev, uuid_t *uuid)
    621 {
    622 	printf("%s:", dev);
    623 	printf("uuid: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
    624 	       uuid->time_low,
    625 	       uuid->time_mid,
    626 	       uuid->time_hi_and_version,
    627 	       uuid->clock_seq_and_node[0],
    628 	       uuid->clock_seq_and_node[1],
    629 	       uuid->clock_seq_and_node[2],
    630 	       uuid->clock_seq_and_node[3],
    631 	       uuid->clock_seq_and_node[4],
    632 	       uuid->clock_seq_and_node[5],
    633 	       uuid->clock_seq_and_node[6],
    634 	       uuid->clock_seq_and_node[7]
    635 	       );
    636 }
    637 
    638 static int dev_uuid_test(void)
    639 {
    640 	int fd;
    641 	ssize_t rc;
    642 	uuid_t uuid;
    643 
    644 	fd = tipc_connect(dev_name, uuid_name);
    645 	if (fd < 0) {
    646 		fprintf(stderr, "Failed to connect to '%s' service\n",
    647 			"uuid");
    648 		return fd;
    649 	}
    650 
    651 	/* wait for test to complete */
    652 	rc = read(fd, &uuid, sizeof(uuid));
    653 	if (rc < 0) {
    654 		perror("dev_uuid_test: read");
    655 	} else if (rc != sizeof(uuid)) {
    656 		fprintf(stderr, "unexpected uuid size (%d vs. %d)\n",
    657 			(int)rc, (int)sizeof(uuid));
    658 	} else {
    659 		print_uuid(dev_name, &uuid);
    660 	}
    661 
    662 	tipc_close(fd);
    663 
    664 	return 0;
    665 }
    666 
    667 static int ta_access_test(void)
    668 {
    669 	int fd;
    670 
    671 	if (!opt_silent) {
    672 		printf("%s:\n", __func__);
    673 	}
    674 
    675 	fd = tipc_connect(dev_name, ta_only_name);
    676 	if (fd >= 0) {
    677 		fprintf(stderr, "Succeed to connect to '%s' service\n",
    678 			"ta_only");
    679 		tipc_close(fd);
    680 	}
    681 
    682 	fd = tipc_connect(dev_name, ns_only_name);
    683 	if (fd < 0) {
    684 		fprintf(stderr, "Failed to connect to '%s' service\n",
    685 			"ns_only");
    686 		return fd;
    687 	}
    688 	tipc_close(fd);
    689 
    690 	if (!opt_silent) {
    691 		printf("%s: done\n",__func__);
    692 	}
    693 
    694 	return 0;
    695 }
    696 
    697 
    698 static int writev_test(uint repeat, uint msgsz, bool var)
    699 {
    700 	uint i;
    701 	ssize_t rc;
    702 	size_t  msg_len;
    703 	int  echo_fd = -1;
    704 	char tx0_buf[msgsz];
    705 	char tx1_buf[msgsz];
    706 	char rx_buf [msgsz];
    707 	struct iovec iovs[2]= {{tx0_buf, 0}, {tx1_buf, 0}};
    708 
    709 	if (!opt_silent) {
    710 		printf("%s: repeat %u: msgsz %u: variable %s\n",
    711 			__func__, repeat, msgsz, var ? "true" : "false");
    712 	}
    713 
    714 	echo_fd = tipc_connect(dev_name, echo_name);
    715 	if (echo_fd < 0) {
    716 		fprintf(stderr, "Failed to connect to service\n");
    717 		return echo_fd;
    718 	}
    719 
    720 	for (i = 0; i < repeat; i++) {
    721 
    722 		msg_len = msgsz;
    723 		if (opt_variable && msgsz) {
    724 			msg_len = rand() % msgsz;
    725 		}
    726 
    727 		iovs[0].iov_len = msg_len / 3;
    728 		iovs[1].iov_len = msg_len - iovs[0].iov_len;
    729 
    730 		memset(tx0_buf, i + 1, iovs[0].iov_len);
    731 		memset(tx1_buf, i + 2, iovs[1].iov_len);
    732 		memset(rx_buf,  i + 3, sizeof(rx_buf));
    733 
    734 		rc = writev(echo_fd, iovs, 2);
    735 		if (rc < 0) {
    736 			perror("writev_test: writev");
    737 			break;
    738 		}
    739 
    740 		if ((size_t)rc != msg_len) {
    741 			fprintf(stderr,
    742 				"%s: %s: data size mismatch (%zd vs. %zd)\n",
    743 				__func__, "writev", (size_t)rc, msg_len);
    744 			break;
    745 		}
    746 
    747 		rc = read(echo_fd, rx_buf, sizeof(rx_buf));
    748 		if (rc < 0) {
    749 			perror("writev_test: read");
    750 			break;
    751 		}
    752 
    753 		if ((size_t)rc != msg_len) {
    754 			fprintf(stderr,
    755 				"%s: %s: data size mismatch (%zd vs. %zd)\n",
    756 				__func__, "read", (size_t)rc, msg_len);
    757 			break;
    758 		}
    759 
    760 		if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
    761 			fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
    762 			break;
    763 		}
    764 
    765 		if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
    766 			fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
    767 			break;
    768 		}
    769 	}
    770 
    771 	tipc_close(echo_fd);
    772 
    773 	if (!opt_silent) {
    774 		printf("%s: done\n",__func__);
    775 	}
    776 
    777 	return 0;
    778 }
    779 
    780 static int readv_test(uint repeat, uint msgsz, bool var)
    781 {
    782 	uint i;
    783 	ssize_t rc;
    784 	size_t  msg_len;
    785 	int  echo_fd = -1;
    786 	char tx_buf [msgsz];
    787 	char rx0_buf[msgsz];
    788 	char rx1_buf[msgsz];
    789 	struct iovec iovs[2]= {{rx0_buf, 0}, {rx1_buf, 0}};
    790 
    791 	if (!opt_silent) {
    792 		printf("%s: repeat %u: msgsz %u: variable %s\n",
    793 			__func__, repeat, msgsz, var ? "true" : "false");
    794 	}
    795 
    796 	echo_fd = tipc_connect(dev_name, echo_name);
    797 	if (echo_fd < 0) {
    798 		fprintf(stderr, "Failed to connect to service\n");
    799 		return echo_fd;
    800 	}
    801 
    802 	for (i = 0; i < repeat; i++) {
    803 
    804 		msg_len = msgsz;
    805 		if (opt_variable && msgsz) {
    806 			msg_len = rand() % msgsz;
    807 		}
    808 
    809 		iovs[0].iov_len = msg_len / 3;
    810 		iovs[1].iov_len = msg_len - iovs[0].iov_len;
    811 
    812 		memset(tx_buf,  i + 1, sizeof(tx_buf));
    813 		memset(rx0_buf, i + 2, iovs[0].iov_len);
    814 		memset(rx1_buf, i + 3, iovs[1].iov_len);
    815 
    816 		rc = write(echo_fd, tx_buf, msg_len);
    817 		if (rc < 0) {
    818 			perror("readv_test: write");
    819 			break;
    820 		}
    821 
    822 		if ((size_t)rc != msg_len) {
    823 			fprintf(stderr,
    824 				"%s: %s: data size mismatch (%zd vs. %zd)\n",
    825 				__func__, "write", (size_t)rc, msg_len);
    826 			break;
    827 		}
    828 
    829 		rc = readv(echo_fd, iovs, 2);
    830 		if (rc < 0) {
    831 			perror("readv_test: readv");
    832 			break;
    833 		}
    834 
    835 		if ((size_t)rc != msg_len) {
    836 			fprintf(stderr,
    837 				"%s: %s: data size mismatch (%zd vs. %zd)\n",
    838 				__func__, "write", (size_t)rc, msg_len);
    839 			break;
    840 		}
    841 
    842 		if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
    843 			fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
    844 			break;
    845 		}
    846 
    847 		if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
    848 			fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
    849 			break;
    850 		}
    851 	}
    852 
    853 	tipc_close(echo_fd);
    854 
    855 	if (!opt_silent) {
    856 		printf("%s: done\n",__func__);
    857 	}
    858 
    859 	return 0;
    860 }
    861 
    862 
    863 int main(int argc, char **argv)
    864 {
    865 	int rc = 0;
    866 
    867 	if (argc <= 1) {
    868 		print_usage_and_exit(argv[0], EXIT_FAILURE, false);
    869 	}
    870 
    871 	parse_options(argc, argv);
    872 
    873 	if (!dev_name) {
    874 		dev_name = TIPC_DEFAULT_DEVNAME;
    875 	}
    876 
    877 	if (!test_name) {
    878 		fprintf(stderr, "need a Test to run\n");
    879 		print_usage_and_exit(argv[0], EXIT_FAILURE, true);
    880 	}
    881 
    882 	if (strcmp(test_name, "connect") == 0) {
    883 		rc = connect_test(opt_repeat);
    884 	} else if (strcmp(test_name, "connect_foo") == 0) {
    885 		rc = connect_foo(opt_repeat);
    886 	} else if (strcmp(test_name, "burst_write") == 0) {
    887 		rc = burst_write_test(opt_repeat, opt_msgburst, opt_msgsize, opt_variable);
    888 	} else if (strcmp(test_name, "select") == 0) {
    889 		rc = select_test(opt_repeat, opt_msgburst,  opt_msgsize);
    890 	} else if (strcmp(test_name, "blocked_read") == 0) {
    891 		rc = blocked_read_test(opt_repeat);
    892 	} else if (strcmp(test_name, "closer1") == 0) {
    893 		rc = closer1_test(opt_repeat);
    894 	} else if (strcmp(test_name, "closer2") == 0) {
    895 		rc = closer2_test(opt_repeat);
    896 	} else if (strcmp(test_name, "closer3") == 0) {
    897 		rc = closer3_test(opt_repeat);
    898 	} else if (strcmp(test_name, "echo") == 0) {
    899 		rc = echo_test(opt_repeat, opt_msgsize, opt_variable);
    900 	} else if(strcmp(test_name, "ta2ta-ipc") == 0) {
    901 		rc = ta2ta_ipc_test();
    902 	} else if (strcmp(test_name, "dev-uuid") == 0) {
    903 		rc = dev_uuid_test();
    904 	} else if (strcmp(test_name, "ta-access") == 0) {
    905 		rc = ta_access_test();
    906 	} else if (strcmp(test_name, "writev") == 0) {
    907 		rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
    908 	} else if (strcmp(test_name, "readv") == 0) {
    909 		rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
    910 	} else {
    911 		fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
    912 		print_usage_and_exit(argv[0], EXIT_FAILURE, true);
    913 	}
    914 
    915 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
    916 }
    917