diff options
-rw-r--r-- | src/mongo/transport/asio_utils.h | 67 | ||||
-rw-r--r-- | src/mongo/transport/transport_layer_asio.cpp | 37 |
2 files changed, 94 insertions, 10 deletions
diff --git a/src/mongo/transport/asio_utils.h b/src/mongo/transport/asio_utils.h index e786d9f7eb9..7590c3ddfd6 100644 --- a/src/mongo/transport/asio_utils.h +++ b/src/mongo/transport/asio_utils.h @@ -51,6 +51,73 @@ namespace mongo::transport { +/** + * Generic wrapper for making an ASIO socket get_option or set_option call + * having a payload of type `T`, which is usually just `int` so it's the default. + * Can be value-initializd with a `T`. A reference to the payload is available + * using the dereferencing operators. + * + * Models Asio GettableSocketOption and SettableSocketOption. + * https://www.boost.org/doc/libs/1_80_0/doc/html/boost_asio/reference/GettableSocketOption.html + * https://www.boost.org/doc/libs/1_80_0/doc/html/boost_asio/reference/SettableSocketOption.html + * + * The Asio-required accessors must accept a `Protocol` argument, which we ignore. + * The kinds of options we use don't need it. + * https://www.boost.org/doc/libs/1_80_0/doc/html/boost_asio/reference/Protocol.html + * + * Example: + * using TcpInfoOption = SocketOption<IPPROTO_TCP, TCP_INFO, tcp_info>; + * ... + * TcpInfoOption tcpiOption; + * socket.get_option(tcpiOption); + * tcp_info& infoOut = *tcpiOption; + */ +template <int optLevel, int optName, typename T = int> +class SocketOption { +public: + SocketOption() = default; + explicit SocketOption(T d) : _data{std::move(d)} {} + template <typename Protocol> + int level(const Protocol&) const { + return optLevel; + } + template <typename Protocol> + int name(const Protocol&) const { + return optName; + } + template <typename Protocol> + T* data(const Protocol&) { + return &**this; + } + template <typename Protocol> + const T* data(const Protocol&) const { + return &**this; + } + template <typename Protocol> + size_t size(const Protocol&) const { + return sizeof(_data); + } + template <typename Protocol> + void resize(const Protocol&, size_t) const {} + + T& operator*() { + return _data; + } + const T& operator*() const { + return _data; + } + + T* operator->() { + return &**this; + } + const T* operator->() const { + return &**this; + } + +private: + T _data{}; +}; + inline SockAddr endpointToSockAddr(const asio::generic::stream_protocol::endpoint& endPoint) { SockAddr wrappedAddr(endPoint.data(), endPoint.size()); return wrappedAddr; diff --git a/src/mongo/transport/transport_layer_asio.cpp b/src/mongo/transport/transport_layer_asio.cpp index 59bdb1380ec..2d056e6c71b 100644 --- a/src/mongo/transport/transport_layer_asio.cpp +++ b/src/mongo/transport/transport_layer_asio.cpp @@ -35,6 +35,10 @@ #include <fmt/format.h> #include <fstream> +#ifdef __linux__ +#include <netinet/tcp.h> +#endif + #include <asio.hpp> #include <asio/system_timer.hpp> #include <boost/algorithm/string.hpp> @@ -81,8 +85,20 @@ namespace mongo { namespace transport { namespace { + +using TcpKeepaliveOption = SocketOption<SOL_SOCKET, SO_KEEPALIVE>; +#ifdef __linux__ +using TcpInfoOption = SocketOption<IPPROTO_TCP, TCP_INFO, tcp_info>; +using TcpKeepaliveCountOption = SocketOption<IPPROTO_TCP, TCP_KEEPCNT>; +using TcpKeepaliveIdleSecsOption = SocketOption<IPPROTO_TCP, TCP_KEEPIDLE>; +using TcpKeepaliveIntervalSecsOption = SocketOption<IPPROTO_TCP, TCP_KEEPINTVL>; +#ifdef TCP_USER_TIMEOUT +using TcpUserTimeoutMillisOption = SocketOption<IPPROTO_TCP, TCP_USER_TIMEOUT, unsigned>; +#endif +#endif // __linux__ + #ifdef TCP_FASTOPEN -using TCPFastOpen = asio::detail::socket_option::integer<IPPROTO_TCP, TCP_FASTOPEN>; +using TcpFastOpenOption = SocketOption<IPPROTO_TCP, TCP_FASTOPEN>; #endif /** * On systems with TCP_FASTOPEN_CONNECT (linux >= 4.11), @@ -92,7 +108,7 @@ using TCPFastOpen = asio::detail::socket_option::integer<IPPROTO_TCP, TCP_FASTOP * https://github.com/torvalds/linux/commit/19f6d3f3c8422d65b5e3d2162e30ef07c6e21ea2 */ #ifdef TCP_FASTOPEN_CONNECT -using TCPFastOpenConnect = asio::detail::socket_option::boolean<IPPROTO_TCP, TCP_FASTOPEN_CONNECT>; +using TcpFastOpenConnectOption = SocketOption<IPPROTO_TCP, TCP_FASTOPEN_CONNECT>; #endif /** @@ -682,7 +698,7 @@ StatusWith<TransportLayerASIO::ASIOSessionHandle> TransportLayerASIO::_doSyncCon const auto family = protocol.family(); if ((family == AF_INET) || (family == AF_INET6)) { setSocketOption(sock, - TCPFastOpenConnect(gTCPFastOpenClient), + TcpFastOpenConnectOption(gTCPFastOpenClient), "connect (sync) TCP fast open", logv2::LogSeverity::Info(), ec); @@ -868,7 +884,7 @@ Future<SessionHandle> TransportLayerASIO::asyncConnect( #ifdef TCP_FASTOPEN_CONNECT std::error_code ec; setSocketOption(connector->socket, - TCPFastOpenConnect(gTCPFastOpenClient), + TcpFastOpenConnectOption(gTCPFastOpenClient), "connect (async) TCP fast open", logv2::LogSeverity::Info(), ec); @@ -1208,7 +1224,7 @@ Status TransportLayerASIO::setup() { #ifdef TCP_FASTOPEN if (gTCPFastOpenServer && ((addr.family() == AF_INET) || (addr.family() == AF_INET6))) { setSocketOption(acceptor, - TCPFastOpen(gTCPFastOpenQueueSize), + TcpFastOpenOption(gTCPFastOpenQueueSize), "acceptor TCP fast open", logv2::LogSeverity::Info(), ec); @@ -1433,11 +1449,12 @@ void TransportLayerASIO::_acceptConnection(GenericAcceptor& acceptor) { } #ifdef TCPI_OPT_SYN_DATA - struct tcp_info info; - socklen_t info_len = sizeof(info); - if (!getsockopt(peerSocket.native_handle(), IPPROTO_TCP, TCP_INFO, &info, &info_len) && - (info.tcpi_options & TCPI_OPT_SYN_DATA)) { - networkCounter.acceptedTFOIngress(); + try { + TcpInfoOption tcpi{}; + peerSocket.get_option(tcpi); + if (tcpi->tcpi_options & TCPI_OPT_SYN_DATA) + networkCounter.acceptedTFOIngress(); + } catch (const asio::system_error&) { } #endif |