diff --git a/Libraries/LibCore/CMakeLists.txt b/Libraries/LibCore/CMakeLists.txt index 620db4ed93b..2522634788f 100644 --- a/Libraries/LibCore/CMakeLists.txt +++ b/Libraries/LibCore/CMakeLists.txt @@ -12,7 +12,9 @@ set(SOURCES ) if (WIN32) - list(APPEND SOURCES SystemWindows.cpp) + list(APPEND SOURCES + SocketpairWindows.cpp + SystemWindows.cpp) else() list(APPEND SOURCES System.cpp) endif() diff --git a/Libraries/LibCore/SocketAddressWindows.h b/Libraries/LibCore/SocketAddressWindows.h index 4e72acc7b4a..6a59a8ecce2 100644 --- a/Libraries/LibCore/SocketAddressWindows.h +++ b/Libraries/LibCore/SocketAddressWindows.h @@ -16,6 +16,7 @@ typedef char CHAR; typedef unsigned char UCHAR; typedef const CHAR* PCSTR; typedef USHORT ADDRESS_FAMILY; +typedef int socklen_t; #define WINAPI_FAMILY_PARTITION(x) 1 #define FAR diff --git a/Libraries/LibCore/SocketpairWindows.cpp b/Libraries/LibCore/SocketpairWindows.cpp new file mode 100644 index 00000000000..fe717266630 --- /dev/null +++ b/Libraries/LibCore/SocketpairWindows.cpp @@ -0,0 +1,101 @@ +/* https://github.com/ncm/selectable-socketpair +Copyright 2007, 2010 by Nathan C. Myers +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + The name of the author must not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#include + +namespace Core::System { + +int windows_socketpair(SOCKET socks[2], int make_overlapped) +{ + union { + struct sockaddr_in inaddr; + struct sockaddr addr; + } a; + SOCKET listener; + int e; + socklen_t addrlen = sizeof(a.inaddr); + DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0); + int reuse = 1; + + if (socks == 0) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + socks[0] = socks[1] = -1; + + listener = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listener == INVALID_SOCKET) + return SOCKET_ERROR; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + for (;;) { + if (::setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, (socklen_t)sizeof(reuse)) == -1) + break; + if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + memset(&a, 0, sizeof(a)); + if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) + break; + // win32 getsockname may only set the port number, p=0.0005. + // ( http://msdn.microsoft.com/library/ms738543.aspx ): + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_family = AF_INET; + + if (::listen(listener, 1) == SOCKET_ERROR) + break; + + socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); + if (socks[0] == INVALID_SOCKET) + break; + if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + socks[1] = ::accept(listener, NULL, NULL); + if (socks[1] == INVALID_SOCKET) + break; + + closesocket(listener); + return 0; + } + + e = WSAGetLastError(); + closesocket(listener); + closesocket(socks[0]); + closesocket(socks[1]); + WSASetLastError(e); + socks[0] = socks[1] = -1; + return SOCKET_ERROR; +} + +} diff --git a/Libraries/LibCore/System.h b/Libraries/LibCore/System.h index 7d8517e9ae3..323982dd880 100644 --- a/Libraries/LibCore/System.h +++ b/Libraries/LibCore/System.h @@ -32,11 +32,11 @@ # include # include #else +# include "SocketAddressWindows.h" # define O_CLOEXEC O_NOINHERIT # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) using sighandler_t = void (*)(int); -using socklen_t = int; #endif #if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID) && !defined(AK_OS_WINDOWS) diff --git a/Libraries/LibCore/SystemWindows.cpp b/Libraries/LibCore/SystemWindows.cpp index 5d6a0a19302..fec598601ef 100644 --- a/Libraries/LibCore/SystemWindows.cpp +++ b/Libraries/LibCore/SystemWindows.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2021-2022, Sam Atkins * Copyright (c) 2022, Matthias Zimmerman * Copyright (c) 2023, Cameron Youell - * Copyright (c) 2024, stasoid + * Copyright (c) 2024-2025, stasoid * * SPDX-License-Identifier: BSD-2-Clause */ @@ -19,6 +19,8 @@ namespace Core::System { +int windows_socketpair(SOCKET socks[2], int make_overlapped); + static void invalid_parameter_handler(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t) { } @@ -225,6 +227,20 @@ bool is_socket(int handle) return GetFileType(to_handle(handle)) == FILE_TYPE_PIPE; } +ErrorOr socketpair(int domain, int type, int protocol, int sv[2]) +{ + if (domain != AF_LOCAL || type != SOCK_STREAM || protocol != 0) + return Error::from_string_literal("Unsupported argument value"); + + SOCKET socks[2] = {}; + if (windows_socketpair(socks, true)) + return Error::from_windows_error(); + + sv[0] = socks[0]; + sv[1] = socks[1]; + return {}; +} + ErrorOr sleep_ms(u32 milliseconds) { Sleep(milliseconds); diff --git a/Meta/check-style.py b/Meta/check-style.py index 4409edbf94a..50684084cf5 100755 --- a/Meta/check-style.py +++ b/Meta/check-style.py @@ -23,6 +23,7 @@ GOOD_LICENSE_HEADER_PATTERN = re.compile( LICENSE_HEADER_CHECK_EXCLUDES = { 'AK/Checked.h', 'AK/Function.h', + 'Libraries/LibCore/SocketpairWindows.cpp', } # We check that "#pragma once" is present