DEV9: Deduplicate some UDP sockets code

This commit is contained in:
TheLastRar 2025-04-12 16:32:50 +01:00
parent a755131488
commit 68cdf08968
7 changed files with 246 additions and 250 deletions

View File

@ -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

View File

@ -0,0 +1,182 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include <bit>
#include "common/Console.h"
#ifdef __POSIX__
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <netinet/in.h>
#endif
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <winsock2.h>
#else
#include <unistd.h>
#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<u16> port)
{
SOCKET client = INVALID_SOCKET;
#elif defined(__POSIX__)
int CreateSocket(IP_Address adapterIP, std::optional<u16> 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<const char*>(&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<in_addr>(adapterIP);
if (port.has_value())
endpoint.sin_port = htons(port.value());
ret = bind(client, reinterpret_cast<const sockaddr*>(&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<std::optional<ReceivedPayload>, bool> RecvFrom(SOCKET client, u16 port)
#elif defined(__POSIX__)
std::tuple<std::optional<ReceivedPayload>, 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<char*>(&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<char*>(&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<u8[]> 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<u8[]>(available);
#ifdef _WIN32
int fromlen = sizeof(endpoint);
#elif defined(__POSIX__)
socklen_t fromlen = sizeof(endpoint);
#endif
ret = recvfrom(client, reinterpret_cast<char*>(buffer.get()), available, 0, reinterpret_cast<sockaddr*>(&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<UDP_Packet> iRet = std::make_unique<UDP_Packet>(recived);
iRet->destinationPort = port;
iRet->sourcePort = ntohs(endpoint.sin_port);
return {ReceivedPayload{std::bit_cast<IP_Address>(endpoint.sin_addr), std::move(iRet)}, true};
}
return {std::nullopt, true};
}
} // namespace Sessions::UDP_Common

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#pragma once
#include <tuple>
#ifdef _WIN32
#include <winsock2.h>
#elif defined(__POSIX__)
#include <sys/socket.h>
#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<u16> port);
#elif defined(__POSIX__)
int CreateSocket(PacketReader::IP::IP_Address adapterIP, std::optional<u16> 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<std::optional<ReceivedPayload>, bool> RecvFrom(SOCKET client, u16 port);
#elif defined(__POSIX__)
std::tuple<std::optional<ReceivedPayload>, bool> RecvFrom(int client, u16 port);
#endif
} // namespace Sessions::UDP_Common

View File

@ -21,6 +21,7 @@
#include <unistd.h>
#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<const char*>(&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<const char*>(&broadcastEnable), sizeof(broadcastEnable));
const int ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&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<in_addr>(adapterIP);
endpoint.sin_port = htons(port);
ret = bind(client, reinterpret_cast<const sockaddr*>(&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<ReceivedPayload> 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<char*>(&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<char*>(&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<u8[]> 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<u8[]>(available);
#ifdef _WIN32
int fromlen = sizeof(endpoint);
#elif defined(__POSIX__)
socklen_t fromlen = sizeof(endpoint);
#endif
ret = recvfrom(client, reinterpret_cast<char*>(buffer.get()), available, 0, reinterpret_cast<sockaddr*>(&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<UDP_Packet> iRet = std::make_unique<UDP_Packet>(recived);
iRet->destinationPort = port;
iRet->sourcePort = ntohs(endpoint.sin_port);
IP_Address srvIP = std::bit_cast<IP_Address>(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");

View File

@ -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<ReceivedPayload> 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<char*>(&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<char*>(&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<u8[]> 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<u8[]>(available);
#ifdef _WIN32
int fromlen = sizeof(endpoint);
#elif defined(__POSIX__)
socklen_t fromlen = sizeof(endpoint);
#endif
ret = recvfrom(client, reinterpret_cast<char*>(buffer.get()), available, 0, reinterpret_cast<sockaddr*>(&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<UDP_Packet> iRet = std::make_unique<UDP_Packet>(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<const char*>(&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<in_addr>(adapterIP);
ret = bind(client, reinterpret_cast<const sockaddr*>(&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<in_addr>(destIP);
endpoint.sin_port = htons(destPort);
ret = connect(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
const int ret = connect(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
if (ret == SOCKET_ERROR)
{

View File

@ -195,6 +195,7 @@
<ClCompile Include="DEV9\Sessions\TCP_Session\TCP_Session_Out.cpp" />
<ClCompile Include="DEV9\Win32\pcap_io_win32.cpp" />
<ClCompile Include="DEV9\Sessions\BaseSession.cpp" />
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_Common.cpp" />
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.cpp" />
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_Session.cpp" />
<ClCompile Include="DEV9\smap.cpp" />
@ -636,6 +637,7 @@
<ClInclude Include="DEV9\Sessions\BaseSession.h" />
<ClInclude Include="DEV9\Sessions\ICMP_Session\ICMP_Session.h" />
<ClInclude Include="DEV9\Sessions\TCP_Session\TCP_Session.h" />
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_Common.h" />
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.h" />
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_BaseSession.h" />
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_Session.h" />

View File

@ -944,6 +944,9 @@
<ClCompile Include="DEV9\Sessions\TCP_Session\TCP_Session_Out.cpp">
<Filter>System\Ps2\DEV9\Sessions\TCP_Session</Filter>
</ClCompile>
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_Common.cpp">
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
</ClCompile>
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.cpp">
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
</ClCompile>
@ -1844,6 +1847,9 @@
<ClInclude Include="DEV9\Sessions\TCP_Session\TCP_Session.h">
<Filter>System\Ps2\DEV9\Sessions\TCP_Session</Filter>
</ClInclude>
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_Common.h">
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
</ClInclude>
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.h">
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
</ClInclude>