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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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