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.

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