#include #include #include #include #include #include #include #include #include #include #include #include "handler.h" using namespace std; struct Pipes { int rfd, wfd; }; static pair start_process(const vector &cmd) { int host2child[2], child2host[2]; if (pipe(host2child) < 0 || pipe(child2host) < 0) { perror("pipe"); exit(1); } pid_t pid = fork(); if (pid == 0) { close(host2child[1]); close(child2host[0]); dup2(host2child[0], STDIN_FILENO); dup2(child2host[1], STDOUT_FILENO); vector argv(cmd.size() + 1); for (size_t i = 0; i < cmd.size(); i++) { argv[i] = (char*)cmd[i].data(); fprintf(stderr, "argv[%zu] = %p (%s)\n", i, cmd[i].data(), cmd[i].data()); } argv[cmd.size()] = nullptr; execvp(argv[0], argv.data()); perror("execvp"); exit(1); } if (pid < 0) { perror("fork"); exit(1); } close(host2child[0]); close(child2host[1]); return make_pair(pid, Pipes{child2host[0], host2child[1]}); } static bool poll_process_exited(pid_t pid) { int status; pid_t ret = waitpid(pid, &status, WNOHANG); if (ret == 0) return false; if (ret < 0) { if (errno == EINTR) return false; // wut? we said WNOHANG, right? perror("wait"); return true; } assert(ret == pid); return WIFEXITED(status); } static void wait_process_exited(pid_t pid) { while (true) { int status; pid_t ret = waitpid(pid, &status, 0); if (ret < 0) { if (errno == EINTR) continue; perror("wait"); exit(1); } if (ret == 0) continue; // wut? assert(ret == pid); if (WIFEXITED(pid)) break; } } int main(int argc, char **argv) { vector server_args(argc - 1); for (int i = 0; i < argc - 1; i++) server_args[i] = argv[i + 1]; // make sure we actually receive the signal signal(SIGCHLD, [](int) {}); pid_t child_pid; Pipes pipes; tie(child_pid, pipes) = start_process(server_args); int exit_code = 0; while (true) { fd_set inset; FD_ZERO(&inset); FD_SET(pipes.rfd, &inset); int ret = select(pipes.rfd + 1, &inset, nullptr, nullptr, nullptr); if (poll_process_exited(child_pid)) { child_pid = -1; goto exit_cleanup; } if (ret < 0) { if (errno == EINTR) continue; perror("select"); exit_code = 1; goto exit_cleanup; } if (FD_ISSET(pipes.rfd, &inset)) { uint8_t buffer[24]; size_t cursor = 0; while (cursor < 24) { ssize_t nread = read(pipes.rfd, buffer + cursor, 24 - cursor); if (nread < 0) { perror("read"); goto exit_cleanup; } cursor += nread; } if (memcmp(buffer, "payl", 4) != 0) { fprintf(stderr, "Invalid event message from server: id bytes '%c%c%c%c'\n", buffer[0], buffer[1], buffer[2], buffer[3]); fprintf(stderr, "<"); fwrite(buffer, 1, 24, stderr); fprintf(stderr, ">\n"); exit_code = 1; goto exit_cleanup; } uint32_t source_addr = *(uint32_t*)&buffer[4]; array payload; memcpy(payload.data(), &buffer[8], 16); uint16_t seqnum = handle_icmp(source_addr, payload); if (write(pipes.wfd, &seqnum, 2) != 2) { perror("write"); exit_code = 1; goto exit_cleanup; } } } exit_cleanup: if (child_pid != -1) { kill(child_pid, SIGTERM); wait_process_exited(child_pid); } return exit_code; }