1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/time.h>
4 #include <sys/un.h>
5 #include <sys/wait.h>
6 
7 #include <arpa/inet.h>
8 #include <netinet/in.h>
9 
10 #include <err.h>
11 #include <errno.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 
18 #define WRITE_WAIT_TIME	8	/* unit: sec */
19 #define READ_WAIT_MIN	6	/* unit: sec */
20 
21 static void
22 usage(const char *cmd)
23 {
24 	fprintf(stderr, "%s -p port\n", cmd);
25 	exit(1);
26 }
27 
28 static void
29 connect_client(int port, int ctrl_s)
30 {
31 	struct sockaddr_in in;
32 	int s, dummy;
33 
34 	s = socket(AF_INET, SOCK_STREAM, 0);
35 	if (s < 0)
36 		err(1, "client socket failed");
37 
38 	memset(&in, 0, sizeof(in));
39 	in.sin_family = AF_INET;
40 	in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
41 	in.sin_port = htons(port);
42 	if (connect(s, (const struct sockaddr *)&in, sizeof(in)) < 0)
43 		err(1, "connect failed");
44 
45 	/* connect is done */
46 	write(ctrl_s, &dummy, sizeof(dummy));
47 
48 	sleep(WRITE_WAIT_TIME);
49 	write(s, &dummy, sizeof(dummy));
50 
51 	pause();
52 	exit(0);
53 }
54 
55 int
56 main(int argc, char *argv[])
57 {
58 	struct sockaddr_in in;
59 	int serv_s, s, ctrl_s[2];
60 	int opt, port, dummy, n, status, panic, ex;
61 	struct timespec stime, etime;
62 	pid_t pid;
63 
64 	ex = 1;
65 	panic = 0;
66 
67 	port = 0;
68 	while ((opt = getopt(argc, argv, "p:")) != -1) {
69 		char *endptr;
70 
71 		switch (opt) {
72 		case 'p':
73 			port = strtol(optarg, &endptr, 0);
74 			if (*endptr != '\0')
75 				errx(1, "invalid -p");
76 			break;
77 
78 		default:
79 			usage(argv[0]);
80 		}
81 	}
82 	if (port <= 0)
83 		usage(argv[0]);
84 
85 	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ctrl_s) < 0)
86 		err(1, "socketpair failed");
87 
88 	serv_s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
89 	if (serv_s < 0)
90 		err(1, "socket failed");
91 
92 	memset(&in, 0, sizeof(in));
93 	in.sin_family = AF_INET;
94 	in.sin_port = htons(port);
95 	if (bind(serv_s, (const struct sockaddr *)&in, sizeof(in)) < 0)
96 		err(1, "bind failed");
97 
98 	if (listen(serv_s, 0) < 0)
99 		err(1, "listen failed");
100 
101 	pid = fork();
102 	if (pid < 0) {
103 		err(1, "fork failed");
104 	} else if (pid == 0) {
105 		close(ctrl_s[0]);
106 		connect_client(port, ctrl_s[1]);
107 		abort();
108 	}
109 
110 	/* Wait for the connect */
111 	read(ctrl_s[0], &dummy, sizeof(dummy));
112 
113 	s = accept4(serv_s, NULL, NULL, 0);
114 	if (s < 0) {
115 		warn("accept4 failed");
116 		goto done;
117 	}
118 	panic = 1;
119 
120 	clock_gettime(CLOCK_MONOTONIC, &stime);
121 	n = read(s, &dummy, sizeof(dummy));
122 	if (n < 0) {
123 		warn("read failed");
124 		goto done;
125 	} else if (n != sizeof(dummy)) {
126 		warnx("read size mismatch");
127 		goto done;
128 	}
129 	clock_gettime(CLOCK_MONOTONIC, &etime);
130 
131 	if (etime.tv_sec - stime.tv_sec < READ_WAIT_MIN) {
132 		warnx("invalid wait time %ld", etime.tv_sec - stime.tv_sec);
133 		goto done;
134 	}
135 
136 	ex = 0;
137 	panic = 0;
138 	fprintf(stderr, "passed\n");
139 done:
140 	kill(pid, SIGKILL);
141 	waitpid(pid, &status, 0);
142 	if (panic)
143 		abort();
144 	exit(ex);
145 }
146