summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/transport/asio_utils.h67
-rw-r--r--src/mongo/transport/transport_layer_asio.cpp37
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