⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netudp.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
字号:
/*///////////////////////////////////////////////////////////////////////////
UDP连接封装管理


李亦
2006.6.15
/*///////////////////////////////////////////////////////////////////////////

#include "platform/platform.h"
#include "platform/event.h"
#include "sim/netConnection.h"
#include "server/net/netUDP.h"
#include "core/bitStream.h"
#include "math/mRandom.h"
#include "platform/gameInterface.h"

//NetUDP *GNet = NULL;

namespace RPGServer
{

NetUDP::NetUDP(NetManager* pManager)
:Parent(pManager)
{
   //AssertFatal(GNet == NULL, "ERROR: Multiple net interfaces declared.");
   //GNet = this;
	//m_pNetManager = pManager;
   //mLastTimeoutCheckTime = 0;
   //mAllowConnections = true;

}



void NetUDP::processPacketReceiveEvent(PacketReceiveEvent *prEvent)
{
   if(prEvent->data[0] & 0x01)
	{
		Parent::processPacketReceiveEvent(prEvent);
		return;
	}

   U32 dataSize = prEvent->size - PacketReceiveEventHeaderSize;
   BitStream pStream(prEvent->data, dataSize);

      // Otherwise, it's either a game info packet or a
      // connection handshake packet.

      U8 packetType;
      pStream.read(&packetType);
      NetAddress *addr = &prEvent->sourceAddress;

      if(packetType <= GameHeartbeat)
         handleInfoPacket(addr, packetType, &pStream);
      else
      {
         // check if there's a connection already:
         NetConnection *conn;
         switch(packetType)
         {
            case ConnectChallengeRequest:
               handleConnectChallengeRequest(addr, &pStream);
               break;
            case ConnectRequest:
               handleConnectRequest(addr, &pStream);
               break;
            case ConnectChallengeResponse:
               handleConnectChallengeResponse(addr, &pStream);
               break;
            case ConnectAccept:
               handleConnectAccept(addr, &pStream);
               break;
            case Disconnect:
               handleDisconnect(addr, &pStream);
               break;
            case ConnectReject:
               handleConnectReject(addr, &pStream);
               break;
         }//switch
      }//else
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Connection handshaking basic overview:
// The torque engine does a two phase connect handshake to
// prevent a spoofed source address Denial-of-Service (DOS) attack
//
// Basically, the initiator of a connection (client) sends a
// Connect Challenge Request packet to the server to initiate the connection
// The server then hashes the source address of the client request
// with some random magic server data to come up with a 16-byte key that
// the client can then use to gain entry to the server.
// This way there are no partially active connection records on the
// server at all.
//
// The client then sends a Connect Request packet to the server,
// including any game specific data necessary to start a connection (a
// server password, for instance), along with the key the server sent
// on the Connect Challenge Response packet.
//
// The server, on receipt of the Connect Request, compares the
// entry key with a computed key, makes sure it can create the requested
// NetConnection subclass, and then passes all processing on to the connection
// instance.
//
// If the subclass reads and accepts he connect request successfully, the
// server sends a Connect Accept packet - otherwise the connection
// is rejected with the sendConnectReject function
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------


void NetUDP::sendConnectChallengeRequest(NetConnection *conn)
{

   Con::printf("Sending Connect challenge Request");
   BitStream *out = BitStream::getPacketStream();
   out->write(U8(ConnectChallengeRequest));
   out->write(conn->getSequence());
   conn->mConnectSendCount++;
   conn->mConnectLastSendTime = Platform::getVirtualMilliseconds();
   BitStream::sendPacketStream(conn->getNetAddress());
}

void NetUDP::handleConnectChallengeRequest(const NetAddress *addr, BitStream *stream)
{
   char buf[256];
   Net::addressToString(addr, buf);
   Con::printf("Got Connect challenge Request from %s", buf);
   if(!mAllowConnections)
      return;

   U32 connectSequence;
   stream->read(&connectSequence);

   if(!mRandomDataInitialized)
      initRandomData();

   U32 addressDigest[4];
   computeNetMD5(addr, connectSequence, addressDigest);

   BitStream *out = BitStream::getPacketStream();
   out->write(U8(ConnectChallengeResponse));
   out->write(connectSequence);
   out->write(addressDigest[0]);
   out->write(addressDigest[1]);
   out->write(addressDigest[2]);
   out->write(addressDigest[3]);

   BitStream::sendPacketStream(addr);
}

//-----------------------------------------------------------------------------

void NetUDP::handleConnectChallengeResponse(const NetAddress *address, BitStream *stream)
{
   Con::printf("Got Connect challenge Response");
   U32 connectSequence;
   stream->read(&connectSequence);

   NetConnection *conn = findPendingConnection(address, connectSequence);
   if(!conn || conn->getConnectionState() != NetConnection::AwaitingChallengeResponse)
      return;

   U32 addressDigest[4];
   stream->read(&addressDigest[0]);
   stream->read(&addressDigest[1]);
   stream->read(&addressDigest[2]);
   stream->read(&addressDigest[3]);
   conn->setAddressDigest(addressDigest);

   conn->setConnectionState(NetConnection::AwaitingConnectResponse);
   conn->mConnectSendCount = 0;
   Con::printf("Sending Connect Request");
   sendConnectRequest(conn);
}

//-----------------------------------------------------------------------------

void NetUDP::sendConnectRequest(NetConnection *conn)
{
   BitStream *out = BitStream::getPacketStream();
   out->write(U8(ConnectRequest));
   out->write(conn->getSequence());

   U32 addressDigest[4];
   conn->getAddressDigest(addressDigest);
   out->write(addressDigest[0]);
   out->write(addressDigest[1]);
   out->write(addressDigest[2]);
   out->write(addressDigest[3]);

   out->writeString(conn->getClassName());
   conn->writeConnectRequest(out);
   conn->mConnectSendCount++;
   conn->mConnectLastSendTime = Platform::getVirtualMilliseconds();

   BitStream::sendPacketStream(conn->getNetAddress());
}

//-----------------------------------------------------------------------------

void NetUDP::handleConnectRequest(const NetAddress *address, BitStream *stream)
{
   if(!mAllowConnections)
      return;
   Con::printf("Got Connect Request");
   U32 connectSequence;
   stream->read(&connectSequence);

   // see if the connection is in the main connection table:

   NetConnection *connect = NetConnection::lookup(address);
   if(connect && connect->getSequence() == connectSequence)
   {
      sendConnectAccept(connect);
      return;
   }
   U32 addressDigest[4];
   U32 computedAddressDigest[4];

   stream->read(&addressDigest[0]);
   stream->read(&addressDigest[1]);
   stream->read(&addressDigest[2]);
   stream->read(&addressDigest[3]);

   computeNetMD5(address, connectSequence, computedAddressDigest);
   if(addressDigest[0] != computedAddressDigest[0] ||
      addressDigest[1] != computedAddressDigest[1] ||
      addressDigest[2] != computedAddressDigest[2] ||
      addressDigest[3] != computedAddressDigest[3])
      return; // bogus connection attempt

   if(connect)
   {
      if(connect->getSequence() > connectSequence)
         return; // the existing connection should be kept - the incoming request is stale.
      else
         connect->deleteObject(); // disconnect this one, and allow the new one to be created.
   }

   char connectionClass[255];
   stream->readString(connectionClass);

   ConsoleObject *co = ConsoleObject::create(connectionClass);
   NetConnection *conn = dynamic_cast<NetConnection *>(co);
   if(!conn || !conn->canRemoteCreate())
   {
      delete co;
      return;
   }
   conn->registerObject();
   conn->setNetAddress(address);
   conn->setNetworkConnection(true);
   conn->setSequence(connectSequence);

   const char *errorString = NULL;
   if(!conn->readConnectRequest(stream, &errorString))
   {
      sendConnectReject(conn, errorString);
      conn->deleteObject();
      return;
   }
   conn->setNetworkConnection(true);
   conn->onConnectionEstablished(false);
   conn->setEstablished();
   conn->setConnectSequence(connectSequence);
   sendConnectAccept(conn);
}

//-----------------------------------------------------------------------------

void NetUDP::sendConnectAccept(NetConnection *conn)
{
   BitStream *out = BitStream::getPacketStream();
   out->write(U8(ConnectAccept));
   out->write(conn->getSequence());
   conn->writeConnectAccept(out);
   BitStream::sendPacketStream(conn->getNetAddress());
}

void NetUDP::handleConnectAccept(const NetAddress *address, BitStream *stream)
{
   U32 connectSequence;
   stream->read(&connectSequence);
   NetConnection *conn = findPendingConnection(address, connectSequence);
   if(!conn || conn->getConnectionState() != NetConnection::AwaitingConnectResponse)
      return;
   const char *errorString = NULL;
   if(!conn->readConnectAccept(stream, &errorString))
   {
      conn->handleStartupError(errorString);
      removePendingConnection(conn);
      conn->deleteObject();
      return;
   }

   removePendingConnection(conn); // remove from the pending connection list
   conn->setNetworkConnection(true);
   conn->onConnectionEstablished(true); // notify the connection that it has been established
   conn->setEstablished(); // installs the connection in the connection table, and causes pings/timeouts to happen
   conn->setConnectSequence(connectSequence);
}

void NetUDP::sendConnectReject(NetConnection *conn, const char *reason)
{
   if(!reason)
      return; // if the stream is NULL, we reject silently

   BitStream *out = BitStream::getPacketStream();
   out->write(U8(ConnectReject));
   out->write(conn->getSequence());
   out->writeString(reason);
   BitStream::sendPacketStream(conn->getNetAddress());
}

void NetUDP::handleConnectReject(const NetAddress *address, BitStream *stream)
{
   U32 connectSequence;
   stream->read(&connectSequence);
   NetConnection *conn = findPendingConnection(address, connectSequence);
   if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse &&
                conn->getConnectionState() != NetConnection::AwaitingConnectResponse))
      return;
   removePendingConnection(conn);
   char reason[256];
   stream->readString(reason);
   conn->onConnectionRejected(reason);
   conn->deleteObject();
}

