This uses Apple's connectx() API instead of UNIX connect() API.
Signed-off-by: Karel Bilek <kb@karelbilek.com>
try {
setDscp(fd, d_config.remote.sin4.sin_family, d_config.dscp);
- SConnect(fd, d_config.remote);
+ SConnect(fd, d_config.tcpFastOpen, d_config.remote);
if (sockets.size() > 1) {
(*mplexer.lock())->addReadFD(fd, [](int, boost::any) {});
}
cerr << "Unable to connect to " << server.toStringWithPort() << endl;
return;
}
- SConnect(fileDesc.getHandle(), server);
+ SConnect(fileDesc.getHandle(), false, server);
setTCPNoDelay(fileDesc.getHandle());
dnsdist::crypto::authenticated::Nonce theirs;
dnsdist::crypto::authenticated::Nonce ours;
#include "doq-common.hh"
#include "dolog.hh"
#include "threadname.hh"
+#include "iputils.hh"
#ifdef HAVE_LIBSSL
#include "libssl.hh"
bool fastOpen{false};
if (getOptionalValue<bool>(vars, "tcpFastOpen", fastOpen) > 0) {
if (fastOpen) {
-#ifdef MSG_FASTOPEN
+#if defined(MSG_FASTOPEN) || defined(CONNECTX_FASTOPEN)
config.tcpFastOpen = true;
#else
warnlog("TCP Fast Open has been configured on downstream server %s but is not supported", serverAddressStr);
ComboAddress addr("[2001:db8:53::1]:53");
auto socket = std::make_unique<Socket>(addr.sin4.sin_family, SOCK_STREAM, 0);
socket->setNonBlocking();
- int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0});
+ int res = SConnectWithTimeout(socket->getHandle(), false, addr, timeval{0, 0});
if (res == 0 || res == EINPROGRESS) {
return true;
}
ComboAddress addr("[2001:db8:53::1]:53");
auto socket = std::make_unique<Socket>(addr.sin4.sin_family, SOCK_STREAM, 0);
socket->setNonBlocking();
- int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0});
+ int res = SConnectWithTimeout(socket->getHandle(), false, addr, timeval{0, 0});
if (res == 0 || res == EINPROGRESS) {
return true;
}
return ret;
}
-int SConnect(int sockfd, const ComboAddress& remote)
+static int doConnect(int sockfd, [[maybe_unused]] bool fastopen, const ComboAddress& remote)
{
- int ret = connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+#ifdef CONNECTX_FASTOPEN
+ if (fastopen) {
+ sa_endpoints_t endpoints{};
+
+ endpoints.sae_dstaddr = reinterpret_cast<const struct sockaddr*>(&remote); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+ endpoints.sae_dstaddrlen = remote.getSocklen();
+
+ int flags = CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE;
+ return connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, flags, nullptr, 0, nullptr, nullptr);
+ }
+ else {
+#endif
+ return connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+#ifdef CONNECTX_FASTOPEN
+ }
+#endif
+}
+
+int SConnect(int sockfd, bool fastopen, const ComboAddress& remote)
+{
+ int ret = doConnect(sockfd, fastopen, remote);
if (ret < 0) {
int savederrno = errno;
RuntimeError("connecting socket to " + remote.toStringWithPort() + ": " + stringerror(savederrno));
return ret;
}
-int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout)
+int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout)
{
- int ret = connect(sockfd, reinterpret_cast<const struct sockaddr*>(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
+ int ret = doConnect(sockfd, fastopen, remote);
if (ret < 0) {
int savederrno = errno;
if (savederrno == EINPROGRESS) {
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
+
+#if defined(CONNECT_DATA_IDEMPOTENT) && defined(CONNECT_RESUME_ON_READ_WRITE)
+#define CONNECTX_FASTOPEN 1
+#endif
+
#endif
#ifdef __sun
};
int SSocket(int family, int type, int flags);
-int SConnect(int sockfd, const ComboAddress& remote);
+int SConnect(int sockfd, bool fastopen, const ComboAddress& remote);
/* tries to connect to remote for a maximum of timeout seconds.
sockfd should be set to non-blocking beforehand.
returns 0 on success (the socket is writable), throw a
runtime_error otherwise */
-int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout);
+int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout);
int SBind(int sockfd, const ComboAddress& local);
int SAccept(int sockfd, ComboAddress& remote);
int SListen(int sockfd, int limit);
//! Connect the socket to a specified endpoint
void connect(const ComboAddress& address, int timeout = 0) const
{
- SConnectWithTimeout(d_socket, address, timeval{timeout, 0});
+ SConnectWithTimeout(d_socket, false, address, timeval{timeout, 0});
}
//! For datagram sockets, receive a datagram and learn where it came from
}
else {
if (!s_disableConnectForUnitTests) {
- SConnectWithTimeout(d_socket, remote, /* no timeout, we will handle it ourselves */ timeval{0,0});
+ SConnectWithTimeout(d_socket, fastOpen, remote, /* no timeout, we will handle it ourselves */ timeval{0,0});
}
}
#else
if (!s_disableConnectForUnitTests) {
- SConnectWithTimeout(d_socket, remote, /* no timeout, we will handle it ourselves */ timeval{0,0});
+ SConnectWithTimeout(d_socket, fastOpen, remote, /* no timeout, we will handle it ourselves */ timeval{0,0});
}
#endif /* MSG_FASTOPEN */
}
else {
if (!s_disableConnectForUnitTests) {
- SConnectWithTimeout(d_socket, remote, timeout);
+ SConnectWithTimeout(d_socket, fastOpen, remote, timeout);
}
}
#else
if (!s_disableConnectForUnitTests) {
- SConnectWithTimeout(d_socket, remote, timeout);
+ SConnectWithTimeout(d_socket, fastOpen, remote, timeout);
}
#endif /* MSG_FASTOPEN */