From a0f6036337d47a83c5d9c2b4ebdfeb3d4fc341c0 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Tue, 23 Apr 2024 15:44:03 +0100 Subject: [PATCH 1/9] DEV9: Eliminate some c-style casts in UDP_Session --- .../Sessions/UDP_Session/UDP_FixedPort.cpp | 28 ++++++------ .../DEV9/Sessions/UDP_Session/UDP_Session.cpp | 44 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp index fcc1e429c43e2..4a7feeb32d875 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team // SPDX-License-Identifier: LGPL-3.0+ +#include + #include "common/Assertions.h" #include "common/Console.h" @@ -47,7 +49,7 @@ namespace Sessions } const int reuseAddress = true; //BOOL - ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseAddress, sizeof(reuseAddress)); + 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", @@ -58,7 +60,7 @@ namespace Sessions #endif const int broadcastEnable = true; //BOOL - ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcastEnable, sizeof(broadcastEnable)); + 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", @@ -68,12 +70,12 @@ namespace Sessions errno); #endif - sockaddr_in endpoint{0}; + sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; - *(IP_Address*)&endpoint.sin_addr = adapterIP; + endpoint.sin_addr = std::bit_cast(adapterIP); endpoint.sin_port = htons(parPort); - ret = bind(client, (const sockaddr*)&endpoint, sizeof(endpoint)); + ret = bind(client, reinterpret_cast(&endpoint), sizeof(endpoint)); if (ret == SOCKET_ERROR) Console.Error("DEV9: UDP: Failed to bind socket. Error: %d", @@ -93,7 +95,7 @@ namespace Sessions fd_set sReady; fd_set sExcept; - timeval nowait{0}; + timeval nowait{}; FD_ZERO(&sReady); FD_ZERO(&sExcept); FD_SET(client, &sReady); @@ -118,11 +120,11 @@ namespace Sessions int error = 0; #ifdef _WIN32 int len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0) + if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) Console.Error("DEV9: UDP: Unkown UDP Connection Error (getsockopt Error: %d)", WSAGetLastError()); #elif defined(__POSIX__) socklen_t len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0) + if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) Console.Error("DEV9: UDP: Unkown UDP Connection Error (getsockopt Error: %d)", errno); #endif else @@ -136,7 +138,7 @@ namespace Sessions unsigned long available = 0; PayloadData* recived = nullptr; std::unique_ptr buffer; - sockaddr endpoint{0}; + sockaddr_in endpoint{}; //FIONREAD returns total size of all available messages //but we will read one message at a time @@ -154,7 +156,7 @@ namespace Sessions #elif defined(__POSIX__) socklen_t fromlen = sizeof(endpoint); #endif - ret = recvfrom(client, (char*)buffer.get(), available, 0, &endpoint, &fromlen); + ret = recvfrom(client, reinterpret_cast(buffer.get()), available, 0, reinterpret_cast(&endpoint), &fromlen); } if (ret == SOCKET_ERROR) @@ -175,9 +177,8 @@ namespace Sessions UDP_Packet* iRet = new UDP_Packet(recived); iRet->destinationPort = port; - sockaddr_in* sockaddr = (sockaddr_in*)&endpoint; - destIP = *(IP_Address*)&sockaddr->sin_addr; - iRet->sourcePort = ntohs(sockaddr->sin_port); + destIP = std::bit_cast(endpoint.sin_addr); + iRet->sourcePort = ntohs(endpoint.sin_port); { std::lock_guard numberlock(connectionSentry); @@ -213,7 +214,6 @@ namespace Sessions UDP_Session* s = new UDP_Session(parNewKey, adapterIP, parIsBrodcast, parIsMulticast, client); s->AddConnectionClosedHandler([&](BaseSession* session) { HandleChildConnectionClosed(session); }); - { std::lock_guard numberlock(connectionSentry); connections.push_back(s); diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp index fe710410977b7..c8d60ba72e801 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp @@ -80,7 +80,7 @@ namespace Sessions fd_set sReady; fd_set sExcept; - timeval nowait{0}; + timeval nowait{}; FD_ZERO(&sReady); FD_ZERO(&sExcept); FD_SET(client, &sReady); @@ -105,11 +105,11 @@ namespace Sessions int error = 0; #ifdef _WIN32 int len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0) + if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) Console.Error("DEV9: UDP: Unkown UDP Connection Error (getsockopt Error: %d)", WSAGetLastError()); #elif defined(__POSIX__) socklen_t len = sizeof(error); - if (getsockopt(client, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0) + if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) Console.Error("DEV9: UDP: Unkown UDP Connection Error (getsockopt Error: %d)", errno); #endif else @@ -123,7 +123,7 @@ namespace Sessions unsigned long available = 0; PayloadData* recived = nullptr; std::unique_ptr buffer; - sockaddr endpoint{0}; + sockaddr_in endpoint{}; //FIONREAD returns total size of all available messages //but we will read one message at a time @@ -141,7 +141,7 @@ namespace Sessions #elif defined(__POSIX__) socklen_t fromlen = sizeof(endpoint); #endif - ret = recvfrom(client, (char*)buffer.get(), available, 0, &endpoint, &fromlen); + ret = recvfrom(client, reinterpret_cast(buffer.get()), available, 0, reinterpret_cast(&endpoint), &fromlen); } if (ret == SOCKET_ERROR) @@ -235,7 +235,7 @@ namespace Sessions } const int reuseAddress = true; //BOOL - ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseAddress, sizeof(reuseAddress)); + 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", @@ -247,11 +247,11 @@ namespace Sessions if (adapterIP.integer != 0) { - sockaddr_in endpoint{0}; + sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; - *(IP_Address*)&endpoint.sin_addr = adapterIP; + endpoint.sin_addr = std::bit_cast(adapterIP); - ret = bind(client, (const sockaddr*)&endpoint, sizeof(endpoint)); + ret = bind(client, reinterpret_cast(&endpoint), sizeof(endpoint)); if (ret == SOCKET_ERROR) Console.Error("DEV9: UDP: Failed to bind socket. Error: %d", @@ -264,12 +264,12 @@ namespace Sessions pxAssert(isMulticast == false); - sockaddr_in endpoint{0}; + sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; - *(IP_Address*)&endpoint.sin_addr = destIP; + endpoint.sin_addr = std::bit_cast(destIP); endpoint.sin_port = htons(destPort); - ret = connect(client, (const sockaddr*)&endpoint, sizeof(endpoint)); + ret = connect(client, reinterpret_cast(&endpoint), sizeof(endpoint)); if (ret == SOCKET_ERROR) { @@ -293,24 +293,24 @@ namespace Sessions int ret = SOCKET_ERROR; if (isBroadcast) { - sockaddr_in endpoint{0}; + sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; endpoint.sin_addr.s_addr = INADDR_BROADCAST; endpoint.sin_port = htons(destPort); - ret = sendto(client, (const char*)udpPayload->data, udpPayload->GetLength(), 0, (const sockaddr*)&endpoint, sizeof(endpoint)); + ret = sendto(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0, reinterpret_cast(&endpoint), sizeof(endpoint)); } else if (isMulticast | isFixedPort) { - sockaddr_in endpoint{0}; + sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; - *(IP_Address*)&endpoint.sin_addr = destIP; + endpoint.sin_addr = std::bit_cast(destIP); endpoint.sin_port = htons(destPort); - ret = sendto(client, (const char*)udpPayload->data, udpPayload->GetLength(), 0, (const sockaddr*)&endpoint, sizeof(endpoint)); + ret = sendto(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0, reinterpret_cast(&endpoint), sizeof(endpoint)); } else - ret = send(client, (const char*)udpPayload->data, udpPayload->GetLength(), 0); + ret = send(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0); if (ret == SOCKET_ERROR) { @@ -335,16 +335,16 @@ namespace Sessions pxAssert(isBroadcast == false && isMulticast == false); if (isFixedPort) { - sockaddr_in endpoint{0}; + sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; - *(IP_Address*)&endpoint.sin_addr = destIP; + endpoint.sin_addr = std::bit_cast(destIP); endpoint.sin_port = htons(destPort); - ret = sendto(client, (const char*)udpPayload->data, udpPayload->GetLength(), 0, (const sockaddr*)&endpoint, sizeof(endpoint)); + ret = sendto(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0, reinterpret_cast(&endpoint), sizeof(endpoint)); } else //Do we need to clear the error somehow? - ret = send(client, (const char*)udpPayload->data, udpPayload->GetLength(), 0); + ret = send(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0); if (ret == SOCKET_ERROR) { From c6e7e155991529c991fa9538f8d802910c8e98a3 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Tue, 30 Apr 2024 20:47:55 +0100 Subject: [PATCH 2/9] DEV9: Correct capitalisation on UDP log messages --- .../Sessions/UDP_Session/UDP_FixedPort.cpp | 10 ++++----- .../DEV9/Sessions/UDP_Session/UDP_Session.cpp | 22 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp index 4a7feeb32d875..838768f065a7d 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp @@ -106,7 +106,7 @@ namespace Sessions if (ret == SOCKET_ERROR) { hasData = false; - Console.Error("DEV9: UDP: select failed. Error Code: %d", + Console.Error("DEV9: UDP: select failed. Error code: %d", #ifdef _WIN32 WSAGetLastError()); #elif defined(__POSIX__) @@ -121,14 +121,14 @@ namespace Sessions #ifdef _WIN32 int len = sizeof(error); if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) - Console.Error("DEV9: UDP: Unkown UDP Connection Error (getsockopt Error: %d)", WSAGetLastError()); + 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: Unkown UDP Connection Error (getsockopt Error: %d)", errno); + Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno); #endif else - Console.Error("DEV9: UDP: Recv Error: %d", error); + Console.Error("DEV9: UDP: Recv error: %d", error); } else hasData = FD_ISSET(client, &sReady); @@ -161,7 +161,7 @@ namespace Sessions if (ret == SOCKET_ERROR) { - Console.Error("UDP Recv Error: %d", + Console.Error("DEV9: UDP: UDP recv error: %d", #ifdef _WIN32 WSAGetLastError()); #elif defined(__POSIX__) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp index c8d60ba72e801..8bdcd9a71facc 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp @@ -70,7 +70,7 @@ namespace Sessions if (std::chrono::steady_clock::now() - deathClockStart.load() > MAX_IDLE) { CloseSocket(); - Console.WriteLn("DEV9: UDP: UDPFixed Max Idle Reached"); + Console.WriteLn("DEV9: UDP: Fixed port max idle reached"); RaiseEventConnectionClosed(); } return nullptr; @@ -91,7 +91,7 @@ namespace Sessions if (ret == SOCKET_ERROR) { hasData = false; - Console.Error("DEV9: UDP: Select Failed. Error Code: %d", + Console.Error("DEV9: UDP: Select failed. Error code: %d", #ifdef _WIN32 WSAGetLastError()); #elif defined(__POSIX__) @@ -106,14 +106,14 @@ namespace Sessions #ifdef _WIN32 int len = sizeof(error); if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast(&error), &len) < 0) - Console.Error("DEV9: UDP: Unkown UDP Connection Error (getsockopt Error: %d)", WSAGetLastError()); + 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: Unkown UDP Connection Error (getsockopt Error: %d)", errno); + Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno); #endif else - Console.Error("DEV9: UDP: Recv Error: %d", error); + Console.Error("DEV9: UDP: Recv error: %d", error); } else hasData = FD_ISSET(client, &sReady); @@ -146,7 +146,7 @@ namespace Sessions if (ret == SOCKET_ERROR) { - Console.Error("DEV9: UDP: Recv Error: %d", + Console.Error("DEV9: UDP: Recv error: %d", #ifdef _WIN32 WSAGetLastError()); #elif defined(__POSIX__) @@ -171,7 +171,7 @@ namespace Sessions if (std::chrono::steady_clock::now() - deathClockStart.load() > MAX_IDLE) { //CloseSocket(); - Console.WriteLn("DEV9: UDP: Max Idle Reached"); + Console.WriteLn("DEV9: UDP: Max idle reached"); RaiseEventConnectionClosed(); } @@ -203,7 +203,7 @@ namespace Sessions //client already created if (!(udp.destinationPort == destPort && udp.sourcePort == srcPort)) { - Console.Error("DEV9: UDP: Packet invalid for current session (Duplicate key?)"); + Console.Error("DEV9: UDP: Packet invalid for current session (duplicate key?)"); return false; } } @@ -217,7 +217,7 @@ namespace Sessions if ((destIP.bytes[0] & 0xF0) == 0xE0) { isMulticast = true; - Console.Error("DEV9: UDP: Unexpected Multicast Connection"); + Console.Error("DEV9: UDP: Unexpected multicast connection"); } int ret; @@ -319,7 +319,7 @@ namespace Sessions #elif defined(__POSIX__) ret = errno; #endif - Console.Error("DEV9: UDP: Send Error %d", ret); + Console.Error("DEV9: UDP: Send error %d", ret); //We can recive an ICMP Port Unreacable error, which can get raised in send (and maybe sendto?) //On Windows this an WSAECONNRESET error, although I've not been able to reproduce in testing @@ -348,7 +348,7 @@ namespace Sessions if (ret == SOCKET_ERROR) { - Console.Error("DEV9: UDP: Send Error (Second attempt) %d", + Console.Error("DEV9: UDP: Send error (second attempt) %d", #ifdef _WIN32 WSAGetLastError()); #elif defined(__POSIX__) From cf3ad3f855659789df22a2521bafd14441133a1d Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Wed, 1 May 2024 21:21:04 +0100 Subject: [PATCH 3/9] DEV9: Adjust comments in UDP_Session --- .../Sessions/UDP_Session/UDP_FixedPort.cpp | 27 +++++++++++++--- .../DEV9/Sessions/UDP_Session/UDP_Session.cpp | 32 ++++++++----------- pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h | 11 +++---- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp index 838768f065a7d..eee6729a9a334 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp @@ -30,6 +30,19 @@ using namespace PacketReader::IP::UDP; namespace Sessions { + /* + * The default UDP_Session backend don't bind to the src port the PS2 uses. + * Some games, however, sends the response to a set port, rather than the message source port + * A set of heuristics are used to determine when we should bind the port, these are; + * Any broadcast & multicast packet, and any packet where the src and dst ports are close to each other + * UDP_FixedPort manages the lifetime of socket bound to a specific port, and shares that socket + * with any UDP_Sessions created from it. + * For a UDP_Session with a parent UDP_FixedPort, packets are sent from the UDP_Session, but received + * by the UDP_FixedPort, with the UDP_FixedPort asking each UDP_Session associated with it whether + * it can accept the received packet, broadcast/multicast will accept eveything, while unicast sessions + * only accept packets from the address it sent to + */ + UDP_FixedPort::UDP_FixedPort(ConnectionKey parKey, IP_Address parAdapterIP, u16 parPort) : BaseSession(parKey, parAdapterIP) , client{socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)} @@ -44,11 +57,15 @@ namespace Sessions #elif defined(__POSIX__) errno); #endif - //RaiseEventConnectionClosed(); //TODO + /* + * TODO: Currently error is not correctly handled here + * We would need to call RaiseEventConnectionClosed() + * and also deal with the follow up call to NewClientSession() + */ return; } - const int reuseAddress = true; //BOOL + const int reuseAddress = true; // BOOL on Windows ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddress), sizeof(reuseAddress)); if (ret == SOCKET_ERROR) @@ -59,7 +76,7 @@ namespace Sessions errno); #endif - const int broadcastEnable = true; //BOOL + const int broadcastEnable = true; // BOOL on Windows ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnable), sizeof(broadcastEnable)); if (ret == SOCKET_ERROR) @@ -140,8 +157,8 @@ namespace Sessions std::unique_ptr buffer; sockaddr_in endpoint{}; - //FIONREAD returns total size of all available messages - //but we will read one message at a time + // 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__) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp index 8bdcd9a71facc..82cedf4c994be 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp @@ -31,9 +31,7 @@ using namespace std::chrono_literals; namespace Sessions { const std::chrono::duration - UDP_Session::MAX_IDLE = 120s; //See RFC 4787 Section 4.3 - - //TODO, figure out handling of multicast + UDP_Session::MAX_IDLE = 120s; // See RFC 4787 section 4.3 UDP_Session::UDP_Session(ConnectionKey parKey, IP_Address parAdapterIP) : UDP_BaseSession(parKey, parAdapterIP) @@ -125,8 +123,8 @@ namespace Sessions std::unique_ptr buffer; sockaddr_in endpoint{}; - //FIONREAD returns total size of all available messages - //but we will read one message at a time + // 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__) @@ -170,7 +168,6 @@ namespace Sessions if (std::chrono::steady_clock::now() - deathClockStart.load() > MAX_IDLE) { - //CloseSocket(); Console.WriteLn("DEV9: UDP: Max idle reached"); RaiseEventConnectionClosed(); } @@ -200,7 +197,7 @@ namespace Sessions if (destPort != 0) { - //client already created + // Already created client!? if (!(udp.destinationPort == destPort && udp.sourcePort == srcPort)) { Console.Error("DEV9: UDP: Packet invalid for current session (duplicate key?)"); @@ -209,11 +206,11 @@ namespace Sessions } else { - //create client + // Create client destPort = udp.destinationPort; srcPort = udp.sourcePort; - //Multicast address start with 0b1110 + // Multicast address start with 0b1110 if ((destIP.bytes[0] & 0xF0) == 0xE0) { isMulticast = true; @@ -234,7 +231,7 @@ namespace Sessions return false; } - const int reuseAddress = true; //BOOL + const int reuseAddress = true; // BOOL on Windows ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuseAddress), sizeof(reuseAddress)); if (ret == SOCKET_ERROR) @@ -289,7 +286,7 @@ namespace Sessions PayloadPtr* udpPayload = static_cast(udp.GetPayload()); - //Send + // Send Packet int ret = SOCKET_ERROR; if (isBroadcast) { @@ -321,11 +318,12 @@ namespace Sessions #endif Console.Error("DEV9: UDP: Send error %d", ret); - //We can recive an ICMP Port Unreacable error, which can get raised in send (and maybe sendto?) - //On Windows this an WSAECONNRESET error, although I've not been able to reproduce in testing - //On Linux this is an ECONNREFUSED error (Testing needed to confirm full behaviour) - - //The decision to ignore the error and retry was made to allow R&C Deadlock ressurection team to packet capture eveything + /* + * We can receive an ICMP Port Unreacable error, which can get raised in send (and maybe sendto?) + * On Windows this is an WSAECONNRESET error, although I've not been able to reproduce in testing + * On Linux this is an ECONNREFUSED error (Testing needed to confirm full behaviour) + * We ignore the error and resend to allow packet capture (i.e. wireshark) for server resurrection projects + */ #ifdef _WIN32 if (ret == WSAECONNRESET) #elif defined(__POSIX__) @@ -343,7 +341,6 @@ namespace Sessions ret = sendto(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0, reinterpret_cast(&endpoint), sizeof(endpoint)); } else - //Do we need to clear the error somehow? ret = send(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0); if (ret == SOCKET_ERROR) @@ -387,7 +384,6 @@ namespace Sessions void UDP_Session::Reset() { - //CloseSocket(); RaiseEventConnectionClosed(); } diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h index d25d6839aeb21..20b9688c037cb 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h @@ -28,19 +28,18 @@ namespace Sessions u16 srcPort = 0; u16 destPort = 0; - //Broadcast - const bool isBroadcast; // = false; + // UDP_Session flags + const bool isBroadcast; bool isMulticast = false; - const bool isFixedPort; // = false; - //EndBroadcast + const bool isFixedPort; std::atomic deathClockStart; const static std::chrono::duration MAX_IDLE; public: - //Normal Port + // Normal Port UDP_Session(ConnectionKey parKey, PacketReader::IP::IP_Address parAdapterIP); - //Fixed Port + // Fixed Port #ifdef _WIN32 UDP_Session(ConnectionKey parKey, PacketReader::IP::IP_Address parAdapterIP, bool parIsBroadcast, bool parIsMulticast, SOCKET parClient); #elif defined(__POSIX__) From b3bb40980ebf861f11ed23971747b4fb32ea4584 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Wed, 1 May 2024 22:09:31 +0100 Subject: [PATCH 4/9] DEV9: Improve support for sending multicast packets --- pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp | 14 +++----------- pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp index 82cedf4c994be..3633d353dd62d 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp @@ -36,6 +36,7 @@ namespace Sessions UDP_Session::UDP_Session(ConnectionKey parKey, IP_Address parAdapterIP) : UDP_BaseSession(parKey, parAdapterIP) , isBroadcast(false) + , isMulticast(false) , isFixedPort(false) , deathClockStart(std::chrono::steady_clock::now()) { @@ -180,7 +181,7 @@ namespace Sessions if (!open) return false; - if (isBroadcast || (parDestIP == destIP)) + if (isBroadcast || isMulticast || (parDestIP == destIP)) { deathClockStart.store(std::chrono::steady_clock::now()); return true; @@ -210,13 +211,6 @@ namespace Sessions destPort = udp.destinationPort; srcPort = udp.sourcePort; - // Multicast address start with 0b1110 - if ((destIP.bytes[0] & 0xF0) == 0xE0) - { - isMulticast = true; - Console.Error("DEV9: UDP: Unexpected multicast connection"); - } - int ret; client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (client == INVALID_SOCKET) @@ -259,8 +253,6 @@ namespace Sessions #endif } - pxAssert(isMulticast == false); - sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; endpoint.sin_addr = std::bit_cast(destIP); @@ -297,7 +289,7 @@ namespace Sessions ret = sendto(client, reinterpret_cast(udpPayload->data), udpPayload->GetLength(), 0, reinterpret_cast(&endpoint), sizeof(endpoint)); } - else if (isMulticast | isFixedPort) + else if (isFixedPort) { sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h index 20b9688c037cb..10530f77a3351 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h @@ -30,7 +30,7 @@ namespace Sessions u16 destPort = 0; // UDP_Session flags const bool isBroadcast; - bool isMulticast = false; + const bool isMulticast; const bool isFixedPort; std::atomic deathClockStart; From d7101c3be5613c9ddd172d41ac0d37ea8e365d93 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Wed, 1 May 2024 22:14:05 +0100 Subject: [PATCH 5/9] DEV9: Slightly simplify UDP socket closing --- .../DEV9/Sessions/UDP_Session/UDP_Session.cpp | 27 ++++++++----------- pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h | 3 --- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp index 3633d353dd62d..007e3c92f9154 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.cpp @@ -61,15 +61,15 @@ namespace Sessions IP_Payload* UDP_Session::Recv() { - if (!open) + if (!open.load()) return nullptr; if (isFixedPort) { if (std::chrono::steady_clock::now() - deathClockStart.load() > MAX_IDLE) { - CloseSocket(); Console.WriteLn("DEV9: UDP: Fixed port max idle reached"); + open.store(false); RaiseEventConnectionClosed(); } return nullptr; @@ -178,7 +178,7 @@ namespace Sessions bool UDP_Session::WillRecive(IP_Address parDestIP) { - if (!open) + if (!open.load()) return false; if (isBroadcast || isMulticast || (parDestIP == destIP)) @@ -273,7 +273,7 @@ namespace Sessions } if (srcPort != 0) - open = true; + open.store(true); } PayloadPtr* udpPayload = static_cast(udp.GetPayload()); @@ -360,9 +360,14 @@ namespace Sessions return true; } - void UDP_Session::CloseSocket() + void UDP_Session::Reset() + { + RaiseEventConnectionClosed(); + } + + UDP_Session::~UDP_Session() { - open = false; + open.store(false); if (!isFixedPort && client != INVALID_SOCKET) { #ifdef _WIN32 @@ -373,14 +378,4 @@ namespace Sessions client = INVALID_SOCKET; } } - - void UDP_Session::Reset() - { - RaiseEventConnectionClosed(); - } - - UDP_Session::~UDP_Session() - { - CloseSocket(); - } } // namespace Sessions diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h index 10530f77a3351..9efd11644f117 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_Session.h @@ -52,8 +52,5 @@ namespace Sessions virtual void Reset(); virtual ~UDP_Session(); - - private: - void CloseSocket(); }; } // namespace Sessions From 85888a9a8113694c23e72c0a92119b6a8812a4c7 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Sat, 4 May 2024 15:02:06 +0100 Subject: [PATCH 6/9] DEV9: Better error handling on UDP_FixedPort creation --- .../Sessions/UDP_Session/UDP_FixedPort.cpp | 28 +++++++++++++------ .../DEV9/Sessions/UDP_Session/UDP_FixedPort.h | 4 ++- pcsx2/DEV9/sockets.cpp | 8 ++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp index eee6729a9a334..ee48284d4689a 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp @@ -45,10 +45,14 @@ namespace Sessions UDP_FixedPort::UDP_FixedPort(ConnectionKey parKey, IP_Address parAdapterIP, u16 parPort) : BaseSession(parKey, parAdapterIP) - , client{socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)} - , port(parPort) + , port{parPort} + { + } + + void UDP_FixedPort::Init() { int ret; + client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (client == INVALID_SOCKET) { Console.Error("DEV9: UDP: Failed to open socket. Error: %d", @@ -57,11 +61,7 @@ namespace Sessions #elif defined(__POSIX__) errno); #endif - /* - * TODO: Currently error is not correctly handled here - * We would need to call RaiseEventConnectionClosed() - * and also deal with the follow up call to NewClientSession() - */ + RaiseEventConnectionClosed(); return; } @@ -90,17 +90,23 @@ namespace Sessions sockaddr_in endpoint{}; endpoint.sin_family = AF_INET; endpoint.sin_addr = std::bit_cast(adapterIP); - endpoint.sin_port = htons(parPort); + 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); } IP_Payload* UDP_FixedPort::Recv() @@ -228,6 +234,9 @@ namespace Sessions UDP_Session* UDP_FixedPort::NewClientSession(ConnectionKey parNewKey, bool parIsBrodcast, bool parIsMulticast) { + if (!open.load()) + return nullptr; + UDP_Session* s = new UDP_Session(parNewKey, adapterIP, parIsBrodcast, parIsMulticast, client); s->AddConnectionClosedHandler([&](BaseSession* session) { HandleChildConnectionClosed(session); }); @@ -247,7 +256,10 @@ namespace Sessions { connections.erase(index); if (connections.size() == 0) + { + open.store(false); RaiseEventConnectionClosed(); + } } } diff --git a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.h b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.h index d66eaf9140010..58b46e9240047 100644 --- a/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.h +++ b/pcsx2/DEV9/Sessions/UDP_Session/UDP_FixedPort.h @@ -20,7 +20,7 @@ namespace Sessions class UDP_FixedPort : public BaseSession { private: - std::atomic open{true}; + std::atomic open{false}; #ifdef _WIN32 SOCKET client = INVALID_SOCKET; @@ -38,6 +38,8 @@ namespace Sessions public: UDP_FixedPort(ConnectionKey parKey, PacketReader::IP::IP_Address parAdapterIP, u16 parPort); + void Init(); + virtual PacketReader::IP::IP_Payload* Recv(); virtual bool Send(PacketReader::IP::IP_Payload* payload); virtual void Reset(); diff --git a/pcsx2/DEV9/sockets.cpp b/pcsx2/DEV9/sockets.cpp index 4c1aae975db33..4243118774167 100644 --- a/pcsx2/DEV9/sockets.cpp +++ b/pcsx2/DEV9/sockets.cpp @@ -531,12 +531,20 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt) connections.Add(fKey, fPort); fixedUDPPorts.Add(udp.sourcePort, fPort); + + fPort->Init(); } Console.WriteLn("DEV9: Socket: Creating New UDP Connection from FixedPort %d to %d", udp.sourcePort, udp.destinationPort); s = fPort->NewClientSession(Key, ipPkt->destinationIP == dhcpServer.broadcastIP || ipPkt->destinationIP == IP_Address{{{255, 255, 255, 255}}}, (ipPkt->destinationIP.bytes[0] & 0xF0) == 0xE0); + + if (s == nullptr) + { + Console.Error("DEV9: Socket: Failed to Create New UDP Connection from FixedPort"); + return false; + } } else { From 4081d07dd88d785fb31ec38240b5c0f886feb162 Mon Sep 17 00:00:00 2001 From: Benjamin Moir Date: Sun, 5 May 2024 18:31:23 +1000 Subject: [PATCH 7/9] CDVD: Improve handling of host: paths in cdvdLoadElf --- pcsx2/CDVD/CDVD.cpp | 8 ++-- pcsx2/IopBios.cpp | 102 ++++++++++++++++++++++---------------------- pcsx2/IopBios.h | 2 + 3 files changed, 58 insertions(+), 54 deletions(-) diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 623ba202c562a..17c6d12131e4d 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -13,6 +13,7 @@ #include "Host.h" #include "R3000A.h" #include "Common.h" +#include "IopBios.h" #include "IopHw.h" #include "IopDma.h" #include "VMManager.h" @@ -416,10 +417,11 @@ static bool cdvdUncheckedLoadDiscElf(ElfObject* elfo, IsoReader& isor, const std bool cdvdLoadElf(ElfObject* elfo, const std::string_view& elfpath, bool isPSXElf, Error* error) { - if (elfpath.starts_with("host:")) + if (R3000A::ioman::is_host(elfpath)) { - std::string host_filename(elfpath.substr(5)); - return elfo->OpenFile(host_filename, isPSXElf, error); + const std::string_view path(elfpath.substr(elfpath.find(':') + 1)); + const std::string file_path(R3000A::ioman::host_path(path, false)); + return elfo->OpenFile(file_path, isPSXElf, error); } else if (elfpath.starts_with("cdrom:") || elfpath.starts_with("cdrom0:")) { diff --git a/pcsx2/IopBios.cpp b/pcsx2/IopBios.cpp index 5322461711e14..192158c86286d 100644 --- a/pcsx2/IopBios.cpp +++ b/pcsx2/IopBios.cpp @@ -149,51 +149,6 @@ namespace R3000A 0x1000, }; - static std::string host_path(const std::string& path, bool allow_open_host_root) - { - // We are NOT allowing to use the root of the host unit. - // For now it just supports relative folders from the location of the elf - std::string native_path(Path::Canonicalize(path)); - std::string new_path; - if (!hostRoot.empty() && native_path.starts_with(hostRoot)) - new_path = std::move(native_path); - else if (!hostRoot.empty()) // relative paths - new_path = Path::Combine(hostRoot, native_path); - - // Allow opening the ELF override. - if (new_path == VMManager::Internal::GetELFOverride()) - return new_path; - - // Allow nothing if hostfs isn't enabled. - if (!EmuConfig.HostFs) - { - new_path.clear(); - return new_path; - } - - // Double-check that it falls within the directory of the elf. - // Not a real sandbox, but emulators shouldn't be treated as such. Don't run untrusted code! - std::string canonicalized_path(Path::Canonicalize(new_path)); - - // Are we opening the root of host? (i.e. `host:.` or `host:`) - // We want to allow this as a directory open, but not as a file open. - if (!allow_open_host_root || canonicalized_path != hostRoot) - { - // Only allow descendants of the hostfs directory. - if (canonicalized_path.length() <= hostRoot.length() || // Length has to be equal or longer, - !canonicalized_path.starts_with(hostRoot) || // and start with the host root, - canonicalized_path[hostRoot.length()] != FS_OSPATH_SEPARATOR_CHARACTER) // and we can't access a sibling. - { - Console.Error(fmt::format( - "IopHLE: Denying access to path outside of ELF directory. Requested path: '{}', Resolved path: '{}', ELF directory: '{}'", - path, new_path, hostRoot)); - new_path.clear(); - } - } - - return new_path; - } - // This is a workaround for GHS on *NIX platforms // Whenever a program splits directories with a backslash (ulaunchelf) // the directory is considered non-existant @@ -207,7 +162,7 @@ namespace R3000A static int host_stat(const std::string path, fio_stat_t* host_stats, fio_stat_flags& stat = ioman_stat) { struct stat file_stats; - const std::string file_path(host_path(path, true)); + const std::string file_path(ioman::host_path(path, true)); if (!FileSystem::StatFile(file_path.c_str(), &file_stats)) return -IOP_ENOENT; @@ -303,7 +258,7 @@ namespace R3000A static int open(IOManFile** file, const std::string& full_path, s32 flags, u16 mode) { const std::string path(full_path.substr(full_path.find(':') + 1)); - const std::string file_path(host_path(path, false)); + const std::string file_path(ioman::host_path(path, false)); int native_flags = O_BINARY; // necessary in Windows. switch (flags & IOP_O_RDWR) @@ -401,7 +356,7 @@ namespace R3000A static int open(IOManDir** dir, const std::string& full_path) { std::string relativePath = full_path.substr(full_path.find(':') + 1); - std::string path = host_path(relativePath, true); + std::string path = ioman::host_path(relativePath, true); if (!FileSystem::DirectoryExists(path.c_str())) return -IOP_ENOENT; // Should return ENOTDIR if path is a file? @@ -425,13 +380,13 @@ namespace R3000A { fxio_dirent_t* hostcontent = (fxio_dirent_t*)buf; StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name)); - host_stat(host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat); + host_stat(ioman::host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat); } else { fio_dirent_t* hostcontent = (fio_dirent_t*)buf; StringUtil::Strlcpy(hostcontent->name, dir->FileName, sizeof(hostcontent->name)); - host_stat(host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat); + host_stat(ioman::host_path(Path::Combine(basedir, dir->FileName), true), &hostcontent->stat); } dir = std::next(dir); @@ -559,7 +514,7 @@ namespace R3000A } } - bool is_host(const std::string path) + bool is_host(const std::string_view path) { auto not_number_pos = path.find_first_not_of("0123456789", 4); if (not_number_pos == std::string::npos) @@ -568,6 +523,51 @@ namespace R3000A return (path.compare(0, 4, "host") == 0 && path[not_number_pos] == ':'); } + std::string host_path(const std::string_view path, bool allow_open_host_root) + { + // We are NOT allowing to use the root of the host unit. + // For now it just supports relative folders from the location of the elf + std::string native_path(Path::Canonicalize(path)); + std::string new_path; + if (!hostRoot.empty() && native_path.starts_with(hostRoot)) + new_path = std::move(native_path); + else if (!hostRoot.empty()) // relative paths + new_path = Path::Combine(hostRoot, native_path); + + // Allow opening the ELF override. + if (new_path == VMManager::Internal::GetELFOverride()) + return new_path; + + // Allow nothing if hostfs isn't enabled. + if (!EmuConfig.HostFs) + { + new_path.clear(); + return new_path; + } + + // Double-check that it falls within the directory of the elf. + // Not a real sandbox, but emulators shouldn't be treated as such. Don't run untrusted code! + std::string canonicalized_path(Path::Canonicalize(new_path)); + + // Are we opening the root of host? (i.e. `host:.` or `host:`) + // We want to allow this as a directory open, but not as a file open. + if (!allow_open_host_root || canonicalized_path != hostRoot) + { + // Only allow descendants of the hostfs directory. + if (canonicalized_path.length() <= hostRoot.length() || // Length has to be equal or longer, + !canonicalized_path.starts_with(hostRoot) || // and start with the host root, + canonicalized_path[hostRoot.length()] != FS_OSPATH_SEPARATOR_CHARACTER) // and we can't access a sibling. + { + Console.Error(fmt::format( + "IopHLE: Denying access to path outside of ELF directory. Requested path: '{}', Resolved path: '{}', ELF directory: '{}'", + path, new_path, hostRoot)); + new_path.clear(); + } + } + + return new_path; + } + int open_HLE() { IOManFile* file = NULL; diff --git a/pcsx2/IopBios.h b/pcsx2/IopBios.h index 4a263b8943596..112b0cf390a63 100644 --- a/pcsx2/IopBios.h +++ b/pcsx2/IopBios.h @@ -71,6 +71,8 @@ namespace R3000A namespace ioman { void reset(); + bool is_host(const std::string_view path); + std::string host_path(const std::string_view path, bool allow_open_host_root); } } // namespace R3000A From dc20521b011e56493d22fd28e168965e68819e9c Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Sat, 13 Apr 2024 15:05:51 +0100 Subject: [PATCH 8/9] DEV9: Fix incorrect cmake entry --- pcsx2/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 4ecc6b50b9d1c..e88eab4d68636 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -325,7 +325,7 @@ set(pcsx2DEV9Headers DEV9/ATA/ATA.h DEV9/ATA/HddCreate.h DEV9/DEV9.h - DEV9/InternalServers/DHCP_Server.cpp + DEV9/InternalServers/DHCP_Server.h DEV9/InternalServers/DNS_Logger.h DEV9/InternalServers/DNS_Server.h DEV9/net.h From e53abb198965f91a5fe9ed9518efee7355654046 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Sat, 13 Apr 2024 15:06:58 +0100 Subject: [PATCH 9/9] DEV9: Add DHCP logger Enabled by setting `EthLogDHCP = true` in PCSX2.ini --- pcsx2/CMakeLists.txt | 2 + pcsx2/Config.h | 1 + pcsx2/DEV9/InternalServers/DHCP_Logger.cpp | 338 +++++++++++++++++++++ pcsx2/DEV9/InternalServers/DHCP_Logger.h | 46 +++ pcsx2/DEV9/net.cpp | 25 +- pcsx2/DEV9/net.h | 2 + pcsx2/Pcsx2Config.cpp | 2 + pcsx2/pcsx2.vcxproj | 2 + pcsx2/pcsx2.vcxproj.filters | 6 + 9 files changed, 420 insertions(+), 4 deletions(-) create mode 100644 pcsx2/DEV9/InternalServers/DHCP_Logger.cpp create mode 100644 pcsx2/DEV9/InternalServers/DHCP_Logger.h diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index e88eab4d68636..572b94ab442c6 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -287,6 +287,7 @@ set(pcsx2DEV9Sources DEV9/ATA/ATA_State.cpp DEV9/ATA/ATA_Transfer.cpp DEV9/ATA/HddCreate.cpp + DEV9/InternalServers/DHCP_Logger.cpp DEV9/InternalServers/DHCP_Server.cpp DEV9/InternalServers/DNS_Logger.cpp DEV9/InternalServers/DNS_Server.cpp @@ -325,6 +326,7 @@ set(pcsx2DEV9Headers DEV9/ATA/ATA.h DEV9/ATA/HddCreate.h DEV9/DEV9.h + DEV9/InternalServers/DHCP_Logger.h DEV9/InternalServers/DHCP_Server.h DEV9/InternalServers/DNS_Logger.h DEV9/InternalServers/DNS_Server.h diff --git a/pcsx2/Config.h b/pcsx2/Config.h index e4ab52b9a4afb..c8e1a4a33346a 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -861,6 +861,7 @@ struct Pcsx2Config bool EthEnable{false}; NetApi EthApi{NetApi::Unset}; std::string EthDevice; + bool EthLogDHCP{false}; bool EthLogDNS{false}; bool InterceptDHCP{false}; diff --git a/pcsx2/DEV9/InternalServers/DHCP_Logger.cpp b/pcsx2/DEV9/InternalServers/DHCP_Logger.cpp new file mode 100644 index 0000000000000..f0ebd81bc75c2 --- /dev/null +++ b/pcsx2/DEV9/InternalServers/DHCP_Logger.cpp @@ -0,0 +1,338 @@ +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team +// SPDX-License-Identifier: LGPL-3.0+ + +#include "DHCP_Logger.h" +#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h" +#include "DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.h" + +#include + +#include "common/Console.h" +#include "common/StringUtil.h" + +#include "DEV9/AdapterUtils.h" + +using PacketReader::PayloadPtr; +using namespace PacketReader::IP; +using namespace PacketReader::IP::UDP; +using namespace PacketReader::IP::UDP::DHCP; + +namespace InternalServers +{ +#ifdef _WIN32 + void DHCP_Logger::Init(PIP_ADAPTER_ADDRESSES adapter) +#elif defined(__POSIX__) + void DHCP_Logger::Init(ifaddrs* adapter) +#endif + { + std::optional adIP = AdapterUtils::GetAdapterIP(adapter); + if (adIP.has_value()) + pcIP = adIP.value(); + else + pcIP = {}; + } + + void DHCP_Logger::InspectRecv(IP_Payload* payload) + { + UDP_Packet* udpPacket = static_cast(payload); + PayloadPtr* udpPayload = static_cast(udpPacket->GetPayload()); + DHCP_Packet dhcp(udpPayload->data, udpPayload->GetLength()); + Console.WriteLn("DEV9: DHCP: Host PC IP is %s", IpToString(pcIP).c_str()); + LogPacket(&dhcp); + } + + void DHCP_Logger::InspectSend(IP_Payload* payload) + { + UDP_Packet* udpPacket = static_cast(payload); + PayloadPtr* udpPayload = static_cast(udpPacket->GetPayload()); + DHCP_Packet dhcp(udpPayload->data, udpPayload->GetLength()); + Console.WriteLn("DEV9: DHCP: Host PC IP is %s", IpToString(pcIP).c_str()); + LogPacket(&dhcp); + } + + std::string DHCP_Logger::IpToString(IP_Address ip) + { + return StringUtil::StdStringFromFormat("%u.%u.%u.%u", ip.bytes[0], ip.bytes[1], ip.bytes[2], ip.bytes[3]); + } + + std::string DHCP_Logger::HardwareAddressToString(u8* data, size_t len) + { + std::string str; + if (len != 0) + { + str.reserve(len * 4); + for (size_t i = 0; i < len; i++) + str += StringUtil::StdStringFromFormat("%.2X:", data[i]); + + str.pop_back(); + } // else leave string empty + return str; + } + + std::string DHCP_Logger::ClientIdToString(const std::vector& data) + { + std::string str; + if (data.size() != 0) + { + str.reserve(data.size() * 4); + for (size_t i = 0; i < data.size(); i++) + str += StringUtil::StdStringFromFormat("%.2X:", data[i]); + + str.pop_back(); + } // else leave string empty + return str; + } + + const char* DHCP_Logger::OpToString(u8 op) + { + switch (op) + { + case 1: + return "Request"; + case 2: + return "Reply"; + default: + return "Unknown"; + } + } + + const char* DHCP_Logger::HardwareTypeToString(u8 op) + { + switch (op) + { + case 1: + return "Ethernet"; + case 6: + return "IEEE 802"; + default: + return "Unknown"; + } + } + + const char* DHCP_Logger::OptionToString(u8 option) + { + switch (option) + { + case 0: + return "Nop"; + case 1: + return "Subnet"; + case 3: + return "Routers"; + case 6: + return "DNS"; + case 12: + return "Host Name"; + case 15: + return "DNS Name"; + case 28: + return "Broadcast IP"; + case 46: + return "NetBIOS Type"; + case 50: + return "Requested IP"; + case 51: + return "IP Lease Time"; + case 53: + return "Message Type"; + case 54: + return "Server IP"; + case 55: + return "Request List"; + case 56: + return "Message String"; + case 57: + return "Max Message Size"; + case 58: + return "Renewal Time T1"; + case 59: + return "Rebinding Time T2"; + case 60: + return "Class ID"; + case 61: + return "Client ID"; + case 255: + return "End"; + default: + return "Unknown"; + } + } + + const char* DHCP_Logger::MessageCodeToString(u8 op) + { + switch (op) + { + case 1: + return "DHCP Discover"; + case 2: + return "DHCP Offer"; + case 3: + return "DHCP Request"; + case 4: + return "DHCP Decline"; + case 5: + return "DHCP ACK"; + case 6: + return "DHCP NACK"; + case 7: + return "DHCP Release"; + case 8: + return "DHCP Inform"; + default: + return "Unknown"; + } + } + + void DHCP_Logger::LogPacket(DHCP_Packet* dhcp) + { + Console.WriteLn("DEV9: DHCP: Op %s (%i)", OpToString(dhcp->op), dhcp->op); + Console.WriteLn("DEV9: DHCP: Hardware Type %s (%i)", HardwareTypeToString(dhcp->hardwareType), dhcp->hardwareType); + Console.WriteLn("DEV9: DHCP: Hardware Address Length %i", dhcp->hardwareAddressLength); + Console.WriteLn("DEV9: DHCP: Hops %i", dhcp->hops); + Console.WriteLn("DEV9: DHCP: Transaction ID %i", dhcp->transactionID); + Console.WriteLn("DEV9: DHCP: Seconds %i", dhcp->seconds); + Console.WriteLn("DEV9: DHCP: Flags 0x%.4X", dhcp->flags); + Console.WriteLn("DEV9: DHCP: Client IP %s", IpToString(dhcp->clientIP).c_str()); + Console.WriteLn("DEV9: DHCP: Your IP %s", IpToString(dhcp->yourIP).c_str()); + Console.WriteLn("DEV9: DHCP: Server IP %s", IpToString(dhcp->serverIP).c_str()); + Console.WriteLn("DEV9: DHCP: Gateway IP %s", IpToString(dhcp->gatewayIP).c_str()); + Console.WriteLn("DEV9: DHCP: Gateway IP %s", IpToString(dhcp->gatewayIP).c_str()); + Console.WriteLn("DEV9: DHCP: Client Hardware Address %s", HardwareAddressToString(dhcp->clientHardwareAddress, std::min(dhcp->hardwareAddressLength, 16)).c_str()); + Console.WriteLn("DEV9: DHCP: Magic Cookie 0x%.8X", dhcp->magicCookie); + + Console.WriteLn("DEV9: DHCP: Options Count %i", dhcp->options.size()); + + for (size_t i = 0; i < dhcp->options.size(); i++) + { + BaseOption* entry = dhcp->options[i]; + Console.WriteLn("DEV9: DHCP: Option %s (%i)", OptionToString(entry->GetCode()), entry->GetCode()); + Console.WriteLn("DEV9: DHCP: Option Size %i", entry->GetLength()); + switch (entry->GetCode()) + { + case 0: + break; + case 1: + { + const DHCPopSubnet* subnet = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Subnet %s", IpToString(subnet->subnetMask).c_str()); + break; + } + case 3: + { + const DHCPopRouter* routers = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Routers Count %i", routers->routers.size()); + for (size_t j = 0; j < routers->routers.size(); j++) + Console.WriteLn("DEV9: DHCP: Router %s", IpToString(routers->routers[j]).c_str()); + break; + } + case 6: + { + const DHCPopDNS* dns = static_cast(entry); + Console.WriteLn("DEV9: DHCP: DNS Count %i", dns->dnsServers.size()); + for (size_t j = 0; j < dns->dnsServers.size(); j++) + Console.WriteLn("DEV9: DHCP: DNS %s", IpToString(dns->dnsServers[j]).c_str()); + break; + } + case 12: + { + const DHCPopHostName* name = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Host Name %s", name->hostName.c_str()); + break; + } + case 15: + { + const DHCPopDnsName* name = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Domain Name %s", name->domainName.c_str()); + break; + } + case 28: + { + const DHCPopBCIP* broadcast = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Broadcast IP %s", IpToString(broadcast->broadcastIP).c_str()); + break; + } + case 46: + { + DHCPopNBIOSType* biosType = static_cast(entry); + Console.WriteLn("DEV9: DHCP: NetBIOS B-Node %s", biosType->GetBNode() ? "True" : "False"); + Console.WriteLn("DEV9: DHCP: NetBIOS P-Node %s", biosType->GetPNode() ? "True" : "False"); + Console.WriteLn("DEV9: DHCP: NetBIOS M-Node %s", biosType->GetMNode() ? "True" : "False"); + Console.WriteLn("DEV9: DHCP: NetBIOS H-Node %s", biosType->GetHNode() ? "True" : "False"); + break; + } + case 50: + { + const DHCPopREQIP* req = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Requested IP %s", IpToString(req->requestedIP).c_str()); + break; + } + case 51: + { + const DHCPopIPLT* iplt = static_cast(entry); + Console.WriteLn("DEV9: DHCP: IP Least Time %i", iplt->ipLeaseTime); + break; + } + case 53: + { + const DHCPopMSG* msg = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Message %s (%i)", MessageCodeToString(msg->message), msg->message); + break; + } + case 54: + { + const DHCPopSERVIP* req = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Server IP %s", IpToString(req->serverIP).c_str()); + break; + } + case 55: + { + const DHCPopREQLIST* reqList = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Request Count %i", reqList->requests.size()); + for (size_t j = 0; j < reqList->requests.size(); j++) + Console.WriteLn("DEV9: DHCP: Requested %s (%i)", OptionToString(reqList->requests[j]), reqList->requests[j]); + break; + } + case 56: + { + const DHCPopMSGStr* msg = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Message %s", msg->message.c_str()); + break; + } + case 57: + { + const DHCPopMMSGS* maxMs = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Max Message Size %i", maxMs->maxMessageSize); + break; + } + case 58: + { + const DHCPopT1* t1 = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Renewal Time (T1) %i", t1->ipRenewalTimeT1); + break; + } + case 59: + { + const DHCPopT2* t2 = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Rebinding Time (T2) %i", t2->ipRebindingTimeT2); + break; + } + case 60: + { + const DHCPopClassID* id = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Class ID %s", id->classID.c_str()); + break; + } + case 61: + { + const DHCPopClientID* id = static_cast(entry); + Console.WriteLn("DEV9: DHCP: Client ID %s", ClientIdToString(id->clientID).c_str()); + break; + } + case 255: + break; + default: + break; + } + } + } +} // namespace InternalServers diff --git a/pcsx2/DEV9/InternalServers/DHCP_Logger.h b/pcsx2/DEV9/InternalServers/DHCP_Logger.h new file mode 100644 index 0000000000000..5f796d5895434 --- /dev/null +++ b/pcsx2/DEV9/InternalServers/DHCP_Logger.h @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team +// SPDX-License-Identifier: LGPL-3.0+ + +#pragma once +#include "DEV9/PacketReader/IP/IP_Packet.h" +#include "DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.h" + +#ifdef _WIN32 +#include +#include +#elif defined(__POSIX__) +#include +#include +#endif + +namespace InternalServers +{ + class DHCP_Logger + { + public: + DHCP_Logger(){}; + +#ifdef _WIN32 + void Init(PIP_ADAPTER_ADDRESSES adapter); +#elif defined(__POSIX__) + void Init(ifaddrs* adapter); +#endif + + // Expects a UDP_payload + void InspectRecv(PacketReader::IP::IP_Payload* payload); + // Expects a UDP_payload + void InspectSend(PacketReader::IP::IP_Payload* payload); + + private: + PacketReader::IP::IP_Address pcIP{}; + + std::string IpToString(PacketReader::IP::IP_Address ip); + std::string HardwareAddressToString(u8* data, size_t len); + std::string ClientIdToString(const std::vector& data); + const char* OpToString(u8 op); + const char* HardwareTypeToString(u8 op); + const char* OptionToString(u8 option); + const char* MessageCodeToString(u8 msg); + void LogPacket(PacketReader::IP::UDP::DHCP::DHCP_Packet* payload); + }; +} // namespace InternalServers diff --git a/pcsx2/DEV9/net.cpp b/pcsx2/DEV9/net.cpp index ffcd741a4703f..5c10891a07d4e 100644 --- a/pcsx2/DEV9/net.cpp +++ b/pcsx2/DEV9/net.cpp @@ -205,7 +205,7 @@ NetAdapter::~NetAdapter() void NetAdapter::InspectSend(NetPacket* pkt) { - if (EmuConfig.DEV9.EthLogDNS) + if (EmuConfig.DEV9.EthLogDNS || EmuConfig.DEV9.EthLogDHCP) { EthernetFrame frame(pkt); if (frame.protocol == (u16)EtherType::IPv4) @@ -218,19 +218,26 @@ void NetAdapter::InspectSend(NetPacket* pkt) IP_PayloadPtr* ipPayload = static_cast(ippkt.GetPayload()); UDP_Packet udppkt(ipPayload->data, ipPayload->GetLength()); - if (udppkt.destinationPort == 53) + if (EmuConfig.DEV9.EthLogDNS && udppkt.destinationPort == 53) { Console.WriteLn("DEV9: DNS: Packet Sent To %i.%i.%i.%i", ippkt.destinationIP.bytes[0], ippkt.destinationIP.bytes[1], ippkt.destinationIP.bytes[2], ippkt.destinationIP.bytes[3]); dnsLogger.InspectSend(&udppkt); } + + if (EmuConfig.DEV9.EthLogDHCP && udppkt.destinationPort == 67) + { + Console.WriteLn("DEV9: DHCP: Packet Sent To %i.%i.%i.%i", + ippkt.destinationIP.bytes[0], ippkt.destinationIP.bytes[1], ippkt.destinationIP.bytes[2], ippkt.destinationIP.bytes[3]); + dhcpLogger.InspectSend(&udppkt); + } } } } } void NetAdapter::InspectRecv(NetPacket* pkt) { - if (EmuConfig.DEV9.EthLogDNS) + if (EmuConfig.DEV9.EthLogDNS || EmuConfig.DEV9.EthLogDHCP) { EthernetFrame frame(pkt); if (frame.protocol == (u16)EtherType::IPv4) @@ -243,12 +250,19 @@ void NetAdapter::InspectRecv(NetPacket* pkt) IP_PayloadPtr* ipPayload = static_cast(ippkt.GetPayload()); UDP_Packet udppkt(ipPayload->data, ipPayload->GetLength()); - if (udppkt.sourcePort == 53) + if (EmuConfig.DEV9.EthLogDNS && udppkt.sourcePort == 53) { Console.WriteLn("DEV9: DNS: Packet Sent From %i.%i.%i.%i", ippkt.sourceIP.bytes[0], ippkt.sourceIP.bytes[1], ippkt.sourceIP.bytes[2], ippkt.sourceIP.bytes[3]); dnsLogger.InspectRecv(&udppkt); } + + if (EmuConfig.DEV9.EthLogDHCP && udppkt.sourcePort == 67) + { + Console.WriteLn("DEV9: DHCP: Packet Sent From %i.%i.%i.%i", + ippkt.sourceIP.bytes[0], ippkt.sourceIP.bytes[1], ippkt.sourceIP.bytes[2], ippkt.sourceIP.bytes[3]); + dhcpLogger.InspectRecv(&udppkt); + } } } } @@ -293,6 +307,8 @@ void NetAdapter::InitInternalServer(ifaddrs* adapter, bool dhcpForceEnable, IP_A if (adapter == nullptr) Console.Error("DEV9: InitInternalServer() got nullptr for adapter"); + dhcpLogger.Init(adapter); + dhcpOn = EmuConfig.DEV9.InterceptDHCP || dhcpForceEnable; if (dhcpOn) dhcpServer.Init(adapter, ipOverride, subnetOverride, gatewayOvveride); @@ -336,6 +352,7 @@ bool NetAdapter::InternalServerRecv(NetPacket* pkt) frame.destinationMAC = ps2MAC; frame.protocol = (u16)EtherType::IPv4; frame.WritePacket(pkt); + InspectRecv(pkt); return true; } diff --git a/pcsx2/DEV9/net.h b/pcsx2/DEV9/net.h index 6c0dc9e0b407a..e78bc367e3fce 100644 --- a/pcsx2/DEV9/net.h +++ b/pcsx2/DEV9/net.h @@ -24,6 +24,7 @@ #include "PacketReader/MAC_Address.h" #include "PacketReader/IP/IP_Address.h" +#include "InternalServers/DHCP_Logger.h" #include "InternalServers/DHCP_Server.h" #include "InternalServers/DNS_Logger.h" #include "InternalServers/DNS_Server.h" @@ -99,6 +100,7 @@ class NetAdapter bool dhcpOn = false; protected: + InternalServers::DHCP_Logger dhcpLogger; InternalServers::DHCP_Server dhcpServer = InternalServers::DHCP_Server([&] { InternalSignalReceived(); }); InternalServers::DNS_Logger dnsLogger; InternalServers::DNS_Server dnsServer = InternalServers::DNS_Server([&] { InternalSignalReceived(); }); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index c308903a6a936..228f7ae9a032c 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -1161,6 +1161,7 @@ void Pcsx2Config::DEV9Options::LoadSave(SettingsWrapper& wrap) SettingsWrapEntry(EthEnable); SettingsWrapEnumEx(EthApi, "EthApi", NetApiNames); SettingsWrapEntry(EthDevice); + SettingsWrapEntry(EthLogDHCP); SettingsWrapEntry(EthLogDNS); SettingsWrapEntry(InterceptDHCP); @@ -1254,6 +1255,7 @@ bool Pcsx2Config::DEV9Options::operator==(const DEV9Options& right) const return OpEqu(EthEnable) && OpEqu(EthApi) && OpEqu(EthDevice) && + OpEqu(EthLogDHCP) && OpEqu(EthLogDNS) && OpEqu(InterceptDHCP) && diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index 584fb19b6578e..7661da8d4146a 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -152,6 +152,7 @@ + @@ -490,6 +491,7 @@ + diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index a380ff0dfdbb0..deec19ba763f9 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -884,6 +884,9 @@ System\Ps2\DEV9 + + System\Ps2\DEV9\InternalServers + System\Ps2\DEV9\InternalServers @@ -1736,6 +1739,9 @@ System\Ps2\DEV9 + + System\Ps2\DEV9\InternalServers + System\Ps2\DEV9\InternalServers