Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEV9: TCP Cleanup #11132

Merged
merged 6 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 7 additions & 8 deletions pcsx2/DEV9/Sessions/TCP_Session/TCP_Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,27 @@ namespace Sessions
if (delta > 0.5 * UINT_MAX)
{
delta = -static_cast<s64>(UINT_MAX) + a - b - 1;
Console.Error("DEV9: TCP: [PS2] SequenceNumber Overflow Detected");
Console.Error("DEV9: TCP: [PS2] New Data Offset: %d bytes", delta);
Console.Error("DEV9: TCP: [PS2] Sequence number overflow detected");
Console.Error("DEV9: TCP: [PS2] New data offset: %d bytes", delta);
}
if (delta < -0.5 * UINT_MAX)
{
delta = UINT_MAX - b + a + 1;
Console.Error("DEV9: TCP: [PS2] SequenceNumber Overflow Detected");
Console.Error("DEV9: TCP: [PS2] New Data Offset: %d bytes", delta);
Console.Error("DEV9: TCP: [PS2] Sequence number overflow detected");
Console.Error("DEV9: TCP: [PS2] New data offset: %d bytes", delta);
}
return delta;
}

TCP_Packet* TCP_Session::CreateBasePacket(PayloadData* data)
{
//DevCon.WriteLn("Creating Base Packet");
//DevCon.WriteLn("Creating base packet");
if (data == nullptr)
data = new PayloadData(0);

TCP_Packet* ret = new TCP_Packet(data);

//and now to setup THE ENTIRE THING
// Setup common packet infomation
ret->sourcePort = destPort;
ret->destinationPort = srcPort;

Expand Down Expand Up @@ -149,15 +149,14 @@ namespace Sessions

void TCP_Session::Reset()
{
//CloseSocket();
RaiseEventConnectionClosed();
}

TCP_Session::~TCP_Session()
{
CloseSocket();

//Clear out _recvBuff
// Clear out _recvBuff
while (!_recvBuff.IsQueueEmpty())
{
TCP_Packet* retPay;
Expand Down
62 changes: 32 additions & 30 deletions pcsx2/DEV9/Sessions/TCP_Session/TCP_Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace Sessions
Closing_ClosedByPS2ThenRemote_WaitingForAck,
Closing_ClosedByRemote,
Closing_ClosedByRemoteThenPS2_WaitingForAck,
CloseCompletedFlushBuffer, //Packets in recvBuff to send
CloseCompletedFlushBuffer, // Send any remaining packets in recvBuff
CloseCompleted,
};
enum struct NumCheckResult
Expand All @@ -55,17 +55,17 @@ namespace Sessions
u16 srcPort = 0;
u16 destPort = 0;

u16 maxSegmentSize = 1460; //Accesed By Both In and Out Threads, but set only on Connect Thread
u16 maxSegmentSize = 1460; // Accesed by both in and out threads, but set only on connect thread
int windowScale = 0;
std::atomic<int> windowSize{1460}; //Make atomic instead
std::atomic<int> windowSize{1460};

u32 lastRecivedTimeStamp; //Accesed By Both In and Out Threads
std::chrono::steady_clock::time_point timeStampStart; //Set By In on connect, read by In and Out Threads, unsure as to correct C++ type
bool sendTimeStamps = false; //Accesed By Out Thread Only
u32 lastRecivedTimeStamp; // Accesed by both in and out threads
std::chrono::steady_clock::time_point timeStampStart; // Set by in thread on connect, read by in and out threads
bool sendTimeStamps = false; // Accesed by out thread only

const int receivedPS2SeqNumberCount = 5;
u32 expectedSeqNumber; //Accesed By Out Thread Only
std::vector<u32> receivedPS2SeqNumbers; //Accesed By Out Thread Only
u32 expectedSeqNumber; // Accesed by out thread only
std::vector<u32> receivedPS2SeqNumbers; // Accesed by out thread only

std::mutex myNumberSentry;
const int oldMyNumCount = 64;
Expand All @@ -84,8 +84,7 @@ namespace Sessions
virtual ~TCP_Session();

private:
//Async stuff

// Async functions
void PushRecvBuff(PacketReader::IP::TCP::TCP_Packet* tcp);
PacketReader::IP::TCP::TCP_Packet* PopRecvBuff();

Expand All @@ -99,45 +98,48 @@ namespace Sessions

NumCheckResult CheckRepeatSYNNumbers(PacketReader::IP::TCP::TCP_Packet* tcp);
NumCheckResult CheckNumbers(PacketReader::IP::TCP::TCP_Packet* tcp, bool rejectOldSeq = false);
s32 GetDelta(u32 a, u32 b); //Returns a - b
//Returns true if errored
// Returns a - b, accounting for overflow
s32 GetDelta(u32 a, u32 b);
// Returns true if errored
bool ValidateEmptyPacket(PacketReader::IP::TCP::TCP_Packet* tcp, bool ignoreOld = true);

//PS2 sent SYN
// PS2 sent SYN
PacketReader::IP::TCP::TCP_Packet* ConnectTCPComplete(bool success);
bool SendConnect(PacketReader::IP::TCP::TCP_Packet* tcp);
bool SendConnected(PacketReader::IP::TCP::TCP_Packet* tcp);

bool SendData(PacketReader::IP::TCP::TCP_Packet* tcp);
bool SendNoData(PacketReader::IP::TCP::TCP_Packet* tcp);

//On Close by PS2
//S1: PS2 Sends FIN+ACK
//S2: CloseByPS2Stage1_2 sends ACK, state set to Closing_ClosedByPS2
//S3: When server closes socket, we send FIN in CloseByPS2Stage3
//and set state to Closing_ClosedByPS2ThenRemote_WaitingForAck
//S4: PS2 then Sends ACK

/*
* On close by PS2
* S1: PS2 Sends FIN+ACK
* S2: CloseByPS2Stage1_2 sends ACK, state set to Closing_ClosedByPS2
* S3: When server closes socket, we send FIN in CloseByPS2Stage3
* and set state to Closing_ClosedByPS2ThenRemote_WaitingForAck
* S4: PS2 then Sends ACK
*/
bool CloseByPS2Stage1_2(PacketReader::IP::TCP::TCP_Packet* tcp);
PacketReader::IP::TCP::TCP_Packet* CloseByPS2Stage3();
bool CloseByPS2Stage4(PacketReader::IP::TCP::TCP_Packet* tcp);

//On Close By Server
//S1: CloseByRemoteStage1 sends FIN+ACK, state set to Closing_ClosedByRemote
//S2: PS2 Will then sends ACK, this is only checked after stage4
//S3: PS2 Will send FIN, possible in the previous ACK packet
//S4: CloseByRemoteStage3_4 sends ACK, state set to
//Closing_ClosedByRemoteThenPS2_WaitingForAck
//We Then Check if S3 has been compleated

/*
* On close By Server
* S1: CloseByRemoteStage1 sends FIN+ACK, state set to Closing_ClosedByRemote
* S2: PS2 Will then sends ACK, this is only checked after stage4
* S3: PS2 Will send FIN, possible in the previous ACK packet
* S4: CloseByRemoteStage3_4 sends ACK, state set to
* Closing_ClosedByRemoteThenPS2_WaitingForAck
* we then check if S3 has been completed
*/
PacketReader::IP::TCP::TCP_Packet* CloseByRemoteStage1();
bool CloseByRemoteStage2_ButAfter4(PacketReader::IP::TCP::TCP_Packet* tcp);
bool CloseByRemoteStage3_4(PacketReader::IP::TCP::TCP_Packet* tcp);

//Error on sending data
// Error on sending data
void CloseByRemoteRST();

//Returned TCP_Packet Takes ownership of data
// Returned TCP_Packet takes ownership of data
PacketReader::IP::TCP::TCP_Packet* CreateBasePacket(PacketReader::PayloadData* data = nullptr);

void CloseSocket();
Expand Down
59 changes: 30 additions & 29 deletions pcsx2/DEV9/Sessions/TCP_Session/TCP_Session_In.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,20 @@ namespace Sessions
return nullptr;
}
case TCP_State::SentSYN_ACK:
//Don't read data untill PS2 ACKs connection
// Don't read data untill PS2 ACKs connection
return nullptr;
case TCP_State::CloseCompletedFlushBuffer:
//When TCP connection is closed by the server
//the server is the last to send a packet
//so the event must be raised here
/*
* When TCP connection is closed by the server
* the server is the last to send a packet
* so the event must be raised here
*/
state = TCP_State::CloseCompleted;
RaiseEventConnectionClosed();
return nullptr;
case TCP_State::Connected:
case TCP_State::Closing_ClosedByPS2:
//Only accept data in above two states
// Only accept data in above two states
break;
default:
return nullptr;
Expand All @@ -70,8 +72,8 @@ namespace Sessions
if (ShouldWaitForAck())
return nullptr;

//Note, windowSize will be updated before _ReceivedAckNumber, potential race condition
//in practice, we just get a smaller or -ve maxSize
// Note, windowSize will be updated before _ReceivedAckNumber, potential race condition
// in practice, we just get a smaller or -ve maxSize
const u32 outstanding = GetOutstandingSequenceLength();

int maxSize = 0;
Expand All @@ -86,8 +88,8 @@ namespace Sessions
int err = 0;
int recived;

//FIONREAD uses unsigned long on windows and int on linux
//Zero init so we don't have bad data on any unused bytes
// FIONREAD uses unsigned long on windows and int on linux
// Zero init so we don't have bad data on any unused bytes
unsigned long available = 0;
#ifdef _WIN32
err = ioctlsocket(client, FIONREAD, &available);
Expand All @@ -97,10 +99,10 @@ namespace Sessions
if (err != SOCKET_ERROR)
{
if (available > static_cast<uint>(maxSize))
Console.WriteLn("DEV9: TCP: Got a lot of data: %lu Using: %d", available, maxSize);
Console.WriteLn("DEV9: TCP: Got a lot of data: %lu using: %d", available, maxSize);

buffer = std::make_unique<u8[]>(maxSize);
recived = recv(client, (char*)buffer.get(), maxSize, 0);
recived = recv(client, reinterpret_cast<char*>(buffer.get()), maxSize, 0);
if (recived == -1)
#ifdef _WIN32
err = WSAGetLastError();
Expand All @@ -113,17 +115,16 @@ namespace Sessions
#ifdef _WIN32
case WSAEINVAL:
case WSAESHUTDOWN:
//In theory, this should only occur when the PS2 has RST the connection
//and the call to TCPSession.Recv() occurs at just the right time.

// In theory, this should only occur when the PS2 has RST the connection
// and the call to TCPSession.Recv() occurs at just the right time.
//Console.WriteLn("DEV9: TCP: Recv() on shutdown socket");
return nullptr;
case WSAEWOULDBLOCK:
return nullptr;
#elif defined(__POSIX__)
case EINVAL:
case ESHUTDOWN:
//See WSAESHUTDOWN
// See WSAESHUTDOWN
//Console.WriteLn("DEV9: TCP: Recv() on shutdown socket");
return nullptr;
case EWOULDBLOCK:
Expand All @@ -133,16 +134,16 @@ namespace Sessions
break;
default:
CloseByRemoteRST();
Console.Error("DEV9: TCP: Recv Error: %d", err);
Console.Error("DEV9: TCP: Recv error: %d", err);
return nullptr;
}

//Server Closed Socket
// Server closed the Socket
if (recived == 0)
{
int result = shutdown(client, SD_RECEIVE);
const int result = shutdown(client, SD_RECEIVE);
if (result == SOCKET_ERROR)
Console.Error("DEV9: TCP: Shutdown SD_RECEIVE Error: %d",
Console.Error("DEV9: TCP: Shutdown SD_RECEIVE error: %d",
#ifdef _WIN32
WSAGetLastError());
#elif defined(__POSIX__)
Expand All @@ -157,7 +158,7 @@ namespace Sessions
return CloseByPS2Stage3();
default:
CloseByRemoteRST();
Console.Error("DEV9: TCP: Remote Close In Invalid State");
Console.Error("DEV9: TCP: Remote close occured with invalid TCP state");
break;
}
return nullptr;
Expand All @@ -174,7 +175,7 @@ namespace Sessions
iRet->SetPSH(true);

myNumberACKed.store(false);
//DevCon.WriteLn("DEV9: TCP: myNumberACKed Reset");
//DevCon.WriteLn("DEV9: TCP: myNumberACKed reset");
return iRet;
}
}
Expand All @@ -189,7 +190,7 @@ namespace Sessions
state = TCP_State::SentSYN_ACK;

