Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

676 lines
20 KiB

  1. /************************************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. File Name: SocketPool.cpp
  4. Abstract: Implementation of the socket pool (CSocketPool class)
  5. and the callback function for IO Context.
  6. Notes:
  7. History: 08/01/2001 Created by Hao Yu (haoyu)
  8. ************************************************************************************************/
  9. #include <stdafx.h>
  10. #include <ThdPool.hxx>
  11. #include <SockPool.hxx>
  12. #include <GlobalDef.h>
  13. typedef int (*FUNCGETADDRINFO)(const char *, const char *, const struct addrinfo *, struct addrinfo **);
  14. typedef void (*FUNCFREEADDRINFO)(struct addrinfo *);
  15. //The call back function for IO Context
  16. VOID IOCallBack(PULONG_PTR pCompletionKey ,LPOVERLAPPED pOverlapped, DWORD dwBytesRcvd)
  17. {
  18. ASSERT( NULL != pCompletionKey );
  19. char szBuffer[MAX_PATH]="+OK Server Ready";
  20. WSABUF wszBuf={MAX_PATH, szBuffer};
  21. DWORD dwNumSent=0;
  22. DWORD dwFlag=0;
  23. long lLockValue;
  24. PIO_CONTEXT pIoContext=(PIO_CONTEXT)pCompletionKey;
  25. if(pIoContext->m_ConType == LISTEN_SOCKET)
  26. {
  27. ASSERT(pOverlapped != NULL);
  28. //This is a new connection
  29. g_PerfCounters.IncPerfCntr(e_gcTotConnection);
  30. g_PerfCounters.IncPerfCntr(e_gcConnectionRate);
  31. g_PerfCounters.IncPerfCntr(e_gcConnectedSocketCnt);
  32. pIoContext=CONTAINING_RECORD(pOverlapped, IO_CONTEXT, m_Overlapped);
  33. pIoContext->m_dwLastIOTime=GetTickCount();
  34. pIoContext->m_dwConnectionTime=pIoContext->m_dwLastIOTime;
  35. pIoContext->m_lLock=LOCKED_TO_PROCESS_POP3_CMD;
  36. if(ERROR_SUCCESS!=g_FreeList.RemoveFromList( &(pIoContext->m_ListEntry) ))
  37. {
  38. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,POP3SVR_SOCKET_REQUEST_BEFORE_INIT);
  39. }
  40. g_BusyList.AppendToList( &(pIoContext->m_ListEntry) );
  41. g_SocketPool.DecrementFreeSocketCount();
  42. pIoContext->m_pPop3Context->Reset();
  43. pIoContext->m_pPop3Context->ProcessRequest(pIoContext, pOverlapped, dwBytesRcvd);
  44. if(DELETE_PENDING == pIoContext->m_ConType)
  45. {
  46. g_BusyList.RemoveFromList(&(pIoContext->m_ListEntry));
  47. if(g_SocketPool.IsMoreSocketsNeeded())
  48. {
  49. if(g_SocketPool.ReuseIOContext(pIoContext))
  50. {
  51. return;
  52. }
  53. }
  54. delete(pIoContext->m_pPop3Context);
  55. delete(pIoContext);
  56. }
  57. else
  58. {
  59. InterlockedExchange(&(pIoContext->m_lLock), UNLOCKED);
  60. }
  61. if( g_SocketPool.IsMoreSocketsNeeded() )
  62. {
  63. if(!g_SocketPool.AddSockets())
  64. {
  65. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,POP3SVR_CREATE_ADDITIONAL_SOCKET_FAILED);
  66. }
  67. }
  68. if( g_SocketPool.IsMaxSocketUsed())
  69. {
  70. SetEvent(g_hDoSEvent);
  71. }
  72. }
  73. else
  74. {
  75. lLockValue = InterlockedCompareExchange(&(pIoContext->m_lLock), LOCKED_TO_PROCESS_POP3_CMD, UNLOCKED);
  76. while(UNLOCKED!=lLockValue)
  77. {
  78. //This thread have to wait for the previous command to finish
  79. //Or the timeout thread to mark it as timed out
  80. Sleep(10);
  81. lLockValue = InterlockedCompareExchange(&(pIoContext->m_lLock), LOCKED_TO_PROCESS_POP3_CMD, UNLOCKED);
  82. }
  83. if(CONNECTION_SOCKET == pIoContext->m_ConType )
  84. {
  85. pIoContext->m_pPop3Context->ProcessRequest(pIoContext, pOverlapped, dwBytesRcvd);
  86. }
  87. if(DELETE_PENDING == pIoContext->m_ConType)
  88. {
  89. g_BusyList.RemoveFromList(&(pIoContext->m_ListEntry));
  90. if(g_SocketPool.IsMoreSocketsNeeded())
  91. {
  92. if(g_SocketPool.ReuseIOContext(pIoContext))
  93. {
  94. return;
  95. }
  96. }
  97. delete(pIoContext->m_pPop3Context);
  98. delete(pIoContext);
  99. }
  100. else
  101. {
  102. pIoContext->m_dwLastIOTime=GetTickCount();
  103. InterlockedExchange(&(pIoContext->m_lLock), UNLOCKED);
  104. }
  105. }
  106. }
  107. CSocketPool::CSocketPool()
  108. {
  109. InitializeCriticalSection(&m_csInitGuard);
  110. m_sMainSocket = INVALID_SOCKET;
  111. m_lMaxSocketCount = 0;
  112. m_lMinSocketCount = 0;
  113. m_lThreshold = 0;
  114. m_lTotalSocketCount = 0;
  115. m_lFreeSocketCount = 0;
  116. m_bInit = FALSE;
  117. m_lAddThreadToken = 1l;
  118. m_iSocketFamily = 0;
  119. m_iSocketType = 0;
  120. m_iSocketProtocol = 0;
  121. }
  122. CSocketPool::~CSocketPool()
  123. {
  124. if(m_bInit)
  125. {
  126. Uninitialize();
  127. }
  128. DeleteCriticalSection(&m_csInitGuard);
  129. }
  130. BOOL CSocketPool::CreateMainSocket(u_short usPort)
  131. {
  132. BOOL bRetVal = TRUE;
  133. PSOCKADDR addr;
  134. SOCKADDR_IN inAddr;
  135. INT addrLength;
  136. OSVERSIONINFOEX osVersion;
  137. HMODULE hMd=NULL;
  138. FUNCGETADDRINFO fgetaddrinfo=NULL;
  139. FUNCFREEADDRINFO ffreeaddrinfo=NULL;
  140. char szPort[33]; //max bytes of buffer for _ultoa
  141. addrinfo aiHints,*paiList=NULL, *paiIndex=NULL;
  142. int iRet;
  143. osVersion.dwOSVersionInfoSize=sizeof(OSVERSIONINFOEX);
  144. if( !GetVersionEx((LPOSVERSIONINFO)(&osVersion)) )
  145. {
  146. // This should never happen
  147. return FALSE;
  148. }
  149. if( (osVersion.dwMajorVersion>=5) //Only work with XP
  150. &&
  151. (osVersion.dwMinorVersion >1)
  152. &&
  153. ( (osVersion.wProductType == VER_NT_SERVER ) ||
  154. (osVersion.wProductType == VER_NT_DOMAIN_CONTROLLER) )
  155. &&
  156. (!
  157. ((osVersion.wSuiteMask & VER_SUITE_SMALLBUSINESS ) ||
  158. (osVersion.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED ) ||
  159. (osVersion.wSuiteMask & VER_SUITE_PERSONAL ) ) ) )
  160. {
  161. //These are the SKUs we support
  162. }
  163. else
  164. {
  165. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  166. POP3SVR_UNSUPPORTED_OS);
  167. return FALSE;
  168. }
  169. if(osVersion.dwMinorVersion > 0 ) //XP
  170. {
  171. hMd=GetModuleHandle(_T("WS2_32.dll"));
  172. if(NULL == hMd)
  173. {
  174. return FALSE;
  175. }
  176. fgetaddrinfo=(FUNCGETADDRINFO)GetProcAddress(hMd, "getaddrinfo");
  177. ffreeaddrinfo=(FUNCFREEADDRINFO)GetProcAddress(hMd, "freeaddrinfo");
  178. if( (NULL == fgetaddrinfo) ||
  179. (NULL == ffreeaddrinfo))
  180. {
  181. return FALSE;
  182. }
  183. _ultoa(usPort, szPort, 10);
  184. memset(&aiHints, 0, sizeof(aiHints));
  185. aiHints.ai_socktype = SOCK_STREAM;
  186. aiHints.ai_flags = AI_PASSIVE;
  187. iRet=fgetaddrinfo(NULL, szPort, &aiHints, &paiList);
  188. if(iRet!=0)
  189. {
  190. //Error case
  191. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  192. POP3SVR_FAILED_TO_CREATE_SOCKET,
  193. WSAGetLastError());
  194. bRetVal=FALSE;
  195. goto EXIT;
  196. }
  197. for(paiIndex=paiList; paiIndex!=NULL; paiIndex=paiIndex->ai_next)
  198. {
  199. if( ( (paiIndex->ai_family == PF_INET ) && (g_dwIPVersion != 6 ) ) ||
  200. ( (g_dwIPVersion==6) && (paiIndex->ai_family == PF_INET6 ) ) )
  201. {
  202. //Find the first (usually the only) addrinfo
  203. m_iSocketFamily=paiIndex->ai_family; //For create AcceptEx socket
  204. m_iSocketType=paiIndex->ai_socktype;
  205. m_iSocketProtocol=paiIndex->ai_protocol;
  206. m_sMainSocket = WSASocket(
  207. m_iSocketFamily,
  208. m_iSocketType,
  209. m_iSocketProtocol,
  210. NULL, // protocol info
  211. 0, // Group ID = 0 => no constraints
  212. WSA_FLAG_OVERLAPPED // completion port notifications
  213. );
  214. if(INVALID_SOCKET == m_sMainSocket)
  215. {
  216. //This is not the socket family supported by the machine.
  217. continue;
  218. }
  219. break;
  220. }
  221. }
  222. if(INVALID_SOCKET==m_sMainSocket)
  223. {
  224. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  225. POP3SVR_FAILED_TO_CREATE_SOCKET,
  226. WSAGetLastError());
  227. bRetVal=FALSE;
  228. goto EXIT;
  229. }
  230. if ( bind( m_sMainSocket, paiIndex->ai_addr, paiIndex->ai_addrlen) != 0)
  231. {
  232. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  233. POP3SVR_FAILED_TO_BIND_MAIN_SOCKET,
  234. WSAGetLastError());
  235. bRetVal=FALSE;
  236. goto EXIT;
  237. }
  238. }
  239. else //Win2k
  240. {
  241. m_iSocketFamily=PF_INET;
  242. m_iSocketType=SOCK_STREAM;
  243. m_iSocketProtocol=IPPROTO_TCP;
  244. m_sMainSocket = WSASocket(
  245. m_iSocketFamily,
  246. m_iSocketType,
  247. m_iSocketProtocol,
  248. NULL, // protocol info
  249. 0, // Group ID = 0 => no constraints
  250. WSA_FLAG_OVERLAPPED // completion port notifications
  251. );
  252. if(INVALID_SOCKET == m_sMainSocket)
  253. {
  254. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  255. POP3SVR_FAILED_TO_CREATE_SOCKET,
  256. WSAGetLastError());
  257. bRetVal=FALSE;
  258. goto EXIT;
  259. }
  260. addr = (PSOCKADDR)&inAddr;
  261. addrLength = sizeof(inAddr);
  262. ZeroMemory(addr, addrLength);
  263. inAddr.sin_family = AF_INET;
  264. inAddr.sin_port = htons(usPort);
  265. inAddr.sin_addr.s_addr = INADDR_ANY;
  266. if ( bind( m_sMainSocket, addr, addrLength) != 0)
  267. {
  268. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  269. POP3SVR_FAILED_TO_BIND_MAIN_SOCKET,
  270. WSAGetLastError());
  271. bRetVal=FALSE;
  272. goto EXIT;
  273. }
  274. }
  275. if ( listen( m_sMainSocket, m_iBackLog) != 0)
  276. {
  277. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  278. POP3SVR_FAILED_TO_LISTEN_ON_MAIN_SOCKET,
  279. WSAGetLastError());
  280. bRetVal=FALSE;
  281. goto EXIT;
  282. }
  283. m_stMainIOContext.m_hAsyncIO = m_sMainSocket;
  284. m_stMainIOContext.m_ConType = LISTEN_SOCKET;
  285. m_stMainIOContext.m_pCallBack = IOCallBack;
  286. m_stMainIOContext.m_pPop3Context = NULL;
  287. m_stMainIOContext.m_dwLastIOTime = 0; //No Timeout on this socket
  288. m_stMainIOContext.m_lLock = UNLOCKED;
  289. // Associate the main socket to the completion port
  290. bRetVal = g_ThreadPool.AssociateContext(&m_stMainIOContext);
  291. EXIT:
  292. if(!bRetVal)
  293. {
  294. //Clean up the main listening socket
  295. if( INVALID_SOCKET != m_sMainSocket )
  296. {
  297. closesocket(m_sMainSocket);
  298. m_sMainSocket=INVALID_SOCKET;
  299. }
  300. }
  301. if(NULL != paiList)
  302. {
  303. ffreeaddrinfo(paiList);
  304. }
  305. return bRetVal;
  306. }
  307. BOOL CSocketPool::Initialize(DWORD dwMax, DWORD dwMin, DWORD dwThreshold, u_short usPort, int iBackLog)
  308. {
  309. BOOL bRetVal=FALSE;
  310. EnterCriticalSection(&m_csInitGuard);
  311. ASSERT( ( dwMax >= dwMin + dwThreshold ) &&
  312. ( dwMin > 0 ) );
  313. if( !( (dwMax >= dwMin + dwThreshold ) &&
  314. ( dwMin > 0 ) ) )
  315. {
  316. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  317. EVENT_POP3_NO_CONFIG_DATA);
  318. goto EXIT;
  319. }
  320. if(!m_bInit)
  321. {
  322. WSADATA wsaData;
  323. INT iErr;
  324. iErr = WSAStartup( MAKEWORD( 2, 0), &wsaData);
  325. if( iErr != 0 )
  326. {
  327. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  328. POP3SVR_WINSOCK_FAILED_TO_INIT,
  329. iErr);
  330. bRetVal=FALSE;
  331. goto EXIT;
  332. }
  333. m_lMaxSocketCount = dwMax;
  334. m_lMinSocketCount = dwMin;
  335. m_lThreshold = dwThreshold;
  336. m_lFreeSocketCount = 0;
  337. m_lTotalSocketCount= 0;
  338. m_iBackLog = iBackLog;
  339. //First Create the Main socket
  340. if( bRetVal = CreateMainSocket(usPort) )
  341. {
  342. //Now create the initial pool of AcceptEx sockets
  343. bRetVal = AddSocketsP(m_lMinSocketCount);
  344. }
  345. m_bInit=bRetVal;
  346. }
  347. EXIT:
  348. LeaveCriticalSection(&m_csInitGuard);
  349. return bRetVal;
  350. }
  351. // Called after
  352. BOOL CSocketPool::IsMoreSocketsNeeded()
  353. {
  354. if ( (g_dwServerStatus != SERVICE_RUNNING ) &&
  355. (g_dwServerStatus != SERVICE_PAUSED ) )
  356. {
  357. return FALSE;
  358. }
  359. if ( ( m_lTotalSocketCount < m_lMinSocketCount) ||
  360. (( m_lFreeSocketCount < m_lThreshold ) &&
  361. ( m_lTotalSocketCount <m_lMaxSocketCount )) )
  362. {
  363. return TRUE;
  364. }
  365. else
  366. {
  367. return FALSE;
  368. }
  369. }
  370. BOOL CSocketPool::MaintainSocketCount()
  371. {
  372. if ( g_dwServerStatus != SERVICE_RUNNING )
  373. {
  374. return FALSE;
  375. }
  376. if(
  377. ( ( m_lFreeSocketCount < m_lThreshold ) &&
  378. ( m_lTotalSocketCount+m_lThreshold >= m_lMaxSocketCount ) )
  379. ||
  380. ( m_lTotalSocketCount <= m_lMinSocketCount )
  381. )
  382. {
  383. return TRUE;
  384. }
  385. else
  386. {
  387. return FALSE;
  388. }
  389. }
  390. BOOL CSocketPool::Uninitialize()
  391. {
  392. BOOL bRetVal=TRUE;
  393. EnterCriticalSection(&m_csInitGuard);
  394. if(m_bInit)
  395. {
  396. // Close the main socket here
  397. closesocket(m_sMainSocket);
  398. m_sMainSocket=INVALID_SOCKET;
  399. //AcceptEx Sockes should already have been cleaned with IO Context,
  400. if(WSACleanup () )
  401. {
  402. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  403. POP3SVR_WINSOCK_FAILED_TO_CLEANUP,
  404. WSAGetLastError());
  405. return FALSE;
  406. }
  407. m_bInit=FALSE;
  408. }
  409. LeaveCriticalSection(&m_csInitGuard);
  410. return bRetVal;
  411. }
  412. // For working threading to call when a new connection was established
  413. BOOL CSocketPool::AddSockets()
  414. {
  415. BOOL bRetVal=TRUE;
  416. if( g_dwServerStatus != SERVICE_RUNNING )
  417. {
  418. return TRUE;
  419. }
  420. ASSERT(TRUE == m_bInit);
  421. // Make sure only one thread get to add the socket
  422. if( InterlockedExchange(&m_lAddThreadToken,0) )
  423. {
  424. bRetVal = AddSocketsP(m_lThreshold);
  425. InterlockedExchange(&m_lAddThreadToken,1);
  426. }
  427. return bRetVal;
  428. }
  429. BOOL CSocketPool::AddSocketsP(DWORD dwNumOfSocket)
  430. {
  431. int i;
  432. BOOL bRetVal=TRUE;
  433. PIO_CONTEXT pIoContext=NULL;
  434. for(i=0; i<dwNumOfSocket; i++)
  435. {
  436. if( (g_dwServerStatus != SERVICE_RUNNING ) &&
  437. (g_dwServerStatus != SERVICE_START_PENDING) )
  438. {
  439. return TRUE;
  440. }
  441. if(m_lMaxSocketCount < InterlockedIncrement(&m_lTotalSocketCount) )
  442. {
  443. InterlockedDecrement(&m_lTotalSocketCount);
  444. return TRUE;
  445. }
  446. pIoContext=new (IO_CONTEXT);
  447. if(NULL==pIoContext)
  448. {
  449. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  450. POP3SVR_NOT_ENOUGH_MEMORY);
  451. bRetVal=FALSE;
  452. break;
  453. }
  454. pIoContext->m_pPop3Context=new(POP3_CONTEXT);
  455. pIoContext->m_pCallBack = IOCallBack;
  456. if(NULL == pIoContext->m_pPop3Context )
  457. {
  458. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  459. POP3SVR_NOT_ENOUGH_MEMORY);
  460. bRetVal=FALSE;
  461. delete(pIoContext);
  462. break;
  463. }
  464. bRetVal=CreateAcceptSocket(pIoContext);
  465. if(!bRetVal)
  466. {
  467. delete(pIoContext->m_pPop3Context);
  468. delete(pIoContext);
  469. break;
  470. }
  471. InterlockedIncrement(&m_lFreeSocketCount);
  472. if(m_lTotalSocketCount >= m_lMaxSocketCount)
  473. {
  474. break;
  475. }
  476. }
  477. if(!bRetVal)
  478. {
  479. InterlockedDecrement(&m_lTotalSocketCount);
  480. }
  481. return bRetVal;
  482. }
  483. //Called when a new connection is establised
  484. //and a AcceptEx socket is used
  485. void CSocketPool::DecrementFreeSocketCount()
  486. {
  487. if(0==InterlockedDecrement(&m_lFreeSocketCount))
  488. {
  489. AddSockets();
  490. }
  491. }
  492. //Called when a socket is closed
  493. void CSocketPool::DecrementTotalSocketCount()
  494. {
  495. if(0==InterlockedDecrement(&m_lTotalSocketCount))
  496. {
  497. //Some socket must be created to avoid
  498. //this denial of service problem.
  499. AddSockets();
  500. }
  501. }
  502. //Called when a socked is closed, however, the a new
  503. // AcceptEx socket should be created to maintain
  504. // total socket count, but keep the IOContext
  505. // to re-use
  506. BOOL CSocketPool::ReuseIOContext(PIO_CONTEXT pIoContext)
  507. {
  508. ASSERT( NULL != pIoContext);
  509. if(InterlockedIncrement(&m_lTotalSocketCount) > m_lMaxSocketCount)
  510. {
  511. InterlockedDecrement(&m_lTotalSocketCount);
  512. return FALSE;
  513. }
  514. pIoContext->m_pPop3Context->Reset();
  515. if( CreateAcceptSocket(pIoContext) )
  516. {
  517. InterlockedIncrement(&m_lFreeSocketCount);
  518. return TRUE;
  519. }
  520. else
  521. {
  522. InterlockedDecrement(&m_lTotalSocketCount);
  523. return FALSE;
  524. }
  525. }
  526. BOOL CSocketPool::CreateAcceptSocket(PIO_CONTEXT pIoContext)
  527. {
  528. ASSERT(NULL != pIoContext);
  529. SOCKET sNew;
  530. DWORD dwRcvd;
  531. int iErr;
  532. BOOL bRetVal=FALSE;
  533. BOOL bAddToList=FALSE;
  534. sNew=WSASocket(m_iSocketFamily,
  535. m_iSocketType,
  536. m_iSocketProtocol,
  537. NULL, // protocol info
  538. 0, // Group ID = 0 => no constraints
  539. WSA_FLAG_OVERLAPPED // completion port notifications
  540. );
  541. if(INVALID_SOCKET == sNew)
  542. {
  543. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  544. POP3SVR_FAILED_TO_CREATE_SOCKET,
  545. WSAGetLastError());
  546. goto EXIT;
  547. }
  548. pIoContext->m_hAsyncIO=sNew;
  549. pIoContext->m_ConType=CONNECTION_SOCKET;
  550. pIoContext->m_lLock=UNLOCKED;
  551. ZeroMemory(&(pIoContext->m_Overlapped), sizeof(OVERLAPPED));
  552. g_FreeList.AppendToList( &(pIoContext->m_ListEntry) );
  553. bAddToList=TRUE;
  554. // Now add the new Context to the Completion Port
  555. if( bRetVal = g_ThreadPool.AssociateContext(pIoContext))
  556. {
  557. bRetVal=AcceptEx(m_sMainSocket,
  558. sNew,
  559. (LPVOID)(pIoContext->m_Buffer),
  560. 0,
  561. MIN_SOCKADDR_SIZE,
  562. MIN_SOCKADDR_SIZE,
  563. &dwRcvd,
  564. &(pIoContext->m_Overlapped));
  565. if(!bRetVal)
  566. {
  567. iErr= WSAGetLastError();
  568. if(ERROR_IO_PENDING!=iErr)
  569. {
  570. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  571. POP3SVR_CALL_ACCEPTEX_FAILED,
  572. iErr);
  573. }
  574. else
  575. {
  576. bRetVal=TRUE;
  577. }
  578. }
  579. }
  580. EXIT:
  581. if(!bRetVal)
  582. {
  583. if(INVALID_SOCKET != sNew)
  584. {
  585. closesocket(sNew);
  586. }
  587. if(bAddToList)
  588. {
  589. g_FreeList.RemoveFromList(&(pIoContext->m_ListEntry));
  590. }
  591. }
  592. return bRetVal;
  593. }
  594. BOOL CSocketPool::IsMaxSocketUsed()
  595. {
  596. return ( (m_lTotalSocketCount==m_lMaxSocketCount) &&
  597. (m_lFreeSocketCount == 0 ) );
  598. }