|
//***********************************************************************
// (c) Copyright 1999-2003 Santronics Software, Inc. All Rights Reserved.
//***********************************************************************
// File Name : spserver.cpp
// Subsystem : Protocal Server
// Date : 03/03/2003
// Author : Hector Santos, Santronics Software, Inc.
// VERSION : 1.00P
//
// Revision History:
// Version Date Author Comments
// ------- -------- ------ -------------------------------------------
// v1.00P 03/03/03 HLS Public Release version (non-SSL version)
//***********************************************************************
#include "spserver.h"
#define assert ASSERT
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
const BYTE DM = 242;
const BYTE WILL = 251;
const BYTE WONT = 252;
const BYTE DO = 253;
const BYTE DONT = 254;
const BYTE IAC = 255;
static long TotalConnections = 0;
CSPServer::CSPServer(CSocketIO *s, TSPDispatch *dispatch, long maxconnect)
: Control(s), Dispatch(dispatch), MaxConnections(maxconnect)
{
if (MaxConnections < 1)MaxConnections=100;
commandname = NULL;
Done = FALSE;
dwTimeoutSeconds = 15*60; //default 15 minute wait time
}
CSPServer::~CSPServer()
{
InitiateShutdown();
Stop();
delete Control;
}
void CSPServer::ProcessCommand(char *cmdline)
{
if (!cmdline[0]) {
return;
}
char cmd[1024];
ZeroMemory(&cmd,sizeof(cmd));
char *s = strchr(cmdline, ' ');
char *args;
if (s) {
strncpy(cmd, cmdline, s-cmdline);
cmd[s-cmdline] = 0;
args = &cmdline[s-cmdline+1];
} else {
strncpy(cmd, cmdline,sizeof(cmd)-1);
args = &cmdline[strlen(cmdline)];
}
BOOL ok = FALSE;
DWORD i = 0;
while (Dispatch[i].cmd) {
// added abbreviation logic
char dcmd[100];
char dcmda[100];
ZeroMemory(&dcmd,sizeof(dcmd));
ZeroMemory(&dcmda,sizeof(dcmda));
strncpy(dcmd,Dispatch[i].cmd,sizeof(dcmd)-1);
char *star = strchr(dcmd,'*');
if (star) {
*star = 0;
strcpy(dcmda,dcmd);
strcat(dcmd,star+1);
}
//
if (!stricmp(cmd, dcmd) || (strlen(dcmda) && (!stricmp(cmd, dcmda)))) {
commandname = cmd;
ok = (this->*Dispatch[i].f)(args);
commandname = NULL;
break;
}
i++;
}
if (!ok) {
SendCommandError(cmdline);
}
}
/*virtual */
BOOL CSPServer::CheckAbort()
{
if (Done) return TRUE;
return (WaitForSingleObject(TerminateEvent, 0) == WAIT_OBJECT_0);
}
/* virtual */
void CSPServer::Go()
{
// Check if we are at maxconnections! if so, abort.
InterlockedIncrement(&TotalConnections);
if (TotalConnections > MaxConnections) {
// Connection Limit Exceeded
InterlockedDecrement(&TotalConnections);
return;
}
SendWelcome();
char cmdline[1024];
while (!Done && !CheckAbort()) {
LastCommandTime = GetTickCount();
if (!GetCommand(cmdline, sizeof(cmdline))) {
break;
}
SessionTrace("C: ",cmdline);
if (!PreprocessLine(cmdline)) {
ProcessCommand(cmdline);
}
}
Cleanup();
InterlockedDecrement(&TotalConnections);
}
/* virtual */
void CSPServer::SendCommandError(const char *cmdline)
{
Send("500 '%s': command not understood\r\n", cmdline);
}
BOOL CSPServer::Send(const TCHAR *format, ...)
{
va_list args;
va_start(args, format);
char buf[MAX_SEND_BUFFER_LEN];
buf[MAX_SEND_BUFFER_LEN-1] = 0;
_vsntprintf(buf, sizeof(buf)-1, format, args);
va_end(args);
int len = strlen(buf);
int n = Control->Send(buf, len, 0);
SessionTrace("S: ",buf);
return n == len;
}
BOOL CSPServer::GetCommand(char *s, DWORD len)
{
DWORD Status = 0;
BOOL lastIAC = FALSE;
DWORD i = 0;
while (i < len-1) {
if (!Control->Online()) {
return FALSE;
}
DWORD dwMSecs = dwTimeoutSeconds*1000;
Status = Control->WaitForReceivedData(dwMSecs, TerminateEvent);
if (Status == WAIT_ABANDONED) {
OnWaitReceivedDataAbandoned();
// Connection was closed, exiting.
return FALSE;
}
if (Status == WAIT_TIMEOUT) {
if (QueryAllowTimeoutDisconnect()) {
// Connection with timed out, exiting.
return FALSE;
}
// we were told not to disconnect, try again
continue;
}
//
// Note: Status will mostly be ZERO (WAIT_OBJECT0). if the socket was closed
// in FillBuffer() (called by WaitForReceivedData(), the select() function
// still returns 1 which means 1 socket was signed. But there is no error
// with this. So let Recv() do its thing to try to read the socket, and in
// this case, it will error and we can use the WSAGetLastError()
//
unsigned char c = 0;
if (!Control->Recv(c)) {
// the only possible reason for this is a socket close
OnReceiveByteError(WSAGetLastError());
return FALSE;
}
s[i]=c;
DumpReceivedByte(BYTE(s[i]));
if (lastIAC) {
char t[2];
t[0] = IAC;
switch (BYTE(s[i])) {
case WILL:
case WONT:
t[1] = DONT;
Control->Send((char *)&t, 2);
break;
case DO:
case DONT:
t[1] = WONT;
Control->Send((char *)&t, 2);
break;
}
lastIAC = FALSE;
} else {
switch (BYTE(s[i])) {
case '\r':
s[i] = 0;
DumpReceivedByte(00);
return TRUE;
case '\n':
// do nothing, ignore
DumpReceivedByte(01);
break;
case DM:
// ignore this, probably accompanied by ftp ABOR command
break;
case IAC:
lastIAC = TRUE;
break;
default:
i++;
break;
}
}
}
s[i] = 0;
return TRUE;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.