#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define WRITE_WAIT_TIME 8 /* unit: sec */ #define READ_WAIT_MIN 6 /* unit: sec */ static void usage(const char *cmd) { fprintf(stderr, "%s -p port\n", cmd); exit(1); } static void connect_client(int port, int ctrl_s) { struct sockaddr_in in; int s, dummy; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) err(1, "client socket failed"); memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); in.sin_port = htons(port); if (connect(s, (const struct sockaddr *)&in, sizeof(in)) < 0) err(1, "connect failed"); /* Make sure server side compltes the 3-way handshake */ sleep(1); /* connect is done */ write(ctrl_s, &dummy, sizeof(dummy)); sleep(WRITE_WAIT_TIME); write(s, &dummy, sizeof(dummy)); pause(); exit(0); } int main(int argc, char *argv[]) { struct sockaddr_in in; int serv_s, s, ctrl_s[2]; int opt, port, dummy, n, status, panic, ex; struct timespec stime, etime; pid_t pid; ex = 1; panic = 0; port = 0; while ((opt = getopt(argc, argv, "p:")) != -1) { char *endptr; switch (opt) { case 'p': port = strtol(optarg, &endptr, 0); if (*endptr != '\0') errx(1, "invalid -p"); break; default: usage(argv[0]); } } if (port <= 0) usage(argv[0]); if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ctrl_s) < 0) err(1, "socketpair failed"); serv_s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (serv_s < 0) err(1, "socket failed"); memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); if (bind(serv_s, (const struct sockaddr *)&in, sizeof(in)) < 0) err(1, "bind failed"); if (listen(serv_s, 0) < 0) err(1, "listen failed"); pid = fork(); if (pid < 0) { err(1, "fork failed"); } else if (pid == 0) { close(ctrl_s[0]); connect_client(port, ctrl_s[1]); abort(); } /* Wait for the connect */ read(ctrl_s[0], &dummy, sizeof(dummy)); s = accept4(serv_s, NULL, NULL, 0); if (s < 0) { warn("accept4 failed"); goto done; } panic = 1; clock_gettime(CLOCK_MONOTONIC, &stime); n = read(s, &dummy, sizeof(dummy)); if (n < 0) { warn("read failed"); goto done; } else if (n != sizeof(dummy)) { warnx("read size mismatch"); goto done; } clock_gettime(CLOCK_MONOTONIC, &etime); if (etime.tv_sec - stime.tv_sec < READ_WAIT_MIN) { warnx("invalid wait time %ld", etime.tv_sec - stime.tv_sec); goto done; } ex = 0; panic = 0; fprintf(stderr, "passed\n"); done: kill(pid, SIGKILL); waitpid(pid, &status, 0); if (panic) abort(); exit(ex); }