Skip to content

Commit

Permalink
LibCore/System: Add dup, fd_to_handle, handle_to_fd on Windows
Browse files Browse the repository at this point in the history
Also teach close and dup to work with pseudo file descriptors.

Also implement and call init_crt_and_wsa.

Also add is_socket.
  • Loading branch information
stasoid committed Dec 21, 2024
1 parent 5db1a40 commit cb07fb1
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 14 deletions.
12 changes: 7 additions & 5 deletions Libraries/LibCore/AnonymousBufferWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
*/

#include <LibCore/AnonymousBuffer.h>
#include <windows.h>
#include <LibCore/System.h>

#include <AK/Windows.h>

namespace Core {

Expand All @@ -23,7 +25,7 @@ AnonymousBufferImpl::~AnonymousBufferImpl()
VERIFY(UnmapViewOfFile(m_data));

if (m_fd != -1)
VERIFY(CloseHandle((HANDLE)(intptr_t)m_fd));
MUST(System::close(m_fd));
}

ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size)
Expand All @@ -32,16 +34,16 @@ ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t s
if (!map_handle)
return Error::from_windows_error();

return create((int)(intptr_t)map_handle, size);
return create(handle_to_fd(map_handle, System::FileMappingHandle), size);
}

ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(int fd, size_t size)
{
void* ptr = MapViewOfFile((HANDLE)(intptr_t)fd, FILE_MAP_ALL_ACCESS, 0, 0, size);
void* ptr = MapViewOfFile(System::fd_to_handle(fd), FILE_MAP_ALL_ACCESS, 0, 0, size);
if (!ptr)
return Error::from_windows_error();

return adopt_nonnull_ref_or_enomem(new (nothrow) AnonymousBufferImpl(fd, size, ptr));
return adopt_ref(*new AnonymousBufferImpl(fd, size, ptr));
}

ErrorOr<AnonymousBuffer> AnonymousBuffer::create_with_size(size_t size)
Expand Down
7 changes: 4 additions & 3 deletions Libraries/LibCore/EventLoopImplementationWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

#include <LibCore/EventLoopImplementationWindows.h>
#include <LibCore/Notifier.h>
#include <LibCore/System.h>
#include <LibCore/ThreadEventQueue.h>
#include <WinSock2.h>
#include <io.h>

#include <AK/Windows.h>

struct Handle {
HANDLE handle = NULL;
Expand Down Expand Up @@ -181,7 +182,7 @@ void EventLoopManagerWindows::register_notifier(Notifier& notifier)
{
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
VERIFY(event);
SOCKET socket = _get_osfhandle(notifier.fd());
SOCKET socket = (SOCKET)System::fd_to_handle(notifier.fd());
VERIFY(socket != INVALID_SOCKET);
int rc = WSAEventSelect(socket, event, notifier_type_to_network_event(notifier.type()));
VERIFY(rc == 0);
Expand Down
6 changes: 6 additions & 0 deletions Libraries/LibCore/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1004,4 +1004,10 @@ int getpid()
return ::getpid();
}

bool is_socket(int fd)
{
auto result = fstat(fd);
return !result.is_error() && S_ISSOCK(result.value().st_mode);
}

}
13 changes: 13 additions & 0 deletions Libraries/LibCore/System.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ using socklen_t = int;

namespace Core::System {

#ifdef AK_OS_WINDOWS
enum HandleType {
FileHandle,
DirectoryHandle,
SocketHandle,
FileMappingHandle
};
int handle_to_fd(intptr_t handle, HandleType);
int handle_to_fd(void* handle, HandleType);
void* fd_to_handle(int fd);
#endif

#if !defined(AK_OS_MACOS) && !defined(AK_OS_HAIKU)
ErrorOr<int> accept4(int sockfd, struct sockaddr*, socklen_t*, int flags);
#endif
Expand Down Expand Up @@ -180,5 +192,6 @@ ErrorOr<void> set_resource_limits(int resource, rlim_t limit);
#endif

int getpid();
bool is_socket(int fd);

}
103 changes: 97 additions & 6 deletions Libraries/LibCore/SystemWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,58 @@
#include <AK/ByteString.h>
#include <AK/ScopeGuard.h>
#include <LibCore/System.h>
#include <Windows.h>
#include <direct.h>
#include <io.h>
#include <sys/mman.h>

#include <AK/Windows.h>

