#include "stdafx.h" #include #include #include #ifdef WIN32 #include #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 = 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 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); }