From 81c41bdfdc56f05973fae70e80e80919f18f50c9 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Mon, 29 Aug 2022 19:28:34 +0000 Subject: SERVER-69175 transport::SocketOption class template This reverts commit 0fbba9495da3c621deddbee47cff3fda00b07bec. ifdef TCP_USER_TIMEOUT --- src/mongo/transport/asio_utils.h | 67 ++++++++++++++++++++++++++++ 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; + * ... + * TcpInfoOption tcpiOption; + * socket.get_option(tcpiOption); + * tcp_info& infoOut = *tcpiOption; + */ +template +class SocketOption { +public: + SocketOption() = default; + explicit SocketOption(T d) : _data{std::move(d)} {} + template + int level(const Protocol&) const { + return optLevel; + } + template + int name(const Protocol&) const { + return optName; + } + template + T* data(const Protocol&) { + return &**this; + } + template + const T* data(const Protocol&) const { + return &**this; + } + template + size_t size(const Protocol&) const { + return sizeof(_data); + } + template + 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 #include +#ifdef __linux__ +#include +#endif + #include #include #include @@ -81,8 +85,20 @@ namespace mongo { namespace transport { namespace { + +using TcpKeepaliveOption = SocketOption; +#ifdef __linux__ +using TcpInfoOption = SocketOption; +using TcpKeepaliveCountOption = SocketOption; +using TcpKeepaliveIdleSecsOption = SocketOption; +using TcpKeepaliveIntervalSecsOption = SocketOption; +#ifdef TCP_USER_TIMEOUT +using TcpUserTimeoutMillisOption = SocketOption; +#endif +#endif // __linux__ + #ifdef TCP_FASTOPEN -using TCPFastOpen = asio::detail::socket_option::integer; +using TcpFastOpenOption = SocketOption; #endif /** * On systems with TCP_FASTOPEN_CONNECT (linux >= 4.11), @@ -92,7 +108,7 @@ using TCPFastOpen = asio::detail::socket_option::integer; +using TcpFastOpenConnectOption = SocketOption; #endif /** @@ -682,7 +698,7 @@ StatusWith 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 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 -- cgit v1.2.1