Initial commit
This commit is contained in:
309
Torque/SDK/engine/game/net/tcpObject.cc
Normal file
309
Torque/SDK/engine/game/net/tcpObject.cc
Normal file
@@ -0,0 +1,309 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "game/net/tcpObject.h"
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "platform/event.h"
|
||||
#include "platform/gameInterface.h"
|
||||
#include "console/simBase.h"
|
||||
#include "console/consoleInternal.h"
|
||||
#include "game/demoGame.h"
|
||||
|
||||
TCPObject *TCPObject::table[TCPObject::TableSize] = {0, };
|
||||
|
||||
IMPLEMENT_CONOBJECT(TCPObject);
|
||||
|
||||
TCPObject *TCPObject::find(NetSocket tag)
|
||||
{
|
||||
for(TCPObject *walk = table[U32(tag) & TableMask]; walk; walk = walk->mNext)
|
||||
if(walk->mTag == tag)
|
||||
return walk;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TCPObject::addToTable(NetSocket newTag)
|
||||
{
|
||||
removeFromTable();
|
||||
mTag = newTag;
|
||||
mNext = table[U32(mTag) & TableMask];
|
||||
table[U32(mTag) & TableMask] = this;
|
||||
}
|
||||
|
||||
void TCPObject::removeFromTable()
|
||||
{
|
||||
for(TCPObject **walk = &table[U32(mTag) & TableMask]; *walk; walk = &((*walk)->mNext))
|
||||
{
|
||||
if(*walk == this)
|
||||
{
|
||||
*walk = mNext;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TCPObject::TCPObject()
|
||||
{
|
||||
mBuffer = NULL;
|
||||
mBufferSize = 0;
|
||||
mPort = 0;
|
||||
mTag = InvalidSocket;
|
||||
mNext = NULL;
|
||||
mState = Disconnected;
|
||||
}
|
||||
|
||||
TCPObject::~TCPObject()
|
||||
{
|
||||
disconnect();
|
||||
dFree(mBuffer);
|
||||
}
|
||||
|
||||
bool TCPObject::processArguments(S32 argc, const char **argv)
|
||||
{
|
||||
if(argc == 0)
|
||||
return true;
|
||||
else if(argc == 1)
|
||||
{
|
||||
addToTable(U32(dAtoi(argv[0])));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TCPObject::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
const char *name = getName();
|
||||
|
||||
if(name && name[0] && getClassRep())
|
||||
{
|
||||
Namespace *parent = getClassRep()->getNameSpace();
|
||||
Con::linkNamespaces(parent->mName, name);
|
||||
mNameSpace = Con::lookupNamespace(name);
|
||||
|
||||
}
|
||||
|
||||
Sim::getTCPGroup()->addObject(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
U32 TCPObject::onReceive(U8 *buffer, U32 bufferLen)
|
||||
{
|
||||
// we got a raw buffer event
|
||||
// default action is to split the buffer into lines of text
|
||||
// and call processLine on each
|
||||
// for any incomplete lines we have mBuffer
|
||||
U32 start = 0;
|
||||
parseLine(buffer, &start, bufferLen);
|
||||
return start;
|
||||
}
|
||||
|
||||
void TCPObject::parseLine(U8 *buffer, U32 *start, U32 bufferLen)
|
||||
{
|
||||
// find the first \n in buffer
|
||||
U32 i;
|
||||
U8 *line = buffer + *start;
|
||||
|
||||
for(i = *start; i < bufferLen; i++)
|
||||
if(buffer[i] == '\n' || buffer[i] == 0)
|
||||
break;
|
||||
U32 len = i - *start;
|
||||
|
||||
if(i == bufferLen || mBuffer)
|
||||
{
|
||||
// we've hit the end with no newline
|
||||
mBuffer = (U8 *) dRealloc(mBuffer, mBufferSize + len + 1);
|
||||
dMemcpy(mBuffer + mBufferSize, line, len);
|
||||
mBufferSize += len;
|
||||
*start = i;
|
||||
|
||||
// process the line
|
||||
if(i != bufferLen)
|
||||
{
|
||||
mBuffer[mBufferSize] = 0;
|
||||
if(mBufferSize && mBuffer[mBufferSize-1] == '\r')
|
||||
mBuffer[mBufferSize - 1] = 0;
|
||||
U8 *temp = mBuffer;
|
||||
mBuffer = 0;
|
||||
mBufferSize = 0;
|
||||
|
||||
processLine(temp);
|
||||
dFree(temp);
|
||||
}
|
||||
}
|
||||
else if(i != bufferLen)
|
||||
{
|
||||
line[len] = 0;
|
||||
if(len && line[len-1] == '\r')
|
||||
line[len-1] = 0;
|
||||
processLine(line);
|
||||
}
|
||||
if(i != bufferLen)
|
||||
*start = i + 1;
|
||||
}
|
||||
|
||||
void TCPObject::onConnectionRequest(const NetAddress *addr, U32 connectId)
|
||||
{
|
||||
char idBuf[16];
|
||||
char addrBuf[256];
|
||||
Net::addressToString(addr, addrBuf);
|
||||
dSprintf(idBuf, sizeof(idBuf), "%d", connectId);
|
||||
Con::executef(this, 3, "onConnectRequest", addrBuf, idBuf);
|
||||
}
|
||||
|
||||
bool TCPObject::processLine(U8 *line)
|
||||
{
|
||||
Con::executef(this, 2, "onLine", line);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPObject::onDNSResolved()
|
||||
{
|
||||
mState = DNSResolved;
|
||||
Con::executef(this, 1, "onDNSResolved");
|
||||
}
|
||||
|
||||
void TCPObject::onDNSFailed()
|
||||
{
|
||||
mState = Disconnected;
|
||||
Con::executef(this, 1, "onDNSFailed");
|
||||
}
|
||||
|
||||
void TCPObject::onConnected()
|
||||
{
|
||||
mState = Connected;
|
||||
Con::executef(this, 1, "onConnected");
|
||||
}
|
||||
|
||||
void TCPObject::onConnectFailed()
|
||||
{
|
||||
mState = Disconnected;
|
||||
Con::executef(this, 1, "onConnectFailed");
|
||||
}
|
||||
|
||||
void TCPObject::finishLastLine()
|
||||
{
|
||||
if(mBufferSize)
|
||||
{
|
||||
mBuffer[mBufferSize] = 0;
|
||||
processLine(mBuffer);
|
||||
dFree(mBuffer);
|
||||
mBuffer = 0;
|
||||
mBufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TCPObject::onDisconnect()
|
||||
{
|
||||
finishLastLine();
|
||||
mState = Disconnected;
|
||||
Con::executef(this, 1, "onDisconnect");
|
||||
}
|
||||
|
||||
void TCPObject::listen(U16 port)
|
||||
{
|
||||
mState = Listening;
|
||||
U32 newTag = Net::openListenPort(port);
|
||||
addToTable(newTag);
|
||||
}
|
||||
|
||||
void TCPObject::connect(const char *address)
|
||||
{
|
||||
NetSocket newTag = Net::openConnectTo(address);
|
||||
addToTable(newTag);
|
||||
}
|
||||
|
||||
void TCPObject::disconnect()
|
||||
{
|
||||
if( mTag != InvalidSocket ) {
|
||||
Net::closeConnectTo(mTag);
|
||||
}
|
||||
removeFromTable();
|
||||
}
|
||||
|
||||
void TCPObject::send(const U8 *buffer, U32 len)
|
||||
{
|
||||
Net::sendtoSocket(mTag, buffer, S32(len));
|
||||
}
|
||||
|
||||
ConsoleMethod( TCPObject, send, void, 3, 0, "(...)"
|
||||
"Parameters are transmitted as strings, one at a time.")
|
||||
{
|
||||
for(S32 i = 2; i < argc; i++)
|
||||
object->send((const U8 *) argv[i], dStrlen(argv[i]));
|
||||
}
|
||||
|
||||
ConsoleMethod( TCPObject, listen, void, 3, 3, "(int port)"
|
||||
"Start listening on the specified ports for connections.")
|
||||
{
|
||||
object->listen(U32(dAtoi(argv[2])));
|
||||
}
|
||||
|
||||
ConsoleMethod( TCPObject, connect, void, 3, 3, "(string addr)"
|
||||
"Connect to the given address.")
|
||||
{
|
||||
object->connect(argv[2]);
|
||||
}
|
||||
|
||||
ConsoleMethod( TCPObject, disconnect, void, 2, 2, "Disconnect from whatever we're connected to, if anything.")
|
||||
{
|
||||
object->disconnect();
|
||||
}
|
||||
|
||||
void DemoGame::processConnectedReceiveEvent(ConnectedReceiveEvent* event )
|
||||
{
|
||||
TCPObject *tcpo = TCPObject::find(event->tag);
|
||||
if(!tcpo)
|
||||
{
|
||||
Con::printf("Got bad connected receive event.");
|
||||
return;
|
||||
}
|
||||
U32 size = U32(event->size - ConnectedReceiveEventHeaderSize);
|
||||
U8 *buffer = event->data;
|
||||
|
||||
while(size)
|
||||
{
|
||||
U32 ret = tcpo->onReceive(buffer, size);
|
||||
AssertFatal(ret <= size, "Invalid return size");
|
||||
size -= ret;
|
||||
buffer += ret;
|
||||
}
|
||||
}
|
||||
|
||||
void DemoGame::processConnectedAcceptEvent( ConnectedAcceptEvent* event )
|
||||
{
|
||||
TCPObject *tcpo = TCPObject::find(event->portTag);
|
||||
if(!tcpo)
|
||||
return;
|
||||
tcpo->onConnectionRequest(&event->address, event->connectionTag);
|
||||
}
|
||||
|
||||
void DemoGame::processConnectedNotifyEvent( ConnectedNotifyEvent* event )
|
||||
{
|
||||
TCPObject *tcpo = TCPObject::find(event->tag);
|
||||
if(!tcpo)
|
||||
return;
|
||||
switch(event->state)
|
||||
{
|
||||
case ConnectedNotifyEvent::DNSResolved:
|
||||
tcpo->onDNSResolved();
|
||||
break;
|
||||
case ConnectedNotifyEvent::DNSFailed:
|
||||
tcpo->onDNSFailed();
|
||||
break;
|
||||
case ConnectedNotifyEvent::Connected:
|
||||
tcpo->onConnected();
|
||||
break;
|
||||
case ConnectedNotifyEvent::ConnectFailed:
|
||||
tcpo->onConnectFailed();
|
||||
break;
|
||||
case ConnectedNotifyEvent::Disconnected:
|
||||
tcpo->onDisconnect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user