From f80c7c4cd5c090b9a31f89a0eb3d86cbe928c50b Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sat, 30 Jul 2022 05:58:23 +0200 Subject: core, network: Add ability to proxy socket packets --- src/core/internal_network/network.cpp | 61 ++++--- src/core/internal_network/network.h | 43 +---- src/core/internal_network/socket_proxy.cpp | 282 +++++++++++++++++++++++++++++ src/core/internal_network/socket_proxy.h | 102 +++++++++++ src/core/internal_network/sockets.h | 136 ++++++++++---- 5 files changed, 524 insertions(+), 100 deletions(-) create mode 100644 src/core/internal_network/socket_proxy.cpp create mode 100644 src/core/internal_network/socket_proxy.h (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 36c43cc8f..160cc83e4 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -32,6 +32,7 @@ #include "core/internal_network/network.h" #include "core/internal_network/network_interface.h" #include "core/internal_network/sockets.h" +#include "network/network.h" namespace Network { @@ -114,7 +115,10 @@ Errno TranslateNativeError(int e) { return Errno::NETDOWN; case WSAENETUNREACH: return Errno::NETUNREACH; + case WSAEMSGSIZE: + return Errno::MSGSIZE; default: + UNIMPLEMENTED_MSG("Unimplemented errno={}", e); return Errno::OTHER; } } @@ -125,7 +129,6 @@ using SOCKET = int; using WSAPOLLFD = pollfd; using ULONG = u64; -constexpr SOCKET INVALID_SOCKET = -1; constexpr SOCKET SOCKET_ERROR = -1; constexpr int SD_RECEIVE = SHUT_RD; @@ -206,7 +209,10 @@ Errno TranslateNativeError(int e) { return Errno::NETDOWN; case ENETUNREACH: return Errno::NETUNREACH; + case EMSGSIZE: + return Errno::MSGSIZE; default: + UNIMPLEMENTED_MSG("Unimplemented errno={}", e); return Errno::OTHER; } } @@ -329,16 +335,6 @@ PollEvents TranslatePollRevents(short revents) { return result; } -template -Errno SetSockOpt(SOCKET fd, int option, T value) { - const int result = - setsockopt(fd, SOL_SOCKET, option, reinterpret_cast(&value), sizeof(value)); - if (result != SOCKET_ERROR) { - return Errno::SUCCESS; - } - return GetAndLogLastError(); -} - } // Anonymous namespace NetworkInstance::NetworkInstance() { @@ -350,26 +346,15 @@ NetworkInstance::~NetworkInstance() { } std::optional GetHostIPv4Address() { - const std::string& selected_network_interface = Settings::values.network_interface.GetValue(); - const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); - if (network_interfaces.size() == 0) { - LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces"); + const auto interface = Network::GetSelectedNetworkInterface(); + if (!interface.has_value()) { + LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface"); return {}; } - const auto res = - std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) { - return iface.name == selected_network_interface; - }); - - if (res != network_interfaces.end()) { - char ip_addr[16] = {}; - ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); - return TranslateIPv4(res->ip_address); - } else { - LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); - return {}; - } + char ip_addr[16] = {}; + ASSERT(inet_ntop(AF_INET, &interface->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); + return TranslateIPv4(interface->ip_address); } std::pair Poll(std::vector& pollfds, s32 timeout) { @@ -412,7 +397,19 @@ Socket::~Socket() { fd = INVALID_SOCKET; } -Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {} +Socket::Socket(Socket&& rhs) noexcept { + fd = std::exchange(rhs.fd, INVALID_SOCKET); +} + +template +Errno Socket::SetSockOpt(SOCKET _fd, int option, T value) { + const int result = + setsockopt(_fd, SOL_SOCKET, option, reinterpret_cast(&value), sizeof(value)); + if (result != SOCKET_ERROR) { + return Errno::SUCCESS; + } + return GetAndLogLastError(); +} Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol)); @@ -423,7 +420,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { return GetAndLogLastError(); } -std::pair Socket::Accept() { +std::pair Socket::Accept() { sockaddr addr; socklen_t addrlen = sizeof(addr); const SOCKET new_socket = accept(fd, &addr, &addrlen); @@ -634,4 +631,8 @@ bool Socket::IsOpened() const { return fd != INVALID_SOCKET; } +void Socket::HandleProxyPacket(const ProxyPacket& packet) { + LOG_WARNING(Network, "ProxyPacket received, but not in Proxy mode!"); +} + } // namespace Network diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h index 10e5ef10d..36994c22e 100644 --- a/src/core/internal_network/network.h +++ b/src/core/internal_network/network.h @@ -8,6 +8,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" +#include "common/socket_types.h" #ifdef _WIN32 #include @@ -17,6 +18,7 @@ namespace Network { +class SocketBase; class Socket; /// Error code for network functions @@ -31,46 +33,11 @@ enum class Errno { HOSTUNREACH, NETDOWN, NETUNREACH, + TIMEDOUT, + MSGSIZE, OTHER, }; -/// Address families -enum class Domain { - INET, ///< Address family for IPv4 -}; - -/// Socket types -enum class Type { - STREAM, - DGRAM, - RAW, - SEQPACKET, -}; - -/// Protocol values for sockets -enum class Protocol { - ICMP, - TCP, - UDP, -}; - -/// Shutdown mode -enum class ShutdownHow { - RD, - WR, - RDWR, -}; - -/// Array of IPv4 address -using IPv4Address = std::array; - -/// Cross-platform sockaddr structure -struct SockAddrIn { - Domain family; - IPv4Address ip; - u16 portno; -}; - /// Cross-platform poll fd structure enum class PollEvents : u16 { @@ -86,7 +53,7 @@ enum class PollEvents : u16 { DECLARE_ENUM_FLAG_OPERATORS(PollEvents); struct PollFD { - Socket* socket; + SocketBase* socket; PollEvents events; PollEvents revents; }; diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp new file mode 100644 index 000000000..6e8924822 --- /dev/null +++ b/src/core/internal_network/socket_proxy.cpp @@ -0,0 +1,282 @@ +// Copyright 2022 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/internal_network/network.h" +#include "core/internal_network/network_interface.h" +#include "core/internal_network/socket_proxy.h" + +namespace Network { + +ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {} + +ProxySocket::ProxySocket(ProxySocket&& rhs) noexcept : room_network{rhs.room_network} { + fd = std::exchange(rhs.fd, INVALID_SOCKET); +} + +ProxySocket::~ProxySocket() { + if (fd == INVALID_SOCKET) { + return; + } + fd = INVALID_SOCKET; +} + +void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { + if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno || + closed) { + return; + } + std::lock_guard guard(packets_mutex); + received_packets.push(packet); +} + +template +Errno ProxySocket::SetSockOpt(SOCKET _fd, int option, T value) { + socket_options[option] = reinterpret_cast(&value); + return Errno::SUCCESS; +} + +Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) { + protocol = socket_protocol; + socket_options[0x1008] = reinterpret_cast(&type); + + return Errno::SUCCESS; +} + +std::pair ProxySocket::Accept() { + LOG_WARNING(Network, "(STUBBED) called"); + return {AcceptResult{}, Errno::SUCCESS}; +} + +Errno ProxySocket::Connect(SockAddrIn addr_in) { + LOG_WARNING(Network, "(STUBBED) called"); + return Errno::SUCCESS; +} + +std::pair ProxySocket::GetPeerName() { + LOG_WARNING(Network, "(STUBBED) called"); + return {SockAddrIn{}, Errno::SUCCESS}; +} + +std::pair ProxySocket::GetSockName() { + LOG_WARNING(Network, "(STUBBED) called"); + return {SockAddrIn{}, Errno::SUCCESS}; +} + +Errno ProxySocket::Bind(SockAddrIn addr) { + if (is_bound) { + LOG_WARNING(Network, "Rebinding Socket is unimplemented!"); + return Errno::SUCCESS; + } + local_endpoint = addr; + is_bound = true; + + return Errno::SUCCESS; +} + +Errno ProxySocket::Listen(s32 backlog) { + LOG_WARNING(Network, "(STUBBED) called"); + return Errno::SUCCESS; +} + +Errno ProxySocket::Shutdown(ShutdownHow how) { + LOG_WARNING(Network, "(STUBBED) called"); + return Errno::SUCCESS; +} + +std::pair ProxySocket::Recv(int flags, std::vector& message) { + LOG_WARNING(Network, "(STUBBED) called"); + ASSERT(flags == 0); + ASSERT(message.size() < static_cast(std::numeric_limits::max())); + + return {static_cast(0), Errno::SUCCESS}; +} + +std::pair ProxySocket::RecvFrom(int flags, std::vector& message, SockAddrIn* addr) { + ASSERT(flags == 0); + ASSERT(message.size() < static_cast(std::numeric_limits::max())); + + { + std::lock_guard guard(packets_mutex); + if (received_packets.size() > 0) { + return ReceivePacket(flags, message, addr, message.size()); + } + } + + if (blocking) { + if (receive_timeout > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(receive_timeout)); + } + } else { + return {-1, Errno::AGAIN}; + } + + std::lock_guard guard(packets_mutex); + if (received_packets.size() > 0) { + return ReceivePacket(flags, message, addr, message.size()); + } + + return {-1, Errno::TIMEDOUT}; +} + +std::pair ProxySocket::ReceivePacket(int flags, std::vector& message, + SockAddrIn* addr, std::size_t max_length) { + ProxyPacket& packet = received_packets.front(); + if (addr) { + addr->family = Domain::INET; + addr->ip = packet.local_endpoint.ip; // The senders ip address + addr->portno = packet.local_endpoint.portno; // The senders port number + } + + bool peek = (flags & FLAG_MSG_PEEK) != 0; + std::size_t read_bytes; + if (packet.data.size() > max_length) { + read_bytes = max_length; + message.clear(); + std::copy(packet.data.begin(), packet.data.begin() + read_bytes, + std::back_inserter(message)); + message.resize(max_length); + + if (protocol == Protocol::UDP) { + if (!peek) { + received_packets.pop(); + } + return {-1, Errno::MSGSIZE}; + } else if (protocol == Protocol::TCP) { + std::vector numArray(packet.data.size() - max_length); + std::copy(packet.data.begin() + max_length, packet.data.end(), + std::back_inserter(numArray)); + packet.data = numArray; + } + } else { + read_bytes = packet.data.size(); + message.clear(); + std::copy(packet.data.begin(), packet.data.end(), std::back_inserter(message)); + message.resize(max_length); + if (!peek) { + received_packets.pop(); + } + } + + return {static_cast(read_bytes), Errno::SUCCESS}; +} + +std::pair ProxySocket::Send(const std::vector& message, int flags) { + LOG_WARNING(Network, "(STUBBED) called"); + ASSERT(message.size() < static_cast(std::numeric_limits::max())); + ASSERT(flags == 0); + + return {static_cast(0), Errno::SUCCESS}; +} + +void ProxySocket::SendPacket(ProxyPacket& packet) { + if (auto room_member = room_network.GetRoomMember().lock()) { + if (room_member->IsConnected()) { + room_member->SendProxyPacket(packet); + } + } +} + +std::pair ProxySocket::SendTo(u32 flags, const std::vector& message, + const SockAddrIn* addr) { + ASSERT(flags == 0); + + if (!is_bound) { + LOG_ERROR(Network, "ProxySocket is not bound!"); + return {static_cast(message.size()), Errno::SUCCESS}; + } + + if (auto room_member = room_network.GetRoomMember().lock()) { + if (!room_member->IsConnected()) { + return {static_cast(message.size()), Errno::SUCCESS}; + } + } + + ProxyPacket packet; + packet.local_endpoint = local_endpoint; + packet.remote_endpoint = *addr; + packet.protocol = protocol; + packet.broadcast = broadcast; + + auto& ip = local_endpoint.ip; + auto ipv4 = Network::GetHostIPv4Address(); + // If the ip is all zeroes (INADDR_ANY) or if it matches the hosts ip address, + // replace it with a "fake" routing address + if (std::all_of(ip.begin(), ip.end(), [](u8 i) { return i == 0; }) || (ipv4 && ipv4 == ip)) { + if (auto room_member = room_network.GetRoomMember().lock()) { + packet.local_endpoint.ip = room_member->GetFakeIpAddress(); + } + } + + packet.data.clear(); + std::copy(message.begin(), message.end(), std::back_inserter(packet.data)); + + SendPacket(packet); + + return {static_cast(message.size()), Errno::SUCCESS}; +} + +Errno ProxySocket::Close() { + fd = INVALID_SOCKET; + closed = true; + + return Errno::SUCCESS; +} + +Errno ProxySocket::SetLinger(bool enable, u32 linger) { + struct Linger { + u16 linger_enable; + u16 linger_time; + } values; + values.linger_enable = enable ? 1 : 0; + values.linger_time = static_cast(linger); + + return SetSockOpt(fd, SO_LINGER, values); +} + +Errno ProxySocket::SetReuseAddr(bool enable) { + return SetSockOpt(fd, SO_REUSEADDR, enable ? 1 : 0); +} + +Errno ProxySocket::SetBroadcast(bool enable) { + broadcast = enable; + return SetSockOpt(fd, SO_BROADCAST, enable ? 1 : 0); +} + +Errno ProxySocket::SetSndBuf(u32 value) { + return SetSockOpt(fd, SO_SNDBUF, value); +} + +Errno ProxySocket::SetKeepAlive(bool enable) { + return Errno::SUCCESS; +} + +Errno ProxySocket::SetRcvBuf(u32 value) { + return SetSockOpt(fd, SO_RCVBUF, value); +} + +Errno ProxySocket::SetSndTimeo(u32 value) { + send_timeout = value; + return SetSockOpt(fd, SO_SNDTIMEO, static_cast(value)); +} + +Errno ProxySocket::SetRcvTimeo(u32 value) { + receive_timeout = value; + return SetSockOpt(fd, SO_RCVTIMEO, static_cast(value)); +} + +Errno ProxySocket::SetNonBlock(bool enable) { + blocking = !enable; + return Errno::SUCCESS; +} + +bool ProxySocket::IsOpened() const { + return fd != INVALID_SOCKET; +} + +} // namespace Network diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h new file mode 100644 index 000000000..ef7d5b554 --- /dev/null +++ b/src/core/internal_network/socket_proxy.h @@ -0,0 +1,102 @@ +// Copyright 2022 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "core/internal_network/sockets.h" +#include "network/network.h" + +namespace Network { + +class ProxySocket : public SocketBase { +public: + ProxySocket(RoomNetwork& room_network_) noexcept; + ~ProxySocket() override; + + ProxySocket(const ProxySocket&) = delete; + ProxySocket& operator=(const ProxySocket&) = delete; + + ProxySocket(ProxySocket&& rhs) noexcept; + + // Avoid closing sockets implicitly + ProxySocket& operator=(ProxySocket&&) noexcept = delete; + + void HandleProxyPacket(const ProxyPacket& packet); + + Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override; + + Errno Close() override; + + std::pair Accept() override; + + Errno Connect(SockAddrIn addr_in) override; + + std::pair GetPeerName() override; + + std::pair GetSockName() override; + + Errno Bind(SockAddrIn addr) override; + + Errno Listen(s32 backlog) override; + + Errno Shutdown(ShutdownHow how) override; + + std::pair Recv(int flags, std::vector& message) override; + + std::pair RecvFrom(int flags, std::vector& message, SockAddrIn* addr) override; + + std::pair ReceivePacket(int flags, std::vector& message, SockAddrIn* addr, + std::size_t max_length); + + std::pair Send(const std::vector& message, int flags) override; + + void SendPacket(ProxyPacket& packet); + + std::pair SendTo(u32 flags, const std::vector& message, + const SockAddrIn* addr) override; + + Errno SetLinger(bool enable, u32 linger) override; + + Errno SetReuseAddr(bool enable) override; + + Errno SetBroadcast(bool enable) override; + + Errno SetKeepAlive(bool enable) override; + + Errno SetSndBuf(u32 value) override; + + Errno SetRcvBuf(u32 value) override; + + Errno SetSndTimeo(u32 value) override; + + Errno SetRcvTimeo(u32 value) override; + + Errno SetNonBlock(bool enable) override; + + template + Errno SetSockOpt(SOCKET fd, int option, T value); + + bool IsOpened() const override; + + bool broadcast = false; + bool closed = false; + u32 send_timeout = 0; + u32 receive_timeout = 0; + std::map socket_options; + bool is_bound = false; + SockAddrIn local_endpoint{}; + bool blocking = true; + std::queue received_packets; + Protocol protocol; + + std::mutex packets_mutex; + + RoomNetwork& room_network; +}; + +} // namespace Network diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h index 77e27e928..92dc49993 100644 --- a/src/core/internal_network/sockets.h +++ b/src/core/internal_network/sockets.h @@ -14,20 +14,92 @@ #include "common/common_types.h" #include "core/internal_network/network.h" +#include "network/network.h" // TODO: C++20 Replace std::vector usages with std::span namespace Network { -class Socket { +class SocketBase { public: +#ifdef YUZU_UNIX + using SOCKET = int; + static constexpr SOCKET INVALID_SOCKET = -1; + static constexpr SOCKET SOCKET_ERROR = -1; +#endif + struct AcceptResult { - std::unique_ptr socket; + std::unique_ptr socket; SockAddrIn sockaddr_in; }; + virtual ~SocketBase() {} + + virtual SocketBase& operator=(const SocketBase&) = delete; + + // Avoid closing sockets implicitly + virtual SocketBase& operator=(SocketBase&&) noexcept = delete; + + virtual Errno Initialize(Domain domain, Type type, Protocol protocol) = 0; + + virtual Errno Close() = 0; + + virtual std::pair Accept() = 0; + + virtual Errno Connect(SockAddrIn addr_in) = 0; + + virtual std::pair GetPeerName() = 0; + + virtual std::pair GetSockName() = 0; + + virtual Errno Bind(SockAddrIn addr) = 0; + + virtual Errno Listen(s32 backlog) = 0; + + virtual Errno Shutdown(ShutdownHow how) = 0; + + virtual std::pair Recv(int flags, std::vector& message) = 0; + + virtual std::pair RecvFrom(int flags, std::vector& message, + SockAddrIn* addr) = 0; + + virtual std::pair Send(const std::vector& message, int flags) = 0; + + virtual std::pair SendTo(u32 flags, const std::vector& message, + const SockAddrIn* addr) = 0; + + virtual Errno SetLinger(bool enable, u32 linger) = 0; + + virtual Errno SetReuseAddr(bool enable) = 0; + + virtual Errno SetKeepAlive(bool enable) = 0; + + virtual Errno SetBroadcast(bool enable) = 0; - explicit Socket() = default; - ~Socket(); + virtual Errno SetSndBuf(u32 value) = 0; + + virtual Errno SetRcvBuf(u32 value) = 0; + + virtual Errno SetSndTimeo(u32 value) = 0; + + virtual Errno SetRcvTimeo(u32 value) = 0; + + virtual Errno SetNonBlock(bool enable) = 0; + + virtual bool IsOpened() const = 0; + + virtual void HandleProxyPacket(const ProxyPacket& packet) = 0; + +#if defined(_WIN32) + SOCKET fd = INVALID_SOCKET; +#elif YUZU_UNIX + int fd = -1; +#endif +}; + +class Socket : public SocketBase { +public: + Socket() = default; + ~Socket() override; Socket(const Socket&) = delete; Socket& operator=(const Socket&) = delete; @@ -37,57 +109,57 @@ public: // Avoid closing sockets implicitly Socket& operator=(Socket&&) noexcept = delete; - Errno Initialize(Domain domain, Type type, Protocol protocol); + Errno Initialize(Domain domain, Type type, Protocol protocol) override; - Errno Close(); + Errno Close() override; - std::pair Accept(); + std::pair Accept() override; - Errno Connect(SockAddrIn addr_in); + Errno Connect(SockAddrIn addr_in) override; - std::pair GetPeerName(); + std::pair GetPeerName() override; - std::pair GetSockName(); + std::pair GetSockName() override; - Errno Bind(SockAddrIn addr); + Errno Bind(SockAddrIn addr) override; - Errno Listen(s32 backlog); + Errno Listen(s32 backlog) override; - Errno Shutdown(ShutdownHow how); + Errno Shutdown(ShutdownHow how) override; - std::pair Recv(int flags, std::vector& message); + std::pair Recv(int flags, std::vector& message) override; - std::pair RecvFrom(int flags, std::vector& message, SockAddrIn* addr); + std::pair RecvFrom(int flags, std::vector& message, SockAddrIn* addr) override; - std::pair Send(const std::vector& message, int flags); + std::pair Send(const std::vector& message, int flags) override; - std::pair SendTo(u32 flags, const std::vector& message, const SockAddrIn* addr); + std::pair SendTo(u32 flags, const std::vector& message, + const SockAddrIn* addr) override; - Errno SetLinger(bool enable, u32 linger); + Errno SetLinger(bool enable, u32 linger) override; - Errno SetReuseAddr(bool enable); + Errno SetReuseAddr(bool enable) override; - Errno SetKeepAlive(bool enable); + Errno SetKeepAlive(bool enable) override; - Errno SetBroadcast(bool enable); + Errno SetBroadcast(bool enable) override; - Errno SetSndBuf(u32 value); + Errno SetSndBuf(u32 value) override; - Errno SetRcvBuf(u32 value); + Errno SetRcvBuf(u32 value) override; - Errno SetSndTimeo(u32 value); + Errno SetSndTimeo(u32 value) override; - Errno SetRcvTimeo(u32 value); + Errno SetRcvTimeo(u32 value) override; - Errno SetNonBlock(bool enable); + Errno SetNonBlock(bool enable) override; - bool IsOpened() const; + template + Errno SetSockOpt(SOCKET fd, int option, T value); -#if defined(_WIN32) - SOCKET fd = INVALID_SOCKET; -#elif YUZU_UNIX - int fd = -1; -#endif + bool IsOpened() const override; + + void HandleProxyPacket(const ProxyPacket& packet) override; }; std::pair Poll(std::vector& poll_fds, s32 timeout); -- cgit v1.2.3 From bb84f5353927e473f39fc5fac741a623b48a1ef1 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sat, 30 Jul 2022 20:16:47 +0200 Subject: Make copyright headers SPDX-compliant --- src/core/internal_network/socket_proxy.cpp | 5 ++--- src/core/internal_network/socket_proxy.h | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 6e8924822..b9c50430e 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -1,6 +1,5 @@ -// Copyright 2022 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include #include diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index ef7d5b554..614f91e99 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -1,6 +1,5 @@ -// Copyright 2022 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once -- cgit v1.2.3 From a5cd639cb627013c22d14331bd0e91228ac44e84 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sat, 30 Jul 2022 21:27:31 +0200 Subject: core/socket_proxy: Fix compilation --- src/core/internal_network/socket_proxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index 614f91e99..c9155f1af 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -25,7 +25,7 @@ public: // Avoid closing sockets implicitly ProxySocket& operator=(ProxySocket&&) noexcept = delete; - void HandleProxyPacket(const ProxyPacket& packet); + void HandleProxyPacket(const ProxyPacket& packet) override; Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override; -- cgit v1.2.3 From 6d41088153b4b932b4f2524d4252993a5642f998 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Mon, 1 Aug 2022 22:47:39 +0200 Subject: core, yuzu: Address first part of review comments --- src/core/internal_network/network.cpp | 8 ++++---- src/core/internal_network/socket_proxy.cpp | 10 +++++----- src/core/internal_network/socket_proxy.h | 3 ++- src/core/internal_network/sockets.h | 6 +----- 4 files changed, 12 insertions(+), 15 deletions(-) (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 160cc83e4..3b6906f7d 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -352,8 +352,8 @@ std::optional GetHostIPv4Address() { return {}; } - char ip_addr[16] = {}; - ASSERT(inet_ntop(AF_INET, &interface->ip_address, ip_addr, sizeof(ip_addr)) != nullptr); + std::array ip_addr = {}; + ASSERT(inet_ntop(AF_INET, &interface->ip_address, ip_addr.data(), sizeof(ip_addr)) != nullptr); return TranslateIPv4(interface->ip_address); } @@ -402,9 +402,9 @@ Socket::Socket(Socket&& rhs) noexcept { } template -Errno Socket::SetSockOpt(SOCKET _fd, int option, T value) { +Errno Socket::SetSockOpt(SOCKET fd_, int option, T value) { const int result = - setsockopt(_fd, SOL_SOCKET, option, reinterpret_cast(&value), sizeof(value)); + setsockopt(fd_, SOL_SOCKET, option, reinterpret_cast(&value), sizeof(value)); if (result != SOCKET_ERROR) { return Errno::SUCCESS; } diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index b9c50430e..216893ba1 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -30,19 +30,19 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { closed) { return; } - std::lock_guard guard(packets_mutex); + std::lock_guard guard(packets_mutex); received_packets.push(packet); } template -Errno ProxySocket::SetSockOpt(SOCKET _fd, int option, T value) { +Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) { socket_options[option] = reinterpret_cast(&value); return Errno::SUCCESS; } Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) { protocol = socket_protocol; - socket_options[0x1008] = reinterpret_cast(&type); + SetSockOpt(fd, SO_TYPE, type); return Errno::SUCCESS; } @@ -101,7 +101,7 @@ std::pair ProxySocket::RecvFrom(int flags, std::vector& message, ASSERT(message.size() < static_cast(std::numeric_limits::max())); { - std::lock_guard guard(packets_mutex); + std::lock_guard guard(packets_mutex); if (received_packets.size() > 0) { return ReceivePacket(flags, message, addr, message.size()); } @@ -115,7 +115,7 @@ std::pair ProxySocket::RecvFrom(int flags, std::vector& message, return {-1, Errno::AGAIN}; } - std::lock_guard guard(packets_mutex); + std::lock_guard guard(packets_mutex); if (received_packets.size() > 0) { return ReceivePacket(flags, message, addr, message.size()); } diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index c9155f1af..ad917cac3 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -14,7 +14,7 @@ namespace Network { class ProxySocket : public SocketBase { public: - ProxySocket(RoomNetwork& room_network_) noexcept; + explicit ProxySocket(RoomNetwork& room_network_) noexcept; ~ProxySocket() override; ProxySocket(const ProxySocket&) = delete; @@ -82,6 +82,7 @@ public: bool IsOpened() const override; +private: bool broadcast = false; bool closed = false; u32 send_timeout = 0; diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h index 92dc49993..a70429b19 100644 --- a/src/core/internal_network/sockets.h +++ b/src/core/internal_network/sockets.h @@ -32,7 +32,7 @@ public: std::unique_ptr socket; SockAddrIn sockaddr_in; }; - virtual ~SocketBase() {} + virtual ~SocketBase() = default; virtual SocketBase& operator=(const SocketBase&) = delete; @@ -89,11 +89,7 @@ public: virtual void HandleProxyPacket(const ProxyPacket& packet) = 0; -#if defined(_WIN32) SOCKET fd = INVALID_SOCKET; -#elif YUZU_UNIX - int fd = -1; -#endif }; class Socket : public SocketBase { -- cgit v1.2.3 From 5cd95fa949492c4da0bf2de93ac902f1838aa340 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Wed, 3 Aug 2022 19:38:11 +0200 Subject: internal_network: Fix mingw compilation Apparently, "interface" is a reserved keyword on this compiler. --- src/core/internal_network/network.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 3b6906f7d..cdf38a2a4 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -346,15 +346,16 @@ NetworkInstance::~NetworkInstance() { } std::optional GetHostIPv4Address() { - const auto interface = Network::GetSelectedNetworkInterface(); - if (!interface.has_value()) { + const auto network_interface = Network::GetSelectedNetworkInterface(); + if (!network_interface.has_value()) { LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface"); return {}; } std::array ip_addr = {}; - ASSERT(inet_ntop(AF_INET, &interface->ip_address, ip_addr.data(), sizeof(ip_addr)) != nullptr); - return TranslateIPv4(interface->ip_address); + ASSERT(inet_ntop(AF_INET, &network_interface->ip_address, ip_addr.data(), sizeof(ip_addr)) != + nullptr); + return TranslateIPv4(network_interface->ip_address); } std::pair Poll(std::vector& pollfds, s32 timeout) { -- cgit v1.2.3 From 72b90a5bbf7a9308f7172f38be88e29bab58a21b Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 13 Aug 2022 13:11:01 -0500 Subject: core: network: Address review comments --- src/core/internal_network/socket_proxy.cpp | 46 ++++++++++++++++-------------- src/core/internal_network/socket_proxy.h | 13 +++------ 2 files changed, 29 insertions(+), 30 deletions(-) (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 216893ba1..7ce22dbfa 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -14,10 +14,6 @@ namespace Network { ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {} -ProxySocket::ProxySocket(ProxySocket&& rhs) noexcept : room_network{rhs.room_network} { - fd = std::exchange(rhs.fd, INVALID_SOCKET); -} - ProxySocket::~ProxySocket() { if (fd == INVALID_SOCKET) { return; @@ -36,7 +32,6 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { template Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) { - socket_options[option] = reinterpret_cast(&value); return Errno::SUCCESS; } @@ -100,27 +95,36 @@ std::pair ProxySocket::RecvFrom(int flags, std::vector& message, ASSERT(flags == 0); ASSERT(message.size() < static_cast(std::numeric_limits::max())); - { - std::lock_guard guard(packets_mutex); - if (received_packets.size() > 0) { - return ReceivePacket(flags, message, addr, message.size()); + const auto timestamp = std::chrono::steady_clock::now(); + + while (true) { + { + std::lock_guard guard(packets_mutex); + if (received_packets.size() > 0) { + return ReceivePacket(flags, message, addr, message.size()); + } } - } - if (blocking) { - if (receive_timeout > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(receive_timeout)); + if (!blocking) { + return {-1, Errno::AGAIN}; } - } else { - return {-1, Errno::AGAIN}; - } - std::lock_guard guard(packets_mutex); - if (received_packets.size() > 0) { - return ReceivePacket(flags, message, addr, message.size()); - } + // TODO: break if socket connection is lost + + std::this_thread::yield(); + + if (receive_timeout == 0) { + continue; + } - return {-1, Errno::TIMEDOUT}; + const auto time_diff = std::chrono::steady_clock::now() - timestamp; + const auto time_diff_ms = + std::chrono::duration_cast(time_diff).count(); + + if (time_diff_ms > receive_timeout) { + return {-1, Errno::TIMEDOUT}; + } + } } std::pair ProxySocket::ReceivePacket(int flags, std::vector& message, diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index ad917cac3..f12b5f567 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -7,6 +7,7 @@ #include #include +#include "common/common_funcs.h" #include "core/internal_network/sockets.h" #include "network/network.h" @@ -14,17 +15,12 @@ namespace Network { class ProxySocket : public SocketBase { public: + YUZU_NON_COPYABLE(ProxySocket); + YUZU_NON_MOVEABLE(ProxySocket); + explicit ProxySocket(RoomNetwork& room_network_) noexcept; ~ProxySocket() override; - ProxySocket(const ProxySocket&) = delete; - ProxySocket& operator=(const ProxySocket&) = delete; - - ProxySocket(ProxySocket&& rhs) noexcept; - - // Avoid closing sockets implicitly - ProxySocket& operator=(ProxySocket&&) noexcept = delete; - void HandleProxyPacket(const ProxyPacket& packet) override; Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override; @@ -87,7 +83,6 @@ private: bool closed = false; u32 send_timeout = 0; u32 receive_timeout = 0; - std::map socket_options; bool is_bound = false; SockAddrIn local_endpoint{}; bool blocking = true; -- cgit v1.2.3 From 4976d14009aded6edadcb07add398d091997bde0 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Mon, 15 Aug 2022 23:31:01 +0200 Subject: core/socket_proxy: Final nits --- src/core/internal_network/socket_proxy.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/core/internal_network') diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 7ce22dbfa..49d067f4c 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -32,6 +32,7 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { template Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) { + LOG_DEBUG(Network, "(STUBBED) called"); return Errno::SUCCESS; } @@ -95,8 +96,12 @@ std::pair ProxySocket::RecvFrom(int flags, std::vector& message, ASSERT(flags == 0); ASSERT(message.size() < static_cast(std::numeric_limits::max())); + // TODO (flTobi): Verify the timeout behavior and break when connection is lost const auto timestamp = std::chrono::steady_clock::now(); - + // When receive_timeout is set to zero, the socket is supposed to wait indefinitely until a + // packet arrives. In order to prevent lost packets from hanging the emulation thread, we set + // the timeout to 5s instead + const auto timeout = receive_timeout == 0 ? 5000 : receive_timeout; while (true) { { std::lock_guard guard(packets_mutex); @@ -109,19 +114,13 @@ std::pair ProxySocket::RecvFrom(int flags, std::vector& message, return {-1, Errno::AGAIN}; } - // TODO: break if socket connection is lost - std::this_thread::yield(); - if (receive_timeout == 0) { - continue; - } - const auto time_diff = std::chrono::steady_clock::now() - timestamp; const auto time_diff_ms = std::chrono::duration_cast(time_diff).count(); - if (time_diff_ms > receive_timeout) { + if (time_diff_ms > timeout) { return {-1, Errno::TIMEDOUT}; } } -- cgit v1.2.3