void NetUDP::handleDisconnect(const NetAddress *address, BitStream *stream)
{
   NetConnection *conn = NetConnection::lookup(address);
   if(!conn)
      return;

   U32 connectSequence;
   char reason[256];

   stream->read(&connectSequence);
   stream->readString(reason);

   if(conn->getSequence() != connectSequence)
      return;

   conn->onDisconnect(reason);
   conn->deleteObject();
}

void NetUDP::handleInfoPacket(const NetAddress *address, U8 packetType, BitStream *stream)
{
}





void NetUDP::startConnection(NetConnection *conn)
{
   addPendingConnection(conn);
   conn->mConnectionSendCount = 0;
   conn->setConnectSequence(Platform::getVirtualMilliseconds());
   conn->setConnectionState(NetConnection::AwaitingChallengeResponse);

   // This is a the client side of the connection, so set the connection to
   // server flag. We need to set this early so that if the connection times
   // out, its onRemove() will handle the cleanup properly.
   conn->setIsConnectionToServer();

   // Everything set, so send off the request.
   sendConnectChallengeRequest(conn);
}


void NetUDP::sendDisconnectPacket(NetConnection *conn, const char *reason)
{
   Con::printf("Issuing Disconnect packet.");

   // send a disconnect packet...
   U32 connectSequence = conn->getSequence();

   BitStream *out = BitStream::getPacketStream();
   out->write(U8(Disconnect));
   out->write(connectSequence);
   out->writeString(reason);

   BitStream::sendPacketStream(conn->getNetAddress());
}



void NetUDP::checkTimeouts()
{
	Parent::checkTimeouts();

   U32 time = Platform::getVirtualMilliseconds();
   if(time < mLastTimeoutCheckTime + TimeoutCheckInterval)
		return;

	for(U32 i = 0; i < mPendingConnections.size();)
	{
		NetConnection *pending = mPendingConnections[i];

		if(pending->getConnectionState() == NetConnection::AwaitingChallengeResponse &&
			time > pending->mConnectLastSendTime + ChallengeRetryTime)
		{
			if(pending->mConnectSendCount > ChallengeRetryCount)
			{
				pending->onConnectTimedOut();
				removePendingConnection(pending);
				pending->deleteObject();
				continue;
			}
			else
				sendConnectChallengeRequest(pending);
		}
		else if(pending->getConnectionState() == NetConnection::AwaitingConnectResponse &&
			time > pending->mConnectLastSendTime + ConnectRetryTime)
		{
			if(pending->mConnectSendCount > ConnectRetryCount)
			{
				pending->onConnectTimedOut();
				removePendingConnection(pending);
				pending->deleteObject();
				continue;
			}
			else
				sendConnectRequest(pending);
		}
		i++;
	}

}



};//namespace RPGServer

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -