0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

SERVER-69175 transport::SocketOption class template

This commit is contained in:
Billy Donahue 2022-08-26 21:02:31 +00:00 committed by Evergreen Agent
parent 79d393bff2
commit a52ef30f9b
2 changed files with 92 additions and 10 deletions

View File

@ -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;

View File

@ -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,18 @@ 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>;
using TcpUserTimeoutMillisOption = SocketOption<IPPROTO_TCP, TCP_USER_TIMEOUT, unsigned>;
#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 +106,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 +696,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 +882,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 +1222,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 +1447,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