mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-25 23:17:28 +00:00
328 lines
7.3 KiB
C++
328 lines
7.3 KiB
C++
|
#include "TelnetTransport.h"
|
||
|
#include "TCPInterface.h"
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <stdarg.h>
|
||
|
#include "LinuxStrings.h"
|
||
|
|
||
|
// #define _PRINTF_DEBUG
|
||
|
|
||
|
#define ECHO_INPUT
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma warning( push )
|
||
|
#endif
|
||
|
|
||
|
TelnetTransport::TelnetTransport()
|
||
|
{
|
||
|
tcpInterface=0;
|
||
|
sendSuffix=0;
|
||
|
sendPrefix=0;
|
||
|
}
|
||
|
TelnetTransport::~TelnetTransport()
|
||
|
{
|
||
|
Stop();
|
||
|
if (sendSuffix)
|
||
|
rakFree(sendSuffix);
|
||
|
if (sendPrefix)
|
||
|
rakFree(sendPrefix);
|
||
|
}
|
||
|
bool TelnetTransport::Start(unsigned short port, bool serverMode)
|
||
|
{
|
||
|
AutoAllocate();
|
||
|
assert(serverMode);
|
||
|
return tcpInterface->Start(port, 64);
|
||
|
}
|
||
|
void TelnetTransport::Stop(void)
|
||
|
{
|
||
|
if (tcpInterface==0) return;
|
||
|
tcpInterface->Stop();
|
||
|
unsigned i;
|
||
|
for (i=0; i < remoteClients.Size(); i++)
|
||
|
delete remoteClients[i];
|
||
|
remoteClients.Clear();
|
||
|
}
|
||
|
void TelnetTransport::Send( SystemAddress systemAddress, const char *data,... )
|
||
|
{
|
||
|
if (tcpInterface==0) return;
|
||
|
|
||
|
char text[REMOTE_MAX_TEXT_INPUT];
|
||
|
size_t prefixLength;
|
||
|
if (sendPrefix)
|
||
|
{
|
||
|
strcpy(text, sendPrefix);
|
||
|
prefixLength = strlen(sendPrefix);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
text[0]=0;
|
||
|
prefixLength=0;
|
||
|
}
|
||
|
va_list ap;
|
||
|
va_start(ap, data);
|
||
|
_vsnprintf(text+prefixLength, REMOTE_MAX_TEXT_INPUT-prefixLength, data, ap);
|
||
|
va_end(ap);
|
||
|
text[REMOTE_MAX_TEXT_INPUT-1]=0;
|
||
|
|
||
|
if (sendSuffix)
|
||
|
{
|
||
|
size_t length = strlen(text);
|
||
|
size_t availableChars = REMOTE_MAX_TEXT_INPUT-length-1;
|
||
|
strncat(text, sendSuffix, availableChars);
|
||
|
}
|
||
|
|
||
|
tcpInterface->Send(text, (unsigned int) strlen(text), systemAddress);
|
||
|
}
|
||
|
void TelnetTransport::CloseConnection( SystemAddress systemAddress )
|
||
|
{
|
||
|
tcpInterface->CloseConnection(systemAddress);
|
||
|
}
|
||
|
Packet* TelnetTransport::Receive( void )
|
||
|
{
|
||
|
if (tcpInterface==0) return 0;
|
||
|
Packet *p = tcpInterface->Receive();
|
||
|
if (p==0)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
if (p->data[0]==255)
|
||
|
{
|
||
|
unsigned i;
|
||
|
for (i=0; i < p->length; i++)
|
||
|
{
|
||
|
printf("%i ", p->data[i]);
|
||
|
}
|
||
|
printf("\n");
|
||
|
tcpInterface->DeallocatePacket(p);
|
||
|
return 0;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// 127 is delete - ignore that
|
||
|
// 9 is tab
|
||
|
// 27 is escape
|
||
|
if (p->data[0]>=127 || p->data[0]==9 || p->data[0]==27)
|
||
|
{
|
||
|
tcpInterface->DeallocatePacket(p);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Hack - I don't know what the hell this is about but cursor keys send 3 characters at a time. I can block these
|
||
|
//Up=27,91,65
|
||
|
//Down=27,91,66
|
||
|
//Right=27,91,67
|
||
|
//Left=27,91,68
|
||
|
if (p->length==3 && p->data[0]==27 && p->data[1]==91 && p->data[2]>=65 && p->data[2]<=68)
|
||
|
{
|
||
|
tcpInterface->DeallocatePacket(p);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Get this guy's cursor buffer. This is real bullcrap that I have to do this.
|
||
|
unsigned i;
|
||
|
TelnetClient *remoteClient=0;
|
||
|
for (i=0; i < remoteClients.Size(); i++)
|
||
|
{
|
||
|
if (remoteClients[i]->systemAddress==p->systemAddress)
|
||
|
remoteClient=remoteClients[i];
|
||
|
}
|
||
|
assert(remoteClient);
|
||
|
if (remoteClient==0)
|
||
|
{
|
||
|
tcpInterface->DeallocatePacket(p);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Echo
|
||
|
#ifdef ECHO_INPUT
|
||
|
tcpInterface->Send((const char *)p->data, p->length, p->systemAddress);
|
||
|
#endif
|
||
|
|
||
|
bool gotLine;
|
||
|
// Process each character in turn
|
||
|
for (i=0; i < p->length; i++)
|
||
|
{
|
||
|
|
||
|
#ifdef ECHO_INPUT
|
||
|
if (p->data[i]==8)
|
||
|
{
|
||
|
char spaceThenBack[2];
|
||
|
spaceThenBack[0]=' ';
|
||
|
spaceThenBack[1]=8;
|
||
|
tcpInterface->Send((const char *)spaceThenBack, 2, p->systemAddress);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
gotLine=ReassembleLine(remoteClient, p->data[i]);
|
||
|
if (gotLine && remoteClient->textInput[0])
|
||
|
{
|
||
|
Packet *reassembledLine = (Packet*) rakMalloc(sizeof(Packet));
|
||
|
reassembledLine->length=(unsigned int) strlen(remoteClient->textInput);
|
||
|
assert(reassembledLine->length < REMOTE_MAX_TEXT_INPUT);
|
||
|
reassembledLine->data= (unsigned char*) rakMalloc( reassembledLine->length+1 );
|
||
|
memcpy(reassembledLine->data, remoteClient->textInput, reassembledLine->length);
|
||
|
#ifdef _PRINTF_DEBUG
|
||
|
memset(remoteClient->textInput, 0, REMOTE_MAX_TEXT_INPUT);
|
||
|
#endif
|
||
|
reassembledLine->data[reassembledLine->length]=0;
|
||
|
reassembledLine->systemAddress=p->systemAddress;
|
||
|
tcpInterface->DeallocatePacket(p);
|
||
|
return reassembledLine;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tcpInterface->DeallocatePacket(p);
|
||
|
return 0;
|
||
|
}
|
||
|
void TelnetTransport::DeallocatePacket( Packet *packet )
|
||
|
{
|
||
|
if (tcpInterface==0) return;
|
||
|
rakFree(packet->data);
|
||
|
rakFree(packet);
|
||
|
}
|
||
|
SystemAddress TelnetTransport::HasNewConnection(void)
|
||
|
{
|
||
|
unsigned i;
|
||
|
SystemAddress newConnection;
|
||
|
newConnection = tcpInterface->HasNewConnection();
|
||
|
// 03/16/06 Can't force the stupid windows telnet to use line mode or local echo so now I have to track all the remote players and their
|
||
|
// input buffer
|
||
|
if (newConnection != UNASSIGNED_SYSTEM_ADDRESS)
|
||
|
{
|
||
|
unsigned char command[10];
|
||
|
// http://www.pcmicro.com/netfoss/RFC857.html
|
||
|
// IAC WON'T ECHO
|
||
|
command[0]=255; // IAC
|
||
|
//command[1]=253; // WON'T
|
||
|
command[1]=251; // WILL
|
||
|
command[2]=1; // ECHO
|
||
|
tcpInterface->Send((const char*)command, 3, newConnection);
|
||
|
|
||
|
/*
|
||
|
// Tell the other side to use line mode
|
||
|
// http://www.faqs.org/rfcs/rfc1184.html
|
||
|
// IAC DO LINEMODE
|
||
|
// command[0]=255; // IAC
|
||
|
// command[1]=252; // DO
|
||
|
// command[2]=34; // LINEMODE
|
||
|
// tcpInterface->Send((const char*)command, 3, newConnection);
|
||
|
|
||
|
*/
|
||
|
|
||
|
TelnetClient *remoteClient=0;
|
||
|
for (i=0; i < remoteClients.Size(); i++)
|
||
|
{
|
||
|
if (remoteClients[i]->systemAddress==newConnection)
|
||
|
{
|
||
|
remoteClient=remoteClients[i];
|
||
|
remoteClient->cursorPosition=0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (remoteClient==0)
|
||
|
{
|
||
|
remoteClient=new TelnetClient;
|
||
|
remoteClient->cursorPosition=0;
|
||
|
remoteClient->systemAddress=newConnection;
|
||
|
#ifdef _PRINTF_DEBUG
|
||
|
memset(remoteClient->textInput, 0, REMOTE_MAX_TEXT_INPUT);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
remoteClients.Insert(remoteClient);
|
||
|
}
|
||
|
return newConnection;
|
||
|
}
|
||
|
SystemAddress TelnetTransport::HasLostConnection(void)
|
||
|
{
|
||
|
SystemAddress systemAddress;
|
||
|
unsigned i;
|
||
|
systemAddress=tcpInterface->HasLostConnection();
|
||
|
if (systemAddress!=UNASSIGNED_SYSTEM_ADDRESS)
|
||
|
{
|
||
|
for (i=0; i < remoteClients.Size(); i++)
|
||
|
{
|
||
|
if (remoteClients[i]->systemAddress==systemAddress)
|
||
|
{
|
||
|
delete remoteClients[i];
|
||
|
remoteClients[i]=remoteClients[remoteClients.Size()-1];
|
||
|
remoteClients.RemoveFromEnd();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return systemAddress;
|
||
|
}
|
||
|
CommandParserInterface* TelnetTransport::GetCommandParser(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
void TelnetTransport::SetSendSuffix(const char *suffix)
|
||
|
{
|
||
|
if (sendSuffix)
|
||
|
{
|
||
|
rakFree(sendSuffix);
|
||
|
sendSuffix=0;
|
||
|
}
|
||
|
if (suffix)
|
||
|
{
|
||
|
sendSuffix = (char*) rakMalloc(strlen(suffix)+1);
|
||
|
strcpy(sendSuffix, suffix);
|
||
|
}
|
||
|
}
|
||
|
void TelnetTransport::SetSendPrefix(const char *prefix)
|
||
|
{
|
||
|
if (sendPrefix)
|
||
|
{
|
||
|
rakFree(sendPrefix);
|
||
|
sendPrefix=0;
|
||
|
}
|
||
|
if (prefix)
|
||
|
{
|
||
|
sendPrefix = (char*) rakMalloc(strlen(prefix)+1);
|
||
|
strcpy(sendPrefix, prefix);
|
||
|
}
|
||
|
}
|
||
|
void TelnetTransport::AutoAllocate(void)
|
||
|
{
|
||
|
if (tcpInterface==0)
|
||
|
tcpInterface=new TCPInterface;
|
||
|
}
|
||
|
bool TelnetTransport::ReassembleLine(TelnetTransport::TelnetClient* remoteClient, unsigned char c)
|
||
|
{
|
||
|
if (c=='\n')
|
||
|
{
|
||
|
remoteClient->textInput[remoteClient->cursorPosition]=0;
|
||
|
remoteClient->cursorPosition=0;
|
||
|
#ifdef _PRINTF_DEBUG
|
||
|
printf("[Done] %s\n", remoteClient->textInput);
|
||
|
#endif
|
||
|
return true;
|
||
|
}
|
||
|
else if (c==8) // backspace
|
||
|
{
|
||
|
if (remoteClient->cursorPosition>0)
|
||
|
{
|
||
|
remoteClient->textInput[--remoteClient->cursorPosition]=0;
|
||
|
#ifdef _PRINTF_DEBUG
|
||
|
printf("[Back] %s\n", remoteClient->textInput);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
else if (c>=32 && c <127)
|
||
|
{
|
||
|
if (remoteClient->cursorPosition < REMOTE_MAX_TEXT_INPUT)
|
||
|
{
|
||
|
remoteClient->textInput[remoteClient->cursorPosition++]=c;
|
||
|
#ifdef _PRINTF_DEBUG
|
||
|
printf("[Norm] %s\n", remoteClient->textInput);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma warning( pop )
|
||
|
#endif
|