namespace Core::System {

static void invalid_parameter_handler(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t)
{
}

static int init_crt_and_wsa()
{
WSADATA wsa;
WORD version = MAKEWORD(2, 2);
int rc = WSAStartup(version, &wsa);
VERIFY(!rc && wsa.wVersion == version);

// Make _get_osfhandle return -1 instead of crashing on invalid fd in release (debug still __debugbreak's)
_set_invalid_parameter_handler(invalid_parameter_handler);
return 0;
}

static auto dummy = init_crt_and_wsa();

int handle_to_fd(HANDLE handle, HandleType type)
{
return handle_to_fd((intptr_t)handle, type);
}

int handle_to_fd(intptr_t handle, HandleType type)
{
if (type != SocketHandle && type != FileMappingHandle)
return _open_osfhandle(handle, 0);

// Special treatment for socket and file mapping handles because:
// * _open_osfhandle doesn't support file mapping handles
// * _close doesn't properly support socket handles (it calls CloseHandle instead of closesocket)
// Handle value is held in lower 31 bits, and sign bit is set to indicate this is not a regular fd.
VERIFY((handle >> 31) == 0); // must be 0 ⩽ handle ⩽ 0x7FFFFFFF
return (1 << 31) | handle;
}

HANDLE fd_to_handle(int fd)
{
if (fd >= 0)
return (HANDLE)_get_osfhandle(fd);
if (fd == -1)
return INVALID_HANDLE_VALUE;
return (HANDLE)(intptr_t)(fd & ~(1 << 31));
}

ErrorOr<int> open(StringView path, int options, mode_t mode)
{
ByteString string_path = path;
Expand All @@ -31,9 +76,7 @@ ErrorOr<int> open(StringView path, int options, mode_t mode)
HANDLE dir_handle = CreateFile(sz_path, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (dir_handle == INVALID_HANDLE_VALUE)
return Error::from_windows_error();
int dir_fd = _open_osfhandle((intptr_t)dir_handle, 0);
if (dir_fd != -1)
return dir_fd;
return handle_to_fd(dir_handle, DirectoryHandle);
}
return Error::from_syscall("open"sv, -error);
}
Expand All @@ -42,6 +85,20 @@ ErrorOr<int> open(StringView path, int options, mode_t mode)

ErrorOr<void> close(int fd)
{
if (fd < 0) {
HANDLE handle = fd_to_handle(fd);
if (handle == INVALID_HANDLE_VALUE)
return Error::from_string_literal("Invalid file descriptor");
if (is_socket(fd)) {
if (closesocket((SOCKET)handle))
return Error::from_windows_error();
} else {
if (!CloseHandle(handle))
return Error::from_windows_error();
}
return {};
}

if (_close(fd) < 0)
return Error::from_syscall("close"sv, -errno);
return {};
Expand Down Expand Up @@ -83,7 +140,7 @@ ErrorOr<void> ftruncate(int fd, off_t length)
if (result.is_error())
return result.release_error();

if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0)
if (SetEndOfFile(fd_to_handle(fd)) == 0)
return Error::from_windows_error();
return {};
}
Expand Down Expand Up @@ -189,4 +246,38 @@ int getpid()
return GetCurrentProcessId();
}

ErrorOr<int> dup(int fd)
{
if (fd < 0) {
HANDLE handle = fd_to_handle(fd);
if (handle == INVALID_HANDLE_VALUE)
return Error::from_string_literal("Invalid file descriptor");

if (is_socket(fd)) {
WSAPROTOCOL_INFO pi = {};
if (WSADuplicateSocket((SOCKET)handle, GetCurrentProcessId(), &pi))
return Error::from_windows_error();
SOCKET socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, &pi, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
if (socket == INVALID_SOCKET)
return Error::from_windows_error();
return handle_to_fd(socket, SocketHandle);
} else {
if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
return Error::from_windows_error();
return handle_to_fd(handle, FileMappingHandle);
}
}

int new_fd = _dup(fd);
if (new_fd < 0)
return Error::from_syscall("dup"sv, -errno);
return new_fd;
}

bool is_socket(int fd)
{
int val, len = sizeof(val);
return !::getsockopt((SOCKET)fd_to_handle(fd), SOL_SOCKET, SO_TYPE, (char*)&val, &len);
}

}

0 comments on commit cb07fb1

Please sign in to comment.