PDA

View Full Version : Improved NetCode


Wiz
03-02-2005, 03:09 AM
OK, first of all, this code will *not* work with the big netcode changes on EQlive. This is ONLY for people who run older-version servers.

That said, this rewrite to netcode will fix a lot of existing issues such as login bug, insta-LD bug, and in general is a lot more stable than the current netcode.

Simply do the following swaps in the below /common/ files.

EQNetwork.cpp

Swap out EQNetworkConnection::Process for:


#ifdef WIN32
void EQNetworkConnection::Process(SOCKET sock) {
#else
void EQNetworkConnection::Process(int sock) {
#endif
if (!CheckNetActive())
return;
InQueue_Struct* iqs = 0;
while ((iqs = InQueuePop())) {
MakeEQPacket(iqs->app, iqs->ackreq);
safe_delete(iqs->app);
delete iqs;
}
CreateCombinedPacket();
if (timeout_timer->Check()) {
Close();
}
fraglist.CheckTimers();

if (datarate_timer->Check(0))
{
datarate_timer->Start();
dataflow -= datarate_tic;
if (dataflow < 0)
dataflow = 0;
}

EQNetworkPacket* pack;
int32 size;
uchar* data;
sockaddr_in to;
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = rPort;
to.sin_addr.s_addr = rIP;

LinkedListIterator<EQNetworkPacket*> iterator(SendQueue);
iterator.Reset();
if (iterator.MoreElements()) {
keep_alive_timer->Start();
}
else if (IsFree()) {
SetState(EQNC_Finished);
}
#ifdef PRIORITYTEST
if(DataQueueFull() && GetState() == EQNC_Active && queue_check_timer->Check())
{
PacketPriority();
}
#endif

int nas=0, ka=0;
//This sends out "pure" packets that verify to the client that it and the server is still on talking terms
if ( (GetState() == EQNC_Active) && ((nas=no_ack_sent_timer->Check(0)) || (ka=keep_alive_timer->Check(0))) )
{
APPLAYER outapp;
outapp.opcode = 0xFFFF;
outapp.priority = 5;
MakeEQPacket(&outapp, ka);
}

iterator.Reset();
while (iterator.MoreElements() && (!DataQueueFull())) {
pack = iterator.GetData();
if (GetState() != EQNC_Active || (pack->SentCount == 0 && Timer::GetCurrentTime() >= (pack->LastSent+1000)))
{
cout<<""; //Magic cout. This tiny artifical pause will keep the packet process from sending out packets too rapidly and getting them discarded in the process. Especially important during log in/zone processes.

pack->SentCount = 1; //A packet that's been sent shouldn't be resent as long as the connection is moving along smoothly, this just inflates packetrate and causes trouble.

if (GetState() == EQNC_Active && pack->dwARQ == arsp_response + 10) //This code checks if 10 packets have been sent since last ARSP ("we got this packet yo") response from client, and if so, tags those ten packets that haven't been verifiably recieved for a resend. Should probably be condensed into a function for cleanliness :P
{
LinkedListIterator<EQNetworkPacket*> iterator2(SendQueue);
iterator2.Reset();
while (iterator2.MoreElements())
{
EQNetworkPacket* pack2 = iterator2.GetData();
if (pack2->dwARQ == pack->dwARQ)
break;
iterator2.Advance();
}
}

if (pack->HDR.a2_Closing && pack->HDR.a6_Closing) //Closing bits. Terminates the connection properly.
{
size = pack->ReturnPacket(&data);
sendto(sock, (char*) data, size, 0, (sockaddr*) &to, sizeof(to));
delete[] data;

iterator.RemoveCurrent();
continue;
}
else if (GetState() != EQNC_Active) { //Nothing but closing bits to be sent after a connection close. It's not recieved, so why waste processing power?
iterator.RemoveCurrent();
continue;
}
else //SendOut
{
size = pack->ReturnPacket(&data);
sendto(sock, (char*) data, size, 0, (sockaddr*) &to, sizeof(to));
delete[] data;

if (!pack->HDR.a1_ARQ) { //Wtf is this for?
iterator.RemoveCurrent();
continue;
}

dataflow += size;
pack->LastSent = Timer::GetCurrentTime();
}
}
iterator.Advance();
if (!iterator.MoreElements()) //This terminates the process properly after a closed connection has cleaned out the queue.
{
if (GetState() != EQNC_Active)
{
SetState(EQNC_Error);
}
}
}
}


Add this line to the IncomingARSP() function, just below iterator.Reset();


arsp_response = arsp;


Add this line to EQNetworkConnection::EQNetworkConnection


arsp_response = 0;


Add this line under the private part of the EQNetworkConnection class in EQNetwork.h


int16 arsp_response;


There, you're done. Pat yourself on the back and feel free to feedback any issues.

mangoo
03-02-2005, 07:56 AM
Very nice Wiz, thanks =).

fathernitwit
03-04-2005, 06:56 AM
Hey wiz,

in this code:

if (GetState() == EQNC_Active && pack->dwARQ == arsp_response + 10) //This code checks if 10 packets have been sent since last ARSP ("we got this packet yo") response from client, and if so, tags those ten packets that haven't been verifiably recieved for a resend. Should probably be condensed into a function for cleanliness :P
{
LinkedListIterator<EQNetworkPacket*> iterator2(SendQueue);
iterator2.Reset();
while (iterator2.MoreElements())
{
EQNetworkPacket* pack2 = iterator2.GetData();
if (pack2->dwARQ == pack->dwARQ)
break;
iterator2.Advance();
}
}


I imagine that you wanted to set SentCount to 0 so it would be resent.. but you dont, so I imagine packets will never get resent. In fact, this loop does nothing at all.

Wiz
03-04-2005, 07:23 AM
Hey wiz,

in this code:

if (GetState() == EQNC_Active && pack->dwARQ == arsp_response + 10) //This code checks if 10 packets have been sent since last ARSP ("we got this packet yo") response from client, and if so, tags those ten packets that haven't been verifiably recieved for a resend. Should probably be condensed into a function for cleanliness :P
{
LinkedListIterator<EQNetworkPacket*> iterator2(SendQueue);
iterator2.Reset();
while (iterator2.MoreElements())
{
EQNetworkPacket* pack2 = iterator2.GetData();
if (pack2->dwARQ == pack->dwARQ)
break;
iterator2.Advance();
}
}


I imagine that you wanted to set SentCount to 0 so it would be resent.. but you dont, so I imagine packets will never get resent. In fact, this loop does nothing at all.

... strange. It most certainly does something in my code, I must have omitted it somehow doesn't in the pasted code. Just throw in a pack2->SentCount = 0 there.