diff --git a/Libraries/LibCore/CMakeLists.txt b/Libraries/LibCore/CMakeLists.txt index c4b90d12b67..0a6799a034a 100644 --- a/Libraries/LibCore/CMakeLists.txt +++ b/Libraries/LibCore/CMakeLists.txt @@ -43,7 +43,6 @@ set(SOURCES Resource.cpp ResourceImplementation.cpp ResourceImplementationFile.cpp - Socket.cpp SystemServerTakeover.cpp TCPServer.cpp ThreadEventQueue.cpp @@ -54,11 +53,13 @@ set(SOURCES if (WIN32) list(APPEND SOURCES ProcessWindows.cpp + SocketWindows.cpp AnonymousBufferWindows.cpp EventLoopImplementationWindows.cpp) else() list(APPEND SOURCES Process.cpp + Socket.cpp AnonymousBuffer.cpp EventLoopImplementationUnix.cpp) endif() diff --git a/Libraries/LibCore/SocketWindows.cpp b/Libraries/LibCore/SocketWindows.cpp new file mode 100644 index 00000000000..084a5a549dd --- /dev/null +++ b/Libraries/LibCore/SocketWindows.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2018-2021, Andreas Kling + * Copyright (c) 2021, sin-ack + * Copyright (c) 2025, stasoid + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include + +#define MSG_DONTWAIT 0x40 + +namespace Core { + +ErrorOr PosixSocketHelper::read(Bytes buffer, int flags) +{ + if (!is_open()) + return Error::from_errno(ENOTCONN); + + // FIXME: also take into account if PosixSocketHelper is blocking/non-blocking (see set_blocking) + bool blocking = !(flags & MSG_DONTWAIT); + WSABUF buf = { static_cast(buffer.size()), reinterpret_cast(buffer.data()) }; + DWORD nread = 0; + DWORD fl = 0; + OVERLAPPED ov = {}; + + if (WSARecv(m_fd, &buf, 1, &nread, &fl, blocking ? NULL : &ov, NULL) == SOCKET_ERROR) { + + auto error = GetLastError(); + + if (error == WSA_IO_PENDING) { + CancelIo(to_handle(m_fd)); + return Error::from_errno(EWOULDBLOCK); + } + + if (error == WSAECONNRESET) + return Error::from_errno(ECONNRESET); + + return Error::from_windows_error(error); + } + + if (nread == 0) + did_reach_eof_on_read(); + + return buffer.trim(nread); +} + +void PosixSocketHelper::did_reach_eof_on_read() +{ + m_last_read_was_eof = true; + + // If a socket read is EOF, then no more data can be read from it because + // the protocol has disconnected. In this case, we can just disable the + // notifier if we have one. + if (m_notifier) + m_notifier->set_enabled(false); +} + +ErrorOr PosixSocketHelper::write(ReadonlyBytes buffer, int flags) +{ + if (!is_open()) + return Error::from_errno(ENOTCONN); + + // FIXME: Implement non-blocking PosixSocketHelper::write + (void)flags; + WSABUF buf = { static_cast(buffer.size()), reinterpret_cast(const_cast(buffer.data())) }; + DWORD nwritten = 0; + + if (WSASend(m_fd, &buf, 1, &nwritten, 0, NULL, NULL) == SOCKET_ERROR) + return Error::from_windows_error(); + + return nwritten; +} + +ErrorOr PosixSocketHelper::can_read_without_blocking(int timeout) const +{ + struct pollfd pollfd = { + .fd = static_cast(m_fd), + .events = POLLIN, + .revents = 0 + }; + + auto result = WSAPoll(&pollfd, 1, timeout); + if (result == SOCKET_ERROR) + return Error::from_windows_error(); + return result; +} + +ErrorOr PosixSocketHelper::set_blocking(bool) +{ + // FIXME: Implement Core::PosixSocketHelper::set_blocking + // Currently does nothing, sockets are always blocking. + return {}; +} + +ErrorOr PosixSocketHelper::set_close_on_exec(bool enabled) +{ + if (!SetHandleInformation(to_handle(m_fd), HANDLE_FLAG_INHERIT, enabled ? 0 : HANDLE_FLAG_INHERIT)) + return Error::from_windows_error(); + return {}; +} + +ErrorOr PosixSocketHelper::pending_bytes() const +{ + VERIFY(0 && "Core::PosixSocketHelper::pending_bytes is not implemented"); +} + +void PosixSocketHelper::setup_notifier() +{ + if (!m_notifier) + m_notifier = Notifier::construct(m_fd, Notifier::Type::Read); +} + +void PosixSocketHelper::close() +{ + if (!is_open()) + return; + + if (m_notifier) + m_notifier->set_enabled(false); + + MUST(System::close(m_fd)); + m_fd = -1; +} + +ErrorOr LocalSocket::read_without_waiting(Bytes buffer) +{ + return m_helper.read(buffer, MSG_DONTWAIT); +} + +ErrorOr> LocalSocket::adopt_fd(int fd, PreventSIGPIPE prevent_sigpipe) +{ + if (fd == -1) + return Error::from_errno(EBADF); + + auto socket = adopt_own(*new LocalSocket(prevent_sigpipe)); + socket->m_helper.set_fd(fd); + socket->setup_notifier(); + return socket; +} + +Optional LocalSocket::fd() const +{ + if (!is_open()) + return {}; + return m_helper.fd(); +} + +ErrorOr LocalSocket::release_fd() +{ + if (!is_open()) { + return Error::from_errno(ENOTCONN); + } + + auto fd = m_helper.fd(); + m_helper.set_fd(-1); + return fd; +} + +}