mirror of
https://github.com/tribes2/engine.git
synced 2026-01-20 19:54:46 +00:00
981 lines
28 KiB
C++
981 lines
28 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma warning(disable:4786) // Remove STL warnings.
|
|
|
|
#include "Platform/platform.h"
|
|
#include "Core/dnet.h"
|
|
#include "console/simBase.h"
|
|
#include "Sim/netConnection.h"
|
|
#include "console/console.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "Core/bitStream.h"
|
|
#include "Sim/netObject.h"
|
|
#include "game/gameConnection.h"
|
|
#include "game/serverQuery.h"
|
|
#include "game/targetManager.h"
|
|
#include "game/netDispatch.h"
|
|
#include "Platform/gameInterface.h"
|
|
#include "game/tribesGame.h"
|
|
#include "game/banList.h"
|
|
|
|
const char *gServerConnectionName = "ServerConnection";
|
|
const char *gLocalClientConnectionName = "LocalClientConnection";
|
|
|
|
bool gAllowConnections = false;
|
|
|
|
bool isServerOnline()
|
|
{
|
|
if(Game->isJournalReading())
|
|
{
|
|
U32 res;
|
|
Game->journalRead(&res);
|
|
return bool(res);
|
|
}
|
|
else
|
|
{
|
|
bool ret = false;
|
|
// Authentication removed...
|
|
ret = true;
|
|
|
|
if(Game->isJournalWriting())
|
|
Game->journalWrite(U32(ret));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
bool isClientOnline()
|
|
{
|
|
if(Game->isJournalReading())
|
|
{
|
|
U32 res;
|
|
Game->journalRead(&res);
|
|
return bool(res);
|
|
}
|
|
else
|
|
{
|
|
bool ret = false;
|
|
// Authentication removed...
|
|
ret = true;
|
|
|
|
if(Game->isJournalWriting())
|
|
Game->journalWrite(U32(ret));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
bool validateAuthenticatedServer()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool validateAuthenticatedClient()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
ConsoleFunction(startHeartbeat, void, 1, 1, "startHeartbeat()")
|
|
{
|
|
argc; argv;
|
|
|
|
if(validateAuthenticatedServer())
|
|
startHeartbeat();
|
|
}
|
|
|
|
enum {
|
|
MaxConnectArgs = 16,
|
|
MaxPendingConnects = 20,
|
|
PendingConnectTimeout = 7000, // 7 seconds
|
|
|
|
ChallengeRetryCount = 4,
|
|
ChallengeRetryTime = 2500, // 2.5 seconds
|
|
|
|
ConnectRetryCount = 4,
|
|
ConnectRetryTime = 2500,
|
|
TimeoutCheckInterval = 1500, // check for timeouts every 1.5 secs
|
|
MaxAuthInfoSize = 1024,
|
|
MaxPasswordLength = 16,
|
|
};
|
|
|
|
//----------------------------------------------------------------
|
|
// Client add and drop management
|
|
//----------------------------------------------------------------
|
|
|
|
void GameClientAdded(GameConnection *newClient, S32 argc, const char **argv)
|
|
{
|
|
SimGroup *g = Sim::getClientGroup();
|
|
g->addObject(newClient);
|
|
const char *vargs[MaxConnectArgs + 2];
|
|
vargs[0] = "onConnect";
|
|
vargs[1] = NULL;
|
|
if(argc > MaxConnectArgs)
|
|
argc = MaxConnectArgs;
|
|
for(S32 i = 0; i < argc; i++)
|
|
vargs[i + 2] = argv[i];
|
|
|
|
Con::execute(newClient, argc + 2, vargs);
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------
|
|
// Connect protocol message formats
|
|
//----------------------------------------------------------------
|
|
|
|
// ConnectChallengeRequest
|
|
// ProtocolVersion
|
|
// Certificate
|
|
// ClientConnectSequence
|
|
// Password
|
|
|
|
// ConnectChallengeResponse
|
|
// ProtocolVersion
|
|
// ServerConnectSequence
|
|
// ClientConnectSequence
|
|
|
|
// ConnectChallengeReject
|
|
// ClientConnectSequence
|
|
// Reason
|
|
|
|
// ConnectRequest
|
|
// ServerConnectSequence
|
|
// ClientConnectSequence
|
|
// ProtocolVersion
|
|
// console args
|
|
|
|
// ConnectAccept
|
|
// ServerConnectSequence
|
|
// ClientConnectSequence
|
|
// ProtocolVersion
|
|
// ClientID
|
|
|
|
// ConnectReject
|
|
// ServerConnectSequence
|
|
// ClientConnectSequence
|
|
// Reason
|
|
|
|
// Disconnect
|
|
// ServerConnectSequence
|
|
// ClientConnectSequence
|
|
// Reason string
|
|
|
|
//----------------------------------------------------------------
|
|
// Connect request and server response structures
|
|
//----------------------------------------------------------------
|
|
|
|
struct ConnectRequestStruct
|
|
{
|
|
enum {
|
|
NotConnecting,
|
|
Challenging,
|
|
Connecting,
|
|
} state;
|
|
|
|
U32 clientConnectSequence;
|
|
U32 serverConnectSequence;
|
|
U32 protocolVersion;
|
|
U32 lastSendTime;
|
|
U32 sendCount;
|
|
NetAddress serverAddress;
|
|
U32 challenge;
|
|
bool authenticated;
|
|
char password[MaxPasswordLength + 1];
|
|
|
|
U32 argc;
|
|
char *argv[MaxConnectArgs];
|
|
U8 argBuffer[MaxPacketDataSize];
|
|
};
|
|
|
|
struct ConnectRequestPending
|
|
{
|
|
// Certificate needs to be stored here.
|
|
// V12: Challenge stuff was partially hacked out
|
|
U32 challenge1;
|
|
|
|
NetAddress sourceAddress;
|
|
U32 clientProtocolVersion;
|
|
U32 clientConnectSequence;
|
|
U32 serverConnectSequence;
|
|
U32 lastRecvTime;
|
|
};
|
|
|
|
ConnectRequestStruct gConnectRequest;
|
|
|
|
ConnectRequestPending gPendingConnects[MaxPendingConnects];
|
|
U32 gNumPendingConnects;
|
|
|
|
void connectRequestRejected(const char *buffer)
|
|
{
|
|
Con::executef(2, "onConnectRequestRejected", buffer);
|
|
}
|
|
|
|
void challengeRequestRejected(const char *buffer)
|
|
{
|
|
Con::executef(2, "onChallengeRequestRejected", buffer);
|
|
}
|
|
|
|
void connectRequestTimedOut()
|
|
{
|
|
gConnectRequest.state = ConnectRequestStruct::NotConnecting;
|
|
Con::executef(1, "onConnectRequestTimedOut");
|
|
}
|
|
|
|
void connectionToServerTimedOut()
|
|
{
|
|
Con::executef(1, "onConnectionToServerTimedOut");
|
|
}
|
|
|
|
void connectionToServerLost(const char* msg)
|
|
{
|
|
Con::executef(2, "onConnectionToServerLost", msg);
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
// Connect request and server response functions
|
|
//----------------------------------------------------------------
|
|
|
|
void sendConnectChallengeRequest()
|
|
{
|
|
BitStream *out = BitStream::getPacketStream();
|
|
out->write(U8(ConnectChallengeRequest));
|
|
out->write(CurrentProtocolVersion);
|
|
out->write(gConnectRequest.clientConnectSequence);
|
|
out->writeString(gConnectRequest.password);
|
|
// Authentication removed...
|
|
|
|
gConnectRequest.sendCount++;
|
|
gConnectRequest.lastSendTime = Platform::getVirtualMilliseconds();
|
|
|
|
Con::printf("Connect Challenge Request: %d", gConnectRequest.sendCount);
|
|
|
|
BitStream::sendPacketStream(&gConnectRequest.serverAddress);
|
|
}
|
|
|
|
void sendConnectChallengeResponse(U32 index)
|
|
{
|
|
ConnectRequestPending *p = gPendingConnects + index;
|
|
|
|
BitStream *out = BitStream::getPacketStream();
|
|
|
|
out->write(U8(ConnectChallengeResponse));
|
|
out->write(CurrentProtocolVersion);
|
|
out->write(p->serverConnectSequence);
|
|
out->write(p->clientConnectSequence);
|
|
|
|
// Authentication removed...
|
|
|
|
p->lastRecvTime = Platform::getVirtualMilliseconds();
|
|
Con::printf("Sent challenge response");
|
|
|
|
BitStream::sendPacketStream(&p->sourceAddress);
|
|
}
|
|
|
|
void rejectConnectChallengeRequest(const NetAddress *source, U32 clientConnectSequence, const char *reason)
|
|
{
|
|
BitStream *out = BitStream::getPacketStream();
|
|
|
|
out->write(U8(ConnectChallengeReject));
|
|
out->write(clientConnectSequence);
|
|
out->writeString(reason);
|
|
BitStream::sendPacketStream(source);
|
|
}
|
|
|
|
void handleConnectChallengeRequest(const NetAddress *source, BitStream *stream)
|
|
{
|
|
if(!gAllowConnections)
|
|
return;
|
|
|
|
// reasons for rejection
|
|
// password wrong
|
|
// server full
|
|
// bad protocol version
|
|
// invalid certificate
|
|
// don't meet tribe/UID connect restrictions
|
|
|
|
U32 protoVersion;
|
|
U32 clientConnectSequence;
|
|
const char *rejectString = NULL;
|
|
char joinPassword[MaxPasswordLength + 1];
|
|
|
|
stream->read(&protoVersion);
|
|
stream->read(&clientConnectSequence);
|
|
|
|
if(protoVersion < MinRequiredProtocolVersion)
|
|
{
|
|
rejectConnectChallengeRequest(source, clientConnectSequence, "CHR_PROTOCOL");
|
|
return;
|
|
}
|
|
|
|
if(protoVersion > CurrentProtocolVersion)
|
|
protoVersion = CurrentProtocolVersion;
|
|
|
|
// first time out any outstanding challenge requests:
|
|
U32 time = Platform::getVirtualMilliseconds();
|
|
|
|
for(U32 i = 0; i < gNumPendingConnects;)
|
|
{
|
|
ConnectRequestPending *p = gPendingConnects + i;
|
|
|
|
// see if this is already in the list:
|
|
if(Net::compareAddresses(source, &p->sourceAddress) && p->clientConnectSequence == clientConnectSequence)
|
|
{
|
|
// just up the time and ping back
|
|
sendConnectChallengeResponse(i);
|
|
return;
|
|
}
|
|
if(time > p->lastRecvTime + PendingConnectTimeout)
|
|
*p = gPendingConnects[--gNumPendingConnects];
|
|
else
|
|
i++;
|
|
}
|
|
|
|
// Test the password:
|
|
stream->readString(joinPassword);
|
|
const char* password = Con::getVariable( "$Host::Password" );
|
|
if ( password[0] )
|
|
{
|
|
if ( dStrncmp( password, joinPassword, MaxPasswordLength ) != 0 )
|
|
{
|
|
// IMPORTANT! Do NOT change the message here, it is used by the game.
|
|
rejectConnectChallengeRequest(source, clientConnectSequence, "PASSWORD");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// V12: Challenge stuff was partially hacked out
|
|
U32 challenge1 = 0;
|
|
|
|
if(stream->readFlag())
|
|
{
|
|
U8 buffer[MaxAuthInfoSize];
|
|
U32 size = stream->readInt(16);
|
|
|
|
if(size > MaxAuthInfoSize)
|
|
{
|
|
rejectConnectChallengeRequest(source, clientConnectSequence, "CHR_INVALID_CHALLENGE_PACKET");
|
|
return;
|
|
}
|
|
|
|
// V12: Used to have WON stuff here...
|
|
}
|
|
|
|
U32 index;
|
|
if(gNumPendingConnects == MaxPendingConnects)
|
|
index = mRandI(0, MaxPendingConnects-1);
|
|
else
|
|
index = gNumPendingConnects++;
|
|
|
|
ConnectRequestPending *p = gPendingConnects + index;
|
|
p->challenge1 = challenge1;
|
|
p->clientConnectSequence = clientConnectSequence;
|
|
p->sourceAddress = *source;
|
|
p->clientProtocolVersion = protoVersion;
|
|
p->serverConnectSequence = Platform::getVirtualMilliseconds();
|
|
|
|
Con::printf("Got challenge request");
|
|
sendConnectChallengeResponse(index);
|
|
}
|
|
|
|
void sendConnectRequest()
|
|
{
|
|
gConnectRequest.sendCount++;
|
|
gConnectRequest.lastSendTime = Platform::getVirtualMilliseconds();
|
|
|
|
BitStream *out = BitStream::getPacketStream();
|
|
|
|
out->write(U8(ConnectRequest));
|
|
out->write(gConnectRequest.serverConnectSequence);
|
|
out->write(gConnectRequest.clientConnectSequence);
|
|
out->write(gConnectRequest.protocolVersion);
|
|
if(out->writeFlag(gConnectRequest.authenticated))
|
|
{
|
|
out->write(gConnectRequest.challenge);
|
|
}
|
|
out->write(gConnectRequest.argc);
|
|
for(U32 i = 0; i < gConnectRequest.argc; i++)
|
|
out->writeString(gConnectRequest.argv[i]);
|
|
|
|
Con::printf("Sent connect request");
|
|
BitStream::sendPacketStream(&gConnectRequest.serverAddress);
|
|
}
|
|
|
|
void handleConnectChallengeResponse(const NetAddress *addr, BitStream *stream)
|
|
{
|
|
if(gConnectRequest.state != ConnectRequestStruct::Challenging)
|
|
return;
|
|
if(!Net::compareAddresses(&gConnectRequest.serverAddress, addr))
|
|
return;
|
|
U32 serverProtocol;
|
|
U32 serverConnectSequence;
|
|
U32 clientConnectSequence;
|
|
|
|
stream->read(&serverProtocol);
|
|
stream->read(&serverConnectSequence);
|
|
stream->read(&clientConnectSequence);
|
|
|
|
// must be an old connect request...
|
|
if(clientConnectSequence != gConnectRequest.clientConnectSequence)
|
|
return;
|
|
|
|
// check if it's authenticated
|
|
gConnectRequest.authenticated = stream->readFlag();
|
|
if(gConnectRequest.authenticated)
|
|
{
|
|
// V12: Authentication removed...
|
|
// V12: Used to have WON stuff here...
|
|
}
|
|
|
|
gConnectRequest.state = ConnectRequestStruct::Connecting;
|
|
gConnectRequest.serverConnectSequence = serverConnectSequence;
|
|
gConnectRequest.sendCount = 0;
|
|
gConnectRequest.protocolVersion = serverProtocol < CurrentProtocolVersion ? serverProtocol : CurrentProtocolVersion;
|
|
Con::printf("Got challenge response");
|
|
|
|
sendConnectRequest();
|
|
}
|
|
|
|
void GameConnection::connectionError(const char *errorString)
|
|
{
|
|
if(isServerConnection())
|
|
{
|
|
Con::printf("Connection error: %s.", errorString);
|
|
connectionToServerLost( errorString );
|
|
}
|
|
else
|
|
{
|
|
Con::printf("Client %d packet error: %s.", getId(), errorString);
|
|
setDisconnectReason("Packet Error.");
|
|
}
|
|
deleteObject();
|
|
}
|
|
|
|
void handleDisconnect(const NetAddress *addr, BitStream *stream)
|
|
{
|
|
Con::printf("Got disconnect packet.");
|
|
|
|
NetConnection *conn = NetConnection::lookup(addr);
|
|
U32 serverConnectSequence, clientConnectSequence;
|
|
stream->read(&serverConnectSequence);
|
|
stream->read(&clientConnectSequence);
|
|
char reason[256];
|
|
stream->readString(reason);
|
|
|
|
U32 cServerConnectSequence, cClientConnectSequence;
|
|
if(!conn)
|
|
return;
|
|
conn->getSequences(&cClientConnectSequence, &cServerConnectSequence);
|
|
if(cClientConnectSequence != clientConnectSequence ||
|
|
cServerConnectSequence != serverConnectSequence)
|
|
return;
|
|
|
|
// ok, it's gone.
|
|
if(conn->isServerConnection())
|
|
{
|
|
Con::printf("Connection with server lost.");
|
|
connectionToServerLost( reason );
|
|
}
|
|
else
|
|
{
|
|
Con::printf("Client %d disconnected.", conn->getId());
|
|
((GameConnection *) conn)->setDisconnectReason(reason);
|
|
}
|
|
conn->deleteObject();
|
|
}
|
|
|
|
void handleConnectAccept(const NetAddress *addr, BitStream *stream)
|
|
{
|
|
if(gConnectRequest.state != ConnectRequestStruct::Connecting)
|
|
return;
|
|
if(!Net::compareAddresses(&gConnectRequest.serverAddress, addr))
|
|
return;
|
|
|
|
U32 serverConnectSequence, clientConnectSequence;
|
|
U32 protocol, id;
|
|
stream->read(&serverConnectSequence);
|
|
stream->read(&clientConnectSequence);
|
|
stream->read(&protocol);
|
|
stream->read(&id);
|
|
|
|
if(serverConnectSequence != gConnectRequest.serverConnectSequence ||
|
|
clientConnectSequence != gConnectRequest.clientConnectSequence ||
|
|
protocol > CurrentProtocolVersion ||
|
|
protocol < MinRequiredProtocolVersion)
|
|
return;
|
|
|
|
// ok, we can connect up now:
|
|
gConnectRequest.state = ConnectRequestStruct::NotConnecting;
|
|
|
|
GameConnection *conn = new GameConnection(false, true, true);
|
|
conn->registerObject();
|
|
NetConnection::setServerConnection(conn);
|
|
|
|
conn->setProtocolVersion(protocol);
|
|
conn->setSequences(clientConnectSequence, serverConnectSequence);
|
|
conn->setConnectSequence(clientConnectSequence ^ serverConnectSequence);
|
|
conn->setNetAddress(addr);
|
|
conn->setNetworkConnection(true);
|
|
|
|
Sim::getRootGroup()->addObject(conn, gServerConnectionName);
|
|
Con::executef(1, "ServerConnectionAccepted");
|
|
Con::printf("Connection accepted - id %d protocol %d", id, protocol);
|
|
}
|
|
|
|
void sendConnectAccept(NetConnection *conn)
|
|
{
|
|
BitStream *out = BitStream::getPacketStream();
|
|
|
|
out->write(U8(ConnectAccept));
|
|
U32 clientConnectSeq, serverConnectSeq;
|
|
U32 protocol;
|
|
|
|
conn->getSequences(&clientConnectSeq, &serverConnectSeq);
|
|
protocol = conn->getProtocolVersion();
|
|
|
|
out->write(serverConnectSeq);
|
|
out->write(clientConnectSeq);
|
|
out->write(protocol);
|
|
out->write(U32(conn->getId()));
|
|
Con::printf("Sending connect accept: %d", conn->getId());
|
|
|
|
BitStream::sendPacketStream(conn->getNetAddress());
|
|
}
|
|
|
|
void handleConnectReject(const NetAddress *address, BitStream *stream)
|
|
{
|
|
if(gConnectRequest.state != ConnectRequestStruct::Connecting)
|
|
return;
|
|
U32 clientConnectSequence, serverConnectSequence;
|
|
stream->read(&serverConnectSequence);
|
|
stream->read(&clientConnectSequence);
|
|
|
|
if(!Net::compareAddresses(address, &gConnectRequest.serverAddress) ||
|
|
clientConnectSequence != gConnectRequest.clientConnectSequence ||
|
|
serverConnectSequence != gConnectRequest.serverConnectSequence)
|
|
return;
|
|
char buffer[256];
|
|
stream->readString(buffer);
|
|
gConnectRequest.state = ConnectRequestStruct::NotConnecting;
|
|
connectRequestRejected(buffer);
|
|
}
|
|
|
|
void handleConnectChallengeReject(const NetAddress *address, BitStream *stream)
|
|
{
|
|
if(gConnectRequest.state != ConnectRequestStruct::Challenging)
|
|
return;
|
|
U32 clientConnectSequence;
|
|
stream->read(&clientConnectSequence);
|
|
|
|
if(!Net::compareAddresses(address, &gConnectRequest.serverAddress) ||
|
|
clientConnectSequence != gConnectRequest.clientConnectSequence)
|
|
return;
|
|
char buffer[256];
|
|
stream->readString(buffer);
|
|
gConnectRequest.state = ConnectRequestStruct::NotConnecting;
|
|
challengeRequestRejected(buffer);
|
|
}
|
|
|
|
void handleConnectRequest(const NetAddress *address, BitStream *stream)
|
|
{
|
|
if(!gAllowConnections)
|
|
return;
|
|
|
|
char addrString[256];
|
|
|
|
Net::addressToString(address, addrString);
|
|
Con::printf("Connection request from: %s", addrString);
|
|
|
|
U32 serverConnectSequence;
|
|
U32 clientConnectSequence;
|
|
U32 protocolRequestVersion;
|
|
|
|
stream->read(&serverConnectSequence);
|
|
stream->read(&clientConnectSequence);
|
|
stream->read(&protocolRequestVersion);
|
|
|
|
const char *rejectString = NULL;
|
|
|
|
if(protocolRequestVersion < MinRequiredProtocolVersion ||
|
|
protocolRequestVersion > CurrentProtocolVersion)
|
|
rejectString = "CR_INVALID_PROTOCOL_VERSION";
|
|
|
|
U32 i;
|
|
for(i = 0; i < gNumPendingConnects; i++)
|
|
{
|
|
ConnectRequestPending *p = gPendingConnects + i;
|
|
|
|
if(Net::compareAddresses(address, &p->sourceAddress) &&
|
|
p->clientConnectSequence == clientConnectSequence &&
|
|
p->serverConnectSequence == serverConnectSequence)
|
|
break;
|
|
}
|
|
if(i == gNumPendingConnects)
|
|
{
|
|
// if it's not in the pending list, check if
|
|
// we're already connected to this guy:
|
|
NetConnection *connect = NetConnection::lookup(address);
|
|
if(connect)
|
|
{
|
|
U32 clientConSeq, serverConSeq;
|
|
connect->getSequences(&clientConSeq, &serverConSeq);
|
|
|
|
// we already accepted this connection:
|
|
if(clientConSeq == clientConnectSequence &&
|
|
serverConSeq == serverConnectSequence)
|
|
sendConnectAccept(connect);
|
|
}
|
|
return;
|
|
}
|
|
U32 clientId = 0;
|
|
|
|
// check the peer auth...
|
|
if(stream->readFlag())
|
|
{
|
|
// V12: Authentication removed...
|
|
// V12: Also used to have WON stuff here...
|
|
rejectString = "CR_INVALID_CONNECT_PACKET";
|
|
}
|
|
|
|
if ( !rejectString )
|
|
{
|
|
if ( gBanList.isBanned( 0 /* V12: Was Won net ID */, addrString ) )
|
|
rejectString = "CR_YOUAREBANNED";
|
|
else if ( Con::getIntVariable( "$HostGamePlayerCount" ) >= Con::getIntVariable( "$Host::MaxPlayers" ) )
|
|
rejectString = "CR_SERVERFULL";
|
|
}
|
|
|
|
// erase the request from the pending list
|
|
gPendingConnects[i] = gPendingConnects[--gNumPendingConnects];
|
|
gPendingConnects[gNumPendingConnects].challenge1 = NULL; // kill the byte buffer.
|
|
|
|
const char *argv[MaxConnectArgs];
|
|
char argbuf[MaxConnectArgs][256];
|
|
U32 argc;
|
|
|
|
stream->read(&argc);
|
|
if(argc > MaxConnectArgs)
|
|
rejectString = "CR_INVALID_CONNECT_PACKET";
|
|
else
|
|
{
|
|
for(U32 i = 0; i < argc; i++)
|
|
{
|
|
argv[i] = argbuf[i];
|
|
stream->readString(argbuf[i]);
|
|
}
|
|
}
|
|
|
|
if(rejectString)
|
|
{
|
|
BitStream *out = BitStream::getPacketStream();
|
|
out->write(U8(ConnectReject));
|
|
out->write(serverConnectSequence);
|
|
out->write(clientConnectSequence);
|
|
out->writeString(rejectString);
|
|
|
|
|
|
BitStream::sendPacketStream(address);
|
|
}
|
|
else
|
|
{
|
|
Con::printf("Accepting connect... CLIENT ID = %d", clientId);
|
|
// let this guy into the game:
|
|
GameConnection *conn = new GameConnection(true, false, true);
|
|
|
|
conn->registerObject();
|
|
conn->setProtocolVersion(protocolRequestVersion);
|
|
conn->setNetAddress(address);
|
|
conn->setNetworkConnection(true);
|
|
|
|
conn->setSequences(clientConnectSequence, serverConnectSequence);
|
|
conn->setConnectSequence(clientConnectSequence ^ serverConnectSequence);
|
|
sendConnectAccept(conn);
|
|
GameClientAdded(conn, argc, argv);
|
|
}
|
|
}
|
|
|
|
static void cConnect(SimObject *, S32 argc, const char **argv)
|
|
{
|
|
if(!validateAuthenticatedClient())
|
|
return;
|
|
gConnectRequest.state = ConnectRequestStruct::Challenging;
|
|
gConnectRequest.clientConnectSequence = Platform::getVirtualMilliseconds();
|
|
|
|
if(!Net::stringToAddress(argv[1], &gConnectRequest.serverAddress))
|
|
return;
|
|
|
|
gConnectRequest.protocolVersion = CurrentProtocolVersion;
|
|
dStrncpy( gConnectRequest.password, argv[2], MaxPasswordLength );
|
|
|
|
argc -= 3;
|
|
if(argc > MaxConnectArgs)
|
|
argc = MaxConnectArgs;
|
|
|
|
U32 bufPos = 0;
|
|
U32 i;
|
|
for(i = 0; i < argc; i++)
|
|
{
|
|
const char *str = argv[i + 3];
|
|
U32 len = dStrlen(str);
|
|
|
|
if(bufPos + len + 1 > MaxPacketDataSize)
|
|
break;
|
|
dStrcpy((char *) gConnectRequest.argBuffer + bufPos, str);
|
|
gConnectRequest.argv[i] = (char *) gConnectRequest.argBuffer + bufPos;
|
|
bufPos += len + 1;
|
|
}
|
|
gConnectRequest.argc = i;
|
|
gConnectRequest.sendCount = 0;
|
|
// Authentication removed...
|
|
sendConnectChallengeRequest();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// Connection initiation console commands
|
|
//----------------------------------------------------------------
|
|
|
|
static void cAllowConnections(SimObject *, S32, const char **argv)
|
|
{
|
|
if(!validateAuthenticatedServer())
|
|
return;
|
|
gAllowConnections = dAtob(argv[1]);
|
|
}
|
|
|
|
static void cLocalConnect(SimObject *, S32 argc, const char** argv)
|
|
{
|
|
if(!validateAuthenticatedClient())
|
|
return;
|
|
|
|
GameConnection *clientConnection = new GameConnection(false, true, true);
|
|
GameConnection *serverConnection = new GameConnection(true, false, true);
|
|
|
|
clientConnection->registerObject();
|
|
Sim::getRootGroup()->addObject(clientConnection, gServerConnectionName);
|
|
|
|
serverConnection->registerObject();
|
|
serverConnection->assignName(gLocalClientConnectionName);
|
|
NetConnection::setServerConnection(clientConnection);
|
|
NetConnection::setLocalClientConnection(serverConnection);
|
|
|
|
clientConnection->setRemoteConnectionObjectId(serverConnection->getId());
|
|
serverConnection->setRemoteConnectionObjectId(clientConnection->getId());
|
|
|
|
// V12: Used to have WON stuff here...
|
|
|
|
clientConnection->setProtocolVersion(CurrentProtocolVersion);
|
|
serverConnection->setProtocolVersion(CurrentProtocolVersion);
|
|
clientConnection->setConnectSequence(0);
|
|
serverConnection->setConnectSequence(0);
|
|
|
|
GameClientAdded(serverConnection, argc - 1, argv + 1);
|
|
Con::executef( 1, "LocalConnectionAccepted" );
|
|
}
|
|
|
|
void clientNetProcess()
|
|
{
|
|
NetConnection *con = NetConnection::getServerConnection();
|
|
if (con)
|
|
con->checkPacketSend();
|
|
}
|
|
|
|
void serverNetProcess()
|
|
{
|
|
NetObject::collapseDirtyList(); // collapse all the mask bits...
|
|
|
|
SimGroup *clientGroup = Sim::getClientGroup();
|
|
for(SimGroup::iterator i = clientGroup->begin(); i != clientGroup->end(); i++)
|
|
{
|
|
NetConnection *con = (NetConnection *)(*i);
|
|
if(con->isLocalConnection() || con->isNetworkConnection())
|
|
con->checkPacketSend();
|
|
}
|
|
}
|
|
|
|
BitStream gPacketStream(NULL, 0);
|
|
|
|
void TribesGame::processPacketReceiveEvent(PacketReceiveEvent * prEvent)
|
|
{
|
|
U32 dataSize = prEvent->size - PacketReceiveEventHeaderSize;
|
|
gPacketStream.setBuffer(prEvent->data, dataSize);
|
|
if(!(prEvent->data[0] & 0x01)) // it's a non-protocol packet of some sort...
|
|
{
|
|
U8 packetType;
|
|
gPacketStream.read(&packetType);
|
|
NetAddress *addr = &prEvent->sourceAddress;
|
|
|
|
if(packetType <= GameHeartbeat)
|
|
handleInfoPacket(addr, packetType, &gPacketStream);
|
|
else
|
|
{
|
|
switch(packetType)
|
|
{
|
|
case ConnectChallengeRequest:
|
|
handleConnectChallengeRequest(addr, &gPacketStream);
|
|
break;
|
|
case ConnectRequest:
|
|
handleConnectRequest(addr, &gPacketStream);
|
|
break;
|
|
case ConnectChallengeResponse:
|
|
handleConnectChallengeResponse(addr, &gPacketStream);
|
|
break;
|
|
case ConnectAccept:
|
|
handleConnectAccept(addr, &gPacketStream);
|
|
break;
|
|
case Disconnect:
|
|
handleDisconnect(addr, &gPacketStream);
|
|
break;
|
|
case ConnectReject:
|
|
handleConnectReject(addr, &gPacketStream);
|
|
break;
|
|
case ConnectChallengeReject:
|
|
handleConnectChallengeReject(addr, &gPacketStream);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// lookup the connection in the addressTable
|
|
NetConnection *conn = NetConnection::lookup(&prEvent->sourceAddress);
|
|
if(conn)
|
|
conn->processRawPacket(&gPacketStream);
|
|
}
|
|
}
|
|
|
|
void dispatchInit()
|
|
{
|
|
gConnectRequest.state = ConnectRequestStruct::NotConnecting;
|
|
gNumPendingConnects = 0;
|
|
|
|
Con::addCommand("allowConnections", cAllowConnections, "allowConnections(bool);", 2, 2);
|
|
Con::addCommand("localConnect", cLocalConnect, "localConnect();", 1, 16);
|
|
Con::addCommand("connect", cConnect, "connect(addr);", 2, 17);
|
|
}
|
|
|
|
//void GameConnectionRemoved(GameConnection *conn)
|
|
//{
|
|
// if(conn->isNetworkConnection())
|
|
// {
|
|
// Con::printf("Issuing Disconnect packet.");
|
|
//
|
|
// // send a disconnect packet...
|
|
// U32 serverConnectSequence, clientConnectSequence;
|
|
// conn->getSequences(&clientConnectSequence, &serverConnectSequence);
|
|
//
|
|
// BitStream *out = BitStream::getPacketStream();
|
|
// out->write(U8(Disconnect));
|
|
// out->write(serverConnectSequence);
|
|
// out->write(clientConnectSequence);
|
|
// out->writeString("");
|
|
//
|
|
// BitStream::sendPacketStream(conn->getNetAddress());
|
|
// }
|
|
//}
|
|
|
|
void dispatchCheckTimeouts()
|
|
{
|
|
static U32 lastTimeoutCheckTime = 0;
|
|
U32 time = Platform::getVirtualMilliseconds();
|
|
if(time > lastTimeoutCheckTime + TimeoutCheckInterval)
|
|
{
|
|
// check the connection state:
|
|
if(gConnectRequest.state == ConnectRequestStruct::Challenging &&
|
|
time > gConnectRequest.lastSendTime + ChallengeRetryTime)
|
|
{
|
|
if(gConnectRequest.sendCount > ChallengeRetryCount)
|
|
connectRequestTimedOut();
|
|
else
|
|
sendConnectChallengeRequest();
|
|
}
|
|
else if(gConnectRequest.state == ConnectRequestStruct::Connecting &&
|
|
time > gConnectRequest.lastSendTime + ConnectRetryTime)
|
|
{
|
|
if(gConnectRequest.sendCount > ConnectRetryCount)
|
|
connectRequestTimedOut();
|
|
else
|
|
sendConnectRequest();
|
|
}
|
|
|
|
lastTimeoutCheckTime = time;
|
|
NetConnection *walk = NetConnection::getConnectionList();
|
|
|
|
while(walk)
|
|
{
|
|
NetConnection *next = walk->getNext();
|
|
if(walk->checkTimeout(time))
|
|
{
|
|
// this baddie timed out
|
|
if(walk->isServerConnection())
|
|
{
|
|
Con::printf("Connection to server timed out");
|
|
connectionToServerTimedOut();
|
|
}
|
|
else
|
|
{
|
|
Con::printf("Client %d timed out.", walk->getId());
|
|
((GameConnection *) walk)->setDisconnectReason("TimedOut");
|
|
}
|
|
walk->deleteObject();
|
|
}
|
|
walk = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
// DNet external function declarations
|
|
//----------------------------------------------------------------
|
|
|
|
void GameConnectionRejected(NetConnectionId id, BitStream *stream)
|
|
{
|
|
GameConnection *conn = (GameConnection *) Sim::findObject(id);
|
|
if(conn)
|
|
conn->deleteObject();
|
|
Con::printf("Connection rejected: %s", stream->getBuffer());
|
|
}
|
|
|
|
|
|
void GameConnectionEstablished(NetConnectionId id)
|
|
{
|
|
Con::printf("Connection established %d", id);
|
|
}
|
|
|
|
ConsoleFunction(startRecord, void, 2, 2, "startRecord(fileName)")
|
|
{
|
|
argc;
|
|
NetConnection *conn = NetConnection::getServerConnection();
|
|
if(!conn)
|
|
return;
|
|
conn->startDemoRecord(argv[1]);
|
|
}
|
|
|
|
ConsoleFunction(stopRecord, void, 1, 1, "stopRecord();")
|
|
{
|
|
argc; argv;
|
|
NetConnection *conn = NetConnection::getServerConnection();
|
|
if(!conn)
|
|
return;
|
|
conn->stopRecording();
|
|
}
|
|
|
|
ConsoleFunction(playDemo, void, 2, 2, "playDemo(recFileName)")
|
|
{
|
|
argc;
|
|
GameConnection *conn = new GameConnection(false, true, false);
|
|
conn->registerObject();
|
|
NetConnection::setServerConnection(conn);
|
|
|
|
Sim::getRootGroup()->addObject(conn, gServerConnectionName);
|
|
if(!conn->replayDemoRecord(argv[1]))
|
|
{
|
|
Con::printf("Unable to open demo file %s.", argv[1]);
|
|
conn->deleteObject();
|
|
}
|
|
}
|
|
|