// Include files #include "socketcontextpool.h" // Local definitions #define SetLeft(P,L) { (P)->left = L; if (L) (L)->parent = P; } #define SetRight(P,R) { (P)->right = R; if (R) (R)->parent = P; } // Global data // cSocketContextPool Constructor cSocketContextPool::cSocketContextPool(CRITICAL_SECTION* cs, u_long bufferLength) : mCs(cs), mBufferLength(bufferLength) { // Pool Usage Pointer mPagedPoolUsage = NULL; mNonPagedPoolUsage = NULL; // BST Root Pointer mBstRoot = NULL; // ¸Þ¸ð¸® Ä«¿îÅÍ ÃʱâÈ­. mQuotaPagedPoolUsage = 0; mQuotaNonPagedPoolUsage = 0; mWorkingSetSize = 0; } // ~cSocketContextPool Destructor. cSocketContextPool::~cSocketContextPool(void) { // cSocketContextPool¸¦ Á¾·á. Shutdown( ); } // DefaultWorkingSize Method bool cSocketContextPool::DefaultWorkingSize(DWORD workingSize) { cCSLock lock( mCs ); // Critical Section PerSocketContext* temp = NULL; try { while ( workingSize > 0 ) { temp = GetPool( ); if ( temp == NULL ) throw false; // Socket Context¸¦ Áغñ. workingSize--; } throw true; } catch ( bool boolean ) { while ( mPagedPoolUsage != NULL ) { ReleasePool( mPagedPoolUsage ); } return boolean; } } // GetProcessMemoryInfo Method void cSocketContextPool::GetProcessMemoryInfo(SIZE_T& quotaPagedPoolUsage, SIZE_T& quotaNonPagedPoolUsage, SIZE_T& workingSetSize) { cCSLock lock( mCs ); quotaPagedPoolUsage = mQuotaPagedPoolUsage; quotaNonPagedPoolUsage = mQuotaNonPagedPoolUsage; workingSetSize = mWorkingSetSize; } // Shutdown Method void cSocketContextPool::Shutdown( ) { cCSLock lock( mCs ); PerSocketContext* temp; // BST Shutdown while ( mBstRoot != NULL ) { DetachBst( mBstRoot ); } // Pool Usage Shutdown - PagedPoolUsage while ( mPagedPoolUsage != NULL ) { temp = mPagedPoolUsage; mPagedPoolUsage = mPagedPoolUsage->next; FreeSocketContext( &temp ); } // Pool Usage Shutdown - NonPagedPoolUsage while ( mNonPagedPoolUsage != NULL ) { temp = mNonPagedPoolUsage; mNonPagedPoolUsage = mNonPagedPoolUsage->next; FreeSocketContext( &temp ); } } // AllocSocketContext Method - PerSocketContext¸¦ »ý¼º. PerSocketContext* cSocketContextPool::AllocSocketContext( ) { PerSocketContext* perSocketContext = (PerSocketContext*)GlobalAlloc( GPTR, sizeof(PerSocketContext) ); if ( perSocketContext != NULL ) { // Socket Context¸¦ ÃʱâÈ­. perSocketContext->socket = INVALID_SOCKET; // Ŭ¶óÀÌ¾ðÆ® ¼ÒÄÏ, PerIoContext¿Í ÂüÁ¶. perSocketContext->seq = 0; // Sequence Number. perSocketContext->statusData = 0; // »óÅ ÃʱâÈ­. memset( &perSocketContext->addr, 0, sizeof(SOCKADDR_IN) ); // ÀÎÅÍ³Ý ÁÖ¼Ò. perSocketContext->timeToLive = 0; // Time To Live. perSocketContext->buffer = (char*)GlobalAlloc( GPTR, mBufferLength ); // ¸Þ¸ð¸®¸¦ ÇÒ´çÇÑ´Ù. - GPTR »ç¿ë½Ã 0À¸·Î ÃʱâÈ­µÈ´Ù. perSocketContext->offset = 0; // ¹öÆÛÀÇ ¿ÀÇÁ¼Â. perSocketContext->length = mBufferLength; // ¹öÆÛÀÇ ±æÀÌ. perSocketContext->Internal = 0; // ³»ºÎ ¿ÀÇÁ¼Â. perSocketContext->InternalHigh = 0; // ³»ºÎ ¿ÀÇÁ¼Â. perSocketContext->cid = 0; // Connection ID. perSocketContext->wsaBuf = (char*)GlobalAlloc( GPTR, mBufferLength*2 );// ¸Þ¸ð¸®¸¦ ÇÒ´çÇÑ´Ù. - GPTR »ç¿ë½Ã 0À¸·Î ÃʱâÈ­µÈ´Ù. perSocketContext->wsaOff = 0; // ¹öÆÛÀÇ ¿ÀÇÁ¼Â. perSocketContext->wsaLen = mBufferLength*2; // ¹öÆÛÀÇ ±æÀÌ. perSocketContext->prev = NULL; // ¼±Çü¸®½ºÆ®ÀÇ Æ÷ÀÎÅÍ - ÀÌÀü perSocketContext->next = NULL; // ¼±Çü¸®½ºÆ®ÀÇ Æ÷ÀÎÅÍ - ´ÙÀ½ perSocketContext->parent = NULL; // BST Æ÷ÀÎÅÍ - ¸ðü perSocketContext->left = NULL; // BST Æ÷ÀÎÅÍ - ¿ÞÂÊ perSocketContext->right = NULL; // BST Æ÷ÀÎÅÍ - ¿À¸¥ÂÊ // mWorkingSetSize¸¦ Áõ°¡. mWorkingSetSize++; } return perSocketContext; } // FreeSocketContext Method - PerSocketContext¸¦ »èÁ¦. void cSocketContextPool::FreeSocketContext(PerSocketContext** perSocketContext) { if ( perSocketContext != NULL ) { if ( (*perSocketContext)->socket != INVALID_SOCKET ) { // force the subsequent closesocket to be abortative. // LINGER linger; linger.l_onoff = 1; linger.l_linger = 0; setsockopt( (*perSocketContext)->socket, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger) ); closesocket( (*perSocketContext)->socket ); (*perSocketContext)->socket = INVALID_SOCKET; } if ( (*perSocketContext)->wsaBuf != NULL ) { GlobalFree ( (*perSocketContext)->wsaBuf ); (*perSocketContext)->wsaBuf = NULL; } if ( (*perSocketContext)->buffer != NULL ) { GlobalFree ( (*perSocketContext)->buffer ); (*perSocketContext)->buffer = NULL; } GlobalFree ( (*perSocketContext) ); (*perSocketContext) = NULL; // mWorkingSetSize¸¦ °¨¼Ò. mWorkingSetSize--; } } // CompareCID Method int cSocketContextPool::CompareCID(PerSocketContext* perSocketContext1, PerSocketContext* perSocketContext2) { return (perSocketContext1->cid - perSocketContext2->cid); } int cSocketContextPool::CompareCID(int cid1, int cid2) { return (cid1 - cid2); } // AttachPool Method void cSocketContextPool::AttachPool(PerSocketContext** pool, PerSocketContext* perSocketContext) { if ( (*pool) != NULL ) { (*pool)->prev = perSocketContext; perSocketContext->prev = NULL; perSocketContext->next = (*pool); } (*pool) = perSocketContext; } // DetachPool Method void cSocketContextPool::DetachPool(PerSocketContext** pool, PerSocketContext* perSocketContext) { PerSocketContext* prev = perSocketContext->prev; PerSocketContext* next = perSocketContext->next; if ( prev == NULL && next == NULL ) { (*pool) = NULL; } else if ( prev == NULL && next != NULL ) { next->prev = NULL; (*pool) = next; } else if ( prev != NULL && next == NULL ) { prev->next = NULL; } else if ( prev != NULL && next != NULL ) { prev->next = next; next->prev = prev; } perSocketContext->prev = NULL; perSocketContext->next = NULL; } // AttachBst Method bool cSocketContextPool::AttachBst(PerSocketContext* perSocketContext) { PerSocketContext* parent = NULL; PerSocketContext* child = mBstRoot; int result; while ( child != NULL ) { parent = child; result = CompareCID( child->cid, perSocketContext->cid ); if ( result == 0 ) return false; else if ( result > 0 ) child = child->left; else if ( result < 0 ) child = child->right; } if ( parent == NULL ) { mBstRoot = perSocketContext; } else if ( CompareCID( parent, perSocketContext ) > 0 ) { SetLeft( parent, perSocketContext ); } else // if ( CompareCID( parent, perSocketContext ) < 0 ) { SetRight( parent, perSocketContext ); } return true; } // DetachBst Method bool cSocketContextPool::DetachBst(PerSocketContext* perSocketContext) { PerSocketContext* parent = perSocketContext->parent; PerSocketContext* left = perSocketContext->left; PerSocketContext* right = perSocketContext->right; PerSocketContext* child = NULL; if ( left == NULL ) { child = right; } else if ( right == NULL ) { child = left; } else { child = right; while ( child->left != NULL ) child = child->left; if ( child->parent != perSocketContext ) { SetLeft( child->parent, child->right ); SetRight( child, right ); } child->parent = parent; SetLeft( child, left ); } if ( mBstRoot == perSocketContext ) { mBstRoot = child; if ( mBstRoot != NULL ) mBstRoot->parent = NULL; } else if ( perSocketContext == parent->left ) { SetLeft( parent, child ); } else { SetRight( parent, child ); } perSocketContext->parent = NULL; perSocketContext->left = NULL; perSocketContext->right = NULL; return true; } // GetPool Method PerSocketContext* cSocketContextPool::GetPool( ) { PerSocketContext* perSocketContext = mNonPagedPoolUsage; if ( perSocketContext != NULL ) { // ÆäÀÌÁö ¾ÈµÈ Ç® »ç¿ë·®¸¦ Â÷°¨. DetachPool( &mNonPagedPoolUsage, perSocketContext ); mQuotaNonPagedPoolUsage--; } else { // ÆäÀÌÁö°¡ ¾øÀ» °æ¿ì »õ·Î »ý¼º. perSocketContext = AllocSocketContext( ); } if ( perSocketContext != NULL ) { AttachPool( &mPagedPoolUsage, perSocketContext ); mQuotaPagedPoolUsage++; } return perSocketContext; } // ReleasePool Method void cSocketContextPool::ReleasePool(PerSocketContext* perSocketContext, bool isDelete) { // ÆäÀÌÁö µÈ Ç® »ç¿ë·®À» Â÷°¨. DetachPool( &mPagedPoolUsage, perSocketContext ); mQuotaPagedPoolUsage--; if ( isDelete != true ) { // ÆäÀÌÁö ¾ÈµÈ Ç® »ç¿ë·®À» Áõ°¨. AttachPool( &mNonPagedPoolUsage, perSocketContext ); mQuotaNonPagedPoolUsage++; } else { // ÆäÀÌÁö »èÁ¦. FreeSocketContext( &perSocketContext ); } } // ClearCID Method bool cSocketContextPool::ClearCID(PerSocketContext* perSocketContext) { // BST - ¿¬°á»èÁ¦. if ( perSocketContext->status.connectionID ) { perSocketContext->status.connectionID = false; perSocketContext->status.closeWait = true; return DetachBst( perSocketContext ); } return false; } // GetCID Method PerSocketContext* cSocketContextPool::GetCID(DWORD cid) { cCSLock lock( mCs ); PerSocketContext* perSocketContext = mBstRoot; int result; while ( perSocketContext != NULL ) { result = CompareCID( perSocketContext->cid, cid ); if ( result == 0 ) { return (perSocketContext->socket != INVALID_SOCKET ? perSocketContext : NULL); } else if ( result > 0 ) { perSocketContext = perSocketContext->left; } else if ( result < 0 ) { perSocketContext = perSocketContext->right; } } return NULL; } // SetCID Method bool cSocketContextPool::SetCID(PerSocketContext* perSocketContext, DWORD cid) { perSocketContext->cid = cid; perSocketContext->status.connectionID = AttachBst( perSocketContext ); return perSocketContext->status.connectionID; } // GetPerSocketContext Method // ReleasePerSocketContext¿Í ÇÔ²² LIFO¸¦ ÀÌ·é´Ù. LIFO´Â Context Switching¸¦ ÃÖ¼ÒÈ­ Çϱâ À§ÇØ »ç¿ë PerSocketContext* cSocketContextPool::GetPerSocketContext(SOCKET socket, SOCKADDR_IN addr, DWORD ttl) { cCSLock lock( mCs ); // Critical Section PerSocketContext* perSocketContext = GetPool( ); // Socket Context¸¦ Áغñ. if ( perSocketContext != NULL ) { perSocketContext->socket = socket; // ¼ÒÄÏ °ª º¹»ç. perSocketContext->addr = addr; // IP ÁÖ¼Ò º¹»ç. perSocketContext->timeToLive = GetTickCount( ) + ttl; // TTL. } return perSocketContext; } // ReleasePerSocketContext Method // GetPerSocketContext¿Í ÇÔ²² LIFO¸¦ ÀÌ·é´Ù. LIFO´Â Context Switching¸¦ ÃÖ¼ÒÈ­ Çϱâ À§ÇØ »ç¿ë void cSocketContextPool::ReleasePerSocketContext(PerSocketContext* perSocketContext, bool isDelete) { cCSLock lock( mCs ); // Critical Section LINGER linger; // force the subsequent closesocket to be abortative. // linger.l_onoff = 1; linger.l_linger = 0; setsockopt( perSocketContext->socket, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger) ); closesocket( perSocketContext->socket ); // BST - ¿¬°áÁ¾·á. if ( perSocketContext->status.connectionID ) DetachBst( perSocketContext ); perSocketContext->socket = INVALID_SOCKET; // ¼ÒÄÏ, ÃʱâÈ­. perSocketContext->seq = 0; // SEQ, ÃʱâÈ­. perSocketContext->ack = 0; // ACK, ÃʱâÈ­. perSocketContext->statusData = 0; // »óÅÂ, ÃʱâÈ­. ZeroMemory( &perSocketContext->addr, sizeof(SOCKADDR_IN) ); // ÁÖ¼Ò, ÃʱâÈ­. perSocketContext->timeToLive = 0; // TTL ÃʱâÈ­. ZeroMemory( perSocketContext->buffer, perSocketContext->offset + perSocketContext->InternalHigh ); // ¸Þ¸ð¸® ÃʱâÈ­. perSocketContext->offset = 0; // ¿ÀÇÁ¼Â ÃʱâÈ­. perSocketContext->Internal = 0; // ³»ºÎ ÃʱâÈ­. perSocketContext->InternalHigh = 0; // ³»ºÎ ÃʱâÈ­. perSocketContext->cid = 0; // CID ÃʱâÈ­. ZeroMemory( perSocketContext->wsaBuf, perSocketContext->wsaOff ); // ¸Þ¸ð¸® ÃʱâÈ­. perSocketContext->wsaOff = 0; // ¿ÀÇÁ¼Â ÃʱâÈ­. // Socket Context¸¦ ȸ¼ö. ReleasePool( perSocketContext, isDelete ); }