Source code of Windows XP (NT5)
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.

874 lines
22 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1998 **/
  4. /**********************************************************************/
  5. /*
  6. acptctxt.cxx
  7. This file contains the implementations of the PASV_ACCEPT_CONTEXT and ACCEPT_CONTEXT_ENTRY
  8. classes used to deal with async PASV connections
  9. */
  10. #include "ftpdp.hxx"
  11. #include "auxctrs.h"
  12. #include "acptctxt.hxx"
  13. PASV_ACCEPT_CONTEXT::PASV_ACCEPT_CONTEXT() :
  14. m_dwErr( ERROR_SUCCESS ),
  15. m_dwNumEvents( 0 ),
  16. m_hWatchThread( NULL ),
  17. m_dwThreadId( 0 ),
  18. m_dwSignature( ACCEPT_CONTEXT_GOOD_SIG )
  19. /*++
  20. Constructor
  21. Arguments:
  22. None
  23. Returns:
  24. Nothing
  25. --*/
  26. {
  27. if ( ( m_ahEvents[NEEDUPDATE_INDEX] = WSACreateEvent() ) == WSA_INVALID_EVENT ||
  28. ( m_ahEvents[CANUPDATE_INDEX] = WSACreateEvent() ) == WSA_INVALID_EVENT ||
  29. ( m_ahEvents[HAVEUPDATED_INDEX] = WSACreateEvent() ) == WSA_INVALID_EVENT ||
  30. ( m_ahEvents[EXITTHREAD_INDEX] = WSACreateEvent() ) == WSA_INVALID_EVENT )
  31. {
  32. m_dwErr = WSAGetLastError();
  33. DBGWARN((DBG_CONTEXT,
  34. "WSACreateEvent failed : 0x%x\n",
  35. m_dwErr));
  36. return;
  37. }
  38. m_dwNumEvents = 4;
  39. INITIALIZE_CRITICAL_SECTION( &m_csLock );
  40. //
  41. // Create the watching thread
  42. //
  43. m_hWatchThread = CreateThread( NULL,
  44. 0,
  45. AcceptThreadFunc,
  46. this,
  47. 0,
  48. &m_dwThreadId );
  49. if ( !m_hWatchThread )
  50. {
  51. m_dwErr = GetLastError();
  52. DBGERROR((DBG_CONTEXT,
  53. "Failed to create thread to watch for PASV accept events : 0x%x\n",
  54. m_dwErr));
  55. }
  56. }
  57. PASV_ACCEPT_CONTEXT::~PASV_ACCEPT_CONTEXT()
  58. /*++
  59. Destructor
  60. Arguments:
  61. None
  62. Returns:
  63. Nothing
  64. --*/
  65. {
  66. DWORD dwRet = 0;
  67. //
  68. // Tell watch thread to shut down
  69. //
  70. if ( !WSASetEvent( m_ahEvents[EXITTHREAD_INDEX] ) )
  71. {
  72. DBGPRINTF((DBG_CONTEXT,
  73. "WSASetEvent failed : 0x%x\n",
  74. WSAGetLastError()));
  75. }
  76. //
  77. // wait for thread to shut down
  78. //
  79. if ( WaitForSingleObject( m_hWatchThread,
  80. INFINITE ) == WAIT_FAILED )
  81. {
  82. DBGWARN((DBG_CONTEXT,
  83. "Waiting for thread shutdown failed : 0x%x\n",
  84. GetLastError()));
  85. }
  86. CloseHandle( m_hWatchThread );
  87. DeleteCriticalSection( &m_csLock );
  88. m_dwSignature = ACCEPT_CONTEXT_BAD_SIG;
  89. }
  90. BOOL PASV_ACCEPT_CONTEXT::RemoveAcceptEvent( IN WSAEVENT hEvent,
  91. IN USER_DATA *pUserData,
  92. OUT PBOOL pfFound )
  93. /*++
  94. Removes the event to be signalled when a socket is accept()'able
  95. Arguments:
  96. hEvent - event to be removed
  97. pUserData - USER_DATA attached to signalled event
  98. pfFound - BOOL set to TRUE if event was found, FALSE if not
  99. Returns:
  100. BOOL indicating success or failure
  101. --*/
  102. {
  103. *pfFound = FALSE;
  104. DWORD dwIndex = 0;
  105. DWORD dwRet = ERROR_SUCCESS;
  106. DWORD dwWait = 0;
  107. //
  108. // Look for the wanted event
  109. //
  110. for ( DWORD i = LASTPREALLOC_INDEX; i < m_dwNumEvents; i++ )
  111. {
  112. if ( m_ahEvents[i] == hEvent )
  113. {
  114. DBG_ASSERT( m_apUserData[i] == pUserData );
  115. *pfFound = TRUE;
  116. dwIndex = i;
  117. break;
  118. }
  119. }
  120. //
  121. // Didn't find the event, but function succeeded
  122. //
  123. if ( !*pfFound )
  124. {
  125. return TRUE;
  126. }
  127. //
  128. // Signal that we want to update the list of events
  129. //
  130. if ( !WSASetEvent( m_ahEvents[NEEDUPDATE_INDEX] ) )
  131. {
  132. dwRet = WSAGetLastError();
  133. DBGPRINTF((DBG_CONTEXT,
  134. "WSASetEvent failed : 0x%x\n",
  135. dwRet));
  136. goto exit;
  137. }
  138. //
  139. // Wait until we can update the list
  140. //
  141. dwWait = WSAWaitForMultipleEvents( 1,
  142. &(m_ahEvents[CANUPDATE_INDEX]),
  143. TRUE,
  144. 900000, // 15 minutes should do it....
  145. FALSE );
  146. switch (dwWait)
  147. {
  148. case WSA_WAIT_EVENT_0:
  149. {
  150. //
  151. // Remove the data associated with the socket
  152. //
  153. //
  154. // we're not going to use the context any more, so remove the reference we hold to it
  155. //
  156. m_apUserData[dwIndex]->DeReference();
  157. memmove( (PVOID) (m_ahEvents + dwIndex),
  158. (PVOID) (m_ahEvents + (dwIndex + 1) ),
  159. sizeof(WSAEVENT) * (m_dwNumEvents - dwIndex - 1) );
  160. memmove( (PVOID) ( m_apUserData + dwIndex ),
  161. (PVOID) (m_apUserData + (dwIndex + 1) ),
  162. sizeof(LPUSER_DATA) * (m_dwNumEvents - dwIndex - 1) );
  163. memmove( (PVOID) (m_adwNumTimeouts + dwIndex),
  164. (PVOID) (m_adwNumTimeouts + (dwIndex + 1) ),
  165. sizeof(DWORD) * (m_dwNumEvents - dwIndex - 1) );
  166. m_dwNumEvents--;
  167. //
  168. // reset to known state
  169. //
  170. if ( !WSAResetEvent( m_ahEvents[CANUPDATE_INDEX] ) )
  171. {
  172. dwRet = WSAGetLastError();
  173. DBGWARN((DBG_CONTEXT,
  174. "WSAResetEvent failed : 0x%x\n",
  175. GetLastError()));
  176. goto exit;
  177. }
  178. //
  179. // signal that watch thread can start watching again
  180. //
  181. if ( !WSASetEvent( m_ahEvents[HAVEUPDATED_INDEX] ) )
  182. {
  183. dwRet = WSAGetLastError();
  184. DBGPRINTF((DBG_CONTEXT,
  185. "WSASetEvent failed : 0x%x\n",
  186. GetLastError()));
  187. goto exit;
  188. }
  189. }
  190. break;
  191. case WSA_WAIT_TIMEOUT:
  192. {
  193. IF_DEBUG( PASV )
  194. {
  195. DBGWARN((DBG_CONTEXT,
  196. "Wait timed out ... \n"));
  197. }
  198. dwRet = ERROR_TIMEOUT;
  199. goto exit;
  200. }
  201. break;
  202. default:
  203. {
  204. DBGERROR((DBG_CONTEXT,
  205. "Invalid return from WSAWaitForMultipleEvents : 0x%x\n",
  206. dwWait));
  207. dwRet = ERROR_INVALID_PARAMETER;
  208. }
  209. }
  210. exit:
  211. return ( dwRet == ERROR_SUCCESS ? TRUE : FALSE );
  212. }
  213. DWORD PASV_ACCEPT_CONTEXT::AddAcceptEvent( WSAEVENT hEvent,
  214. LPUSER_DATA pUserData )
  215. /*++
  216. Adds an event to be signalled when a socket is accept()'able
  217. Arguments:
  218. hEvent - event that will be signalled
  219. pUserData - USER_DATA context to attach to signalled event
  220. Returns:
  221. Error code
  222. --*/
  223. {
  224. DWORD dwRet = 0;
  225. DWORD dwWait = 0;
  226. if ( m_dwNumEvents == WSA_MAXIMUM_WAIT_EVENTS )
  227. {
  228. return ERROR_INVALID_PARAMETER;
  229. }
  230. //
  231. // Signal that we want to update the list of events
  232. //
  233. if ( !WSASetEvent( m_ahEvents[NEEDUPDATE_INDEX] ) )
  234. {
  235. dwRet = WSAGetLastError();
  236. DBGWARN((DBG_CONTEXT,
  237. "WSASetEvent failed : 0x%x\n",
  238. dwRet));
  239. goto exit;
  240. }
  241. //
  242. // Wait until we can update the list
  243. //
  244. dwWait = WSAWaitForMultipleEvents( 1,
  245. &(m_ahEvents[CANUPDATE_INDEX]),
  246. TRUE,
  247. 10000, //10 secs seems like a reasonable time to wait
  248. FALSE );
  249. switch (dwWait)
  250. {
  251. case WSA_WAIT_EVENT_0:
  252. {
  253. //
  254. // cool, we can update the list
  255. //
  256. m_ahEvents[m_dwNumEvents] = hEvent;
  257. //
  258. // add a reference to make sure nobody deletes the context out from under us
  259. //
  260. pUserData->Reference();
  261. m_apUserData[m_dwNumEvents] = pUserData;
  262. m_adwNumTimeouts[m_dwNumEvents] = 0;
  263. m_dwNumEvents++;
  264. //
  265. // reset to known state
  266. //
  267. if ( !WSAResetEvent( m_ahEvents[CANUPDATE_INDEX] ) )
  268. {
  269. pUserData->DeReference();
  270. m_dwNumEvents--; //make sure event isn't still seen as valid
  271. dwRet = WSAGetLastError();
  272. DBGWARN((DBG_CONTEXT,
  273. "WSAResetEvent failed : 0x%x\n",
  274. GetLastError()));
  275. goto exit;
  276. }
  277. //
  278. // signal that watch thread can start watching again
  279. //
  280. if ( !WSASetEvent( m_ahEvents[HAVEUPDATED_INDEX] ) )
  281. {
  282. pUserData->DeReference();
  283. m_dwNumEvents--; //make sure event isn't still seen as valid
  284. dwRet = WSAGetLastError();
  285. DBGWARN((DBG_CONTEXT,
  286. "WSASetEvent failed : 0x%x\n",
  287. GetLastError()));
  288. goto exit;
  289. }
  290. IF_DEBUG ( PASV )
  291. {
  292. DBGPRINTF((DBG_CONTEXT,
  293. "Added event for context 0x%x at index %d\n",
  294. pUserData, m_dwNumEvents - 1));
  295. }
  296. }
  297. break;
  298. case WSA_WAIT_TIMEOUT:
  299. {
  300. IF_DEBUG( PASV )
  301. {
  302. DBGWARN((DBG_CONTEXT,
  303. "Timed out waiting for permission to update PASV event list ... \n"));
  304. }
  305. dwRet = ERROR_TIMEOUT;
  306. goto exit;
  307. }
  308. break;
  309. default:
  310. {
  311. DBGERROR((DBG_CONTEXT,
  312. "Invalid return from WSAWaitForMultipleEvents : 0x%x\n",
  313. dwWait));
  314. dwRet = ERROR_INVALID_PARAMETER;
  315. }
  316. }
  317. exit:
  318. return dwRet;
  319. }
  320. ACCEPT_CONTEXT_ENTRY::ACCEPT_CONTEXT_ENTRY()
  321. /*++
  322. Constructor
  323. Arguments:
  324. None
  325. Returns:
  326. Nothing
  327. --*/
  328. {
  329. m_pAcceptContext = new PASV_ACCEPT_CONTEXT();
  330. if ( !m_pAcceptContext )
  331. {
  332. DBGERROR((DBG_CONTEXT,
  333. "Failed to allocate new PASV_ACCEPT_CONTEXT !\n"));
  334. }
  335. }
  336. ACCEPT_CONTEXT_ENTRY::~ACCEPT_CONTEXT_ENTRY()
  337. /*++
  338. Destructor
  339. Arguments:
  340. None
  341. Returns:
  342. Nothing
  343. --*/
  344. {
  345. if ( m_pAcceptContext )
  346. {
  347. delete m_pAcceptContext;
  348. }
  349. }
  350. DWORD CreateInitialAcceptContext()
  351. /*++
  352. Creates the first PASV_ACCEPT_CONTEXT object
  353. Arguments:
  354. None
  355. Returns:
  356. Error indicating success/failure
  357. --*/
  358. {
  359. ACCEPT_CONTEXT_ENTRY *pEntry = NULL;
  360. DWORD dwRet = ERROR_SUCCESS;
  361. if ( !(pEntry = new ACCEPT_CONTEXT_ENTRY() ) )
  362. {
  363. DBGERROR((DBG_CONTEXT,
  364. "Failed to allocate new ACCEPT_CONTEXT_ENTRY !\n"));
  365. return ERROR_OUTOFMEMORY;
  366. }
  367. if ( NULL == pEntry->m_pAcceptContext )
  368. {
  369. DBGERROR((DBG_CONTEXT,
  370. "Failed to allocate new ACCEPT_CONTEXT_ENTRY::m_pAcceptContext !\n"));
  371. delete pEntry;
  372. return ERROR_OUTOFMEMORY;
  373. }
  374. if ( ( dwRet = pEntry->m_pAcceptContext->ErrorStatus() ) != ERROR_SUCCESS )
  375. {
  376. DBGERROR((DBG_CONTEXT,
  377. "Error occurred constructing PASV_ACCEPT_CONTEXT : 0x%x\n",
  378. pEntry->m_pAcceptContext->ErrorStatus()));
  379. delete pEntry;
  380. return dwRet;
  381. }
  382. InsertHeadList( &g_AcceptContextList, &pEntry->ListEntry );
  383. return dwRet;
  384. }
  385. VOID DeleteAcceptContexts()
  386. /*++
  387. Deletes all of the PASV_ACCEPT_CONTEXT objects
  388. Arguments:
  389. None
  390. Returns:
  391. Nothing
  392. --*/
  393. {
  394. while ( !IsListEmpty( &g_AcceptContextList ) )
  395. {
  396. ACCEPT_CONTEXT_ENTRY *pEntry = CONTAINING_RECORD( g_AcceptContextList.Flink,
  397. ACCEPT_CONTEXT_ENTRY,
  398. ListEntry );
  399. RemoveEntryList( &(pEntry->ListEntry) );
  400. delete pEntry;
  401. }
  402. }
  403. DWORD AddAcceptEvent( WSAEVENT hEvent,
  404. LPUSER_DATA pUserData )
  405. /*++
  406. Adds an accept event to an available PASV_ACCEPT_CONTEXT
  407. Arguments:
  408. hEvent - handle to event to be added
  409. pUserData - USER_DATA context to attach to event
  410. Returns:
  411. Error code indicating success/failure
  412. --*/
  413. {
  414. LIST_ENTRY *pEntry = NULL;
  415. PPASV_ACCEPT_CONTEXT pAcceptContext = NULL;
  416. PACCEPT_CONTEXT_ENTRY pContextEntry = NULL;
  417. DWORD dwRet = ERROR_SUCCESS;
  418. BOOL fFoundOne = FALSE;
  419. pUserData->FakeIOTimes = 0;
  420. //
  421. // Walk the list of contexts looking for one that can handle an additional
  422. // event.
  423. //
  424. // NB : currently [9/20/98], that list contains only a -single- context, so we can handle
  425. // up to a maximum of (WSA_MAXIMUM_WAIT_EVENTS - 4) events. If we want to get really
  426. // fancy, we could add the necessary code to create a new PASV_ACCEPT_CONTEXT as necessary,
  427. // but that also creates a new thread, and actually opens us up even more to a Denial Of
  428. // Service attack, which is partly what this code is trying to avoid
  429. //
  430. for ( pEntry = g_AcceptContextList.Flink;
  431. pEntry != &g_AcceptContextList;
  432. pEntry = pEntry->Flink )
  433. {
  434. pContextEntry = CONTAINING_RECORD( pEntry, ACCEPT_CONTEXT_ENTRY , ListEntry );
  435. pAcceptContext = pContextEntry->m_pAcceptContext;
  436. pAcceptContext->Lock();
  437. if ( pAcceptContext->QueryNumEvents() < WSA_MAXIMUM_WAIT_EVENTS )
  438. {
  439. dwRet = pAcceptContext->AddAcceptEvent( hEvent,
  440. pUserData );
  441. fFoundOne = TRUE;
  442. }
  443. pAcceptContext->Unlock();
  444. if ( fFoundOne )
  445. break;
  446. }
  447. if (!fFoundOne )
  448. {
  449. dwRet = ERROR_OUTOFMEMORY; //not quite the right error
  450. }
  451. return dwRet;
  452. }
  453. BOOL RemoveAcceptEvent( WSAEVENT hEvent,
  454. LPUSER_DATA pUserData )
  455. /*++
  456. Removes an accept event from the appropriate PASV_ACCEPT_CONTEXT
  457. Arguments:
  458. hEvent - handle to event to be removed
  459. pUserData - USER_DATA context attached to event
  460. Returns:
  461. BOOL indicating success/failure
  462. --*/
  463. {
  464. LIST_ENTRY *pEntry = NULL;
  465. PPASV_ACCEPT_CONTEXT pAcceptContext = NULL;
  466. PACCEPT_CONTEXT_ENTRY pContextEntry = NULL;
  467. DWORD dwRet = ERROR_SUCCESS;
  468. BOOL fFound = FALSE;
  469. BOOL fSuccess = FALSE;
  470. //
  471. // Walk the list of contexts looking for the one that holds the event
  472. // event.
  473. //
  474. for ( pEntry = g_AcceptContextList.Flink;
  475. pEntry != &g_AcceptContextList;
  476. pEntry = pEntry->Flink )
  477. {
  478. pContextEntry = CONTAINING_RECORD( pEntry, ACCEPT_CONTEXT_ENTRY , ListEntry );
  479. pAcceptContext = pContextEntry->m_pAcceptContext;
  480. pAcceptContext->Lock();
  481. fSuccess = pAcceptContext->RemoveAcceptEvent( hEvent,
  482. pUserData,
  483. &fFound );
  484. if ( fFound )
  485. {
  486. pAcceptContext->Unlock();
  487. return fSuccess;
  488. }
  489. pAcceptContext->Unlock();
  490. }
  491. return TRUE;
  492. }
  493. DWORD WINAPI PASV_ACCEPT_CONTEXT::AcceptThreadFunc( LPVOID pvContext )
  494. /*++
  495. Thread function for the thread that waits on the accept events
  496. Arguments:
  497. pvContext - context pointer (pointer to PASV_ACCEPT_CONTEXT object)
  498. Returns:
  499. Nothing useful
  500. --*/
  501. {
  502. PPASV_ACCEPT_CONTEXT pAcceptContext = NULL;
  503. WSAEVENT *phAcceptEvents = NULL;
  504. DWORD dwNumEvents = 0;
  505. DWORD dwRet = 0;
  506. WSAEVENT *phNeedUpdate = NULL;
  507. WSAEVENT *phCanUpdate = NULL;
  508. WSAEVENT *phHaveUpdated = NULL;
  509. WSAEVENT *phExitThread = NULL;
  510. DBG_ASSERT( pvContext );
  511. pAcceptContext = (PPASV_ACCEPT_CONTEXT) pvContext;
  512. phAcceptEvents = pAcceptContext->m_ahEvents;
  513. dwNumEvents = pAcceptContext->m_dwNumEvents;
  514. phNeedUpdate = &phAcceptEvents[NEEDUPDATE_INDEX];
  515. phCanUpdate = &phAcceptEvents[CANUPDATE_INDEX];
  516. phHaveUpdated = &phAcceptEvents[HAVEUPDATED_INDEX];
  517. phExitThread = &phAcceptEvents[EXITTHREAD_INDEX];
  518. loop:
  519. // wait timeout should be fairly small, so we can go through list and purge all
  520. // sockets that have been inactive a given # of timeouts
  521. dwRet = WSAWaitForMultipleEvents( dwNumEvents,
  522. phAcceptEvents,
  523. FALSE,
  524. PASV_TIMEOUT_INTERVAL,
  525. FALSE );
  526. if ( dwRet <= (WSA_WAIT_EVENT_0 + dwNumEvents - 1) )
  527. {
  528. //
  529. // One of the events was signalled
  530. //
  531. DWORD dwIndex = dwRet - WSA_WAIT_EVENT_0;
  532. switch (dwIndex)
  533. {
  534. case (NEEDUPDATE_INDEX):
  535. {
  536. //
  537. // Somebody wants to update the list of events to watch for, so signal that
  538. // they can do so and wait for them to tell us they're done with the update
  539. //
  540. if ( !WSAResetEvent( *phNeedUpdate ) ) //back to known state
  541. {
  542. DBGWARN((DBG_CONTEXT,
  543. "WSAResetEvent failed : 0x%x\n",
  544. WSAGetLastError()));
  545. }
  546. if ( !WSASetEvent( *phCanUpdate ) )
  547. {
  548. DBGWARN((DBG_CONTEXT,
  549. "WSASetEvent failed : 0x%x\n",
  550. WSAGetLastError()));
  551. }
  552. if ( WSAWaitForMultipleEvents( 1,
  553. phHaveUpdated,
  554. TRUE,
  555. INFINITE,
  556. FALSE ) == WSA_WAIT_FAILED )
  557. {
  558. DBGERROR((DBG_CONTEXT,
  559. "WSAWaitForMultipleEvents failed : 0x%x\n",
  560. WSAGetLastError()));
  561. }
  562. if ( !WSAResetEvent( *phHaveUpdated ) ) //back to known state
  563. {
  564. DBGWARN((DBG_CONTEXT,
  565. "WSAResetEvent failed : 0x%x\n",
  566. WSAGetLastError()));
  567. }
  568. dwNumEvents = pAcceptContext->m_dwNumEvents;
  569. goto loop;
  570. }
  571. break;
  572. case (CANUPDATE_INDEX):
  573. case (HAVEUPDATED_INDEX):
  574. {
  575. //
  576. // Should never happen !
  577. //
  578. IF_DEBUG ( PASV )
  579. {
  580. DBGERROR((DBG_CONTEXT,
  581. "Invalid event signalled !\n"));
  582. }
  583. }
  584. break;
  585. case (EXITTHREAD_INDEX):
  586. {
  587. //
  588. // We're all done
  589. //
  590. IF_DEBUG ( PASV )
  591. {
  592. DBGPRINTF((DBG_CONTEXT,
  593. "Exiting thread watching for PASV events....\n"));
  594. }
  595. return 0;
  596. }
  597. break;
  598. default:
  599. {
  600. LPUSER_DATA pUserData = NULL;
  601. //
  602. // One of the sockets has become accept()'able.
  603. //
  604. IF_DEBUG ( PASV )
  605. {
  606. DBGPRINTF((DBG_CONTEXT,
  607. "Got an acceptable socket, index : %i, context : 0x%x\n",
  608. dwIndex, pAcceptContext->m_apUserData[dwIndex]));
  609. }
  610. pUserData = pAcceptContext->m_apUserData[dwIndex];
  611. //
  612. // Remove the data associated with the socket
  613. //
  614. memmove( (PVOID) (pAcceptContext->m_ahEvents + dwIndex),
  615. (PVOID) (pAcceptContext->m_ahEvents + (dwIndex + 1) ),
  616. sizeof(WSAEVENT) * (dwNumEvents - dwIndex - 1) );
  617. memmove( (PVOID) ( pAcceptContext->m_apUserData + dwIndex ),
  618. (PVOID) (pAcceptContext->m_apUserData + (dwIndex + 1) ),
  619. sizeof(LPUSER_DATA) * (dwNumEvents - dwIndex - 1) );
  620. memmove( (PVOID) (pAcceptContext->m_adwNumTimeouts + dwIndex),
  621. (PVOID) (pAcceptContext->m_adwNumTimeouts + (dwIndex + 1) ),
  622. sizeof(DWORD) * (dwNumEvents - dwIndex - 1) );
  623. pAcceptContext->m_dwNumEvents--;
  624. dwNumEvents = pAcceptContext->m_dwNumEvents;
  625. //
  626. // deal with restarting processing
  627. //
  628. SignalAcceptableSocket( pUserData );
  629. goto loop;
  630. }
  631. }
  632. }
  633. else if ( dwRet == WSA_WAIT_TIMEOUT )
  634. {
  635. //
  636. // wait timed out, so go through the list of events and remove those that have
  637. // timed out too often
  638. //
  639. for ( DWORD i = LASTPREALLOC_INDEX;//skip the events that don't have a fixed # of timeouts
  640. i < dwNumEvents;
  641. i++ )
  642. {
  643. if ( pAcceptContext->m_adwNumTimeouts[i] == MAX_PASV_TIMEOUTS )
  644. {
  645. DBGPRINTF((DBG_CONTEXT,
  646. "timing out socket at index %i, context 0x%x \n",
  647. i,
  648. pAcceptContext->m_apUserData[i]));
  649. CleanupTimedOutSocketContext( pAcceptContext->m_apUserData[i] );
  650. memmove( (PVOID) (pAcceptContext->m_ahEvents + i),
  651. (PVOID) (pAcceptContext->m_ahEvents + (i+1) ),
  652. sizeof(WSAEVENT) * (dwNumEvents - i - 1) );
  653. memmove( (PVOID) ( pAcceptContext->m_apUserData + i ),
  654. (PVOID) (pAcceptContext->m_apUserData + (i+1) ),
  655. sizeof(LPUSER_DATA) * (dwNumEvents - i - 1) );
  656. memmove( (PVOID) (pAcceptContext->m_adwNumTimeouts + i),
  657. (PVOID) (pAcceptContext->m_adwNumTimeouts + (i+1) ),
  658. sizeof(DWORD) * (dwNumEvents - i - 1) );
  659. //
  660. // need to readjust the index and number of items in the array
  661. //
  662. i--;
  663. dwNumEvents--;
  664. pAcceptContext->m_dwNumEvents--;
  665. }
  666. else
  667. {
  668. pAcceptContext->m_adwNumTimeouts[i]++;
  669. }
  670. }
  671. dwNumEvents = pAcceptContext->m_dwNumEvents;
  672. goto loop;
  673. }
  674. else if ( dwRet == WAIT_IO_COMPLETION )
  675. {
  676. DBGWARN((DBG_CONTEXT,
  677. "Invalid value from WSAWaitForMultipleEvents !\n"));
  678. goto loop;
  679. }
  680. else
  681. {
  682. DBGERROR((DBG_CONTEXT,
  683. "WSAWaitForMultipleEvents returned 0x%x, error : 0x%x\n",
  684. dwRet, WSAGetLastError()));
  685. goto loop;
  686. }
  687. return 0;
  688. }