From 18417582b74eae55180c2f485784575ad56b3f75 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Tue, 5 Nov 2019 10:31:02 +0100 Subject: Add url handler for seqnum_server --- url_handler/handler.cpp | 146 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 url_handler/handler.cpp (limited to 'url_handler/handler.cpp') diff --git a/url_handler/handler.cpp b/url_handler/handler.cpp new file mode 100644 index 0000000..b202d5b --- /dev/null +++ b/url_handler/handler.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include +#include +#include "handler.h" + +using namespace std; + + +static string shell_escape(const string &str) { + string res; + res.reserve(str.size() + 16); + res += '\''; + + for (char c : str) { + if (c == '\'') res += "'\"'\"'"; + else res += c; + } + + res += '\''; + return res; +} + +static string read_file(const string &fname) { + ifstream f(fname); + if (!f) return {}; + + string contents; + char buffer[4096]; + while (true) { + f.read(buffer, sizeof buffer); + contents.insert(contents.size(), buffer, f.gcount()); + if (!f) break; + } + + return contents; +} + +static string download_url(const string &url) { + string tempdir_name = "/tmp/tmp.url_handler.XXXXXX"; + if (mkdtemp(tempdir_name.data()) == nullptr) { + perror("mkdtemp"); + return {}; + } + + string tempfile_name = tempdir_name + "/file"; + + string cmd = "curl -sL " + shell_escape(url) + " >" + shell_escape(tempfile_name); + // fprintf(stderr, "cmd = %s\n", cmd.data()); + + system(cmd.data()); + + string response = read_file(tempfile_name); + filesystem::remove_all(tempdir_name); + + fprintf(stderr, "Received response for url '%s'\n", url.data()); + + return response; +} + +struct State { + string url; + + thread download_thread; + + // mutex protects 'response' and 'response_present'; the download thread + // sets 'response_present' to true and simultaneously 'response' to the + // right value. After 'response_present' can be observed to be true by the + // main thread, the download thread doesn't touch anything anymore. + mutex res_mt; + bool response_present = false; + string response; + + // owned by host thread + size_t rescur = 0; +}; + +static unordered_map> state_map; + +uint16_t handle_icmp(uint32_t source_addr, const array &payload) { + auto state_it = state_map.find(source_addr); + if (state_it == state_map.end()) { + state_it = state_map.emplace(source_addr, make_unique()).first; + } + State &state = *state_it->second; + + switch (payload[0]) { + case 100: // url fragment + // fprintf(stderr, "msg(%u): url fragment\n", source_addr); + { + lock_guard guard(state.res_mt); + if (state.response_present) return 0; + } + for (size_t i = 1; i < 16; i++) { + if (payload[i] == '\0') { + fprintf(stderr, "URL received: <%s>\n", state.url.data()); + state.download_thread = thread([&state]() { + string response = download_url(state.url); + + { + lock_guard guard(state.res_mt); + state.response = move(response); + state.response_present = true; + } + + // fprintf(stderr, "[dlth] response received: <%s>\n", state.response.data()); + }); + break; + } + state.url.push_back(payload[i]); + } + return 1; + + case 101: { // query whether response is ready + // fprintf(stderr, "msg(%u): ready query\n", source_addr); + lock_guard guard(state.res_mt); + return state.response_present ? 1 : 0; + } + + case 102: { // get response + // fprintf(stderr, "msg(%u): get_response\n", source_addr); + { + lock_guard guard(state.res_mt); + if (!state.response_present) return 0; + } + + uint16_t retval = 0; + for (size_t i = 0; i < 2 && state.rescur < state.response.size(); i++) { + retval |= (uint16_t)state.response[state.rescur] << (8 * i); + state.rescur++; + } + + if (state.rescur == state.response.size()) { + state.download_thread.join(); // should already have exited + state_map.erase(state_it); + } + // fprintf(stderr, " -> retval %016X\n", (unsigned)retval); + return retval; + } + } + + return 0; +} -- cgit v1.2.3-70-g09d2