📄 netinterface.cc
字号:
//-----------------------------------------------------------------------------
// 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 + -