From f4ab8fa3d89ce187098c8cd05f7f77a243379f98 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 1 Jul 2026 21:11:31 +0000 Subject: [PATCH] allow configure socket level --- src/core/hle/service/sockets/bsd.cpp | 33 ++--- src/core/hle/service/sockets/bsd.h | 4 +- src/core/internal_network/network.cpp | 152 ++++++++++----------- src/core/internal_network/socket_proxy.cpp | 2 +- src/core/internal_network/socket_proxy.h | 2 +- src/core/internal_network/socket_types.h | 4 + src/core/internal_network/sockets.h | 4 +- 7 files changed, 100 insertions(+), 101 deletions(-) diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 1d10482098..eaf5622406 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -274,14 +274,12 @@ void BSD::GetSockName(HLERequestContext& ctx) { void BSD::GetSockOpt(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const s32 fd = rp.Pop(); - const u32 level = rp.Pop(); - const auto optname = static_cast(rp.Pop()); + const auto level = Network::SocketLevel(rp.Pop()); + const auto optname = Network::OptName(rp.Pop()); std::vector optval(ctx.GetWriteBufferSize()); - LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} len=0x{:x}", fd, level, optname, - optval.size()); - + LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} len=0x{:x}", fd, level, optname, optval.size()); const Network::Errno err = GetSockOptImpl(fd, level, optname, optval); ctx.WriteBuffer(optval); @@ -323,7 +321,7 @@ void BSD::SetSockOpt(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const s32 fd = rp.Pop(); - const u32 level = rp.Pop(); + const Network::SocketLevel level = Network::SocketLevel(rp.Pop()); const Network::OptName optname = Network::OptName(rp.Pop()); const auto optval = ctx.ReadBuffer(); @@ -526,7 +524,7 @@ std::pair BSD::SocketImpl(Network::Domain domain, Network:: file_descriptors[fd].reset(); return {-1, Network::Errno::NOTCONN}; } - if (descriptor.socket->fd < 0) { + if (descriptor.socket->fd == Network::Socket::INVALID_SOCKET) { file_descriptors[fd].reset(); return {-1, bsd_errno}; } @@ -741,7 +739,7 @@ std::pair BSD::FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 } } -Network::Errno BSD::GetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::vector& optval) { +Network::Errno BSD::GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector& optval) { if (!IsFileDescriptorValid(fd)) { return Network::Errno::BADF; } @@ -750,9 +748,8 @@ Network::Errno BSD::GetSockOptImpl(s32 fd, u32 level, Network::OptName optname, return Network::Errno::BADF; } - if (level != static_cast(Network::SocketLevel::SOCKET)) { - UNIMPLEMENTED_MSG("Unknown getsockopt level"); - return Network::Errno::SUCCESS; + if (level != Network::SocketLevel::SOCKET) { + LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname); } Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); @@ -775,7 +772,8 @@ Network::Errno BSD::GetSockOptImpl(s32 fd, u32 level, Network::OptName optname, } } -Network::Errno BSD::SetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::span optval) { +Network::Errno BSD::SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span optval) { + LOG_DEBUG(Service, "fd={},level={},optname={}", fd, level, optname); if (!IsFileDescriptorValid(fd)) { return Network::Errno::BADF; } @@ -784,14 +782,11 @@ Network::Errno BSD::SetSockOptImpl(s32 fd, u32 level, Network::OptName optname, return Network::Errno::BADF; } - if (level != u32(Network::SocketLevel::SOCKET)) { - LOG_WARNING(Service, "(STUBBED) setsockopt with level={}, optname={}", level, optname); - return Network::Errno::SUCCESS; - } - Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); - ASSERT(optval.size() == sizeof(u32)); - return socket->SetSockOpt(fd, optname, optval); + if (level != Network::SocketLevel::SOCKET) { + LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname); + } + return socket->SetSockOpt(fd, level, optname, optval); } Network::Errno BSD::ShutdownImpl(s32 fd, s32 how) { diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 6346d665d3..69bfb4f0c8 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -164,8 +164,8 @@ private: Network::Errno GetSockNameImpl(s32 fd, std::vector& write_buffer); Network::Errno ListenImpl(s32 fd, s32 backlog); std::pair FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg); - Network::Errno GetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::vector& optval); - Network::Errno SetSockOptImpl(s32 fd, u32 level, Network::OptName optname, std::span optval); + Network::Errno GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector& optval); + Network::Errno SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span optval); Network::Errno ShutdownImpl(s32 fd, s32 how); std::pair RecvImpl(s32 fd, u32 flags, std::vector& message); std::pair RecvFromImpl(s32 fd, u32 flags, std::vector& message, diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index bb11ed5a2d..3fadd7eafa 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -129,48 +129,30 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) { } else { return Errno::CONNABORTED; } - case WSAEBADF: - return Errno::BADF; - case WSAEINVAL: - return Errno::INVAL; - case WSAEMFILE: - return Errno::MFILE; - case WSAENOTCONN: - return Errno::NOTCONN; - case WSAEWOULDBLOCK: - return Errno::AGAIN; - case WSAECONNREFUSED: - return Errno::CONNREFUSED; - case WSAECONNRESET: - return Errno::CONNRESET; - case WSAEHOSTUNREACH: - return Errno::HOSTUNREACH; - case WSAENETDOWN: - return Errno::NETDOWN; - case WSAENETUNREACH: - return Errno::NETUNREACH; - case WSAEMSGSIZE: - return Errno::MSGSIZE; - case WSAETIMEDOUT: - return Errno::TIMEDOUT; - case WSAEINPROGRESS: - return Errno::INPROGRESS; - case WSAEISCONN: - return Errno::ISCONN; - case WSAEADDRINUSE: - return Errno::ADDRINUSE; - case WSAEADDRNOTAVAIL: - return Errno::ADDRNOTAVAIL; - case WSAEPROTOTYPE: - return Errno::PROTOTYPE; - case WSAENOPROTOOPT: - return Errno::NOPROTOOPT; - case WSAEPROTONOSUPPORT: - return Errno::PROTONOSUPPORT; - case WSAESOCKTNOSUPPORT: - return Errno::SOCKTNOSUPPORT; - case WSAENOTSUP: - return Errno::NOTSUP; + case WSAEBADF: return Errno::BADF; + case WSAEINVAL: return Errno::INVAL; + case WSAEMFILE: return Errno::MFILE; + case WSAENOTCONN: return Errno::NOTCONN; + case WSAEWOULDBLOCK: return Errno::AGAIN; + case WSAECONNREFUSED: return Errno::CONNREFUSED; + case WSAECONNRESET: return Errno::CONNRESET; + case WSAEHOSTUNREACH: return Errno::HOSTUNREACH; + case WSAENETDOWN: return Errno::NETDOWN; + case WSAENETUNREACH: return Errno::NETUNREACH; + case WSAEMSGSIZE: return Errno::MSGSIZE; + case WSAETIMEDOUT: return Errno::TIMEDOUT; + case WSAEINPROGRESS: return Errno::INPROGRESS; + case WSAEISCONN: return Errno::ISCONN; + case WSAEADDRINUSE: return Errno::ADDRINUSE; + case WSAEADDRNOTAVAIL: return Errno::ADDRNOTAVAIL; + case WSAEPROTOTYPE: return Errno::PROTOTYPE; + case WSAENOPROTOOPT: return Errno::NOPROTOOPT; + case WSAEPROTONOSUPPORT: return Errno::PROTONOSUPPORT; + case WSAESOCKTNOSUPPORT: return Errno::SOCKTNOSUPPORT; +#ifdef WSAENOTSUP + // Not defined by fucking MSVC because MSVC is stupid as shitfuckery + case WSAENOTSUP: return Errno::NOTSUP; +#endif default: UNIMPLEMENTED_MSG("Unimplemented errno={}", e); return Errno::OTHER; @@ -257,7 +239,7 @@ int closesocket(SOCKET fd) { } linger MakeLinger(bool enable, u32 linger_value) { - linger value; + linger value{}; value.l_onoff = enable ? 1 : 0; value.l_linger = linger_value; return value; @@ -302,7 +284,8 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) { NETWORK_ERROR_ELEM(SOCKTNOSUPPORT) \ NETWORK_ERROR_ELEM(NOTSUP) \ NETWORK_ERROR_ELEM(ADDRINUSE) \ - NETWORK_ERROR_ELEM(ADDRNOTAVAIL) + NETWORK_ERROR_ELEM(ADDRNOTAVAIL) \ + NETWORK_ERROR_ELEM(NOTSOCK) #define NETWORK_ERROR_ELEM(name) case E##name: return Errno::name; NETWORK_ERROR_LIST #undef NETWORK_ERROR_ELEM @@ -945,35 +928,30 @@ std::pair Socket::GetSockOpt(SOCKET fd_so, int option) { static s32 TranslateOptNameToNative(Network::OptName optname) { switch (optname) { - case Network::OptName::LINGER: - return SO_LINGER; - case Network::OptName::REUSEADDR: - return SO_REUSEADDR; - case Network::OptName::KEEPALIVE: - return SO_KEEPALIVE; - case Network::OptName::BROADCAST: - return SO_BROADCAST; - case Network::OptName::SNDBUF: - return SO_SNDBUF; - case Network::OptName::RCVBUF: - return SO_RCVBUF; - case Network::OptName::SNDTIMEO: - return SO_SNDTIMEO; - case Network::OptName::RCVTIMEO: - return SO_RCVTIMEO; - case Network::OptName::NOSIGPIPE: - return SO_NOSIGPIPE; + // managarm doesn't like these +#ifdef SO_DEBUG + case Network::OptName::DEBUG: return SO_DEBUG; +#endif +#ifdef SO_ACCEPTCONN + case Network::OptName::ACCEPTCONN: return SO_ACCEPTCONN; +#endif + case Network::OptName::LINGER: return SO_LINGER; + case Network::OptName::REUSEADDR: return SO_REUSEADDR; + case Network::OptName::KEEPALIVE: return SO_KEEPALIVE; + case Network::OptName::BROADCAST: return SO_BROADCAST; + case Network::OptName::SNDBUF: return SO_SNDBUF; + case Network::OptName::RCVBUF: return SO_RCVBUF; + case Network::OptName::SNDTIMEO: return SO_SNDTIMEO; + case Network::OptName::RCVTIMEO: return SO_RCVTIMEO; + case Network::OptName::NOSIGPIPE: return SO_NOSIGPIPE; #ifdef SO_REUSEPORT - case Network::OptName::REUSEPORT: - return SO_REUSEPORT; + case Network::OptName::REUSEPORT: return SO_REUSEPORT; #endif #ifdef SO_ACCEPTFILTER - case Network::OptName::ACCEPTFILTER: - return SO_ACCEPTFILTER; + case Network::OptName::ACCEPTFILTER: return SO_ACCEPTFILTER; #endif #ifdef SO_TIMESTAMP - case Network::OptName::TIMESTAMP: - return SO_TIMESTAMP; + case Network::OptName::TIMESTAMP: return SO_TIMESTAMP; #endif default: UNIMPLEMENTED_MSG("Unimplemented optname={}", optname); @@ -981,6 +959,30 @@ static s32 TranslateOptNameToNative(Network::OptName optname) { } } +static s32 TranslateSocketLevelToNative(Network::SocketLevel level) { + switch (level) { + case Network::SocketLevel::SOCKET: return SOL_SOCKET; + // FreeBSD doesn't define below but Linux does :-( +#ifdef SOL_IP + case Network::SocketLevel::IP: return SOL_IP; +#endif +#ifdef SOL_ICMP + case Network::SocketLevel::ICMP: return SOL_ICMP; +#endif +#ifdef SOL_TCP + case Network::SocketLevel::TCP: return SOL_TCP; +#endif +#ifdef SOL_UDP + case Network::SocketLevel::UDP: return SOL_UDP; +#endif +#ifdef SOL_CONFIG + case Network::SocketLevel::CONFIG: return SOL_CONFIG; +#endif + default: + UNIMPLEMENTED_MSG("Unimplemented level={}", level); + return SOL_SOCKET; + } +} Errno Socket::SetNonBlock(bool enable) { if (EnableNonBlock(fd, enable)) { @@ -990,29 +992,27 @@ Errno Socket::SetNonBlock(bool enable) { return GetAndLogLastError(); } -Errno Socket::SetSockOpt(SOCKET fd_so, Network::OptName optname, std::span optval) { +Errno Socket::SetSockOpt(SOCKET fd_so, Network::SocketLevel level, Network::OptName optname, std::span optval) { + auto const native_level = TranslateSocketLevelToNative(level); + auto const native_optname = TranslateOptNameToNative(optname); // TODO: is it >= or ==? for sizes if (optname == Network::OptName::LINGER) { if (optval.size() >= sizeof(Network::Linger)) { Network::Linger linger{}; std::memcpy(&linger, optval.data(), sizeof(linger)); - auto const linkger_optval = MakeLinger(bool(linger.onoff), linger.linger); - return setsockopt(fd_so, SOL_SOCKET, TranslateOptNameToNative(optname), reinterpret_cast(linkger_optval.data()), socklen_t(linkger_optval.size())) != SOCKET_ERROR + auto const linger_optval = MakeLinger(bool(linger.onoff), linger.linger); + return setsockopt(fd_so, native_level, native_optname, reinterpret_cast(&linger_optval), sizeof(linger_optval)) != SOCKET_ERROR ? Errno::SUCCESS : GetAndLogLastError(); } return Errno::INVAL; } - return setsockopt(fd_so, SOL_SOCKET, TranslateOptNameToNative(optname), reinterpret_cast(optval.data()), socklen_t(optval.size())) != SOCKET_ERROR + return setsockopt(fd_so, native_level, native_optname, reinterpret_cast(optval.data()), socklen_t(optval.size())) != SOCKET_ERROR ? Errno::SUCCESS : GetAndLogLastError(); } Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { - if (type == Type::STREAM && protocol == Protocol::UDP) { - LOG_WARNING(Network, "UDP used with STREAM"); - type = Type::DGRAM; - } fd = socket(TranslateDomainToNative(domain), TranslateTypeToNative(type), TranslateProtocolToNative(protocol)); if (fd != INVALID_SOCKET) return Errno::SUCCESS; diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 376148d28d..c5b961bfc0 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -52,7 +52,7 @@ Errno ProxySocket::SetNonBlock(bool enable) { return Errno::SUCCESS; } -Errno ProxySocket::SetSockOpt(SOCKET fd_, Network::OptName option, std::span optval) { +Errno ProxySocket::SetSockOpt(SOCKET fd_, Network::SocketLevel level, Network::OptName option, std::span optval) { LOG_DEBUG(Network, "(stubbed) called"); // numeric values? if (optval.size() >= sizeof(u32)) { diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index 9f00e1ad0e..a2c5478d4f 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -57,7 +57,7 @@ public: Errno SetNonBlock(bool enable) override; - Errno SetSockOpt(SOCKET fd, Network::OptName option, std::span value) override; + Errno SetSockOpt(SOCKET fd, Network::SocketLevel level, Network::OptName option, std::span value) override; std::pair GetPendingError() override; diff --git a/src/core/internal_network/socket_types.h b/src/core/internal_network/socket_types.h index a973f48761..6fc729e146 100644 --- a/src/core/internal_network/socket_types.h +++ b/src/core/internal_network/socket_types.h @@ -25,6 +25,7 @@ enum class Errno : u32 { INVAL = 22, MFILE = 24, PIPE = 32, + NOTSOCK = 88, MSGSIZE = 90, PROTOTYPE = 91, NOPROTOOPT = 92, @@ -234,7 +235,10 @@ enum class Protocol : u32 { enum class SocketLevel : u32 { IP = 0, + ICMP = 1, TCP = 6, + UDP = 17, + CONFIG = 0xfffe, SOCKET = 0xffff, // i.e. SOL_SOCKET }; diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h index 90c6f4947d..05e8369c03 100644 --- a/src/core/internal_network/sockets.h +++ b/src/core/internal_network/sockets.h @@ -68,7 +68,7 @@ public: virtual Errno SetNonBlock(bool enable) = 0; - virtual Errno SetSockOpt(SOCKET fd, Network::OptName option, std::span value) = 0; + virtual Errno SetSockOpt(SOCKET fd, Network::SocketLevel level, Network::OptName option, std::span value) = 0; virtual std::pair GetPendingError() = 0; @@ -120,7 +120,7 @@ public: Errno SetNonBlock(bool enable) override; - Errno SetSockOpt(SOCKET fd, Network::OptName option, std::span value) override; + Errno SetSockOpt(SOCKET fd, Network::SocketLevel level, Network::OptName option, std::span value) override; std::pair GetPendingError() override;