TCP_Packet* ret = new TCP_Packet(new PayloadData(0));
//Return the fact we connected
// Send packet to say we connected
ret->sourcePort = destPort;
ret->destinationPort = srcPort;

Expand Down Expand Up @@ -223,15 +224,15 @@ namespace Sessions
int error = 0;
#ifdef _WIN32
int len = sizeof(error);
if (getsockopt(client, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0)
Console.Error("DEV9: TCP: Unkown TCP Connection Error (getsockopt Error: %d)", WSAGetLastError());
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
Console.Error("DEV9: TCP: Unkown TCP 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)
Console.Error("DEV9: TCP: Unkown TCP Connection Error (getsockopt Error: %d)", errno);
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
Console.Error("DEV9: TCP: Unkown TCP connection error (getsockopt error: %d)", errno);
#endif
else
Console.Error("DEV9: TCP: Send Error: %d", error);
Console.Error("DEV9: TCP: Send error: %d", error);

state = TCP_State::CloseCompleted;
RaiseEventConnectionClosed();
Expand All @@ -250,7 +251,7 @@ namespace Sessions
ret->SetFIN(true);

myNumberACKed.store(false);
//DevCon.WriteLn("myNumberACKed Reset");
//DevCon.WriteLn("myNumberACKed reset");

state = TCP_State::Closing_ClosedByPS2ThenRemote_WaitingForAck;
return ret;
Expand All @@ -267,7 +268,7 @@ namespace Sessions
ret->SetFIN(true);

myNumberACKed.store(false);
//DevCon.WriteLn("myNumberACKed Reset");
//DevCon.WriteLn("myNumberACKed reset");

state = TCP_State::Closing_ClosedByRemote;
return ret;
Expand Down