From 68cdf08968b239f1547e03e5bef361e676675dc0 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Sat, 12 Apr 2025 16:32:50 +0100 Subject: [PATCH] DEV9: Deduplicate some UDP sockets code --- pcsx2/CMakeLists.txt | 2 + .../DEV9/Sessions/UDP_Session/UDP_Common.cpp | 182 ++++++++++++++++++ pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.h | 31 +++ .../Sessions/UDP_Session/UDP_FixedPort.cpp | 137 ++----------- .../DEV9/Sessions/UDP_Session/UDP_Session.cpp | 136 ++----------- pcsx2/pcsx2.vcxproj | 2 + pcsx2/pcsx2.vcxproj.filters | 6 + 7 files changed, 246 insertions(+), 250 deletions(-) create mode 100644 pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.cpp create mode 100644 pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.h diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 93467e202f..99afcd91fe 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -309,6 +309,7 @@ set(pcsx2DEV9Sources DEV9/Sessions/TCP_Session/TCP_Session.cpp DEV9/Sessions/TCP_Session/TCP_Session_In.cpp DEV9/Sessions/TCP_Session/TCP_Session_Out.cpp + DEV9/Sessions/UDP_Session/UDP_Common.cpp DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp DEV9/Sessions/UDP_Session/UDP_Session.cpp DEV9/smap.cpp @@ -354,6 +355,7 @@ set(pcsx2DEV9Headers DEV9/Sessions/BaseSession.h DEV9/Sessions/ICMP_Session/ICMP_Session.h DEV9/Sessions/TCP_Session/TCP_Session.h + DEV9/Sessions/UDP_Session/UDP_Common.h DEV9/Sessions/UDP_Session/UDP_FixedPort.h DEV9/Sessions/UDP_Session/UDP_BaseSession.h DEV9/Sessions/UDP_Session/UDP_Session.h diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.cpp new file mode 100644 index 0000000000..23bdbae55e --- /dev/null +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.cpp @@ -0,0 +1,182 @@ +// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team +// SPDX-License-Identifier: GPL-3.0+ + +#include + +#include "common/Console.h" + +#ifdef __POSIX__ +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 +#include +#include +#include +#include +#endif + +#ifdef _WIN32 +#include "common/RedtapeWindows.h" +#include +#else +#include +#endif + +#include "UDP_Common.h" +#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h" + +using namespace PacketReader; +using namespace PacketReader::IP; +using namespace PacketReader::IP::UDP; + +namespace Sessions::UDP_Common +{ +#ifdef _WIN32 + SOCKET CreateSocket(IP_Address adapterIP, std::optional port) + { + SOCKET client = INVALID_SOCKET; +#elif defined(__POSIX__) + int CreateSocket(IP_Address adapterIP, std::optional port) + { + int client = INVALID_SOCKET; +#endif + + int ret; + client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (client == INVALID_SOCKET) + { + Console.Error("DEV9: UDP: Failed to open socket. Error: %d", +#ifdef _WIN32 + WSAGetLastError()); +#elif defined(__POSIX__) + errno); +#endif + return INVALID_SOCKET; + } + + constexpr int reuseAddress = true; // BOOL on Windows + ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddress), sizeof(reuseAddress)); + + if (ret == SOCKET_ERROR) + Console.Error("DEV9: UDP: Failed to set SO_REUSEADDR. Error: %d", +#ifdef _WIN32 + WSAGetLastError()); +#elif defined(__POSIX__) + errno); +#endif + + if (port.has_value() || adapterIP != IP_Address{{{0, 0, 0, 0}}}) + { + sockaddr_in endpoint{}; + endpoint.sin_family = AF_INET; + endpoint.sin_addr = std::bit_cast(adapterIP); + if (port.has_value()) + endpoint.sin_port = htons(port.value()); + + ret = bind(client, reinterpret_cast(&endpoint), sizeof(endpoint)); + + if (ret == SOCKET_ERROR) + Console.Error("DEV9: UDP: Failed to bind socket. Error: %d", +#ifdef _WIN32 + WSAGetLastError()); +#elif defined(__POSIX__) + errno); +#endif + } + return client; + } + +#ifdef _WIN32 + std::tuple, bool> RecvFrom(SOCKET client, u16 port) +#elif defined(__POSIX__) + std::tuple, bool> RecvFrom(int client, u16 port) +#endif + { + int ret; + fd_set sReady; + fd_set sExcept; + + // not const Linux + timeval nowait{}; + FD_ZERO(&sReady); + FD_ZERO(&sExcept); + FD_SET(client, &sReady); + FD_SET(client, &sExcept); + ret = select(client + 1, &sReady, nullptr, &sExcept, &nowait); + + if (ret == SOCKET_ERROR) + { + Console.Error("DEV9: UDP: select failed. Error code: %d", +#ifdef _WIN32 + WSAGetLastError()); +#elif defined(__POSIX__) + errno); +#endif + return {std::nullopt, true}; + } + else if (FD_ISSET(client, &sExcept)) + { +#ifdef _WIN32 + int len = sizeof(ret); + if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&ret), &len) < 0) + { + Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", WSAGetLastError()); + } +#elif defined(__POSIX__) + socklen_t len = sizeof(ret); + if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&ret), &len) < 0) + Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno); +#endif + else + Console.Error("DEV9: UDP: Socket error: %d", ret); + + return {std::nullopt, false}; + } + else if (FD_ISSET(client, &sReady)) + { + unsigned long available = 0; + PayloadData* recived = nullptr; + std::unique_ptr buffer; + sockaddr_in endpoint{}; + + // FIONREAD returns total size of all available messages + // however, we only read one message at a time +#ifdef _WIN32 + ret = ioctlsocket(client, FIONREAD, &available); +#elif defined(__POSIX__) + ret = ioctl(client, FIONREAD, &available); +#endif + if (ret != SOCKET_ERROR) + { + buffer = std::make_unique(available); + +#ifdef _WIN32 + int fromlen = sizeof(endpoint); +#elif defined(__POSIX__) + socklen_t fromlen = sizeof(endpoint); +#endif + ret = recvfrom(client, reinterpret_cast(buffer.get()), available, 0, reinterpret_cast(&endpoint), &fromlen); + } + + if (ret == SOCKET_ERROR) + { + Console.Error("DEV9: UDP: UDP recv error: %d", +#ifdef _WIN32 + WSAGetLastError()); +#elif defined(__POSIX__) + errno); +#endif + return {std::nullopt, false}; + } + + recived = new PayloadData(ret); + memcpy(recived->data.get(), buffer.get(), ret); + + std::unique_ptr iRet = std::make_unique(recived); + iRet->destinationPort = port; + iRet->sourcePort = ntohs(endpoint.sin_port); + + return {ReceivedPayload{std::bit_cast(endpoint.sin_addr), std::move(iRet)}, true}; + } + return {std::nullopt, true}; + } +} // namespace Sessions::UDP_Common diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.h b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.h new file mode 100644 index 0000000000..d2233c9b47 --- /dev/null +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team +// SPDX-License-Identifier: GPL-3.0+ + +#pragma once +#include +#ifdef _WIN32 +#include +#elif defined(__POSIX__) +#include +#endif + +#include "common/Pcsx2Defs.h" +#include "DEV9/Sessions/BaseSession.h" + +namespace Sessions::UDP_Common +{ + // Binds the socket when provided with an IP +#ifdef _WIN32 + SOCKET CreateSocket(PacketReader::IP::IP_Address adapterIP, std::optional port); +#elif defined(__POSIX__) + int CreateSocket(PacketReader::IP::IP_Address adapterIP, std::optional port); +#endif + + // Receives from the client and packages the data into ReceivedPayload + // port is the local port to be written to the UDP header in ReceivedPayload +#ifdef _WIN32 + std::tuple, bool> RecvFrom(SOCKET client, u16 port); +#elif defined(__POSIX__) + std::tuple, bool> RecvFrom(int client, u16 port); +#endif +} // namespace Sessions::UDP_Common diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp index 5e08805bc6..9b9ddd09ac 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp @@ -21,6 +21,7 @@ #include #endif +#include "UDP_Common.h" #include "UDP_FixedPort.h" #include "DEV9/PacketReader/IP/UDP/UDP_Packet.h" @@ -51,33 +52,15 @@ namespace Sessions void UDP_FixedPort::Init() { - int ret; - client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + client = UDP_Common::CreateSocket(adapterIP, port); if (client == INVALID_SOCKET) { - Console.Error("DEV9: UDP: Failed to open socket. Error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif RaiseEventConnectionClosed(); return; } - constexpr int reuseAddress = true; // BOOL on Windows - ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddress), sizeof(reuseAddress)); - - if (ret == SOCKET_ERROR) - Console.Error("DEV9: UDP: Failed to set SO_REUSEADDR. Error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - constexpr int broadcastEnable = true; // BOOL on Windows - ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnable), sizeof(broadcastEnable)); + const int ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnable), sizeof(broadcastEnable)); if (ret == SOCKET_ERROR) Console.Error("DEV9: UDP: Failed to set SO_BROADCAST. Error: %d", @@ -87,25 +70,6 @@ namespace Sessions errno); #endif - sockaddr_in endpoint{}; - endpoint.sin_family = AF_INET; - endpoint.sin_addr = std::bit_cast(adapterIP); - endpoint.sin_port = htons(port); - - ret = bind(client, reinterpret_cast(&endpoint), sizeof(endpoint)); - - if (ret == SOCKET_ERROR) - { - Console.Error("DEV9: UDP: Failed to bind socket. Error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - RaiseEventConnectionClosed(); - return; - } - open.store(true); } @@ -114,102 +78,25 @@ namespace Sessions if (!open.load()) return std::nullopt; - int ret; - fd_set sReady; - fd_set sExcept; + std::optional ret; + bool success; + std::tie(ret, success) = UDP_Common::RecvFrom(client, port); - timeval nowait{}; - FD_ZERO(&sReady); - FD_ZERO(&sExcept); - FD_SET(client, &sReady); - FD_SET(client, &sExcept); - ret = select(client + 1, &sReady, nullptr, &sExcept, &nowait); - - bool hasData; - if (ret == SOCKET_ERROR) + if (!success) { - hasData = false; - Console.Error("DEV9: UDP: select failed. Error code: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif + RaiseEventConnectionClosed(); + return std::nullopt; } - else if (FD_ISSET(client, &sExcept)) + else if (ret.has_value()) { - hasData = false; - - int error = 0; -#ifdef _WIN32 - int len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) - Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", WSAGetLastError()); -#elif defined(__POSIX__) - socklen_t len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) - Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno); -#endif - else - Console.Error("DEV9: UDP: Recv error: %d", error); - } - else - hasData = FD_ISSET(client, &sReady); - - if (hasData) - { - unsigned long available = 0; - PayloadData* recived = nullptr; - std::unique_ptr buffer; - sockaddr_in endpoint{}; - - // FIONREAD returns total size of all available messages - // however, we only read one message at a time -#ifdef _WIN32 - ret = ioctlsocket(client, FIONREAD, &available); -#elif defined(__POSIX__) - ret = ioctl(client, FIONREAD, &available); -#endif - if (ret != SOCKET_ERROR) - { - buffer = std::make_unique(available); - -#ifdef _WIN32 - int fromlen = sizeof(endpoint); -#elif defined(__POSIX__) - socklen_t fromlen = sizeof(endpoint); -#endif - ret = recvfrom(client, reinterpret_cast(buffer.get()), available, 0, reinterpret_cast(&endpoint), &fromlen); - } - - if (ret == SOCKET_ERROR) - { - Console.Error("DEV9: UDP: UDP recv error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - RaiseEventConnectionClosed(); - return std::nullopt; - } - - recived = new PayloadData(ret); - memcpy(recived->data.get(), buffer.get(), ret); - - std::unique_ptr iRet = std::make_unique(recived); - iRet->destinationPort = port; - iRet->sourcePort = ntohs(endpoint.sin_port); - - IP_Address srvIP = std::bit_cast(endpoint.sin_addr); { std::lock_guard numberlock(connectionSentry); for (size_t i = 0; i < connections.size(); i++) { UDP_BaseSession* s = connections[i]; - if (s->WillRecive(srvIP)) - return ReceivedPayload{srvIP, std::move(iRet)}; + if (s->WillRecive(ret.value().sourceIP)) + return ret; } } Console.Error("DEV9: UDP: Unexpected packet, dropping"); diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp index 5f246417d3..82b9534bf2 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp @@ -20,6 +20,7 @@ #endif #include "UDP_Session.h" +#include "UDP_Common.h" #include "DEV9/PacketReader/IP/UDP/UDP_Packet.h" using namespace PacketReader; @@ -75,97 +76,17 @@ namespace Sessions return std::nullopt; } - int ret; - fd_set sReady; - fd_set sExcept; + std::optional ret; + bool success; + std::tie(ret, success) = UDP_Common::RecvFrom(client, srcPort); - timeval nowait{}; - FD_ZERO(&sReady); - FD_ZERO(&sExcept); - FD_SET(client, &sReady); - FD_SET(client, &sExcept); - ret = select(client + 1, &sReady, nullptr, &sExcept, &nowait); - - bool hasData; - if (ret == SOCKET_ERROR) + if (!success) { - hasData = false; - Console.Error("DEV9: UDP: Select failed. Error code: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - } - else if (FD_ISSET(client, &sExcept)) - { - hasData = false; - - int error = 0; -#ifdef _WIN32 - int len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) - Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", WSAGetLastError()); -#elif defined(__POSIX__) - socklen_t len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) - Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno); -#endif - else - Console.Error("DEV9: UDP: Recv error: %d", error); - } - else - hasData = FD_ISSET(client, &sReady); - - if (hasData) - { - unsigned long available = 0; - PayloadData* recived = nullptr; - std::unique_ptr buffer; - sockaddr_in endpoint{}; - - // FIONREAD returns total size of all available messages - // however, we only read one message at a time -#ifdef _WIN32 - ret = ioctlsocket(client, FIONREAD, &available); -#elif defined(__POSIX__) - ret = ioctl(client, FIONREAD, &available); -#endif - if (ret != SOCKET_ERROR) - { - buffer = std::make_unique(available); - -#ifdef _WIN32 - int fromlen = sizeof(endpoint); -#elif defined(__POSIX__) - socklen_t fromlen = sizeof(endpoint); -#endif - ret = recvfrom(client, reinterpret_cast(buffer.get()), available, 0, reinterpret_cast(&endpoint), &fromlen); - } - - if (ret == SOCKET_ERROR) - { - Console.Error("DEV9: UDP: Recv error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - RaiseEventConnectionClosed(); - return std::nullopt; - } - - recived = new PayloadData(ret); - memcpy(recived->data.get(), buffer.get(), ret); - - std::unique_ptr iRet = std::make_unique(recived); - iRet->destinationPort = srcPort; - iRet->sourcePort = destPort; - - deathClockStart.store(std::chrono::steady_clock::now()); - - return ReceivedPayload{destIP, std::move(iRet)}; + RaiseEventConnectionClosed(); + return std::nullopt; } + else if (ret.has_value()) + return ret; if (std::chrono::steady_clock::now() - deathClockStart.load() > MAX_IDLE) { @@ -211,54 +132,19 @@ namespace Sessions destPort = udp.destinationPort; srcPort = udp.sourcePort; - int ret; - client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + client = UDP_Common::CreateSocket(adapterIP, std::nullopt); if (client == INVALID_SOCKET) { - Console.Error("DEV9: UDP: Failed to open socket. Error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif RaiseEventConnectionClosed(); return false; } - constexpr int reuseAddress = true; // BOOL on Windows - ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddress), sizeof(reuseAddress)); - - if (ret == SOCKET_ERROR) - Console.Error("DEV9: UDP: Failed to set SO_REUSEADDR. Error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - - if (adapterIP.integer != 0) - { - sockaddr_in endpoint{}; - endpoint.sin_family = AF_INET; - endpoint.sin_addr = std::bit_cast(adapterIP); - - ret = bind(client, reinterpret_cast(&endpoint), sizeof(endpoint)); - - if (ret == SOCKET_ERROR) - Console.Error("DEV9: UDP: Failed to bind socket. Error: %d", -#ifdef _WIN32 - WSAGetLastError()); -#elif defined(__POSIX__) - errno); -#endif - } - sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; endpoint.sin_addr = std::bit_cast(destIP); endpoint.sin_port = htons(destPort); - ret = connect(client, reinterpret_cast(&endpoint), sizeof(endpoint)); + const int ret = connect(client, reinterpret_cast(&endpoint), sizeof(endpoint)); if (ret == SOCKET_ERROR) { diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index 4535dbb8a8..07ec5f367c 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -195,6 +195,7 @@ + @@ -636,6 +637,7 @@ + diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index e72297d4b7..367c744acf 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -944,6 +944,9 @@ System\Ps2\DEV9\Sessions\TCP_Session + + System\Ps2\DEV9\Sessions\UDP_Session + System\Ps2\DEV9\Sessions\UDP_Session @@ -1844,6 +1847,9 @@ System\Ps2\DEV9\Sessions\TCP_Session + + System\Ps2\DEV9\Sessions\UDP_Session + System\Ps2\DEV9\Sessions\UDP_Session