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