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