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.
4149 lines
106 KiB
C++
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);
|
|
}
|