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)
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 	sleep(WRITE_WAIT_TIME);
46 	write(s, &dummy, sizeof(dummy));
47 
48 	pause();
49 	exit(0);
50 }
51 
52 int
53 main(int argc, char *argv[])
54 {
55 	struct sockaddr_in in;
56 	int serv_s, s;
57 	int opt, port, dummy, n, status, panic, ex;
58 	struct timespec stime, etime;
59 	pid_t pid;
60 
61 	ex = 1;
62 	panic = 0;
63 
64 	port = 0;
65 	while ((opt = getopt(argc, argv, "p:")) != -1) {
66 		char *endptr;
67 
68 		switch (opt) {
69 		case 'p':
70 			port = strtol(optarg, &endptr, 0);
71 			if (*endptr != '\0')
72 				errx(1, "invalid -p");
73 			break;
74 
75 		default:
76 			usage(argv[0]);
77 		}
78 	}
79 	if (port <= 0)
80 		usage(argv[0]);
81 
82 	serv_s = socket(AF_INET, SOCK_STREAM, 0);
83 	if (serv_s < 0)
84 		err(1, "socket failed");
85 
86 	memset(&in, 0, sizeof(in));
87 	in.sin_family = AF_INET;
88 	in.sin_port = htons(port);
89 	if (bind(serv_s, (const struct sockaddr *)&in, sizeof(in)) < 0)
90 		err(1, "bind failed");
91 
92 	if (listen(serv_s, 0) < 0)
93 		err(1, "listen failed");
94 
95 	pid = fork();
96 	if (pid < 0) {
97 		err(1, "fork failed");
98 	} else if (pid == 0) {
99 		connect_client(port);
100 		abort();
101 	}
102 
103 	s = accept(serv_s, NULL, NULL);
104 	if (s < 0) {
105 		warn("accept failed");
106 		goto done;
107 	}
108 	panic = 1;
109 
110 	clock_gettime(CLOCK_MONOTONIC, &stime);
111 	n = read(s, &dummy, sizeof(dummy));
112 	if (n < 0) {
113 		warn("read failed");
114 		goto done;
115 	} else if (n != sizeof(dummy)) {
116 		warnx("read size mismatch");
117 		goto done;
118 	}
119 	clock_gettime(CLOCK_MONOTONIC, &etime);
120 
121 	if (etime.tv_sec - stime.tv_sec < READ_WAIT_MIN) {
122 		warnx("invalid wait time %ld", etime.tv_sec - stime.tv_sec);
123 		goto done;
124 	}
125 
126 	ex = 0;
127 	panic = 0;
128 	fprintf(stderr, "passed\n");
129 done:
130 	kill(pid, SIGKILL);
131 	waitpid(pid, &status, 0);
132 	if (panic)
133 		abort();
134 	exit(ex);
135 }
136