diff options
| author | Tom Smeding <tom.smeding@gmail.com> | 2019-11-05 10:31:02 +0100 | 
|---|---|---|
| committer | Tom Smeding <tom.smeding@gmail.com> | 2019-11-05 10:32:46 +0100 | 
| commit | 18417582b74eae55180c2f485784575ad56b3f75 (patch) | |
| tree | 92dd3f0e80cc3e7b02f46485f1700ef2c598093c /url_handler/main.cpp | |
| parent | d179a5b469d609a7c7f15d841dfb95fe77b3125e (diff) | |
Diffstat (limited to 'url_handler/main.cpp')
| -rw-r--r-- | url_handler/main.cpp | 159 | 
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; +}  | 
