#include <folly/net/detail/SocketFileDescriptorMap.h>
#ifdef _WIN32
#include <shared_mutex>
#include <unordered_map>
#include <fcntl.h>
#define STATUS_HANDLE_NOT_CLOSABLE …
namespace folly {
namespace netops {
namespace detail {
namespace {
struct SyncSocketMap {
std::unordered_map<SOCKET, int> map;
std::shared_mutex mutex;
};
SyncSocketMap& getSyncSocketMap() {
static auto& instance = *new SyncSocketMap();
return instance;
}
}
static int closeOnlyFileDescriptor(int fd) {
HANDLE h = (HANDLE)_get_osfhandle(fd);
constexpr DWORD protectFlag = HANDLE_FLAG_PROTECT_FROM_CLOSE;
DWORD handleFlags = 0;
if (!GetHandleInformation(h, &handleFlags)) {
return -1;
}
if (!SetHandleInformation(h, protectFlag, protectFlag)) {
return -1;
}
int c = 0;
__try {
c = ::_close(fd);
} __except (
GetExceptionCode() == STATUS_HANDLE_NOT_CLOSABLE
? EXCEPTION_CONTINUE_EXECUTION
: EXCEPTION_CONTINUE_SEARCH) {
}
if (!SetHandleInformation(h, protectFlag, handleFlags)) {
return -1;
}
if (c != -1) {
return -1;
}
return 0;
}
int SocketFileDescriptorMap::close(int fd) noexcept {
auto hand = SocketFileDescriptorMap::fdToSocket(fd);
auto& smap = getSyncSocketMap();
{
std::unique_lock<std::shared_mutex> lock{smap.mutex};
smap.map.erase(hand);
}
auto r = closeOnlyFileDescriptor(fd);
if (r != 0) {
return r;
}
return closesocket((SOCKET)hand);
}
int SocketFileDescriptorMap::close(SOCKET sock) noexcept {
bool found = false;
int fd = 0;
auto& smap = getSyncSocketMap();
{
std::shared_lock<std::shared_mutex> lock{smap.mutex};
auto it = smap.map.find(sock);
if (it != smap.map.end()) {
found = true;
fd = it->second;
}
}
if (found) {
return SocketFileDescriptorMap::close(fd);
}
return closesocket(sock);
}
SOCKET SocketFileDescriptorMap::fdToSocket(int fd) noexcept {
if (fd == -1) {
return INVALID_SOCKET;
}
return (SOCKET)_get_osfhandle(fd);
}
int SocketFileDescriptorMap::socketToFd(SOCKET sock) noexcept {
if (sock == INVALID_SOCKET) {
return -1;
}
auto& smap = getSyncSocketMap();
{
std::shared_lock<std::shared_mutex> lock{smap.mutex};
auto const it = smap.map.find(sock);
if (it != smap.map.end()) {
return it->second;
}
}
std::unique_lock<std::shared_mutex> lock{smap.mutex};
auto const it = smap.map.find(sock);
if (it != smap.map.end()) {
return it->second;
}
int fd = _open_osfhandle((intptr_t)sock, O_RDWR | O_BINARY);
smap.map.emplace(sock, fd);
return fd;
}
}
}
}
#elif defined(__EMSCRIPTEN__)
#include <stdexcept>
namespace folly {
namespace netops {
namespace detail {
int SocketFileDescriptorMap::close(int fd) noexcept {
std::terminate();
}
int SocketFileDescriptorMap::fdToSocket(int fd) noexcept {
std::terminate();
}
int SocketFileDescriptorMap::socketToFd(int sock) noexcept {
std::terminate();
}
}
}
}
#endif