#include <folly/net/NetOps.h>
#include <fcntl.h>
#include <cerrno>
#ifdef __EMSCRIPTEN__
#include <cassert>
#endif
#include <cstddef>
#include <stdexcept>
#include <folly/CPortability.h>
#include <folly/ScopeGuard.h>
#include <folly/Utility.h>
#include <folly/net/detail/SocketFileDescriptorMap.h>
#ifdef _WIN32
#include <MSWSock.h>
#endif
#if (defined(__linux__) && !defined(__ANDROID__)) || \
(defined(__ANDROID__) && __ANDROID_API__ >= 21 ) || \
defined(__FreeBSD__) || defined(__SGX__) || defined(__EMSCRIPTEN__)
static_assert(folly::to_bool(::recvmmsg));
static_assert(folly::to_bool(::sendmmsg));
#else
static int (*recvmmsg)(...) = …;
static int (*sendmmsg)(...) = …;
#endif
namespace folly {
namespace netops {
namespace {
#ifdef _WIN32
static struct WinSockInit {
WinSockInit() {
WSADATA dat;
WSAStartup(MAKEWORD(2, 2), &dat);
}
~WinSockInit() { WSACleanup(); }
} winsockInit;
static int wsa_error_translator_base(
NetworkSocket, intptr_t, intptr_t, int wsaErr) {
switch (wsaErr) {
case WSAEWOULDBLOCK:
return EAGAIN;
default:
return wsaErr;
}
}
wsa_error_translator_ptr wsa_error_translator = wsa_error_translator_base;
#define translate_wsa_error …
#endif
template <class R, class F, class... Args>
static R wrapSocketFunction(F f, NetworkSocket s, Args... args) { … }
}
#ifdef _WIN32
void set_wsa_error_translator(
wsa_error_translator_ptr translator,
wsa_error_translator_ptr* previousOut) {
PVOID result = nullptr;
do {
*previousOut = wsa_error_translator;
result = InterlockedCompareExchangePointer(
reinterpret_cast<PVOID volatile*>(&wsa_error_translator),
reinterpret_cast<PVOID>(translator),
reinterpret_cast<PVOID>(*previousOut));
} while (result != reinterpret_cast<PVOID>(*previousOut));
}
#endif
NetworkSocket accept(NetworkSocket s, sockaddr* addr, socklen_t* addrlen) { … }
int bind(NetworkSocket s, const sockaddr* name, socklen_t namelen) { … }
int close(NetworkSocket s) { … }
int connect(NetworkSocket s, const sockaddr* name, socklen_t namelen) { … }
int getpeername(NetworkSocket s, sockaddr* name, socklen_t* namelen) { … }
int getsockname(NetworkSocket s, sockaddr* name, socklen_t* namelen) { … }
int getsockopt(
NetworkSocket s, int level, int optname, void* optval, socklen_t* optlen) { … }
int inet_aton(const char* cp, in_addr* inp) { … }
int listen(NetworkSocket s, int backlog) { … }
int poll(PollDescriptor fds[], nfds_t nfds, int timeout) { … }
ssize_t recv(NetworkSocket s, void* buf, size_t len, int flags) { … }
#ifdef _WIN32
ssize_t wsaRecvMesg(NetworkSocket s, WSAMSG* wsaMsg) {
SOCKET h = s.data;
LPFN_WSARECVMSG WSARecvMsg;
GUID WSARecgMsg_GUID = WSAID_WSARECVMSG;
DWORD recMsgBytes;
WSAIoctl(
h,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecgMsg_GUID,
sizeof(WSARecgMsg_GUID),
&WSARecvMsg,
sizeof(WSARecvMsg),
&recMsgBytes,
nullptr,
nullptr);
BOOL connReset = false;
DWORD bytesReturned = 0;
WSAIoctl(
h,
SIO_UDP_CONNRESET,
&connReset,
sizeof(connReset),
nullptr,
0,
&bytesReturned,
nullptr,
nullptr);
DWORD bytesReceived;
int res = WSARecvMsg(h, wsaMsg, &bytesReceived, nullptr, nullptr);
errno = translate_wsa_error(WSAGetLastError(), s, WSARecvMsg, res);
if (res == 0) {
return bytesReceived;
}
if ((wsaMsg->dwFlags & MSG_TRUNC) == MSG_TRUNC) {
return wsaMsg->lpBuffers[0].len + 1;
}
return -1;
}
#endif
ssize_t recvfrom(
NetworkSocket s,
void* buf,
size_t len,
int flags,
sockaddr* from,
socklen_t* fromlen) { … }
ssize_t recvmsg(NetworkSocket s, msghdr* message, int flags) { … }
int recvmmsg(
NetworkSocket s,
mmsghdr* msgvec,
unsigned int vlen,
unsigned int flags,
timespec* timeout) { … }
ssize_t send(NetworkSocket s, const void* buf, size_t len, int flags) { … }
[[maybe_unused]] static ssize_t fakeSendmsg(
[[maybe_unused]] NetworkSocket socket,
[[maybe_unused]] const msghdr* message) { … }
#ifdef _WIN32
[[maybe_unused]] ssize_t wsaSendMsgDirect(
[[maybe_unused]] NetworkSocket socket, [[maybe_unused]] WSAMSG* msg) {
if (msg->Control.len == 0) {
msg->Control.buf = nullptr;
}
SOCKET h = socket.data;
DWORD bytesSent;
auto ret = WSASendMsg(h, msg, 0, &bytesSent, nullptr, nullptr);
errno = translate_wsa_error(WSAGetLastError(), socket, WSASendMsg, ret);
return ret == 0 ? (ssize_t)bytesSent : -1;
}
#endif
[[maybe_unused]] static ssize_t wsaSendMsg(
[[maybe_unused]] NetworkSocket socket,
[[maybe_unused]] const msghdr* message,
[[maybe_unused]] int flags) { … }
ssize_t sendmsg(NetworkSocket socket, const msghdr* message, int flags) { … }
int sendmmsg(
NetworkSocket socket, mmsghdr* msgvec, unsigned int vlen, int flags) { … }
ssize_t sendto(
NetworkSocket s,
const void* buf,
size_t len,
int flags,
const sockaddr* to,
socklen_t tolen) { … }
int setsockopt(
NetworkSocket s,
int level,
int optname,
const void* optval,
socklen_t optlen) { … }
int shutdown(NetworkSocket s, int how) { … }
NetworkSocket socket(int af, int type, int protocol) { … }
#ifdef _WIN32
static int socketpair_win32(
int family, int type, int protocol, intptr_t fd[2]) {
intptr_t listener = -1;
intptr_t connector = -1;
intptr_t acceptor = -1;
struct sockaddr_in listen_addr;
struct sockaddr_in connect_addr;
int size;
int saved_errno = -1;
int family_test;
family_test = family != AF_INET && (family != AF_UNIX);
if (protocol || family_test) {
WSASetLastError(WSAEAFNOSUPPORT);
return -1;
}
if (!fd) {
WSASetLastError(WSAEINVAL);
return -1;
}
listener = ::socket(AF_INET, type, 0);
if (listener < 0) {
return -1;
}
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
listen_addr.sin_port = 0;
if (::bind(listener, (struct sockaddr*)&listen_addr, sizeof(listen_addr)) ==
-1) {
goto tidy_up_and_fail;
}
if (::listen(listener, 1) == -1) {
goto tidy_up_and_fail;
}
connector = ::socket(AF_INET, type, 0);
if (connector < 0) {
goto tidy_up_and_fail;
}
memset(&connect_addr, 0, sizeof(connect_addr));
size = sizeof(connect_addr);
if (::getsockname(listener, (struct sockaddr*)&connect_addr, &size) == -1) {
goto tidy_up_and_fail;
}
if (size != sizeof(connect_addr)) {
goto abort_tidy_up_and_fail;
}
if (::connect(
connector, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) ==
-1) {
goto tidy_up_and_fail;
}
size = sizeof(listen_addr);
acceptor = ::accept(listener, (struct sockaddr*)&listen_addr, &size);
if (acceptor < 0) {
goto tidy_up_and_fail;
}
if (size != sizeof(listen_addr)) {
goto abort_tidy_up_and_fail;
}
if (::getsockname(connector, (struct sockaddr*)&connect_addr, &size) == -1) {
goto tidy_up_and_fail;
}
if (size != sizeof(connect_addr) ||
listen_addr.sin_family != connect_addr.sin_family ||
listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr ||
listen_addr.sin_port != connect_addr.sin_port) {
goto abort_tidy_up_and_fail;
}
::closesocket(listener);
fd[0] = connector;
fd[1] = acceptor;
return 0;
abort_tidy_up_and_fail:
saved_errno = WSAECONNABORTED;
tidy_up_and_fail:
if (saved_errno < 0) {
saved_errno = WSAGetLastError();
}
if (listener != -1) {
::closesocket(listener);
}
if (connector != -1) {
::closesocket(connector);
}
if (acceptor != -1) {
::closesocket(acceptor);
}
WSASetLastError(saved_errno);
return -1;
}
#endif
int socketpair(int domain, int type, int protocol, NetworkSocket sv[2]) { … }
int set_socket_non_blocking(NetworkSocket s) { … }
int set_socket_close_on_exec(NetworkSocket s) { … }
void Msgheader::setName(sockaddr_storage* addrStorage, size_t len) { … }
void Msgheader::setIovecs(const struct iovec* vec, size_t iovec_len) { … }
void Msgheader::setCmsgPtr(char* ctrlBuf) { … }
void Msgheader::setCmsgLen(size_t len) { … }
void Msgheader::setFlags(int flags) { … }
void Msgheader::incrCmsgLen(size_t val) { … }
XPLAT_CMSGHDR* Msgheader::getFirstOrNextCmsgHeader(XPLAT_CMSGHDR* cm) { … }
XPLAT_MSGHDR* Msgheader::getMsg() { … }
XPLAT_CMSGHDR* Msgheader::cmsgNextHrd(XPLAT_CMSGHDR* cm) { … }
XPLAT_CMSGHDR* Msgheader::cmsgFirstHrd() { … }
}
}