Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

4149 lines
106 KiB
C++

#include "stdafx.h"
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#include <io.h>
#endif // WIN32
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifdef WIN32
#pragma comment(lib, "wsock32.lib")
#ifdef USE_OVRIO
#pragma comment(lib, "ws2_32.lib")
#endif // USE_OVRIO
#define SEND_RECV_TYPE char
#define socklen_t int
#else // !WIN32
#ifdef SOLARIS
#define SEND_RECV_TYPE char
#else // !SOLARIS
#define SEND_RECV_TYPE void
#endif // SOLARIS
#ifdef SOLARIS
#define socklen_t int
#endif // SOLARIS
#define SD_RECEIVE SHUT_RD
#define SD_SEND SHUT_WR
#define SD_BOTH SHUT_RDWR
#define SOCKET_ERROR (-1)
#define _open open
#define _close close
#define _stat stat
#define _fstat fstat
#define _O_RDONLY O_RDONLY
#define _O_WRONLY O_WRONLY
#define _O_BINARY 0
#define _O_CREAT O_CREAT
#define _O_TRUNC O_TRUNC
#define WSAENOTSOCK ENOTSOCK // EBADF
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEMSGSIZE EMSGSIZE // send
#define WSAENOTCONN ENOTCONN
#define WSAEFAULT EFAULT
#define WSAEINPROGRESS EINPROGRESS
#define WSAENETDOWN ENETDOWN
#define WSAENETRESET ENETRESET
#define WSAECONNRESET ECONNRESET
#define WSAECONNABORTED ECONNABORTED
#define WSAEADDRINUSE EADDRINUSE
#define WSAETIMEDOUT ETIMEDOUT
#define WSAEHOSTUNREACH EHOSTUNREACH
#define WSAEACCES EACCES
#define WSAEOPNOTSUPP EOPNOTSUPP
#define WSAEINVAL EINVAL
#define WSAESHUTDOWN ESHUTDOWN
#define WSANOTINITIALISED (-10011)
#define WSANO_RECOVERY (-1003)
#define WSAEDISCON (-1020)
#define GetACP() 949
#define SO_MAX_MSG_SIZE 100
typedef hostent* LPHOSTENT;
typedef in_addr* LPIN_ADDR;
#endif // WIN32
//getpeername,getsockname,gethostbyaddr,gethostbyname
BEGIN_PACKET_MAP_RAW(CSOC, (_SPacketMap*)NULL)
PACKET_MAP_ENTRY(CSOC, X_KEEPALIVE, OnKeepAlive)
END_PACKET_MAP(CSOC)
BEGIN_PACKET_MAP(CSOCConnect, CSOC)
PACKET_MAP_ENTRY(CSOCConnect, X_TEXT, OnText)
PACKET_MAP_ENTRY(CSOCConnect, X_TEXTFMT, OnTextFmt)
PACKET_MAP_ENTRY(CSOCConnect, C_FTP, OnFTP)
PACKET_MAP_ENTRY(CSOCConnect, S_FTP, OnFTP)
END_PACKET_MAP(CSOCConnect)
BEGIN_PACKET_MAP(CSOCClient, CSOCConnect)
END_PACKET_MAP(CSOCClient)
BEGIN_PACKET_MAP(CSOCServer, CSOCConnect)
END_PACKET_MAP(CSOCServer)
//#ifdef SR_TRACE
#ifdef TRACE
#undef TRACE
#endif // TRACE
#if 0 // def _DEBUG
static void __cdecl __DbgTrace(const char* pcszFormat, ...)
{/*
va_list ap;
va_start(ap, pcszFormat);
char sz[256];
vsprintf(sz, pcszFormat, ap);
va_end(ap);
::OutputDebugString(sz);*/
}
#define TRACE __DbgTrace
#else // !_DEBUG
static inline void __cdecl __RelTraceIgnore(const char* pcszFormat, ...) {}
#define TRACE 1 ? (void)0 : __RelTraceIgnore
#endif // _DEBUG
//#endif // SR_TRACE
static const struct timeval g_tSelectTimeOut = {0L, 0L}; // t.tv_sec, t.tv_usec
static struct linger g_opt_ling = { 0, 0 }; // ling.l_onoff, ling.l_linger
char SERVERID[] = "";
#ifdef _DEBUG
static const char* EEXCP2MSG(EException eException);
#else // !_DEBUG
#define EEXCP2MSG(x) ""
#endif // _DEBUG
static int __cdecl compare_Timer(const void *elem1, const void *elem2);
static long timer_ConnectCheck(CTimerEvent& Timer);
static int __cdecl qsort_TEXTFmt(const void* elem1, const void* elem2);
static int __cdecl bsearch_TEXTFmt(const void* pcvKey, const void* elem);
#ifdef _DEBUG
static const char* EEXCP2MSG(EException eException)
{
const char* s_pcszaMSG[] = {
"EEXCP_NoError",
// local side...
"EEXCP_TooLowVersion",
"EEXCP_Unknown",
"EEXCP_ConnectionTimeOut",
"EEXCP_ConnectionFailure",
"EEXCP_SendBufferOverflow",
"EEXCP_VersionError",
// fatal socket error...
"EEXCP_WSAENETDOWN",
"EEXCP_WSANO_RECOVERY",
"EEXCP_WSAENETRESET",
"EEXCP_WSAECONNRESET",
"EEXCP_WSAECONNABORTED",
"EEXCP_WSAEADDRINUSE",
"EEXCP_WSAETIMEDOUT",
"EEXCP_WSAEHOSTUNREACH",
"EEXCP_WSAEACCES",
// internal error
"EEXCP_WSANOTINITIALISED",
"EEXCP_WSAEFAULT",
"EEXCP_WSAENOTSOCK",
"EEXCP_WSAENOTCONN",
"EEXCP_WSAEOPNOTSUPP",
"EEXCP_WSAEINVAL",
"EEXCP_DupCreation",
};
return s_pcszaMSG[eException];
}
#endif // _DEBUG
#if !defined(SOLARIS)
inline WORD GetWORD(const BYTE* pbPacket) { return ntohs(UPKV(pbPacket)->m_w); }
inline DWORD GetDWORD(const BYTE* pbPacket) { return ntohl(UPKV(pbPacket)->m_dw); }
inline float GetFLOAT(const BYTE* pbPacket) { return UPKV(pbPacket)->m_f; }
inline double GetDOUBLE(const BYTE* pbPacket) { return UPKV(pbPacket)->m_dbl; }
inline SINT64 GetI64(const BYTE* pbPacket) { return UPKV(pbPacket)->m_i64; }
inline void PutWORD(BYTE* pbPacket, WORD w) { UPKV(pbPacket)->m_w = htons(w); }
inline void PutDWORD(BYTE* pbPacket, DWORD dw) { UPKV(pbPacket)->m_dw = htonl(dw); }
inline void PutFLOAT(BYTE* pbPacket, float f) { UPKV(pbPacket)->m_f = f; }
inline void PutDOUBLE(BYTE* pbPacket, double dbl) { UPKV(pbPacket)->m_dbl = dbl; }
inline void PutI64(BYTE* pbPacket, SINT64 i64) { UPKV(pbPacket)->m_i64 = i64; }
#else // defined(SOLARIS)
inline WORD GetWORD(const BYTE* pbPacket) { WORD w; memcpy(&w, &UPKV(pbPacket)->m_w, sizeof(w)); return ntohs(w); }
inline DWORD GetDWORD(const BYTE* pbPacket) { DWORD dw; memcpy(&dw, &UPKV(pbPacket)->m_dw, sizeof(dw)); return ntohl(dw); }
inline float GetFLOAT(const BYTE* pbPacket) { float f; memcpy(&f, &UPKV(pbPacket)->m_f, sizeof(f)); return f; }
inline double GetDOUBLE(const BYTE* pbPacket) { double dbl; memcpy(&dbl, &UPKV(pbPacket)->m_dbl, sizeof(dbl)); return dbl; }
inline SINT64 GetI64(const BYTE* pbPacket) { SINT64 i64; memcpy(&i64, &UPKV(pbPacket)->m_i64, sizeof(i64)); return i64; }
inline void PutWORD(BYTE* pbPacket, WORD w) { w = htons(w); memcpy(&UPKV(pbPacket)->m_w, &w, sizeof(w)); }
inline void PutDWORD(BYTE* pbPacket, DWORD dw) { dw = htonl(dw); memcpy(&UPKV(pbPacket)->m_dw, &dw, sizeof(dw)); }
inline void PutFLOAT(BYTE* pbPacket, float f) { memcpy(&UPKV(pbPacket)->m_f, &f, sizeof(f)); }
inline void PutDOUBLE(BYTE* pbPacket, double dbl) { memcpy(&UPKV(pbPacket)->m_dbl, &dbl, sizeof(dbl)); }
inline void PutI64(BYTE* pbPacket, SINT64 i64) { memcpy(&UPKV(pbPacket)->m_i64, &i64, sizeof(i64)); }
#endif // defined(SOLARIS)
static int __cdecl compare_Timer(const void *elem1, const void *elem2)
{
HEAPCHK();
DWORD dwTime1 = ((const CTimerEvent*)elem1)->m_dwTime;
DWORD dwTime2 = ((const CTimerEvent*)elem2)->m_dwTime;
if (dwTime1 != dwTime2) {
if (dwTime1 < dwTime2)
return -1;
return +1;
}
HEAPCHK();
return 0;
}
static long timer_ConnectCheck(CTimerEvent& Timer)
{
//TRACE("Connect Timeout : %x\n", Timer.m_pVoid);
((PSOCServer)Timer.m_pVoid)->CallOnConnectionTimeOut();
return -1; // already deleted...
}
static int __cdecl qsort_TEXTFmt(const void* elem1, const void* elem2)
{
WORD wFmt1 = ((const CTEXTFmt*)elem1)->m_DW.m_wFmt, wFmt2 = ((const CTEXTFmt*)elem2)->m_DW.m_wFmt;
if (wFmt1 != wFmt2) {
if (wFmt1 > wFmt2) {
return +1;
} else {
return -1;
}
}
return 0;
}
static int __cdecl bsearch_TEXTFmt(const void* pcvKey, const void* elem)
{
WORD wFmt1 = *(const WORD*)pcvKey;
WORD wFmt2 = ((const CTEXTFmt*)elem)->m_DW.m_wFmt;
if (wFmt1 != wFmt2) {
if (wFmt1 > wFmt2) {
return +1;
} else {
return -1;
}
}
return 0;
}
const char* SkipWord(const char* pcsz)
{
ASSERT(pcsz && ((*pcsz != '\0') && (*pcsz != ' ') && (*pcsz != '\t')));
const char* pcszOrg = pcsz;
char c;
while((c = *++pcsz) != '\0') {
if ((c == '\t') || (c == ' '))
break;
}
return pcsz;
}
const char* SkipWhite(const char* pcsz)
{
ASSERT(pcsz);
char c;
while((c = *pcsz) != '\0') {
if ((c != '\t') && (c != ' '))
return pcsz;
pcsz++;
}
return NULL;
}
const char* SkipWhiteReverse(const char* pcsz)
{
ASSERT(pcsz);
const char* pcszEnd = &pcsz[strlen(pcsz)];
char c;
while(pcszEnd > pcsz) {
if (((c = pcszEnd[-1]) != ' ') && (c != '\t'))
break;
}
return pcszEnd;
}
BOOL IsControlExist(const char* pcsz)
{
BYTE c;
while((c = *(const BYTE*)pcsz++) != '\0') {
if (c < 0x20) {
return TRUE;
}
}
return FALSE;
}
BOOL IsAllDigit(const char* pcsz)
{
BYTE c;
while((c = *(const BYTE*)pcsz++) != '\0') {
if (!(('0' <= c) && (c <= '9'))) {
return FALSE;
}
}
return TRUE;
}
BOOL CheckStringOK(const char* pcsz, int nMin, int nMax)
{
if ((nMin <= strlen(pcsz)) || (strlen(pcsz) <= nMax)) {
if (!IsControlExist(pcsz))
return TRUE;
}
return FALSE;
}
BOOL CheckNumberOK(const char* pcsz, int nMin, int nMax)
{
if (CheckStringOK(pcsz, nMin, nMax)) {
if (IsAllDigit(pcsz))
return TRUE;
}
return FALSE;
}
BOOL IsInvalidCharsExist(const char* pcsz, const char* pcszInvalidChars)
{
ASSERT(pcsz && pcszInvalidChars);
char c;
while((c = *pcsz++) != '\0') {
if (strchr(pcszInvalidChars, c)) {
return TRUE;
}
}
return FALSE;
}
char* cmd_GetString(char*& psz, int nQuoteType/* = 0*/)
{
// nQuoteType: 0 - no quote, 1 - single, 2 - double, 3: single & double...
ASSERT((0 <= nQuoteType) && (nQuoteType <= 3));
char* psz2 = psz;
psz2 = (char*)SkipWhite(psz2);
if (psz2) {
char* pszStart = psz2;
char cStart = *pszStart;
switch(cStart) {
case '\'':
if (!((nQuoteType == 1) || (nQuoteType == 3)))
nQuoteType = 0;
break;
case '"':
if (!((nQuoteType == 2) || (nQuoteType == 3)))
nQuoteType = 0;
break;
default:
nQuoteType = 0;
break;
}
if (nQuoteType) {
pszStart++;
psz2++;
char c;
while((c = *psz2) != '\0') {
if (c == cStart) {
if (((c = psz2[1]) == ' ') || (c == '\t')) {
*psz2 = '\0';
psz2 += 2;
break;
}
}
psz2++;
}
} else {
psz2 = (char*)SkipWord(psz2);
if (*psz2) {
*psz2++ = '\0';
}
}
psz = psz2;
return pszStart;
}
return NULL;
}
int cmd_GetNumber(char*& psz, int& nNumber, int nMin/* = 0*/, int nMax/* = 65536*/)
{
ASSERT((INT_MIN <= nMin) && (nMax < INT_MAX) && (nMin < nMax));
BOOL bNegative = FALSE;
BOOL bSignExist = FALSE;
char* psz2;
while((psz2 = cmd_GetString(psz)) != NULL) {
char c;
while((c = *psz2) != '\0') {
if ((c == '-') || (c == '+')) {
if (nMin < 0) {
if (c == '-')
bNegative = !bNegative;
bSignExist = TRUE;
} else {
return -3; // sign exist...
}
} else {
break;
}
psz2++;
}
if (c == '\0')
continue;
if (IsAllDigit(psz2)) {
while((c = *psz2) == '0')
psz2++;
SINT64 ll = 0;
if (c != '\0') {
while((c = *psz2) != '\0') {
ll *= 10;
ll += c - '0';
psz2++;
if (ll >= INT_MAX) {
return -2;
}
}
}
if (bNegative)
ll = -ll;
if ((nMin <= ll) && (ll < nMax)) {
nNumber = ll;
return +1;
}
return -2; // range error.
} else {
return -1; // non digit char(s) exist...
}
}
if (bSignExist)
return -3; // sign exist but no number...
return 0; // no number...
}
CTEXTFmt::CTEXTFmt(const char* pcszFormat/* = NULL*/)
: CStr(pcszFormat)
{
m_DW.m_wFmt = 0;
m_DW.m_wTX = TX_SYSTEM;
}
CTEXTFmtArray::CTEXTFmtArray()
{
}
CTEXTFmtArray::~CTEXTFmtArray()
{
}
int CTEXTFmtArray::LoadFmts(const char* pcszFile, const char* pcszSignature, BOOL bCheckACP/* = FALSE*/)
{
CStr strFile;
if (bCheckACP) {
UINT uACP = GetACP();
strFile.Format(pcszFile, uACP); // ...cclnt%u.fmt
if (access(strFile, 0) == -1) {
if (uACP != 1252) {
strFile.Format(pcszFile, 1252); // ...cclnt%u.fmt
if (access(strFile, 0) == -1) {
return 0;
} else {
uACP = 1252;
}
} else {
return 0;
}
}
pcszFile = strFile;
}
int nSizeOld = GetSize();
int nSize = nSizeOld;
FILE* pFile = fopen(pcszFile, "rt");
if (pFile) {
BYTE baLine[512];
BYTE* pbEnd = &baLine[sizeof(baLine) - 1];
BYTE* pb = &baLine[0];
while(!feof(pFile)) {
int c = getc(pFile);
if ((c == EOF) || (c == '\0')) {
break;
}
if (c < 0x20) {
if ((c == '\n') || (c == '\r')) {
*pb = '\0';
pb = &baLine[0];
switch(ProcessOneLine(baLine, pcszSignature, nSizeOld, nSize)) {
default: //case 0:
break;
case +1:
nSize++;
break;
case -1:
// assume: none TEXTFmt file?...
goto out_before_close;
}
}
pcszSignature = NULL;
} else {
if (pb < pbEnd) {
*pb++ = (BYTE)c;
} else {
// assume: none TEXTFmt file?...
goto out_before_close;
}
}
}
if (pb != &baLine[0]) {
if (ProcessOneLine(baLine, pcszSignature, nSizeOld, nSize) == +1) {
nSize++;
}
}
out_before_close:
fclose(pFile);
}
FreeExtra();
if ((nSize -= nSizeOld) > 0) {
Sort();
}
return nSize;
}
CTEXTFmt& CTEXTFmtArray::FindTEXTFmt(WORD wFmt) const
{
return *(CTEXTFmt*)bsearch(&wFmt, &GetAt(0), GetSize(), sizeof(CTEXTFmt), bsearch_TEXTFmt);
}
CTEXTFmtArray::CAtoms* CTEXTFmtArray::FindAtoms(const char* pcsz) const
{
const TARRAYPTR(CAtoms*)& paAtoms = m_paAtoms;
int i, nSize = paAtoms.GetSize();
for(i =0; i < nSize; i++) {
CAtoms* pAtoms = paAtoms.At(i);
if (strcmp(pAtoms->m_strTitle, pcsz) == 0)
return pAtoms;
}
return NULL;
}
void CTEXTFmtArray::Sort()
{
qsort(&GetAt(0), GetSize(), sizeof(CTEXTFmt), qsort_TEXTFmt);
}
int CTEXTFmtArray::ProcessOneLine(BYTE baLine[], const char* pcszSignature, int nSizeOld, int nSize)
{
BYTE* pb = &baLine[0];
BYTE b;
pb = (BYTE*)SkipWhite((const char*)pb);
if (pb && (pb[0] != ';')) { // is comment?
BYTE* pbEnd = (BYTE*)SkipWhiteReverse((const char*)pb);
*pbEnd = '\0';
if (pcszSignature) {
// check signature
if (lstrcmpi((const char*)pb, pcszSignature) == 0) {
return 0;
} else {
return -1;
}
} else {
BYTE* p = (BYTE*)strchr((const char*)pb, '=');
if (p) {
*p = '\0';
BYTE* pbStart = &p[1];
p = (BYTE*)SkipWhiteReverse((const char*)p);
WORD wFmt = 0;
BOOL bFmt = FALSE;
BYTE* pbAtoms = pb;
while((b = *pb) == '0') {
pb++;
}
if (CheckNumberOK((const char*)pb, 1, 5)) {
int nATOI = atoi((const char*)pb);
if ((0 <= nATOI) && (nATOI < 65536)) {
bFmt = TRUE;
wFmt = (WORD)nATOI;
}
}
pbStart = (BYTE*)SkipWhite((const char*)pbStart);
if (pbStart) {
if (*pbStart == '"') {
pbStart++;
}
if ((pbStart < pbEnd) && (pbEnd[-1] == '"'))
pbEnd[-1] = '\0';
} else {
pbStart = (BYTE*)"";
}
if (bFmt) {
CTEXTFmt* pTEXTFmt = &FindOnLoad(wFmt, nSizeOld, nSize);
if (!pTEXTFmt) {
pTEXTFmt = &Add();
pTEXTFmt->m_DW.m_wFmt = wFmt;
CTEXTFmtArray::ProcessEscape(pbStart);
pTEXTFmt->Assign((const char*)pbStart);
return +1;
} else {
// default - don't overwrite duplicated entry...
/*
if (bOverWriteIfExist) {
// same value...: pTEXTFmt->m_DW.m_wFmt = (WORD)n;
CTEXTFmtArray::ProcessEscape(pbStart);
pTEXTFmt->Assign((const char*)pbStart);
return 0;
} else {
// don't overwrite...
return 0;
}
*/
}
} else {
// Atom...
CAtoms* pAtoms = FindAtoms((const char*)pbAtoms);
if (!pAtoms) {
pAtoms = new CAtoms((const char*)pbAtoms);
m_paAtoms.Add() = pAtoms;
}
CTEXTFmtArray::ProcessEscape(pbStart);
pAtoms->Add() = (const char*)pbStart;
}
}
}
}
return 0;
}
CTEXTFmt& CTEXTFmtArray::FindOnLoad(WORD wFmt, int nSizeOld, int nSize) const
{
CTEXTFmt* pTEXTFmt = (CTEXTFmt*)bsearch(&wFmt, &GetAt(0), nSizeOld, sizeof(CTEXTFmt), bsearch_TEXTFmt);
if (pTEXTFmt) {
return *pTEXTFmt;
}
pTEXTFmt = &GetAt(nSizeOld);
while(nSizeOld < nSize) {
if (pTEXTFmt->m_DW.m_wFmt == wFmt) {
return *pTEXTFmt;
}
pTEXTFmt++;
nSizeOld++;
}
return *(CTEXTFmt*)NULL;
}
void CTEXTFmtArray::ProcessEscape(BYTE* pb)
{
BYTE b;
while((b = *pb) != '\0') {
if (b == '\\') {
switch(pb[1]) {
case 'r':
*pb = '\r';
strcpy((char*)&pb[1], (const char*)&pb[2]);
break;
case 't':
*pb = '\t';
strcpy((char*)&pb[1], (const char*)&pb[2]);
break;
case 'n':
*pb = '\n';
strcpy((char*)&pb[1], (const char*)&pb[2]);
break;
case '\0':
break;
default:
pb++;
break;
}
}
pb++;
}
}
void Randomize()
{
srand(time(0));
}
DWORD CDAPacket::Push() const
{
return m_wLen;
}
void CDAPacket::Pop(DWORD dw)
{
ASSERT(dw >= m_wLen);
m_pbPacket -= dw - m_wLen;
m_wLen = (WORD)dw;
}
BYTE* CDAPacket::GetData(int nSize)
{
if (nSize <= m_wLen) {
BYTE* pb = m_pbPacket;
m_wLen -= nSize;
m_pbPacket += nSize;
return pb;
} else {
CSOC* pSOC = IsSOC();
if (pSOC) {
pSOC->Drop();
}
return NULL;
}
}
BYTE* __cdecl CDAPacket::Disassemble(const char *pcszFormat, ...)
{
va_list ap;
va_start(ap, pcszFormat);
BYTE* pb = vDisassemble(pcszFormat, ap);
va_end(ap);
return pb;
}
BYTE* __cdecl CDAPacket::vDisassemble(const char* pcszFormat, va_list ap)
{
#ifdef NO_PDCD
#define PACKET_DUMP_CHECK_DISASSEMBLE(SizeInBYTE) pbNext = &pbPacket[SizeInBYTE];
#else // !NO_PDCD
#define PACKET_DUMP_CHECK_DISASSEMBLE(SizeInBYTE) if ((pbNext = &pbPacket[SizeInBYTE]) > pbPacketEnd) { TRACE("Buffer boundary failure... in vDisssemble() %d\n", __LINE__); goto as_failure; }
#endif // NO_PDCD
BYTE* pbPacket = m_pbPacket;
BYTE* pbPacketEnd = &pbPacket[m_wLen];
BYTE* pbNext;
BYTE b;
while((b = *pcszFormat++) != '\0') {
switch(b) {
case 'b':
case 'B':
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(BYTE));
*va_arg(ap, BYTE*) = *pbPacket;
break;
case 'w':
case 'W':
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(WORD));
*va_arg(ap, WORD*) = GetWORD(pbPacket);
break;
case 'n':
case 'd':
case 'D':
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(DWORD));
*va_arg(ap, DWORD*) = GetDWORD(pbPacket);
break;
case 'f':
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(float));
*va_arg(ap, float*) = GetFLOAT(pbPacket);
break;
case 'F':
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(double));
*va_arg(ap, double*) = GetDOUBLE(pbPacket);
break;
case '6':
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(SINT64));
*va_arg(ap, SINT64*) = GetI64(pbPacket);
break;
case 's':
case '$':
{
WORD wLen = strlen((const char*)pbPacket) + 1;
PACKET_DUMP_CHECK_DISASSEMBLE(wLen);
if (b == 's')
*va_arg(ap, char**) = (char*)pbPacket;
else
*va_arg(ap, CStr*) = (const char*)pbPacket;
break;
}
case 'S':
{
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(WORD));
WORD wLen = GetWORD(pbPacket);
if (wLen > 0) {
pbPacket = pbNext;
PACKET_DUMP_CHECK_DISASSEMBLE(wLen);
*va_arg(ap, char**) = (char*)pbPacket;
} else {
*va_arg(ap, char**) = (char*)NULL;
}
break;
}
case 'x':
{
PACKET_DUMP_CHECK_DISASSEMBLE(sizeof(WORD));
WORD wLen = GetWORD(pbPacket);
if (wLen > 0) {
pbPacket = pbNext;
PACKET_DUMP_CHECK_DISASSEMBLE(wLen);
*va_arg(ap, const BYTE**) = (BYTE*)pbPacket;
} else {
*va_arg(ap, const BYTE**) = (BYTE*)NULL;
}
*va_arg(ap, WORD*) = wLen;
break;
}
case 'X':
{
*va_arg(ap, const BYTE**) = (BYTE*)pbPacket;
WORD wLen = va_arg(ap, int); // WORD wLen = va_arg(ap, WORD);
PACKET_DUMP_CHECK_DISASSEMBLE(wLen);
break;
}
case '!':
{
CPacketDumper* pDumper = va_arg(ap, CPacketDumper*);
pbNext = pDumper->Disassemble(pbPacket, pbPacketEnd);
if (!pbNext) {
goto as_failure;
}
ASSERT((m_pbPacket <= pbNext) && (pbNext <= pbPacketEnd));
break;
}
default:
TRACE("Invalid vDisassemble Char %c\n", (char)b);
ASSERT(FALSE);
as_failure:
//fprintf(stderr, "vDisassemble Char %c\n", (char)b);
{
CSOC* pSOC = IsSOC();
if (pSOC) {
pSOC->Drop();
}
}
return FALSE;
}
pbPacket = pbNext;
}
m_wLen = pbPacketEnd - pbPacket;
return m_pbPacket = pbPacket;
#undef PACKET_DUMP_CHECK_DISASSEMBLE
}
CTimerPool::CTimerPool()
{
m_nReEnter = 0;
m_bDirty = FALSE;
m_dwPrecision = 10;
m_dwLastTicks = 0;
}
void CTimerPool::CheckTimers()
{
if (m_nReEnter == 0) {
m_nReEnter++;
int nSize = GetSize();
if (nSize > 0) {
DWORD dwTicks = GetTickCount();
//fprintf(stderr, "1 --- %d <? %d\n", m_dwLastTicks + m_dwPrecision, dwTicks);
if (m_dwLastTicks + m_dwPrecision < dwTicks) {
SetLastTicks(dwTicks);
if (m_bDirty) {
HEAPCHK();
qsort(&GetAt(0), nSize, sizeof(CTimerEvent), compare_Timer);
HEAPCHK();
FreeExtra();
HEAPCHK();
m_bDirty = FALSE;
}
DWORD dwTime = GetTickCount();
HEAPCHK();
int i = 0;
while(i < nSize) {
CTimerEvent& Timer = GetAt(i);
//fprintf(stderr, "1 --- %d <? %d\n", Timer.m_dwTime, dwTime);
if (Timer.m_dwTime < dwTime) {
long lRet = (*Timer.m_pfnTimerProc)(Timer);
if (lRet >= 0) { // stay...
if (lRet == 0) {
Timer.m_dwTime += GetTickCount();
} else {
Timer.m_dwTime = GetTickCount() + lRet;
}
m_bDirty = TRUE;
i++;
break;
} else {
if (lRet == -1) { // already deleted...
nSize--;
} else { // delete this...
HEAPCHK();
Del(i);
HEAPCHK();
nSize--;
}
}
} else {
break;
}
}
HEAPCHK();
}
}
m_nReEnter--;
}
}
CTimerEvent& CTimerPool::AddTimer(PFN_TimerProc pfnTimerProc, DWORD dwTime, void* pVoid)
{
HEAPCHK();
CTimerEvent& Timer = Add();
Timer.m_pfnTimerProc = pfnTimerProc;
Timer.m_dwTime = dwTime + GetTickCount();
Timer.m_pVoid = pVoid;
Timer.m_dwFrame = 0;
//Timer.m_nParam = 0; // not initialized...
//Timer.m_dwParam = 0; // not initialized...
m_bDirty = TRUE;
HEAPCHK();
return Timer;
}
BOOL CTimerPool::DelTimer(int nIndex)
{
HEAPCHK();
int nSize = GetSize();
if ((0 <= nIndex) && (nIndex <nSize)) {
Del(nIndex);
return TRUE;
}
return FALSE;
}
BOOL CTimerPool::DelTimers(PFN_TimerProc pfnTimerProc, void* pVoid, UINT uFlags, int nFromIndex/* = 0*/)
{
//CHK_TIMER_NOVOIDCHECK
HEAPCHK();
int nSize = GetSize();
if (!pfnTimerProc) {
if (nSize) {
Reset();
return TRUE;
}
return FALSE;
}
HEAPCHK();
int i;
if (nFromIndex < 0)
i = 0;
else
i = nFromIndex;
BOOL bDeleted = FALSE;
while(i < nSize) {
CTimerEvent& Timer = GetAt(i);
if ((Timer.m_pfnTimerProc == pfnTimerProc) && ((uFlags & CHK_TIMER_NOVOIDCHECK) || (Timer.m_pVoid == pVoid))) {
HEAPCHK();
Del(i);
HEAPCHK();
nSize--;
if (uFlags & CHK_TIMER_ONCE)
return TRUE;
bDeleted = TRUE;
} else {
i++;
}
}
HEAPCHK();
return bDeleted;
}
int CTimerPool::FindTimer(PFN_TimerProc pfnTimerProc, void* pVoid, UINT uFlags, int nFromIndex/* = 0*/)
{
//CHK_TIMER__NOVOIDCHECK
//CHK_TIMER_ONCE
HEAPCHK();
int i;
if (nFromIndex < 0)
i = 0;
else
i = nFromIndex;
int nSize = GetSize();
if (!pfnTimerProc) {
if (i < nSize) {
return i;
}
return -1;
}
HEAPCHK();
while(i < nSize) {
CTimerEvent& Timer = GetAt(i);
if ((Timer.m_pfnTimerProc == pfnTimerProc) && ((uFlags & CHK_TIMER_NOVOIDCHECK) || (Timer.m_pVoid == pVoid))) {
return i;
} else {
i++;
}
}
HEAPCHK();
return -1;
}
CPacket::CPacket(CSOC* pSOC)
: m_pSOC(pSOC)
{
m_wLen = 0;
ASSERT(pSOC);
}
CPacket::~CPacket()
{
}
void CPacket::Reset()
{
SetLength(0);
}
BYTE* __cdecl CPacket::Assemble(const char *pcszFormat, ...)
{
BYTE* pbEnd;
va_list ap;
va_start(ap, pcszFormat);
pbEnd = vAssemble(pcszFormat, ap);
va_end(ap);
return pbEnd;
}
BYTE* __cdecl CPacket::vAssemble(const char *pcszFormat, va_list ap)
{
#ifdef NO_PDCA
#define PACKET_DUMP_CHECK_ASSEMBLE(SizeInBYTE) pbNext = &pbPacket[SizeInBYTE];
#else // !NO_PDCA
#define PACKET_DUMP_CHECK_ASSEMBLE(SizeInBYTE) if ((pbNext = &pbPacket[SizeInBYTE]) > pbPacketEnd) { TRACE("Buffer boundary failure... in vAssemble() %d\n", __LINE__); goto as_failure; }
#endif // NO_PDCA
BYTE* pbPacket = GetLastPtr();
BYTE* pbPacketEnd = GetEndPtr();
BYTE* pbNext;
BYTE b;
BYTE* pbPacketOld = pbPacket;
while((b = *pcszFormat++) != '\0') {
switch(b) {
case 'b':
case 'B':
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(BYTE));
*pbPacket = va_arg(ap, int); // *pbPacket = va_arg(ap, BYTE);
break;
case 'w':
case 'W':
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(WORD));
PutWORD(pbPacket, va_arg(ap, int)); // PutWORD(pbPacket, va_arg(ap, WORD));
break;
case 'n':
case 'd':
case 'D':
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(DWORD));
PutDWORD(pbPacket, va_arg(ap, DWORD));
break;
case 'f':
{
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(float));
DWORD dwFloat;
dwFloat = va_arg(ap, DWORD);
PutFLOAT(pbPacket, *(float*)&dwFloat); // PutFLOAT(pbPacket, va_arg(ap, float));
break;
}
case 'F':
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(double));
PutDOUBLE(pbPacket, va_arg(ap, double));
break;
case '6':
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(SINT64));
PutI64(pbPacket, va_arg(ap, SINT64));
break;
case 's':
{
const char* pcStr = va_arg(ap, const char*);
ASSERT(pcStr);
WORD wLen = strlen(pcStr) + 1;
PACKET_DUMP_CHECK_ASSEMBLE(wLen);
memcpy(pbPacket, (const char*)pcStr, wLen);
break;
}
case 'S':
{
WORD wLen;
const char* pcStr = va_arg(ap, const char*);
if (pcStr) {
wLen = strlen(pcStr) + 1;
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(WORD) + wLen);
PutWORD(pbPacket, wLen);
memcpy(&pbPacket[sizeof(WORD)], (const char*)pcStr, wLen);
} else {
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(WORD));
wLen = 0;
PutWORD(pbPacket, wLen);
}
break;
}
case 'x': // binary data
{
const BYTE* pb = va_arg(ap, const BYTE*);
ASSERT(pb);
const WORD wLen = va_arg(ap, int); // va_arg(ap, WORD);
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(WORD) + wLen);
PutWORD(pbPacket, wLen);
if (wLen > 0) {
memcpy(&pbPacket[sizeof(WORD)], pb, wLen);
}
break;
}
case 'X': // binary data, sub-packet copy...
{
const BYTE* pb = va_arg(ap, const BYTE*);
const WORD wLen = va_arg(ap, int); // va_arg(ap, WORD);
PACKET_DUMP_CHECK_ASSEMBLE(wLen);
if (wLen > 0) {
ASSERT(pb);
memcpy(pbPacket, pb, wLen);
}
break;
}
case '!':
{
CPacketDumper* pDumper = va_arg(ap, CPacketDumper*);
pbNext = pDumper->Assemble(pbPacket, pbPacketEnd);
if (!pbNext) {
goto as_failure;
}
ASSERT((pbPacketOld <= pbNext) && (pbNext <= pbPacketEnd));
break;
}
default:
TRACE("Invalid vAssemble Char %c\n", (char)b);
ASSERT(FALSE);
as_failure:
DropSOC();
return NULL;
}
pbPacket = pbNext;
}
Prepare(pbPacket - pbPacketOld);
return pbPacket;
#undef PACKET_DUMP_CHECK_ASSEMBLE
}
BYTE* CPacket::DisassembleParamsAndTextFmt(CSOCConnect& SOC, WORD wFmt, const char* pcszParamType, WORD& wTX)
{
const CTEXTFmt& Fmt = SOC.GetTEXTFmt(wFmt);
BYTE* pbPacket = GetLastPtr();
if (&Fmt) {
wTX = Fmt.m_DW.m_wTX;
UFmtParam aFPs[STRF_MAX_PARAMS];
#if STRF_MAX_PARAMS==3
if (SOC.Disassemble(pcszParamType, &aFPs[0], &aFPs[1], &aFPs[2]))
#elif STRF_MAX_PARAMS==7
if (SOC.Disassemble(pcszParamType, &aFPs[0], &aFPs[1], &aFPs[2], &aFPs[3], &aFPs[4], &aFPs[5], &aFPs[6]))
#else // error
#error STRF_MAX_PARAMS size must be 3 or 7...
#endif
{
if (DoTextFmt(Fmt, aFPs, pcszParamType)) {
return pbPacket;
}
}
} else {
wTX = TX_UNKNOWN;
BYTE* pbPacketEnd = GetEndPtr();
char szBuf[36];
int nLen = sprintf(szBuf, "TEXTFmt Missing: %d", (int)wFmt) + 1;
if (nLen <= (pbPacketEnd - pbPacket)) {
Prepare(nLen);
return pbPacket;
} else {
DropSOC();
}
}
return NULL;
}
void CPacket::DropSOC()
{
CSOC& SOC = GetSOC();
if (&SOC) {
SOC.Drop();
}
}
BYTE* CPacket::DoTextFmt(const char* pcszFormat, const UFmtParam aFPs[STRF_MAX_PARAMS], const char caParamType[/*STRF_MAX_PARAMS + 1*/])
{
#ifdef NO_PDCA
#define PACKET_DUMP_CHECK_ASSEMBLE(SizeInBYTE) pbNext = &pbPacket[SizeInBYTE];
#else // !NO_PDCA
#define PACKET_DUMP_CHECK_ASSEMBLE(SizeInBYTE) if ((pbNext = &pbPacket[SizeInBYTE]) > pbPacketEnd) { TRACE("Buffer boundary failure... in DoTextFmt() %d\n", __LINE__); goto as_failure; }
#endif // NO_PDCA
BYTE* pbPacket = GetLastPtr();
BYTE* pbPacketEnd = GetEndPtr();
BYTE* pbNext;
BYTE b;
BYTE* pbPacketOld = pbPacket;
WORD wParams = strlen(&caParamType[0]);
char szBuf[36];
char* pszEnd;
int nLen;
const UFmtParam* pFP = NULL;
while((b = *pcszFormat++) != '\0') {
if (b == '%') {
b = *pcszFormat++;
if (('0' <= b) && (b < ('0' + wParams))) {
b -= '0';
pFP = &aFPs[b];
switch(caParamType[b]) {
case 'b':
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(BYTE));
*pbPacket = pFP->m_c; // char...
break;
case 'B':
nLen = sprintf(szBuf, "%u", (int)pFP->m_b);
check_szBuf:
PACKET_DUMP_CHECK_ASSEMBLE(nLen);
if (nLen > 0) {
memcpy(pbPacket, &szBuf[0], nLen);
}
break;
case 'w':
nLen = sprintf(szBuf, "%d", (int)pFP->m_w);
goto check_szBuf;
case 'W':
nLen = sprintf(szBuf, "%d", (int)pFP->m_s);
goto check_szBuf;
case 'n':
nLen = sprintf(szBuf, "%d", pFP->m_n);
goto check_szBuf;
case 'd':
nLen = sprintf(szBuf, "%ld", pFP->m_l);
goto check_szBuf;
case 'D':
nLen = sprintf(szBuf, "%lu", pFP->m_dw);
goto check_szBuf;
case 'f':
nLen = sprintf(szBuf, "%f", pFP->m_f);
goto check_szBuf;
case 'F':
nLen = sprintf(szBuf, "%lf", pFP->m_F);
goto check_szBuf;
case '6':
nLen = sprintf(szBuf, "%I64", pFP->m_i64);
goto check_szBuf;
case 's':
case 'S':
nLen = strlen(pFP->m_psz);
PACKET_DUMP_CHECK_ASSEMBLE(nLen);
if (nLen > 0) {
memcpy(pbPacket, pFP->m_psz, nLen);
}
break;
default:
TRACE("Invalid DoTextFmt Char %c\n", (char)b);
ASSERT(FALSE);
as_failure:
DropSOC();
return NULL;
}
} else {
if (b != '%') {
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(BYTE) * 2);
pbPacket[0] = '%';
pbPacket[1] = b;
} else {
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(BYTE));
pbPacket[0] = '%';
}
}
} else {
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(BYTE));
pbPacket[0] = b;
}
pbPacket = pbNext;
}
PACKET_DUMP_CHECK_ASSEMBLE(sizeof(BYTE));
*pbPacket++ = '\0';
Prepare(pbPacket - pbPacketOld);
return pbPacket;
#undef PACKET_DUMP_CHECK_ASSEMBLE
}
CSockAddr::CSockAddr(int nPort, const char* pcszAddr/* = NULL*/, short sFamily/* = AF_INET*/)
{
SetTarget(pcszAddr);
SetPort(nPort);
sin_family = sFamily;
memset(&sin_zero[0], 0, sizeof(sin_zero));
}
CSockAddr::CSockAddr(int nPort, u_long ulAddr/* = INADDR_ANY*/, short sFamily/* = AF_INET*/)
{
SetTarget(ulAddr);
SetPort(nPort);
sin_family = sFamily;
memset(&sin_zero[0], 0, sizeof(sin_zero));
}
const char* CSockAddr::GetTarget() const
{
return m_strTarget;
}
void CSockAddr::SetTarget(const char* pcszAddr)
{
if (pcszAddr) {
sin_addr.s_addr = inet_addr(pcszAddr);
if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0̱ HOST/Network Addr
hostent* pHN = gethostbyname(pcszAddr);
if (pHN) {
sin_addr.s_addr = *(u_long*)pHN->h_addr;
}
}
} else {
sin_addr.s_addr = INADDR_ANY;
}
m_strTarget = pcszAddr;
}
void CSockAddr::SetTarget(u_long ulAddr)
{
#if 1 // def WIN32
sin_addr.s_addr = htonl(ulAddr);
#else // !WIN32
sin_addr = inet_makeaddr(ulAddr, 0);
#endif // WIN32
m_strTarget = inet_ntoa(sin_addr);
}
int CSockAddr::GetPort() const
{
return ntohs(sin_port);
}
void CSockAddr::SetPort(int nPort)
{
sin_port = htons((short)nPort);
}
const char* GetHostAddress()
{
char hostname[256];
if (gethostname(hostname, sizeof(hostname)) == 0) {
struct in_addr in;
in.s_addr = inet_addr(hostname);
if (in.s_addr == INADDR_NONE) {
struct hostent* hp;
hp = gethostbyname(hostname);
if (hp) {
struct in_addr** bptr;
bptr = (struct in_addr**)hp->h_addr_list;
if (bptr && *bptr) {
in = **bptr;
}
}
}
if (in.s_addr != INADDR_NONE) {
return inet_ntoa(in);
}
}
return "127.0.0.1";
}
PF_PacketProcessor _SPacketMap::TraceAndModifyBaseCall(BYTE bCmd, PF_PacketProcessor& refPFPP) const
{
ASSERT(this);
ASSERT(&refPFPP);
ASSERT(refPFPP == PFPP_CallBase);
register _SPacketMap* pBaseMap = m_pBaseMap;
if (pBaseMap) {
ASSERT(pBaseMap->m_pPFPP);
PF_PacketProcessor& refPFPP2 = pBaseMap->m_pPFPP[bCmd];
PF_PacketProcessor PFPP = refPFPP2;
if (PFPP == PFPP_CallBase) {
PFPP = pBaseMap->TraceAndModifyBaseCall(bCmd, refPFPP2);
ASSERT(PFPP != PFPP_CallBase);
}
refPFPP = PFPP;
return PFPP;
} else {
refPFPP = &PFPP_Ignore;
return &PFPP_Ignore;
}
}
CFileTransfer::CFileTransfer(DWORD dwFTID, DWORD dwGUARD, const char* pcszFileNameRemote, const char* pcszFileNameLocal)
: m_dwFTID(dwFTID), m_dwGUARD(dwGUARD), m_strFileNameRemote(pcszFileNameRemote), m_strFileNameLocal(pcszFileNameLocal)
{
if (dwFTID == 0) {
m_dwFTID = (long)this;
m_bClientSite = FALSE;
} else {
m_bClientSite = TRUE;
}
m_dwTime = (DWORD)-1;
m_lSize = (DWORD)-1;
m_uMinBPS = 0;
m_uMaxBPS = (DWORD)-1;
m_nFile = -1;
m_lPos = 0;
m_dwStartTime = 0;
}
CFileTransfer::~CFileTransfer()
{
Close();
}
BOOL CFileTransfer::Setup(DWORD& dwError)
{
ASSERT(!m_bClientSite);
ASSERT((m_dwTime == (DWORD)-1) && (m_lSize == (DWORD)-1) && (m_nFile == -1));
int nFile = _open(m_strFileNameLocal, _O_RDONLY | _O_BINARY);
if (nFile != -1) {
struct _stat st;
if (_fstat(nFile, &st) == 0) {
m_dwTime = st.st_mtime;
m_lSize = (long)st.st_size;
m_nFile = nFile;
return TRUE;
} else {
_close(nFile);
nFile = -1;
dwError = (DWORD)-2;
}
} else {
dwError = (DWORD)-1;
}
return FALSE;
}
BOOL CFileTransfer::Setup(DWORD dwTime, long lSize, DWORD& dwError)
{
ASSERT(m_bClientSite);
ASSERT((m_dwTime == (DWORD)-1) && (m_lSize == (DWORD)-1) && (m_nFile == -1));
m_nFile = _open(m_strFileNameLocal, _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC);
if (m_nFile != -1) {
m_dwTime = dwTime;
m_lSize = lSize;
return TRUE;
} else {
dwError = (DWORD)-1;
return FALSE;
}
}
int CFileTransfer::CheckReadPosition(long lPosition) const
{
ASSERT((lPosition >= 0) && this && !m_bClientSite);
if (lPosition == m_lPos) {
if (lPosition == m_lSize) {
return 0; // end of file...
} else {
return +1; // more data to read.
}
} else {
return -1; // error
}
}
int CFileTransfer::Close()
{
int nFile = m_nFile;
if (nFile != -1) {
m_nFile = -1;
if (_close(nFile) != 0) {
nFile = -2;
}
}
return nFile;
}
void CFileTransfer::Start()
{
if (!m_dwStartTime) {
m_dwStartTime = GetTickCount();
}
}
CFTPArray::CFTPArray()
{
SetGrowBy(20);
}
CFTPArray::~CFTPArray()
{
}
int CFTPArray::Find(CFileTransfer* pFTP) const
{
int i, Size = GetSize();
for(i = 0; i < Size; i++) {
if (At(i) == pFTP)
return i;
}
return -1;
}
CFileTransfer* CFTPArray::CutIfExist(CFileTransfer* pFTP)
{
int nIndex = Find(pFTP);
if (nIndex != -1) {
Del(nIndex);
return pFTP;
}
return NULL;
}
#ifdef USE_OVRIO
COVRIO::COVRIO()
{
m_pSOC = NULL;
m_nSize = 0;
//m_ba[/*m_nSize*/];
}
COVRIO::~COVRIO()
{
}
void CALLBACK OVRIO_Completion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
COVRIO* pOVRIO = (COVRIO*)lpOverlapped;
if (pOVRIO) {
(pOVRIO->m_pSOC)->OnOVRIO_Completion(dwError, cbTransferred, pOVRIO, dwFlags);
}
}
#endif // USE_OVRIO
CSOC::CSOC()
: m_Addr(0, (u_long)0)
{
m_nLockCount = 0;
m_hSocket = INVALID_SOCKET;
m_nState = 0;
m_bSendLoop = TRUE;
m_pSOCManager = NULL;
/*
m_DW.m_xAdded = FALSE;
*/
m_dwKASndTicks = m_dwKARcvTicks = 0;
m_dwKARcvTimeOut = 0;
#ifdef WIN32
m_hWndOwner = NULL;
#endif // WIN32
m_ppSOC = NULL;
m_ID.m_uID = CSOC_SERVER_ID;
m_dwDroppingTicks = 0;
#ifdef USE_OVRIO
m_pOVRIOStart = NULL;
#endif // USE_OVRIO
// ...
m_dwVarFlags = 0;
m_DW.m_xAutoDelete = 1;
}
CSOC::~CSOC()
{
Reset();
}
void CSOC::Reset()
{
DoClose();
if (m_ppSOC) {
ASSERT((*m_ppSOC == this) || (*m_ppSOC == NULL));
*m_ppSOC = NULL;
}
#ifdef USE_OVRIO
ASSERT(!m_pOVRIOStart);
m_pOVRIOStart = NULL;
#endif // USE_OVRIO
m_dwKASndTicks = m_dwKARcvTicks = 0;
m_dwDroppingTicks = 0;
m_DW.m_xAdded = FALSE;
m_DW.m_xIsConnected = FALSE;
m_DW.m_xIsConnecting = FALSE;
m_DW.m_xDoDelSocket = FALSE;
m_DW.m_xIsDropping = FALSE;
m_DW.m_xIsSetupFailure = FALSE;
m_DW.m_xGracefulLocal = FALSE;
m_DW.m_xErrSEND = FALSE;
m_DW.m_xErrRECEIVE = FALSE;
m_DW.m_xGracefulRemote = FALSE;
m_DW.m_xAbortyLocal = FALSE;
m_DW.m_xAbortyRemote = FALSE;
m_DW.m_xLoginStarted = FALSE;
m_DW.m_xLoginOK = FALSE;
}
int CSOC::GetSignatureFromPort(int nPort) const
{
return nPort ^ 0x5a5a5a5a;
}
int CSOC::GetConnectionState() const
{
if (IsValidSafe()) {
if (IsDroppingState())
return -1;
else if (IsConnecting())
return -2;
else if (IsConnected())
return +1;
else {
// Time Out?
return -3; // intermediate state
}
}
return 0;
}
void CSOC::Drop()
{
//fprintf(stderr, "CSDOC::Drop()\n");
m_pSOCManager->OnDrop(this);
}
BOOL CSOC::DoSend(const BYTE* pbBuf, int nSize)
{
ASSERT(pbBuf && (nSize > 0));
ASSERT(!m_DW.m_xIsConnecting);
ASSERT(!IsListenSocket());
if (nSize <= MAX_PACKET) {
if (IsSendPossible()) {
#ifdef USE_OVRIO
int nRet;
/*nRet = send(m_hSocket, (const char*)pbBuf, nSize, 0);
if (nRet != SOCKET_ERROR) {
ASSERT(nRet >= 0);
pbBuf = &pbBuf[nRet];
nSize -= nRet;
} else {
// error
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
DoErrorReport(nErr, TRUE);
}*/
if (!IsDroppingState()) {
if (nSize > 0) {
COVRIO* pOVRIO = newCOVRIO(pbBuf, nSize);
if (pOVRIO) {
DWORD dwSent;
WSABUF wsabuf = { nSize, (char*)&pOVRIO->m_ba[0] };
do {
while((nRet = WSASend(m_hSocket, &wsabuf, 1, &dwSent, 0, pOVRIO, OVRIO_Completion)) == 0) {
nSize -= dwSent;
wsabuf.buf += dwSent;
wsabuf.len = nSize;
pOVRIO->m_nSize = nSize;
if (nSize <= 0) {
//OnOVRIO_Completion(0, dwSent, pOVRIO, 0);
return TRUE;
}
}
ASSERT(nRet == SOCKET_ERROR);
} while(((nRet = WSAGetLastError()) == WSAEWOULDBLOCK) || (nRet == WSAEINPROGRESS));
if (nRet == WSA_IO_PENDING) {
return TRUE;
} else {
DoErrorReport(nRet, TRUE);
}
} else {
Drop();
}
} else {
ASSERT(nSize == 0);
return TRUE;
}
}
return FALSE;
#else // !USE_OVRIO
int nMax = m_aSnd.GetMax();
BYTE* pDest;
if ((pDest = m_aSnd.Prepare(nSize)) == NULL) {
int nRetry = 0;
DWORD dwTimeBegin = GetTickCount();
do {
if (m_bSendLoop) {
DWORD dwSendTimeOut = GetSendTimeOut();
DWORD dwTime = dwTimeBegin + dwSendTimeOut;
int nFSOrg = m_aSnd.GetFreeSize();
while(nFSOrg < nSize) {
int nDS = OnSend();
if (IsDroppingState())
return FALSE;
int nFS = nMax - nDS;
DWORD dw = GetTickCount();
if (nFSOrg != nFS) {
dwTime = dw + dwSendTimeOut;
nFSOrg = nFS;
}
if (dwTime <= dw) {
goto noSendLoop;
}
}
} else {
noSendLoop:
if (!OnOverflow(nSize, nRetry, dwTimeBegin)) {
TRACE("SendBuffer overflow %d > %d\n", nSize, m_aSnd.GetFreeSize());
if (!IsDroppingState())
DoExceptions(EEXCP_SendBufferOverflow, TRUE);
return FALSE;
}
}
nRetry++;
} while((pDest = m_aSnd.Prepare(nSize)) == NULL);
}
ASSERT(pDest);
memcpy(pDest, pbBuf, nSize);
return TRUE;
#endif // USE_OVRIO
}
} else {
ASSERT(FALSE);
TRACE("Too large packet to send %d > MAX_PACKET:%d\n", nSize, MAX_PACKET);
Drop();
}
return FALSE;
}
BOOL CSOC::DoSendCmdWOP(BYTE bCmd)
{
// WOP means With Out Param(s)
BYTE ba[sizeof(WORD) + 1/* bCmd */];
PutWORD(&ba[0], 1);
ba[sizeof(WORD)] = bCmd;
return DoSend(&ba[0], sizeof(WORD) + 1/* bCmd */);
}
void CSOC::DoSendLoginOK()
{
if (!IsDroppingState()) {
DoSendX("BB", S_LOGN_RSLT, CSCODE_OK);
}
}
void CSOC::DoSendLoginError()
{
if (!IsDroppingState()) {
DoSendX("BB", S_LOGN_RSLT, CSCODE_ERR);
Drop();
}
}
void CSOC::DoSendLoginError(WORD wErrFMT)
{
if (!IsDroppingState()) {
DoSendX("BBW", S_LOGN_RSLT, CSCODE_ERR, wErrFMT);
Drop();
}
}
BOOL CSOC::DoSend(const CPacket& Packet)
{
ASSERT(&Packet.GetSOC() == this);
WORD wLen = Packet.GetLength();
BYTE* pw = (BYTE*)Packet.GetPacketStart();
PutWORD(pw, wLen);
BOOL bRet = DoSend(pw, wLen + sizeof(WORD));
*(WORD*)pw = wLen;
return bRet;
}
BOOL CSOC::DoSendX(BYTE bCmd, const void* pData, int nLen)
{
ASSERT(nLen > 0);
BYTE ba[MAX_PACKET];
PutWORD(&ba[0], (WORD)(nLen + 1));
ba[sizeof(WORD)] = bCmd;
memcpy(&ba[sizeof(WORD) + 1], pData, nLen);
return DoSend(&ba[0], nLen + 1);
}
BOOL __cdecl CSOC::DoSendX(const char *pcszFormat, ...)
{
va_list ap;
va_start(ap, pcszFormat);
CPacket Packet(this);
Packet.vAssemble(pcszFormat, ap);
va_end(ap);
return DoSend(Packet);
}
BOOL CSOC::DoSendText(BYTE bCmd, const char* pcsz)
{
return DoSendX(bCmd, pcsz, strlen(pcsz) + 1/* '\0' */);
}
BOOL CSOC::DoSendText(const char* pcszID, const char* pcsz, WORD wTX/* = TX_NORMAL*/)
{
return DoSendX("BWss", X_TEXT, wTX, pcszID, pcsz);
}
BOOL __cdecl CSOC::DoSendFmt(WORD wFmt, const char* pcszParamType/* = NULL*/, ...)
{
BOOL bRet;
va_list ap;
va_start(ap, pcszParamType);
bRet = vDoSendFmt(wFmt, pcszParamType, ap);
va_end(ap);
return bRet;
}
BOOL CSOC::vDoSendFmt(WORD wFmt, const char* pcszParamType, va_list ap)
{
if (!pcszParamType)
pcszParamType = "";
else {
ASSERT(strlen(pcszParamType) <= STRF_MAX_PARAMS );
}
CPacket Packet(this);
Packet.Assemble("BWs", X_TEXTFMT, wFmt, pcszParamType);
Packet.vAssemble(pcszParamType, ap);
return DoSend(Packet);
}
const CTEXTFmtArray& CSOC::GetTEXTFmtArray()
{
return *(const CTEXTFmtArray*)NULL;
}
const CTEXTFmt& CSOC::GetTEXTFmt(WORD wFmt)
{
const CTEXTFmtArray& TEXTFmtArray = GetTEXTFmtArray();
if (&TEXTFmtArray) {
return TEXTFmtArray.FindTEXTFmt(wFmt);
}
return *(const CTEXTFmt*)NULL;
}
BOOL CSOC::DoProcessPacket()
{
int nSize;
BYTE* pbHdr;
if ((nSize = m_aRcv.GetBegin(pbHdr)) > 0) {
if (nSize >= (sizeof(WORD) + sizeof(BYTE))) {
WORD wLenOrg = GetWORD(pbHdr);
WORD wLen = wLenOrg + sizeof(WORD);
if (wLen <= nSize) {
m_pbPacket = &pbHdr[sizeof(WORD)];
m_bCmd = *m_pbPacket++;
m_wLen = wLenOrg - 1;
//TRACE("bCmd: %d, wLen: %d\n", m_bCmd, wLenOrg);
DoPacketProcessing();
m_aRcv.RemoveBegin(wLen);
return TRUE;
} else {
}
} else {
}
}
return FALSE;
}
void CSOC::OnOpen()
{
}
BOOL CSOC::OnSetupSocket()
{
int err;
err = setsockopt(m_hSocket, SOL_SOCKET, SO_LINGER, (const char*)&g_opt_ling, sizeof(g_opt_ling));
if (err != SOCKET_ERROR) {
#ifdef WIN32
static u_long s_ulOPT = 1;
err = ioctl(m_hSocket, FIONBIO, &s_ulOPT);
if (err == 0) { // don't use SOCKET_ERROR
return TRUE;
}
#else // !WIN32
int flags = fcntl(m_hSocket, F_GETFL);
flags |= O_NONBLOCK;
err = fcntl(m_hSocket, F_SETFL, flags);
if (err != -1) { // don't use SOCKET_ERROR
return TRUE;
}
#endif /* WIN32 */
}
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
DoErrorReport(nErr);
return FALSE;
}
void CSOC::OnAddSocket()
{
}
void CSOC::OnDropping()
{
}
void CSOC::OnDelSocket()
{
}
void CSOC::OnShutdown()
{
}
void CSOC::OnClose()
{
}
void CSOC::OnDelete()
{
}
void CSOC::OnSendKeepAlive()
{
DoSendCmdWOP(X_KEEPALIVE);
}
#if !defined(USE_OVRIO)
BOOL CSOC::OnOverflow(int nSizeReq, int nRetry, DWORD dwTimeBegin)
{
return FALSE;
}
#endif // !defined(USE_OVRIO)
void CSOC::OnIgnore()
{
TRACE("Ignored Packet - Check!!!: %d, wLen: %d\n", (int)m_bCmd, (int)m_wLen);
}
void CSOC::OnKeepAlive()
{
ResetKeepAliveRcv();
}
#ifdef USE_OVRIO
COVRIO* CSOC::newCOVRIO(const BYTE* pb, int nSize)
{
COVRIO* pOVRIO = (COVRIO*)malloc(sizeof(COVRIO) + nSize);
if (pOVRIO) {
pOVRIO->newCOVRIO();
WSAOVERLAPPED& OVRIO = *pOVRIO;
memset(&OVRIO, 0, sizeof(WSAOVERLAPPED));
pOVRIO->m_pSOC = this;
pOVRIO->m_nSize = nSize;
memcpy(&pOVRIO->m_ba[0], pb, nSize);
pOVRIO->AddTail(m_pOVRIOStart);
}
return pOVRIO;
}
void CSOC::deleteCOVRIO(COVRIO* pOVRIO)
{
if (pOVRIO) {
pOVRIO->CutCheck(m_pOVRIOStart);
pOVRIO->deleteCOVRIO();
free(pOVRIO);
}
}
void CSOC::OnOVRIO_Completion(DWORD dwError, DWORD cbTransferred, COVRIO* pOVRIO, DWORD dwFlags)
{
if (this) {
deleteCOVRIO(pOVRIO);
}
}
#endif // USE_OVRIO
int CSOC::aSnd_GetDataSize()
{
#ifdef USE_OVRIO
int nSize = 0;
COVRIO* pOVRIO = m_pOVRIOStart;
while(pOVRIO) {
nSize += pOVRIO->m_nSize;
pOVRIO = pOVRIO->m_pNext;
}
return nSize;
#else // !USE_OVRIO
return m_aSnd.GetDataSize();
#endif // USE_OVRIO
}
BOOL CSOC::DoClose()
{
if (m_hSocket != INVALID_SOCKET) {
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
#if defined(USE_OVRIO)
SleepEx(0, TRUE);
#endif // defined(USE_OVRIO)
return TRUE;
}
return FALSE;
}
void CSOC::CheckAutoDelete()
{
if (m_DW.m_xAutoDelete)
delete this;
else
Reset();
}
void CSOC::SetDroppingTicks()
{
m_dwDroppingTicks = GetTickCount();
}
BOOL CSOC::CreateAndAttach()
{
if (!IsValid()) {
SOCKET soc;
#ifdef USE_OVRIO
if (IsListenSocket()) {
soc = socket(AF_INET, SOCK_STREAM, 0);
} else {
soc = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
}
#else // !USE_OVRIO
soc = socket(AF_INET, SOCK_STREAM, 0);
#endif // USE_OVRIO
if (soc != INVALID_SOCKET) {
CallOnOpen(soc);
return TRUE;
} else {
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
DoErrorReport(nErr);
}
} else {
DoExceptions(EEXCP_DupCreation);
}
return FALSE;
}
void CSOC::CallOnOpen(SOCKET soc)
{
m_hSocket = soc;
OnOpen();
}
void CSOC::CallOnDropping()
{
m_DW.m_xIsDropping = TRUE;
if (IsListenSocket()) {
((CSOCListen*)this)->SetAllowAccept(FALSE);
}
OnDropping();
}
void CSOC::CallOnShutdown(int nHow)
{
if (!m_DW.m_xGracefulLocal) {
TRACE("m_DW.m_xGracefulLocal STARTED case NORMAL\n");
m_DW.m_xGracefulLocal = 1;
if (IsValid())
shutdown(*this, nHow);
m_DW.m_xErrSEND = TRUE;
OnShutdown();
}
}
void CSOC::CallOnClose()
{
if (!(GetType3() & SOCNEXT_EXCLISTEN)) {
((CSOCConnect*)this)->DoFTPCloseAllAsError();
}
if (DoClose()) {
OnClose();
}
}
void CSOC::CallOnDelete()
{
OnDelete();
CheckAutoDelete();
}
void CSOC::DoPacketProcessing()
{
_SPacketMap* pMap = GetPacketMap();
if (pMap) {
ASSERT(pMap->m_pPFPP);
PF_PacketProcessor& refPFPP = pMap->m_pPFPP[m_bCmd];
PF_PacketProcessor PFPP = refPFPP;
if (PFPP == PFPP_CallBase) {
PFPP = pMap->TraceAndModifyBaseCall(m_bCmd, refPFPP);
ASSERT(PFPP != PFPP_CallBase);
}
(this->*PFPP)();
} else {
TRACE("No PacketMap - Check!!!: %x\n", this);
// do nothing...
}
}
BOOL CSOC::OnReceive()
{
BOOL bPossible;
Lock();
bPossible = IsReceivePossible();
if (bPossible) {
BYTE baBuf[MAX_PACKET];
int nRet;
int nTotalRead = 0;
while((nRet = DoReceive(baBuf, sizeof(baBuf))) > 0) {
nTotalRead += nRet;
break;
}
if (nTotalRead > 0) {
ResetKeepAliveRcv();
}
}
while(DoProcessPacket())
;
if (!bPossible) {
m_aRcv.FreeAll();
TRACE("OnReceive is not possible\n");
Drop();
}
Unlock();
return bPossible;
}
int CSOC::DoReceive(BYTE* pbBuf, int nLen)
{
int nSize = m_aRcv.GetFreeSize();
if (nSize <= 0) {
// buffer overflow...
return 0;
}
if (nSize < nLen) {
nLen = nSize;
}
nLen = recv(m_hSocket, (char*)pbBuf, nLen, 0);
if (nLen != SOCKET_ERROR) {
if (m_DW.m_xIsConnecting) {
TRACE("Connecting From DoReceive: %x\n", this);
((CSOCServer*)this)->CallOnConnect();
}
if (nLen > 0) {
BYTE* pDest = m_aRcv.Prepare(nLen);
//ASSERT(pDest);
memcpy(pDest, pbBuf, nLen);
} else if (nLen == 0) {
m_DW.m_xGracefulRemote = 1;
}
} else {
// error
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS)
#if !defined(WIN32)
&& (nErr != EAGAIN)
#endif // !defined(WIN32)
)
DoErrorReport(nErr);
nLen = 0;
}
return nLen;
}
int CSOC::OnSend()
{
if (IsSendPossible()) {
#ifdef USE_OVRIO
return aSnd_GetDataSize();
#else // !USE_OVRIO
BYTE* pbBuf;
int nSize, nRet;
if ((nSize = m_aSnd.GetBegin(pbBuf)) > 0) {
const BYTE* pbBufOrg = pbBuf;
while(nSize > 0) {
nRet = send(m_hSocket, (const char*)pbBuf, nSize, 0);
if (nRet != SOCKET_ERROR) {
if (nRet <= 0)
break;
ASSERT(!m_DW.m_xIsConnecting);
m_aSnd.RemoveBegin(nRet);
pbBuf += nRet;
nSize -= nRet;
} else {
// error
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
DoErrorReport(nErr, TRUE);
break;
}
}
if (pbBufOrg != pbBuf) {
ResetKeepAliveSnd();
}
}
return nSize;
#endif // USE_OVRIO
} else {
#if !defined(USE_OVRIO)
m_aSnd.FreeAll();
#endif // !defined(USE_OVRIO)
TRACE("Send is not possible\n");
Drop();
return aSnd_GetDataSize();
}
}
void CSOC::SendKeepAlive()
{
if (!IsConnecting()) {
if (aSnd_GetDataSize() == 0) {
OnSendKeepAlive();
}
}
}
void CSOC::ResetKeepAliveAll()
{
ResetKeepAliveRcv();
ResetKeepAliveSnd();
}
void CSOC::ResetKeepAliveRcv()
{
m_dwKARcvTicks = GetTickCount();
}
void CSOC::ResetKeepAliveSnd()
{
m_dwKASndTicks = GetTickCount();
}
EException CSOC::GetExceptionCode(int nErrorCode)
{
EException eException;
switch(nErrorCode) {
case WSAENETDOWN: // network subsystem failure...
eException = EEXCP_WSAENETDOWN;
break;
case WSANO_RECOVERY:
eException = EEXCP_WSANO_RECOVERY;
break;
case WSAENETRESET: // connection broken due to keep alive...
eException = EEXCP_WSAENETRESET;
goto go_AbortyRemote;
case WSAECONNRESET: // socket reset... by remote side or hardware failure
eException = EEXCP_WSAECONNRESET;
goto go_AbortyRemote;
case WSAECONNABORTED: // The virtual circuit was terminated due to a time-out or other failure.
eException = EEXCP_WSAECONNABORTED;
go_AbortyRemote:
if (this) {
m_DW.m_xAbortyRemote = 1;
TRACE("m_DW.m_xAbortyRemote Started...\n");
}
break;
case WSAEADDRINUSE:
eException = EEXCP_WSAEADDRINUSE;
break;
case WSAETIMEDOUT: // connection failure due to time out or ...
eException = EEXCP_WSAETIMEDOUT;
break;
case WSAEHOSTUNREACH:
eException = EEXCP_WSAEHOSTUNREACH;
break;
case WSAEACCES: // broadcast address... - sendto...
eException = EEXCP_WSAEACCES;
break;
case WSANOTINITIALISED:
eException = EEXCP_WSANOTINITIALISED;
break;
case WSAEFAULT: // internal error...
eException = EEXCP_WSAEFAULT;
break;
case WSAENOTSOCK: // internal error...
eException = EEXCP_WSAENOTSOCK;
break;
case WSAENOTCONN:
if (this && IsConnecting()) {
eException = EEXCP_NoError;
} else {
eException = EEXCP_WSAENOTCONN;
}
break;
case WSAEOPNOTSUPP:
eException = EEXCP_WSAEOPNOTSUPP;
break;
case WSAEINVAL:
eException = EEXCP_WSAEINVAL;
break;
case WSAESHUTDOWN: // may be internal error...
#ifdef _DEBUG
if (this) {
TRACE("m_DW.m_xGracefulLocal STARTED case ABONORMAL\n");
}
#endif // _DEBUG
eException = EEXCP_NoError;
break;
case WSAEDISCON:
if (this) {
m_DW.m_xGracefulRemote = 1;
TRACE("m_DW.m_xGracefulRemote STARTED\n");
}
eException = EEXCP_NoError;
break;
default:
//case WSAEINTR: // blocking call canceled...
//case WSAEINPROGRESS:
//case WSAEWOULDBLOCK: // would block...
//case WSAEMSGSIZE: // too large message, UDP?
//case WSAENOBUFS: // No buffer space is available - sending...
eException = EEXCP_NoError;
break;
}
return eException;
}
EException CSOC::DoErrorReport(int nErrorCode, BOOL bDropIfErrorOccur/* = FALSE*/)
{
return DoExceptions(GetExceptionCode(nErrorCode), bDropIfErrorOccur);
}
EException CSOC::DoExceptions(EException eException, BOOL bDropIfErrorOccur/* = FALSE*/)
{
return m_pSOCManager->OnExceptions(this, eException, bDropIfErrorOccur);
}
CSOCListen::CSOCListen(int nPort/* = 0*/, DWORD dwListenTime/* = 500*/)
{
m_DW.m_xAllowAccept = TRUE;
m_ID.m_nID = CSOC_LISTEN_ID;
m_pfnCSC = NULL;
m_dwCSCParam1 = 0;
m_dwCSCParam2 = 0;
SetPort(nPort);
m_dwListenTime = dwListenTime;
m_dwLastCheck = 0;
}
CSOCListen::~CSOCListen()
{
}
void CSOCListen::GetCSCParam(PFN_CreateSOCClient& pfnCSC, DWORD& dwCSCParam1, DWORD& dwCSCParam2) const
{
if (&pfnCSC)
pfnCSC = m_pfnCSC;
if (&dwCSCParam1)
dwCSCParam1 = m_dwCSCParam1;
if (&dwCSCParam2)
dwCSCParam2 = m_dwCSCParam2;
}
void CSOCListen::SetCSCParam(PFN_CreateSOCClient pfnCSC, DWORD dwCSCParam1, DWORD dwCSCParam2)
{
m_pfnCSC = pfnCSC;
m_dwCSCParam1 = dwCSCParam1;
m_dwCSCParam2 = dwCSCParam2;
}
BOOL CSOCListen::BindAndListenSocket()
{
if (bind(m_hSocket, (const struct sockaddr*)&m_Addr, sizeof(sockaddr_in)) != SOCKET_ERROR) {
if (listen(m_hSocket, SOMAXCONN) != SOCKET_ERROR) { // SOMAXCONN <- 5?
return TRUE;
}
}
// bind or listen error...
DoErrorReport(WSAGetLastError());
return FALSE;
}
void CSOCListen::OnAcception()
{
//TRACE("Accepting: %x\n", this);
sockaddr_in Addr;
socklen_t nLen = sizeof(sockaddr_in);
#ifdef USE_OVRIO
SOCKET soc = WSAAccept(m_hSocket, (struct sockaddr*)&Addr, &nLen, NULL, NULL);
#else // !USE_OVRIO
SOCKET soc = accept(m_hSocket, (struct sockaddr*)&Addr, &nLen);
#endif // USE_OVRIO
if (soc != INVALID_SOCKET) {
TRACE("acceptting from %s:%d", inet_ntoa(Addr.sin_addr), GetPort());
CSOCClient* pSOC;
if (m_DW.m_xAllowAccept && OnAddrAcceptionCheck(Addr) && ((pSOC = OnNewClientSocket()) != NULL)) {
*pSOC->GetSockAddr().GetSockAddrIn() = Addr;
pSOC->CallOnOpen(soc);
if (pSOC->OnSetupSocket()) {
if (m_pSOCManager->AddSocket(*pSOC)) {
pSOC->CallOnAccept();
return;
} else {
// too many users
pSOC->DoSendFmt(ESTRF_TOOMANY_CONNECTIONS);
}
}
TRACE("OnSetupSocket failure\n");
pSOC->Drop();
} else {
TRACE("Refusing or SOCKET Creation Failure: %x\n", this);
shutdown(soc, SD_BOTH);
closesocket(soc);
}
} else {
// error.
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
DoErrorReport(nErr, TRUE);
}
}
CSOCClient* CSOCListen::OnNewClientSocket() const
{
if (m_pfnCSC) {
return (*m_pfnCSC)(*this, m_dwCSCParam1, m_dwCSCParam2);
} else {
ASSERT(m_pSOCManager);
return m_pSOCManager->OnNewClientSocket(*this, m_dwCSCParam1, m_dwCSCParam2);
}
}
CSOCConnect::CSOCConnect(DWORD dwLingerTime)
{
m_tConnection = 0;
SetLingerTime(dwLingerTime);
m_pFTPStart = NULL;
}
CSOCConnect::~CSOCConnect()
{
ASSERT(m_pFTPStart == NULL);
}
void CSOCConnect::SetConnectionTime()
{
m_tConnection = time(NULL);
}
DWORD CSOCConnect::GetConnectionTicks() const
{
if (GetConnectionState() == +1) {
return (DWORD)(difftime(time(NULL), m_tConnection) * 1000);
} else {
return (DWORD)-1;
}
}
DWORD CSOCConnect::GetConnectionTimeString(CStr& strTime, BOOL bForceShowMin/* = FALSE*/, BOOL bForceShowHour/* = FALSE*/) const
{
DWORD dwTicks = GetConnectionTicks();
if (dwTicks != (DWORD)-1) {
DWORD dw = dwTicks / 1000;
int nSec = (int)(dw % 60);
int nMin = (int)(dw / 60);
nMin %= 60;
int nHour = (int)(dw / (60 * 60));
if (bForceShowHour || (nHour > 0)) {
strTime.Format("%d:%02d:%02d", nHour, nMin, nSec);
} else if (bForceShowMin || (nMin > 0)) {
strTime.Format("%02d:%02d", nMin, nSec);
} else {
strTime.Format("%02d", nSec);
}
} else {
strTime = NULL;
}
return dwTicks;
}
void CSOCConnect::DoTextDisplay(const char* pcszID, const char* pcszMsg, WORD wTX)
{
TRACE("Do! Implement DoTextDisplay, ID:%s, MSG:%s\n", pcszID, pcszMsg);
}
void CSOCConnect::OnText()
{
char* pszID;
char* pcszMsg;
WORD wTX;
if (Disassemble("Wss", &wTX, &pszID, &pcszMsg)) {
DoTextDisplay(pszID, pcszMsg, wTX);
}
}
void CSOCConnect::OnTextFmt()
{
WORD wFmt;
const char* pcszParamType;
if (Disassemble("Ws", &wFmt, &pcszParamType)) {
WORD wTX;
CPacket Packet(this);
BYTE* pbText = Packet.DisassembleParamsAndTextFmt(*this, wFmt, pcszParamType, wTX);
if (pbText) {
DoTextDisplay(SERVERID, (const char*)pbText, wTX);
}
}
}
void CSOCConnect::OnFTP()
{
ASSERT((m_bCmd == C_FTP) || (m_bCmd == S_FTP));
BOOL bClientSite = (m_bCmd == S_FTP);
DWORD dwFTID;
long lCode;
if (Disassemble("DD", &dwFTID, &lCode)) {
CFileTransfer* pFTP = NULL;
DWORD dwError;
if (dwFTID == 0) {
// filename & info negociation
const char* pcszFileNameRemote;
if (Disassemble("s", &pcszFileNameRemote)) {
if (bClientSite) {
// server response: file info
if (Disassemble("D", &dwFTID)) {
if (dwFTID == 0) {
if (Disassemble("D", &dwError)) {
OnFTPSrvrError((DWORD)lCode, pcszFileNameRemote, dwError);
}
} else {
DWORD dwTime;
long lSize;
if (Disassemble("DD", &dwTime, &lSize)) {
pFTP = OnAllocFileTransfer(dwFTID, (DWORD)lCode, pcszFileNameRemote, dwTime, lSize, dwError);
if (pFTP) {
DoSendX("BDD", C_FTP, dwFTID, 0);
pFTP->AddTail(m_pFTPStart);
} else {
DoSendX("BDD", C_FTP, dwFTID, -1);
}
}
}
}
} else {
// client request file info...
pFTP = OnAllocFileTransfer((DWORD)lCode, pcszFileNameRemote, dwError);
if (pFTP) {
OnFTPFileInfoNotify(pFTP);
pFTP->AddTail(m_pFTPStart);
} else {
DoSendX("BDDsD", S_FTP, (DWORD)lCode, pcszFileNameRemote, 0, dwError);
}
}
}
} else {
if ((pFTP = FindFTP(dwFTID)) == NULL) {
OnFTPNotFound(dwFTID, bClientSite);
} else {
if (lCode < 0) { // error code...
OnFTPError(pFTP, lCode);
} else {
pFTP->Start();
if (bClientSite)
OnFTPRead(pFTP, lCode);
else
OnFTPWrite(pFTP, lCode);
}
}
}
}
}
BOOL CSOCConnect::DoFileTransfer(DWORD dwGUARD, const char* pcszFileNameRemote)
{
DoSendX("BDDs", C_FTP, 0, dwGUARD, pcszFileNameRemote);
return TRUE;
}
CFileTransfer* CSOCConnect::FindFTP(DWORD dwFTID) const
{
CFileTransfer* pFTP = m_pFTPStart;
while(pFTP) {
if (pFTP->m_dwFTID == dwFTID)
break;
pFTP = pFTP->m_pNext;
}
return pFTP;
}
CFileTransfer* CSOCConnect::FindFTP(const char* pcszFileNameRemote) const
{
CFileTransfer* pFTP = m_pFTPStart;
while(pFTP) {
if (strcmp(pFTP->m_strFileNameRemote, pcszFileNameRemote) == 0)
break;
pFTP = pFTP->m_pNext;
}
return pFTP;
}
void CSOCConnect::DoFTPCloseAllAsError()
{
CFileTransfer* pFTP;
while((pFTP = CFileTransfer::CutHead(m_pFTPStart)) != NULL) {
OnFreeFileTransfer(pFTP);
}
}
void CSOCConnect::OnFTPFileInfoNotify(CFileTransfer* pFTP)
{
DoSendX("BDDsDD", S_FTP, 0, pFTP->m_dwGUARD, pFTP->m_strFileNameRemote.String(), pFTP->m_dwFTID, pFTP->m_dwTime, pFTP->m_lSize);
}
void CSOCConnect::OnFTPError(CFileTransfer* pFTP, long lErrorCode)
{
pFTP->Cut(m_pFTPStart);
OnFreeFileTransfer(pFTP);
}
const char* CSOCConnect::OnFTPDirectory(BOOL bClientSite) const
{
return "";
}
const char* CSOCConnect::OnFTPFileNameValidation(const char* pcszFileName) const
{
return pcszFileName;
}
void CSOCConnect::OnFTPFileMap(DWORD dwGUARD, const char* pcszFileNameRemote, CStr& strFileNameLocal, BOOL bClientSite) const
{
const char* pcsz1;
const char* pcsz2;
const char* pcszName;
pcsz1 = strrchr(pcszFileNameRemote, '/');
pcsz2 = strrchr(pcszFileNameRemote, '\\');
if (pcsz1) {
if (pcsz2) {
pcszName = pcsz1 > pcsz2 ? pcsz1: pcsz2;
pcszName++;
} else {
pcszName = &pcsz1[1];
}
} else {
if (pcsz2) {
pcszName = &pcsz2[1];
} else {
pcszName = pcszFileNameRemote;
}
}
strFileNameLocal = OnFTPDirectory(bClientSite);
strFileNameLocal += OnFTPFileNameValidation(pcszName);
}
void CSOCConnect::OnFTPSrvrError(DWORD dwGUARD, const char* pcszFileNameRemote, DWORD dwError)
{
// dw1 >= 0 ? queued files or error...
}
void CSOCConnect::OnFTPNotFound(DWORD dwFTID, BOOL bClientSite)
{
DoSendX("BDD", bClientSite ? C_FTP: S_FTP, dwFTID, (DWORD)(-1)); // no such FTID...
}
CFileTransfer* CSOCConnect::OnAllocFileTransfer(DWORD dwGUARD, const char* pcszFileNameRemote, DWORD& dwError)
{
CStr strFileNameLocal;
OnFTPFileMap(dwGUARD, pcszFileNameRemote, strFileNameLocal, FALSE);
CFileTransfer* pFTP = OnNewFileTransfer(0, dwGUARD, pcszFileNameRemote, strFileNameLocal);
if (pFTP->Setup(dwError)) {
return pFTP;
} else {
OnFreeFileTransfer(pFTP);
return NULL;
}
}
CFileTransfer* CSOCConnect::OnAllocFileTransfer(DWORD dwFTID, DWORD dwGUARD, const char* pcszFileNameRemote, DWORD dwTime, long lSize, DWORD& dwError)
{
CStr strFileNameLocal;
OnFTPFileMap(dwGUARD, pcszFileNameRemote, strFileNameLocal, TRUE);
CFileTransfer* pFTP = OnNewFileTransfer(dwFTID, dwGUARD, pcszFileNameRemote, strFileNameLocal);
if (pFTP->Setup(dwTime, lSize, dwError)) {
return pFTP;
} else {
OnFreeFileTransfer(pFTP);
return NULL;
}
}
CFileTransfer* CSOCConnect::OnNewFileTransfer(DWORD dwFTID, DWORD dwGUARD, const char* pcszFileNameRemote, const char* pcszFileNameLocal)
{
return new CFileTransfer(dwFTID, dwGUARD, pcszFileNameRemote, pcszFileNameLocal);
}
void CSOCConnect::OnFreeFileTransfer(CFileTransfer* pFTP)
{
pFTP->Close();
delete pFTP;
}
void CSOCConnect::OnFTPRead(CFileTransfer* pFTP, long lSize)
{
ASSERT((lSize >= 0) && pFTP && pFTP->m_bClientSite);
if (lSize > 0) {
BYTE* pb = GetData(lSize);
if (pb) {
if (DoFTPWrite(pFTP, pb, lSize)) {
DoSendX("BDD", C_FTP, pFTP->m_dwFTID, pFTP->m_lPos);
} else {
OnFTPError(pFTP, -1);
}
}
} else {
OnFTPTerminate(pFTP);
}
}
void CSOCConnect::OnFTPWrite(CFileTransfer* pFTP, long lPosition)
{
switch(pFTP->CheckReadPosition(lPosition)) {
case 0: // end of data...
DoSendX("BDD", S_FTP, pFTP->m_dwFTID, 0);
OnFTPTerminate(pFTP);
break;
case -1: // error.
OnFTPError(pFTP, -1);
break;
case +1: // more data to read...
{/*
CPacket Packet(this);
Packet.Assemble("BD", S_FTP, pFTP->m_dwFTID);
Packet.Assemble("D"
lCode = DoFTPRead(pFTP, ba, ba);
*/}
break;
}
}
void CSOCConnect::OnFTPTerminate(CFileTransfer* pFTP)
{
}
long CSOCConnect::DoFTPRead(CFileTransfer* pFTP, const BYTE* pb, long lSize)
{
return FALSE;
}
BOOL CSOCConnect::DoFTPWrite(CFileTransfer* pFTP, const BYTE* pb, long lSize)
{
return FALSE;
}
BOOL CSOCConnect::CheckDroppingTicks(DWORD dwTicks)
{
if (OnSend() == 0)
CallOnShutdown(SD_SEND);
BOOL bReadPossible = OnReceive();
BOOL bSendPossible = IsSendPossible();
if (!(bReadPossible || bSendPossible) || ((m_dwDroppingTicks + m_dwLingerTime) < dwTicks)) {
CallOnShutdown(SD_BOTH);
CallOnClose();
return TRUE;
} else {
return FALSE;
}
}
CSOCClient::CSOCClient(DWORD dwLingerTime/* = MY_LINGER_TIME*/)
: CSOCConnect(dwLingerTime)
{
m_ID.m_uID = CSOC_CLIENT_ID;
}
CSOCClient::~CSOCClient()
{
}
BOOL CSOCClient::OnCheckIDAndPassword(const char* pcszID, const char* pcszPW)
{
return TRUE;
}
void CSOCClient::OnAccept()
{
}
void CSOCClient::CallOnAccept()
{
m_DW.m_xIsConnecting = FALSE;
m_DW.m_xIsConnected = TRUE;
SetConnectionTime();
ResetKeepAliveAll();
OnAccept();
}
CSOCServer::CSOCServer(const char* pcszTarget/* = NULL*/, int nPort/* = 0*/, DWORD dwLingerTime/* = MY_LINGER_TIME*/)
: CSOCConnect(dwLingerTime)
{
SetTarget(pcszTarget);
SetPort(nPort);
m_ID.m_uID = CSOC_SERVER_ID;
}
CSOCServer::~CSOCServer()
{
}
void CSOCServer::CallOnConnectionTimeOut()
{
if (m_DW.m_xIsConnecting) {
m_pSOCManager->DoConnecting(this, FALSE);
m_DW.m_xIsConnecting = FALSE;
m_DW.m_xIsConnected = FALSE;
OnConnectionTimeOut();
}
DoExceptions(EEXCP_ConnectionTimeOut, TRUE);
}
void CSOCServer::OnConnect()
{
}
void CSOCServer::OnConnectionTimeOut()
{
}
BOOL CSOCServer::DoConnect()
{
int nErr;
if (m_Addr.sin_addr.s_addr == INADDR_NONE) {
LPHOSTENT lpHost;
lpHost = gethostbyname(m_Addr.m_strTarget);
if (lpHost != NULL)
m_Addr.sin_addr.s_addr = ((LPIN_ADDR)lpHost->h_addr)->s_addr;
else {
nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
DoErrorReport(nErr);
return FALSE;
}
}
#ifdef USE_OVRIO
nErr = WSAConnect(m_hSocket, (const SOCKADDR*)&m_Addr, sizeof(sockaddr_in), NULL, NULL, NULL, NULL);
#else // !USE_OVRIO
#ifdef SOLARIS
nErr = connect(m_hSocket, (SOCKADDR*)&m_Addr, sizeof(sockaddr_in));
#else // !SOLARIS
nErr = connect(m_hSocket, (const SOCKADDR*)&m_Addr, sizeof(sockaddr_in));
#endif // SOLARIS
#endif // USE_OVRIO
if (nErr == SOCKET_ERROR) {
nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS)) {
if (DoErrorReport(nErr) != EEXCP_NoError)
return FALSE;
}
}
return TRUE;
}
void CSOCServer::CallOnConnect()
{
if (m_DW.m_xIsConnecting) {
m_pSOCManager->DoConnecting(this, FALSE);
m_DW.m_xIsConnecting = FALSE;
}
if (!m_DW.m_xIsConnected) {
SetConnectionTime();
ResetKeepAliveAll();
m_DW.m_xIsConnected = TRUE;
OnConnect();
}
}
CSOCUDP::CSOCUDP(int nPort/* = 0*/)
: m_Addr(0, (u_long)0)
{
m_hSocket = INVALID_SOCKET;
m_nPort = nPort;
}
CSOCUDP::~CSOCUDP()
{
Drop();
}
UINT CSOCUDP::GetMAX_MSG_SIZE() const
{
int err;
unsigned int uMMAX;
socklen_t nOptLen = (socklen_t)sizeof(uMMAX);
err = getsockopt(m_hSocket, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*)&uMMAX, &nOptLen);
if (err != SOCKET_ERROR) {
return uMMAX;
}
return 0;
}
BOOL CSOCUDP::CreateAndBind(int nPort/* = 0*/)
{
ASSERT(this && !IsValid());
if ((m_hSocket = socket(AF_INET, SOCK_DGRAM, 0)) != INVALID_SOCKET) {
if (nPort)
m_nPort = nPort;
m_Addr.sin_addr.s_addr = INADDR_ANY;
m_Addr.sin_port = htons((short)nPort);
if (bind(m_hSocket, (const struct sockaddr*)&m_Addr, sizeof(sockaddr_in)) != SOCKET_ERROR) {
return TRUE;
}
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
return FALSE;
}
void CSOCUDP::Drop()
{
if (IsValidSafe()) {
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
}
BOOL CSOCUDP::IsReadable() const
{
ASSERT(IsValid());
XFD_SET fd;
fd.SET(m_hSocket);
fd.Select(0);
if (fd.GetCount() == 1)
return TRUE;
return FALSE;
}
BOOL CSOCUDP::IsWritable() const
{
ASSERT(IsValid());
XFD_SET fd;
fd.SET(m_hSocket);
fd.Select(1);
if (fd.GetCount() == 1)
return TRUE;
return FALSE;
}
int CSOCUDP::Send(const void* pBuffer, int nLen, DWORD dwAddr, int nPort)
{
ASSERT(IsValid());
m_Addr.sin_addr.s_addr = htonl(dwAddr);
m_Addr.sin_port = htons((short)nPort);
return sendto(m_hSocket, (const SEND_RECV_TYPE*)pBuffer, nLen, 0, (const struct sockaddr*)&m_Addr, sizeof(sockaddr_in));
}
int CSOCUDP::Recv(void* pBuffer, int nLen, DWORD& dwAddr, int& nPort)
{
ASSERT(IsValid());
socklen_t nAddrLen = (socklen_t)sizeof(sockaddr_in);
int nRet = recvfrom(m_hSocket, (SEND_RECV_TYPE*)pBuffer, nLen, 0, (struct sockaddr*)&m_Addr, &nAddrLen);
dwAddr = ntohl(m_Addr.sin_addr.s_addr);
nPort = ntohs(m_Addr.sin_port);
return nRet;
}
int CSOCUDP::Send(const void* pBuffer, int nLen, const sockaddr_in& Addr)
{
ASSERT(IsValid());
return sendto(m_hSocket, (const SEND_RECV_TYPE*)pBuffer, nLen, 0, (const struct sockaddr*)&Addr, sizeof(Addr));
}
int CSOCUDP::Recv(void* pBuffer, int nLen, sockaddr_in& Addr)
{
ASSERT(IsValid());
socklen_t nAddrLen = (socklen_t)sizeof(Addr);
return recvfrom(m_hSocket, (SEND_RECV_TYPE*)pBuffer, nLen, 0, (struct sockaddr*)&Addr, &nAddrLen);
}
XFD_SET::XFD_SET()
{
fd_count = 0;
#if !defined(WIN32)
FD_ZERO(&m_FD_SET);
#endif // !defined(WIN32)
}
XFD_SET::XFD_SET(SOCKET soc)
{
fd_count = 1;
fd_array[0] = soc;
#if !defined(WIN32)
FD_ZERO(&m_FD_SET);
FD_SET(soc, &m_FD_SET);
#endif // !defined(WIN32)
}
XFD_SET::XFD_SET(const XFD_SET& that)
{
Assign(that);
}
void XFD_SET::Assign(const XFD_SET& that)
{
fd_count = that.fd_count;
if (fd_count > 0) {
memcpy(&fd_array[0], &that.fd_array[0], fd_count * sizeof(SOCKET));
}
#if !defined(WIN32)
m_FD_SET = that.m_FD_SET;
#endif // !defined(WIN32)
}
int XFD_SET::FindIndexFromHandle(SOCKET soc) const
{
SOCKET* pSOCKET = TBSEARCH_SAMEVALUEUNSIGNED(SOCKET, soc, &fd_array[0], fd_count);
if (pSOCKET) {
ASSERT(*pSOCKET == soc);
return pSOCKET - &fd_array[0];
}
return -1;
}
void XFD_SET::ZERO()
{
fd_count = 0;
#if !defined(WIN32)
FD_ZERO(&m_FD_SET);
#endif // !defined(WIN32)
}
BOOL XFD_SET::ISSET(SOCKET soc)
{
#if defined(WIN32)
return FindIndexFromHandle(soc) != -1;
#else // !defined(WIN32)
return FD_ISSET(soc, &m_FD_SET);
#endif // defined(WIN32)
}
void XFD_SET::SET(SOCKET soc)
{
int nCount = fd_count;
if (nCount <= 0) {
ASSERT(nCount == 0);
fd_array[0] = soc;
} else {
int nIndex = TBRANGE_SAMEVALUEUNSIGNED(SOCKET, soc, &fd_array[0], nCount, TRUE) + 1;
nCount -= nIndex;
SOCKET* ppHOC = &fd_array[nIndex];
if (nCount > 0) {
memmove(&ppHOC[1], ppHOC, sizeof(SOCKET) * nCount);
}
*ppHOC = soc;
}
#if !defined(WIN32)
FD_SET(soc, &m_FD_SET);
#endif // !defined(WIN32)
fd_count++;
}
void XFD_SET::CLR(SOCKET soc)
{
int nIndex = FindIndexFromHandle(soc);
if (nIndex != -1) {
CLR_Index(nIndex);
}
}
void XFD_SET::CLR_Index(int nIndex)
{
ASSERT((0 <= nIndex) && (nIndex < fd_count));
int nMV = (--fd_count - nIndex);
if (nMV > 0) {
SOCKET* p1 = &fd_array[nIndex];
#if !defined(WIN32)
FD_CLR(p1[0], &m_FD_SET);
#endif // !defined(WIN32)
memcpy(p1, &p1[1], sizeof(SOCKET) * nMV);
} else {
ASSERT(nMV == 0);
#if !defined(WIN32)
FD_ZERO(&m_FD_SET);
#endif // !defined(WIN32)
}
}
XFD_ARRAY& XFD_SET::GetFD_ARRAY() const
{
return *(XFD_ARRAY*)this;
}
fd_set& XFD_SET::GetFD_SET() const
{
#if defined(WIN32)
return *(fd_set*)this;
#else // !defined(WIN32)
return *(fd_set*)&m_FD_SET;
#endif // !defined(WIN32)
}
int XFD_SET::Select(int nType)
{
int nCount = fd_count, nRet;
if (nCount > 0) {
#ifdef WIN32
#define tSTO g_tSelectTimeOut
switch(nType) {
case 0:
nRet = select(nCount, this, NULL, NULL, &tSTO);
break;
case 1:
nRet = select(nCount, NULL, this, NULL, &tSTO);
break;
case 2:
nRet = select(nCount, NULL, NULL, this, &tSTO);
break;
default:
ASSERT(FALSE);
}
#undef tSTO
#else // !WIN32
struct timeval tSTO(g_tSelectTimeOut);
int nNumFDs = fd_array[nCount - 1] + 1;
switch(nType) {
case 0:
nRet = select(nNumFDs, &m_FD_SET, NULL, NULL, &tSTO);
break;
case 1:
nRet = select(nNumFDs, NULL, &m_FD_SET, NULL, &tSTO);
break;
case 2:
nRet = select(nNumFDs, NULL, NULL, &m_FD_SET, &tSTO);
break;
default:
ASSERT(FALSE);
}
SOCKET* p = &fd_array[0];
SOCKET* pOld = p;
while(nCount-- > 0) {
SOCKET soc = *p++;
if (FD_ISSET(soc, &m_FD_SET)) {
*pOld++ = soc;
}
}
fd_count = pOld - &fd_array[0];
#endif // WIN32
return nRet;
}
return 0;
}
#ifdef _DEBUG
void XFD_SET::CheckHandleMap() const
{
ASSERT(fd_count <= FD_SETSIZE);
int i, nSize = fd_count;
for(i = 0; i < nSize; i++) {
SOCKET soc = fd_array[i];
for(int k = i + 1; k < nSize; k++) {
ASSERT(soc < fd_array[k]);
}
#if !defined(WIN32)
ASSERT(FD_ISSET(soc, &m_FD_SET));
#endif // !defined(WIN32)
}
}
#endif // _DEBUG
CFDSet::CFDSet()
{
FD_ZERO(&GetFD_SET());
}
CFDSet::~CFDSet()
{
}
CSOC* CFDSet::GetSOCFromHandle(SOCKET soc) const
{
SOCKET* pSOCKET = TBSEARCH_SAMEVALUEUNSIGNED(SOCKET, soc, &fd_array[0], fd_count);
if (pSOCKET) {
ASSERT(*m_paSOCs[pSOCKET - &fd_array[0]] == soc);
return m_paSOCs[pSOCKET - &fd_array[0]];
}
return NULL;
}
PSOC CFDSet::FindSOC(SOCKET soc, int& nIndex) const
{
int nIdx = FindIndexFromHandle(soc);
if (nIdx != -1) {
return m_paSOCs[nIndex = nIdx];
}
return NULL;
}
#ifdef _DEBUG
void CFDSet::CheckHandleMap() const
{
XFD_SET::CheckHandleMap();
int i, nSize = fd_count;
for(i = 0; i < nSize; i++) {
ASSERT(fd_array[i] == *m_paSOCs[i]);
}
}
#endif // _DEBUG
void CFDSet::SET(const CSOC& SOC)
{
SOCKET soc = SOC;
int nCount = fd_count;
if (nCount <= 0) {
ASSERT(nCount == 0);
fd_array[0] = soc;
m_paSOCs[0] = (CSOC*)&SOC;
} else {
int nIndex = TBRANGE_SAMEVALUEUNSIGNED(SOCKET, soc, &fd_array[0], nCount, TRUE) + 1;
nCount -= nIndex;
SOCKET* ppHOC = &fd_array[nIndex];
PSOC* ppSOC = &m_paSOCs[nIndex];
if (nCount > 0) {
memmove(&ppHOC[1], ppHOC, sizeof(SOCKET) * nCount);
memmove(&ppSOC[1], ppSOC, sizeof(PSOC) * nCount);
}
*ppHOC = soc;
*ppSOC = (CSOC*)&SOC;
}
#if !defined(WIN32)
FD_SET(soc, &GetFD_SET());
#endif // !defined(WIN32)
fd_count++;
}
void CFDSet::CLR(const CSOC& SOC)
{
int nIndex = FindIndexFromHandle(SOC);
if (nIndex != -1) {
CLR_Index(nIndex);
}
}
void CFDSet::CLR_Index(int nIndex)
{
int nMV = (--fd_count - nIndex);
if (nMV > 0) {
SOCKET* p1 = &fd_array[nIndex];
memcpy(p1, &p1[1], sizeof(SOCKET) * nMV);
PSOC* pp2 = &m_paSOCs[nIndex];
memcpy(pp2, &pp2[1], sizeof(PSOC) * nMV);
} else {
ASSERT(nMV == 0);
}
}
BOOL CFDSet::AddSOC(CSOC& SOC)
{
ASSERT(&SOC);
int nCount;
if ((nCount = fd_count) < (FD_SETSIZE - 1)) {
#ifdef _DEBUG
CheckHandleMap();
#endif // _DEBUG
ASSERT(GetSOCFromHandle(SOC) == NULL);
SET(SOC);
SOC.SetAdded(TRUE);
#ifdef _DEBUG
CheckHandleMap();
#endif // _DEBUG
return TRUE;
} else {
return FALSE;
}
}
void CFDSet::DelSOC(CSOC& SOC)
{
int nIndex = FindIndexFromHandle(SOC);
if (nIndex != -1) {
DelSOCFromIndex(SOC, nIndex);
}
}
void CFDSet::DelSOCFromIndex(CSOC& SOC, int nIndex)
{
#ifdef _DEBUG
CheckHandleMap();
#endif // _DEBUG
XFD_SET::CLR_Index(nIndex);
// fd_count already decremented...
ASSERT((0 <= nIndex) && (nIndex <= fd_count));
int nMV = (fd_count - nIndex);
if (nMV > 0) {
PSOC* pp1 = &m_paSOCs[nIndex];
memcpy(pp1, &pp1[1], sizeof(PSOC) * nMV);
} else {
ASSERT(nMV == 0);
}
SOC.SetAdded(FALSE);
#ifdef _DEBUG
fd_array[fd_count] = 0;
m_paSOCs[fd_count] = NULL;
CheckHandleMap();
#endif // _DEBUG
}
void CDroppings::AddWithFlush(CSOC* pSOC)
{
if (FindIndex(pSOC) == -1) {
Add() = pSOC;
}
}
CSOCManager::CSOCManager(DWORD dwConnectTimeOut/* = 20000*/)
{
m_nStarted = 0;
// socsystem
m_wVersionRequested = MAKEWORD(2, 2); // 1.1
#ifdef WIN32
//memset(&m_wsaData, 0, sizeof(m_wsaData);
#endif // WIN32
// socmanager
m_nDroppingSockets = 0;
m_dwConnectTimeOut = dwConnectTimeOut;
}
CSOCManager::~CSOCManager()
{
int i, nSize = GetCount();
for(i = 0; i < nSize; i++)
{
CSOC* pSOC = m_paSOCs[i];
pSOC->CheckAutoDelete();
}
FD_ZERO(&GetFD_SET());
}
CSOCListen* CSOCManager::GetListenSocket() const
{
int nCount = GetCount();
PSOC* ppSOCs = GetStartOfSOCs();
while(nCount-- > 0) {
CSOC* pSOC = *ppSOCs++;
if (pSOC) {
if (pSOC->IsListenSocket())
return (CSOCListen*)pSOC;
}
}
return NULL;
}
CSOC* CSOCManager::FindSOC(int nID/* = CSOC_SERVER_ID*/) const
{
int nCount = GetCount();
PSOC* ppSOCs = GetStartOfSOCs();
while(nCount-- > 0) {
CSOC* pSOC = *ppSOCs++;
if (pSOC) {
if (pSOC->m_ID.m_nID == nID)
return pSOC;
}
}
return NULL;
}
CSOCServer* CSOCManager::FindSOCServeLogin(int nID/* = CSOC_SERVER_ID*/) const
{
int nCount = GetCount();
PSOC* ppSOCs = GetStartOfSOCs();
while(nCount-- > 0) {
CSOC* pSOC = *ppSOCs++;
if (pSOC) {
if (pSOC->m_ID.m_nID == nID) {
ASSERT(pSOC->GetType3() == SOCNEXT_EXCSERVER);
if ((pSOC->GetConnectionState() == +1) && pSOC->GetLoginOK()) {
return (CSOCServer*)pSOC;
}
return NULL;
}
}
}
return NULL;
}
CSOC* CSOCManager::GetNextSocket(UINT uType, UINT uMask, CSOC* pSOC, int& nIndex, DWORD dwParam/* = 0*/)
{
int nCount = GetCount();
if (nCount > 0) {
int nIdx;
BOOL bReverse = !!(uMask & SOCNEXT_REVERSE);
if (pSOC) {
if (&nIndex && (nIndex != -1)) {
nIdx = nIndex;
} else {
nIdx = FindIndexFromHandle(*pSOC);
ASSERT(nIdx != -1);
}
} else {
if (bReverse)
nIdx = nCount;
else
nIdx = -1;
}
PSOC* ppSOCs = GetStartOfSOCs();
ppSOCs = &ppSOCs[nIdx];
while(TRUE) {
CSOC* pSOC;
if (bReverse) {
if (--nIdx < 0) {
break;
}
pSOC = *--ppSOCs;
} else {
if (++nIdx >= nCount) {
break;
}
pSOC = *++ppSOCs;
}
if ((uType == ((UINT)-1)) || (uType == pSOC->GetType())) {
if (!(uMask & (SOCNEXT_EXCCLIENT | SOCNEXT_EXCSERVER | SOCNEXT_EXCLISTEN)) || !(pSOC->GetType3() & uMask)) {
if (!(uMask & SOCNEXT_EXCINVALID) || pSOC->IsValid()) {
if (!(uMask & SOCNEXT_EXCDROPPING) || !pSOC->IsDroppingState()) {
if (!(uMask & SOCNEXT_EXCCONNECTTING) || !pSOC->IsConnecting()) {
if (!(uMask & SOCNEXT_CHECKPROC) || pSOC->CheckProc(dwParam)) {
if (&nIndex)
nIndex = nIdx;
return pSOC;
}
}
}
}
}
}
}
}
if (&nIndex)
nIndex = -1;
return NULL;
}
BOOL CSOCManager::DoListen(CSOCListen* pSOCListen, int nPort/* = 0*/)
{
if (pSOCListen) {
if (nPort) {
pSOCListen->SetPort(nPort);
}
if (pSOCListen->CreateAndAttach()) {
if (pSOCListen->OnSetupSocket()) {
if (pSOCListen->BindAndListenSocket()) {
if (AddSocket(*pSOCListen)) {
pSOCListen->m_DW.m_xIsConnecting = FALSE;
pSOCListen->m_DW.m_xIsConnected = TRUE;
TRACE("listenning from %s:%d\n", pSOCListen->m_Addr.GetTarget(), pSOCListen->m_Addr.GetPort());
return TRUE;
}
}
}
}
TRACE("DoListen Failure\n");
pSOCListen->Drop();
}
return FALSE;
}
CSOCListen* CSOCManager::DoListen(int nPort, PFN_CreateSOCClient pfnCSC, DWORD dwCSCParam1, DWORD dwCSCParam2)
{
CSOCListen* pSOCListen;
pSOCListen = new CSOCListen(nPort);
pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2);
if (!DoListen(pSOCListen, nPort)) {
// Ʈ 2 Listen ϴ ?...
pSOCListen = NULL;
}
return pSOCListen;
}
BOOL CSOCManager::DoConnect(CSOCServer* pSOCServer, const char* pcszTarget/* = NULL*/, int nPort/* = 0*/)
{
if (pSOCServer) {
if (pcszTarget)
pSOCServer->SetTarget(pcszTarget);
if (nPort)
pSOCServer->SetPort(nPort);
if (pSOCServer->CreateAndAttach()) {
if (pSOCServer->OnSetupSocket()) {
if (pSOCServer->DoConnect()) {
if (AddSocket(*pSOCServer)) {
pSOCServer->m_DW.m_xIsConnecting = TRUE;
pSOCServer->m_DW.m_xIsConnected = FALSE;
DoConnecting(pSOCServer, TRUE);
return TRUE;
}
}
}
}
TRACE("DoConnect Failure\n");
pSOCServer->Drop();
}
return FALSE;
}
void CSOCManager::DropAll(BOOL bWait/* = TRUE*/)
{
TRACE("DropAll\n");
int i, nSize = GetCount();
for(i = 0; i < nSize; i++)
{
m_paSOCs[i]->Drop();
}
if (bWait) {
while(!IsSafeToShutdown()) {
SingleStep();
}
}
}
EException CSOCManager::OnExceptions(CSOC* pSOC, EException eException, BOOL bDropIfErrorOccur/* = FALSE*/)
{
if (eException == EEXCP_Unknown) {
if (pSOC) {
if (!pSOC->IsListenSocket()) {
// CSOCConnect socket...
if (pSOC->IsConnecting()) {
eException = EEXCP_ConnectionFailure;
}
}
} else {
}
}
switch(eException) {
case EEXCP_TooLowVersion:
case EEXCP_Unknown:
case EEXCP_ConnectionTimeOut:
case EEXCP_ConnectionFailure:
case EEXCP_WSAENETDOWN:
case EEXCP_WSANO_RECOVERY:
case EEXCP_WSAENETRESET:
case EEXCP_WSAECONNRESET:
case EEXCP_WSAECONNABORTED:
case EEXCP_WSAEADDRINUSE:
case EEXCP_WSAETIMEDOUT:
case EEXCP_WSAEHOSTUNREACH:
case EEXCP_WSAEACCES:
case EEXCP_WSANOTINITIALISED:
case EEXCP_WSAEFAULT:
case EEXCP_WSAENOTSOCK:
case EEXCP_WSAENOTCONN:
case EEXCP_WSAEOPNOTSUPP:
case EEXCP_WSAEINVAL:
break;
}
if (eException != EEXCP_NoError) {
TRACE("DoExceptions: %x - CODE %s: %d\n", pSOC, EEXCP2MSG(eException));
//do...
if (bDropIfErrorOccur) {
if (pSOC) {
pSOC->Drop();
}
}
}
return eException;
}
BOOL CSOCManager::Init()
{
if (m_nStarted == 0) {
if (Startup()) {
if (SetupInitialOption()) {
m_nStarted++;
return TRUE;
}
Shutdown();
}
return FALSE;
} else {
m_nStarted++;
return TRUE;
}
}
void CSOCManager::Exit()
{
if (m_nStarted > 0) {
if (--m_nStarted == 0) {
DropAll();
m_aTimerPool.DelTimersAll();
Shutdown();
}
}
}
BOOL CSOCManager::Startup()
{
#ifdef WIN32
/* gotta initialize the winsock stuff */
int err;
err = WSAStartup(m_wVersionRequested, &m_wsaData);
if (err == 0) { // don't use SOCKET_ERROR
if (m_wsaData.wVersion == m_wVersionRequested) {
if (InitSignal())
return TRUE;
} else {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
}
OnExceptions(NULL, EEXCP_TooLowVersion, FALSE);
WSACleanup();
} else {
/* Tell the user that we couldn't find a useable */
/* winsock.dll. */
OnExceptions(NULL, ((CSOC*)NULL)->GetExceptionCode(err), FALSE);
}
return FALSE;
#else // WIN32
return TRUE;
#endif // WIN32
}
void CSOCManager::Shutdown()
{
ExitSignal();
#ifdef WIN32
WSACleanup();
#else // !WIN32
#endif // WIN32
}
BOOL CSOCManager::SetupInitialOption()
{
#ifdef WIN32
#if 1
return TRUE;
#else
int err;
int optval = SO_SYNCHRONOUS_NONALERT;
err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (const char*)&optval,sizeof(optval));
if (err != SOCKET_ERROR) {
return TRUE;
}
DoErrorReport(NULL, WSAGetLastError(), FALSE);
return FALSE;
#endif
#else // !WIN32
return TRUE;
#endif // WIN32
}
BOOL CSOCManager::InitSignal()
{
#ifdef WIN32
#else
//signal(SIGPIPE, SIG_IGN);
//signal(SIGTERM, SIG_IGN);
//signal(SIGCHLD, child_died);
//signal(SIGHUP, quick_shutdown);
#endif
return TRUE;
}
void CSOCManager::ExitSignal()
{
}
void CSOCManager::OnAddSocket(CSOC& SOC)
{
//TRACE("SOC Added: %x - %s\n", pSOC, pSOC ? (pSOC->IsListenSocket() ? "Listenning": "Server"): "?");
}
void CSOCManager::OnDelSocket(CSOC& SOC)
{
//TRACE("SOC Cutted: %x - %s\n", pSOC, pSOC ? (pSOC->IsListenSocket() ? "Listenning": "Server"): "?");
}
void CSOCManager::SingleStep()
{
m_aTimerPool.CheckTimers();
CheckDropping();
if (GetCount() > 0) {
m_FD_Dynamic.Alloc();
CheckFlush();
CheckReading();
m_FD_Dynamic.Free();
}
}
CSOCClient* CSOCManager::OnNewClientSocket(const CSOCListen& SOCListen, DWORD dwCSCParam1, DWORD dwCSCParam2) const
{
ASSERT(FALSE);
return NULL;
}
BOOL CSOCManager::AddSocket(CSOC& SOC)
{
ASSERT(&SOC && (&SOC.GetSOCManager() == NULL));
if (AddSOC(SOC)) {
CallOnAddSocket(SOC);
return TRUE;
}
return FALSE;
}
void CSOCManager::CallOnAddSocket(CSOC& SOC)
{
ASSERT(&SOC);
SOC.SetSOCManager(this);
SOC.OnAddSocket();
OnAddSocket(SOC);
}
void CSOCManager::CallOnDelSocket(CSOC& SOC)
{
ASSERT(&SOC);
OnDelSocket(SOC);
//TRACE("DelSOC{FromIndex}: %x\n", &SOC);
SOC.OnDelSocket();
SOC.SetSOCManager(NULL);
}
void CSOCManager::OnDrop(CSOC* pSOC)
{
if (pSOC) {
if (!pSOC->IsDroppingState()) { // don't use GetLockCount()
pSOC->Lock();
TRACE("Dropping: %x\n", pSOC);
pSOC->CallOnDropping();
if (this) {
ASSERT(pSOC->IsAdded());
pSOC->m_DW.m_xIsSetupFailure = FALSE;
if (pSOC->IsConnecting()) {
pSOC->m_DW.m_xIsConnecting = FALSE;
DoConnecting((CSOCServer*)pSOC, FALSE);
//TRACE("(Connecting), ");
}
pSOC->SetDroppingTicks();
pSOC->m_DW.m_xDoDelSocket = 1;
m_nDroppingSockets++;
} else {
pSOC->Unlock();
ASSERT(!pSOC->IsAdded());
pSOC->m_DW.m_xIsSetupFailure = TRUE;
pSOC->m_DW.m_xIsConnecting = FALSE;
pSOC->CallOnShutdown(SD_BOTH);
pSOC->CallOnClose();
pSOC->CallOnDelete();
}
}
}
}
void CSOCManager::DoConnecting(CSOCServer* pSOCServer, BOOL bConnecting)
{
if (pSOCServer) {
m_aTimerPool.DelTimers(timer_ConnectCheck, pSOCServer, CHK_TIMER_ONCE);
int nIndex = m_paConnectings.FindIndex(pSOCServer);
if (bConnecting) {
TRACE("Connecting Before: %x\n", pSOCServer);
m_aTimerPool.AddTimer(timer_ConnectCheck, GetConnectTimeOut(), pSOCServer);
if (nIndex == -1)
m_paConnectings.Add() = pSOCServer;
} else {
if (nIndex != -1) {
m_paConnectings.Del(nIndex);
}
TRACE("Connecting After: %x\n", pSOCServer);
}
}
}
BOOL CSOCManager::IsSafeToShutdown() const
{
if ((GetCount() == 0) && (m_paDroppings.GetSize() == 0)) {
return TRUE;
}
return FALSE;
}
void CSOCManager::CheckDropping()
{
int nSize;
if ((nSize = m_paDroppings.GetSize()) > 0) {
PSOC* ppSOC = &m_paDroppings.GetAt(0);
int i = 0;
DWORD dwTicks = GetTickCount();
while(i < nSize) {
CSOC* pSOC = *ppSOC;
BOOL bDelete;
if (pSOC->IsListenSocket()) {
pSOC->m_DW.m_xErrSEND = pSOC->m_DW.m_xErrRECEIVE = TRUE;
pSOC->CallOnShutdown(SD_BOTH);
pSOC->CallOnClose();
bDelete = TRUE;; // do delete...
} else {
bDelete = ((CSOCConnect*)pSOC)->CheckDroppingTicks(dwTicks);
}
if (bDelete) {
m_paDroppings.Del(i);
nSize--;
pSOC->CallOnDelete();
} else {
i++;
ppSOC++;
}
}
m_paDroppings.FreeExtra();
}
if (m_nDroppingSockets > 0) {
nSize = GetCount();
PSOC* pp = &GetStartOfSOCs()[nSize];
while(nSize-- > 0) {
CSOC* pSOC = *--pp;
if (pSOC->m_DW.m_xDoDelSocket) {
DelSOCFromIndex(*pSOC, nSize);
CallOnDelSocket(*pSOC);
m_paDroppings.AddWithFlush(pSOC);
pSOC->Unlock();
if (--m_nDroppingSockets <= 0) {
break;
}
}
}
ASSERT(m_nDroppingSockets == 0);
}
}
void CSOCManager::CheckFlush()
{
#if defined(USE_OVRIO)
SleepEx(0, TRUE);
XFD_SET& fd = *m_FD_Dynamic.GetFD_SET(m_paConnectings);
ASSERT(m_paConnectings.GetSize() == fd.GetCount());
#else // !defined(USE_OVRIO)
XFD_SET& fd = *m_FD_Dynamic.GetFD_SET(*this);
#endif // defined(USE_OVRIO)
int nErrorCode = fd.Select(1);
if (nErrorCode != SOCKET_ERROR) {
int i, nCount = fd.GetCount();
SOCKET* p = fd.GetFDs();
for(i = 0; i < nCount; i++) {
SOCKET soc = *p++;
CSOC* pSOC = GetSOCFromHandle(soc);
if (pSOC) {
if (!pSOC->GetLockCount()) {
#if defined(USE_OVRIO)
ASSERT(pSOC->IsConnecting());
((CSOCServer*)pSOC)->CallOnConnect();
#else // !defined(USE_OVRIO)
if (pSOC->IsListenSocket()) {
// buffer empty...
pSOC->m_aSnd.FreeAll();
} else {
if (pSOC->IsConnecting()) {
//if (((CSOCServer*)pSOC)->OnConnectionCheck()) {
((CSOCServer*)pSOC)->CallOnConnect();
//}
} else {
pSOC->OnSend();
}
}
#endif // defined(USE_OVRIO)
}
} else {
// already freed?
}
}
} else {
#ifdef _DEBUG
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
OnExceptions(NULL, ((CSOC*)NULL)->GetExceptionCode(nErr), TRUE);
#endif // _DEBUG
}
}
void CSOCManager::CheckReading()
{
XFD_SET& fd = *m_FD_Dynamic.GetFD_SET(*this);
int nErrorCode = fd.Select(0);
if (nErrorCode != SOCKET_ERROR) {
int i, nCount = fd.GetCount();
SOCKET* p = fd.GetFDs();
for(i = 0; i < nCount; i++) {
SOCKET soc = *p++;
CSOC* pSOC = GetSOCFromHandle(soc);
if (pSOC) {
if (!pSOC->GetLockCount()) {
if (pSOC->IsListenSocket()) {
//if (((CSOCListen*)pSOC)->OnAcceptionCheck()) {
((CSOCListen*)pSOC)->OnAcception();
//}
} else {
pSOC->OnReceive();
if (pSOC->m_dwKARcvTimeOut) {
if (pSOC->m_dwKARcvTicks) {
DWORD dwTicks = GetTickCount();
if (dwTicks - pSOC->m_dwKARcvTicks >= pSOC->m_dwKARcvTimeOut) {
TRACE("RcvTimeOut %ld => %ld\n", dwTicks - pSOC->m_dwKARcvTicks, pSOC->m_dwKARcvTimeOut);
pSOC->Drop();
}
}
}
}
}
} else {
// already freed?
}
}
} else {
#ifdef _DEBUG
int nErr = WSAGetLastError();
if ((nErr != WSAEWOULDBLOCK) && (nErr != WSAEINPROGRESS))
OnExceptions(NULL, ((CSOC*)NULL)->GetExceptionCode(nErr), TRUE);
#endif // _DEBUG
}
}
EException CSOCManager::DoErrorReport(CSOC* pSOC, int nErrorCode, BOOL bDropIfErrorOccur/* = FALSE*/)
{
return OnExceptions(pSOC, pSOC->GetExceptionCode(nErrorCode), bDropIfErrorOccur);
}