summaryrefslogtreecommitdiff
path: root/url_handler/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'url_handler/main.cpp')
-rw-r--r--url_handler/main.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/url_handler/main.cpp b/url_handler/main.cpp
new file mode 100644
index 0000000..47166db
--- /dev/null
+++ b/url_handler/main.cpp
@@ -0,0 +1,159 @@
+#include <vector>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <cstdio>
+#include <cstring>
+#include <cassert>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include "handler.h"
+
+using namespace std;
+
+
+struct Pipes {
+ int rfd, wfd;
+};
+
+static pair<pid_t, Pipes> start_process(const vector<string> &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<char*> 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<string> 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<uint8_t, 16> 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;
+}