173610d44SSepherosa Ziehau #include <sys/types.h>
273610d44SSepherosa Ziehau #include <sys/socket.h>
373610d44SSepherosa Ziehau #include <sys/time.h>
473610d44SSepherosa Ziehau #include <sys/un.h>
573610d44SSepherosa Ziehau #include <sys/wait.h>
673610d44SSepherosa Ziehau 
773610d44SSepherosa Ziehau #include <arpa/inet.h>
873610d44SSepherosa Ziehau #include <netinet/in.h>
973610d44SSepherosa Ziehau 
1073610d44SSepherosa Ziehau #include <err.h>
1173610d44SSepherosa Ziehau #include <errno.h>
1273610d44SSepherosa Ziehau #include <signal.h>
1373610d44SSepherosa Ziehau #include <stdio.h>
1473610d44SSepherosa Ziehau #include <stdlib.h>
1573610d44SSepherosa Ziehau #include <string.h>
1673610d44SSepherosa Ziehau #include <unistd.h>
1773610d44SSepherosa Ziehau 
1873610d44SSepherosa Ziehau #define WRITE_WAIT_TIME	8	/* unit: sec */
1973610d44SSepherosa Ziehau #define READ_WAIT_MIN	6	/* unit: sec */
2073610d44SSepherosa Ziehau 
2173610d44SSepherosa Ziehau static void
usage(const char * cmd)2273610d44SSepherosa Ziehau usage(const char *cmd)
2373610d44SSepherosa Ziehau {
2473610d44SSepherosa Ziehau 	fprintf(stderr, "%s -p port\n", cmd);
2573610d44SSepherosa Ziehau 	exit(1);
2673610d44SSepherosa Ziehau }
2773610d44SSepherosa Ziehau 
2873610d44SSepherosa Ziehau static void
connect_client(int port,int ctrl_s)2973610d44SSepherosa Ziehau connect_client(int port, int ctrl_s)
3073610d44SSepherosa Ziehau {
3173610d44SSepherosa Ziehau 	struct sockaddr_in in;
3273610d44SSepherosa Ziehau 	int s, dummy;
3373610d44SSepherosa Ziehau 
3473610d44SSepherosa Ziehau 	s = socket(AF_INET, SOCK_STREAM, 0);
3573610d44SSepherosa Ziehau 	if (s < 0)
3673610d44SSepherosa Ziehau 		err(1, "client socket failed");
3773610d44SSepherosa Ziehau 
3873610d44SSepherosa Ziehau 	memset(&in, 0, sizeof(in));
3973610d44SSepherosa Ziehau 	in.sin_family = AF_INET;
4073610d44SSepherosa Ziehau 	in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4173610d44SSepherosa Ziehau 	in.sin_port = htons(port);
4273610d44SSepherosa Ziehau 	if (connect(s, (const struct sockaddr *)&in, sizeof(in)) < 0)
4373610d44SSepherosa Ziehau 		err(1, "connect failed");
4473610d44SSepherosa Ziehau 
45*00cac4e7SSepherosa Ziehau 	/* Make sure server side compltes the 3-way handshake */
46*00cac4e7SSepherosa Ziehau 	sleep(1);
47*00cac4e7SSepherosa Ziehau 
4873610d44SSepherosa Ziehau 	/* connect is done */
4973610d44SSepherosa Ziehau 	write(ctrl_s, &dummy, sizeof(dummy));
5073610d44SSepherosa Ziehau 
5173610d44SSepherosa Ziehau 	sleep(WRITE_WAIT_TIME);
5273610d44SSepherosa Ziehau 	write(s, &dummy, sizeof(dummy));
5373610d44SSepherosa Ziehau 
5473610d44SSepherosa Ziehau 	pause();
5573610d44SSepherosa Ziehau 	exit(0);
5673610d44SSepherosa Ziehau }
5773610d44SSepherosa Ziehau 
5873610d44SSepherosa Ziehau int
main(int argc,char * argv[])5973610d44SSepherosa Ziehau main(int argc, char *argv[])
6073610d44SSepherosa Ziehau {
6173610d44SSepherosa Ziehau 	struct sockaddr_in in;
6273610d44SSepherosa Ziehau 	int serv_s, s, ctrl_s[2];
6373610d44SSepherosa Ziehau 	int opt, port, dummy, n, status, panic, ex;
6473610d44SSepherosa Ziehau 	struct timespec stime, etime;
6573610d44SSepherosa Ziehau 	pid_t pid;
6673610d44SSepherosa Ziehau 
6773610d44SSepherosa Ziehau 	ex = 1;
6873610d44SSepherosa Ziehau 	panic = 0;
6973610d44SSepherosa Ziehau 
7073610d44SSepherosa Ziehau 	port = 0;
7173610d44SSepherosa Ziehau 	while ((opt = getopt(argc, argv, "p:")) != -1) {
7273610d44SSepherosa Ziehau 		char *endptr;
7373610d44SSepherosa Ziehau 
7473610d44SSepherosa Ziehau 		switch (opt) {
7573610d44SSepherosa Ziehau 		case 'p':
7673610d44SSepherosa Ziehau 			port = strtol(optarg, &endptr, 0);
7773610d44SSepherosa Ziehau 			if (*endptr != '\0')
7873610d44SSepherosa Ziehau 				errx(1, "invalid -p");
7973610d44SSepherosa Ziehau 			break;
8073610d44SSepherosa Ziehau 
8173610d44SSepherosa Ziehau 		default:
8273610d44SSepherosa Ziehau 			usage(argv[0]);
8373610d44SSepherosa Ziehau 		}
8473610d44SSepherosa Ziehau 	}
8573610d44SSepherosa Ziehau 	if (port <= 0)
8673610d44SSepherosa Ziehau 		usage(argv[0]);
8773610d44SSepherosa Ziehau 
8873610d44SSepherosa Ziehau 	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ctrl_s) < 0)
8973610d44SSepherosa Ziehau 		err(1, "socketpair failed");
9073610d44SSepherosa Ziehau 
9173610d44SSepherosa Ziehau 	serv_s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
9273610d44SSepherosa Ziehau 	if (serv_s < 0)
9373610d44SSepherosa Ziehau 		err(1, "socket failed");
9473610d44SSepherosa Ziehau 
9573610d44SSepherosa Ziehau 	memset(&in, 0, sizeof(in));
9673610d44SSepherosa Ziehau 	in.sin_family = AF_INET;
9773610d44SSepherosa Ziehau 	in.sin_port = htons(port);
9873610d44SSepherosa Ziehau 	if (bind(serv_s, (const struct sockaddr *)&in, sizeof(in)) < 0)
9973610d44SSepherosa Ziehau 		err(1, "bind failed");
10073610d44SSepherosa Ziehau 
10173610d44SSepherosa Ziehau 	if (listen(serv_s, 0) < 0)
10273610d44SSepherosa Ziehau 		err(1, "listen failed");
10373610d44SSepherosa Ziehau 
10473610d44SSepherosa Ziehau 	pid = fork();
10573610d44SSepherosa Ziehau 	if (pid < 0) {
10673610d44SSepherosa Ziehau 		err(1, "fork failed");
10773610d44SSepherosa Ziehau 	} else if (pid == 0) {
10873610d44SSepherosa Ziehau 		close(ctrl_s[0]);
10973610d44SSepherosa Ziehau 		connect_client(port, ctrl_s[1]);
11073610d44SSepherosa Ziehau 		abort();
11173610d44SSepherosa Ziehau 	}
11273610d44SSepherosa Ziehau 
11373610d44SSepherosa Ziehau 	/* Wait for the connect */
11473610d44SSepherosa Ziehau 	read(ctrl_s[0], &dummy, sizeof(dummy));
11573610d44SSepherosa Ziehau 
11673610d44SSepherosa Ziehau 	s = accept4(serv_s, NULL, NULL, 0);
11773610d44SSepherosa Ziehau 	if (s < 0) {
11873610d44SSepherosa Ziehau 		warn("accept4 failed");
11973610d44SSepherosa Ziehau 		goto done;
12073610d44SSepherosa Ziehau 	}
12173610d44SSepherosa Ziehau 	panic = 1;
12273610d44SSepherosa Ziehau 
12373610d44SSepherosa Ziehau 	clock_gettime(CLOCK_MONOTONIC, &stime);
12473610d44SSepherosa Ziehau 	n = read(s, &dummy, sizeof(dummy));
12573610d44SSepherosa Ziehau 	if (n < 0) {
12673610d44SSepherosa Ziehau 		warn("read failed");
12773610d44SSepherosa Ziehau 		goto done;
12873610d44SSepherosa Ziehau 	} else if (n != sizeof(dummy)) {
12973610d44SSepherosa Ziehau 		warnx("read size mismatch");
13073610d44SSepherosa Ziehau 		goto done;
13173610d44SSepherosa Ziehau 	}
13273610d44SSepherosa Ziehau 	clock_gettime(CLOCK_MONOTONIC, &etime);
13373610d44SSepherosa Ziehau 
13473610d44SSepherosa Ziehau 	if (etime.tv_sec - stime.tv_sec < READ_WAIT_MIN) {
13573610d44SSepherosa Ziehau 		warnx("invalid wait time %ld", etime.tv_sec - stime.tv_sec);
13673610d44SSepherosa Ziehau 		goto done;
13773610d44SSepherosa Ziehau 	}
13873610d44SSepherosa Ziehau 
13973610d44SSepherosa Ziehau 	ex = 0;
14073610d44SSepherosa Ziehau 	panic = 0;
14173610d44SSepherosa Ziehau 	fprintf(stderr, "passed\n");
14273610d44SSepherosa Ziehau done:
14373610d44SSepherosa Ziehau 	kill(pid, SIGKILL);
14473610d44SSepherosa Ziehau 	waitpid(pid, &status, 0);
14573610d44SSepherosa Ziehau 	if (panic)
14673610d44SSepherosa Ziehau 		abort();
14773610d44SSepherosa Ziehau 	exit(ex);
14873610d44SSepherosa Ziehau }
149