diff --git a/Libraries/LibCore/CMakeLists.txt b/Libraries/LibCore/CMakeLists.txt index a7a4f581721..5884a85b550 100644 --- a/Libraries/LibCore/CMakeLists.txt +++ b/Libraries/LibCore/CMakeLists.txt @@ -58,11 +58,11 @@ set(SOURCES ) if (WIN32) - # FIXME: Support UDPServer on Windows list(APPEND SOURCES SocketWindows.cpp AnonymousBufferWindows.cpp EventLoopImplementationWindows.cpp + UDPServerWindows.cpp TCPServerWindows.cpp) else() list(APPEND SOURCES diff --git a/Libraries/LibCore/SystemWindows.cpp b/Libraries/LibCore/SystemWindows.cpp index 271887f8a12..98a202bb9b6 100644 --- a/Libraries/LibCore/SystemWindows.cpp +++ b/Libraries/LibCore/SystemWindows.cpp @@ -270,6 +270,22 @@ ErrorOr accept(int sockfd, struct sockaddr* addr, socklen_t* addr_size) return fd; } +ErrorOr sendto(int sockfd, void const* source, size_t source_length, int flags, struct sockaddr const* destination, socklen_t destination_length) +{ + auto sent = ::sendto(sockfd, static_cast(source), source_length, flags, destination, destination_length); + if (sent == SOCKET_ERROR) + return Error::from_windows_error(); + return sent; +} + +ErrorOr recvfrom(int sockfd, void* buffer, size_t buffer_length, int flags, struct sockaddr* address, socklen_t* address_length) +{ + auto received = ::recvfrom(sockfd, static_cast(buffer), buffer_length, flags, address, address_length); + if (received == SOCKET_ERROR) + return Error::from_windows_error(); + return received; +} + ErrorOr getsockname(int sockfd, struct sockaddr* name, socklen_t* name_size) { if (::getsockname(sockfd, name, name_size) == SOCKET_ERROR) diff --git a/Libraries/LibCore/UDPServerWindows.cpp b/Libraries/LibCore/UDPServerWindows.cpp new file mode 100644 index 00000000000..80a1d31d9bd --- /dev/null +++ b/Libraries/LibCore/UDPServerWindows.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025, ayeteadoe + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include + +namespace Core { + +UDPServer::UDPServer(EventReceiver* parent) + : EventReceiver(parent) +{ + m_fd = MUST(Core::System::socket(AF_INET, SOCK_DGRAM, 0)); + int option = 1; + MUST(Core::System::ioctl(m_fd, FIONBIO, option)); + auto const ret = SetHandleInformation(to_handle(m_fd), HANDLE_FLAG_INHERIT, 0); + VERIFY(ret != 0); +} + +UDPServer::~UDPServer() +{ + MUST(Core::System::close(m_fd)); +} + +bool UDPServer::bind(IPv4Address const& address, u16 port) +{ + if (m_bound) + return false; + + auto socket_address = SocketAddress(address, port); + auto in = socket_address.to_sockaddr_in(); + auto bind_result = Core::System::bind(m_fd, (sockaddr const*)&in, sizeof(in)); + if (bind_result.is_error()) { + perror("UDPServer::bind"); + return false; + } + + m_bound = true; + + m_notifier = Notifier::construct(m_fd, Notifier::Type::Read, this); + m_notifier->on_activation = [this] { + if (on_ready_to_receive) + on_ready_to_receive(); + }; + return true; +} + +ErrorOr UDPServer::receive(size_t size, sockaddr_in& in) +{ + auto buf = TRY(ByteBuffer::create_uninitialized(size)); + socklen_t in_len = sizeof(in); + auto bytes_received = TRY(Core::System::recvfrom(m_fd, buf.data(), size, 0, (sockaddr*)&in, &in_len)); + buf.resize(bytes_received); + return buf; +} + +ErrorOr UDPServer::send(ReadonlyBytes buffer, sockaddr_in const& to) +{ + socklen_t to_len = sizeof(to); + return TRY(Core::System::sendto(m_fd, buffer.data(), buffer.size(), 0, (sockaddr const*)&to, to_len)); +} + +Optional UDPServer::local_address() const +{ + if (m_fd == -1) + return {}; + + sockaddr_in address; + socklen_t len = sizeof(address); + if (Core::System::getsockname(m_fd, (sockaddr*)&address, &len).is_error()) + return {}; + + return IPv4Address(address.sin_addr.s_addr); +} + +Optional UDPServer::local_port() const +{ + if (m_fd == -1) + return {}; + + sockaddr_in address; + socklen_t len = sizeof(address); + if (Core::System::getsockname(m_fd, (sockaddr*)&address, &len).is_error()) + return {}; + + return ntohs(address.sin_port); +} + +}