#include <folly/detail/SocketFastOpen.h>
#include <cerrno>
#include <cstdio>
#include <fstream>
#include <folly/portability/Sockets.h>
namespace folly {
namespace detail {
#if FOLLY_ALLOW_TFO && defined(__linux__)
#if !defined(MSG_FASTOPEN)
#define MSG_FASTOPEN …
#endif
#if !defined(TCP_FASTOPEN)
#define TCP_FASTOPEN …
#endif
#if !defined(TCPI_OPT_SYN_DATA)
#define TCPI_OPT_SYN_DATA …
#endif
ssize_t tfo_sendmsg(NetworkSocket sockfd, const struct msghdr* msg, int flags) {
flags |= MSG_FASTOPEN;
return netops::sendmsg(sockfd, msg, flags);
}
int tfo_enable(NetworkSocket sockfd, size_t max_queue_size) {
return netops::setsockopt(
sockfd, SOL_TCP, TCP_FASTOPEN, &max_queue_size, sizeof(max_queue_size));
}
bool tfo_succeeded(NetworkSocket sockfd) {
struct tcp_info info;
socklen_t info_len = sizeof(info);
errno = 0;
if (netops::getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, &info_len) !=
0) {
return false;
}
return info.tcpi_options & TCPI_OPT_SYN_DATA;
}
PlatformTFOSettings tfo_platform_availability() {
static PlatformTFOSettings TFOSettings = [] {
size_t fastOpen = 0;
try {
std::ifstream ifs("/proc/sys/net/ipv4/tcp_fastopen");
if (ifs.is_open()) {
ifs >> fastOpen;
}
} catch (std::exception&) {
}
PlatformTFOSettings settings{};
if ((fastOpen & 1) == 0) {
settings.client = TFOAvailability::None;
} else if ((fastOpen & 4) == 0) {
settings.client = TFOAvailability::WithCookies;
} else {
settings.client = TFOAvailability::Unconditional;
}
if ((fastOpen & 2) == 0) {
settings.server = TFOAvailability::None;
} else if ((fastOpen & 0x200) == 0) {
settings.server = TFOAvailability::WithCookies;
} else {
settings.server = TFOAvailability::Unconditional;
}
return settings;
}();
return TFOSettings;
}
#elif FOLLY_ALLOW_TFO && defined(__APPLE__)
ssize_t tfo_sendmsg(NetworkSocket sockfd, const struct msghdr* msg, int flags) { … }
int tfo_enable(NetworkSocket sockfd, size_t max_queue_size) { … }
bool tfo_succeeded(NetworkSocket ) { … }
PlatformTFOSettings tfo_platform_availability() { … }
#else
ssize_t tfo_sendmsg(
NetworkSocket ,
const struct msghdr* ,
int ) {
errno = EOPNOTSUPP;
return -1;
}
int tfo_enable(NetworkSocket , size_t ) {
errno = ENOPROTOOPT;
return -1;
}
bool tfo_succeeded(NetworkSocket ) {
errno = EOPNOTSUPP;
return false;
}
PlatformTFOSettings tfo_platform_availability() {
static PlatformTFOSettings TFOSettings{
TFOAvailability::None, TFOAvailability::None};
return TFOSettings;
}
#endif
}
}