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

📄 netinterface.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 2 页
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (c) 2002 GarageGames.Com
//-----------------------------------------------------------------------------
#ifdef _USE_TGE_NETCONNTION_

#include "platform/platform.h"
#include "platform/event.h"
#include "sim/netConnection.h"
#include "sim/netInterface.h"
#include "core/bitStream.h"
#include "math/mRandom.h"
#include "platform/gameInterface.h"

NetInterface *GNet = NULL;

NetInterface::NetInterface()
{
   AssertFatal(GNet == NULL, "ERROR: Multiple net interfaces declared.");
   GNet = this;

   mLastTimeoutCheckTime = 0;
   mAllowConnections = true;

}

void NetInterface::initRandomData()
{
   mRandomDataInitialized = true;
   U32 seed = Platform::getRealMilliseconds();

   if(Game->isJournalReading())
      Game->journalRead(&seed);
   else if(Game->isJournalWriting())
      Game->journalWrite(seed);

   MRandomR250 myRandom(seed);
   for(U32 i = 0; i < 12; i++)
      mRandomHashData[i] = myRandom.randI();
}

void NetInterface::addPendingConnection(NetConnection *connection)
{
   Con::printf("Adding a pending connection");
   mPendingConnections.push_back(connection);
}

void NetInterface::removePendingConnection(NetConnection *connection)
{
   for(U32 i = 0; i < mPendingConnections.size(); i++)
      if(mPendingConnections[i] == connection)
         mPendingConnections.erase(i);
}

NetConnection *NetInterface::findPendingConnection(const NetAddress *address, U32 connectSequence)
{
   for(U32 i = 0; i < mPendingConnections.size(); i++)
      if(Net::compareAddresses(address, mPendingConnections[i]->getNetAddress()) &&
            connectSequence == mPendingConnections[i]->getSequence())
         return mPendingConnections[i];
   return NULL;
}

void NetInterface::processPacketReceiveEvent(PacketReceiveEvent *prEvent)
{

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

   // Determine what to do with this packet:

   if(prEvent->data[0] & 0x01) // it's a protocol packet...
   {
      // if the LSB of the first byte is set, it's a game data packet
      // so pass it to the appropriate connection.

      // lookup the connection in the addressTable
      NetConnection *conn = NetConnection::lookup(&prEvent->sourceAddress);
      if(conn)
         conn->processRawPacket(&pStream);
   }
   else
   {
      // 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;
         }
      }
   }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// 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 NetInterface::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 NetInterface::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 NetInterface::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 NetInterface::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 NetInterface::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 NetInterface::sendConnectAccept(NetConnection *conn)

⌨️ 快捷键说明

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