From 7d436179938f59e79cad5f40ba793859f9507049 Mon Sep 17 00:00:00 2001 From: "gavin.smith@coralbay.tv" Date: Sun, 30 Dec 2018 00:25:11 +0000 Subject: [PATCH] Added support for TCP Fast Open in server when using Linux. --- server_http.hpp | 10 ++++++++++ utility.hpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/server_http.hpp b/server_http.hpp index f49c41d..5d3ba4f 100644 --- a/server_http.hpp +++ b/server_http.hpp @@ -351,6 +351,8 @@ namespace SimpleWeb { std::string address; /// Set to false to avoid binding the socket to an address that is already in use. Defaults to true. bool reuse_address = true; + /// Makes use of RFC 7413 or TCP Fast Open (TFO) + bool fast_open = false; }; /// Set before calling start(). Config config; @@ -399,6 +401,14 @@ namespace SimpleWeb { acceptor = std::unique_ptr(new asio::ip::tcp::acceptor(*io_service)); acceptor->open(endpoint.protocol()); acceptor->set_option(asio::socket_base::reuse_address(config.reuse_address)); + if (config.fast_open && is_tcp_fast_open_supported(connection_mode::server)) + { +#if defined(__linux__) && defined(TCP_FASTOPEN) + const int qlen = 5; // This seems to be the value that is used in other examples. + boost::system::error_code ec; + acceptor->set_option(boost::asio::detail::socket_option::integer(qlen), ec); +#endif // End Linux + } acceptor->bind(endpoint); after_bind(); diff --git a/utility.hpp b/utility.hpp index d98ed41..0e4ee3c 100644 --- a/utility.hpp +++ b/utility.hpp @@ -8,6 +8,10 @@ #include #include #include +#if defined(__linux__) +#include +#include +#endif #if __cplusplus > 201402L || _MSVC_LANG > 201402L #include @@ -26,6 +30,35 @@ namespace SimpleWeb { #endif namespace SimpleWeb { + enum class connection_mode { client = 1, server = 2 }; + inline bool is_tcp_fast_open_supported(const connection_mode mode) + { +#if defined(__linux__) + std::ifstream ifs("/proc/sys/net/ipv4/tcp_fastopen"); + if (!ifs.is_open()) { return false; } + std::string line; + if (!std::getline(ifs, line)) { return false; } + std::istringstream iss(line); + uint8_t value = 0; + iss >> value; + if (iss.fail()) { return false; } // Should never happen in theory. + auto mode_matches_request = [](const connection_mode mode, const uint8_t value) + { + const auto m = static_cast(mode); + if (mode == connection_mode::client || + mode == connection_mode::server) + { + return (m & value) != 0; + } + return false; + }; + return mode_matches_request(mode, value); +#else + (void)mode; + return false; +#endif + } + inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept { return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {