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.

1413 lines
28 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. atqbmon.cxx
  5. Abstract:
  6. ATQ Backlog Monitor
  7. Author:
  8. 01-Dec-1998 MCourage
  9. Revision History:
  10. --*/
  11. #include "isatq.hxx"
  12. #include "atqbmon.hxx"
  13. ATQ_BACKLOG_MONITOR * g_pAtqBacklogMonitor = NULL;
  14. ATQ_BACKLOG_MONITOR::ATQ_BACKLOG_MONITOR(
  15. VOID
  16. )
  17. /*++
  18. Routine Description:
  19. Constructor sets up the list and the lock.
  20. Arguments:
  21. None
  22. --*/
  23. {
  24. INITIALIZE_CRITICAL_SECTION( &m_csLock );
  25. InitializeListHead( &m_ListHead );
  26. }
  27. ATQ_BACKLOG_MONITOR::~ATQ_BACKLOG_MONITOR(
  28. VOID
  29. )
  30. /*++
  31. Routine Description:
  32. Destructor cleans up the list and the lock.
  33. Arguments:
  34. None
  35. --*/
  36. {
  37. LIST_ENTRY * pEntry;
  38. ATQ_BMON_SET * pBmonSet;
  39. //
  40. // traverse the list and remove all sets
  41. //
  42. while (!IsListEmpty( &m_ListHead )) {
  43. pEntry = RemoveHeadList( &m_ListHead );
  44. pBmonSet = CONTAINING_RECORD( pEntry, ATQ_BMON_SET, m_SetList );
  45. DBG_ASSERT( pBmonSet->IsEmpty() );
  46. DBG_REQUIRE( pBmonSet->Cleanup() );
  47. }
  48. DeleteCriticalSection( &m_csLock );
  49. }
  50. BOOL
  51. ATQ_BACKLOG_MONITOR::AddEntry(
  52. ATQ_BMON_ENTRY * pBmonEntry
  53. )
  54. /*++
  55. Routine Description:
  56. Adds an entry to the next available ATQ_BMON_SET.
  57. Makes a new set if all current sets are full.
  58. Arguments:
  59. pBmonEntry - The entry to be added
  60. Return Values:
  61. TRUE on success
  62. --*/
  63. {
  64. LIST_ENTRY * pCurrent;
  65. ATQ_BMON_SET * pBmonSet;
  66. BOOL bRetval;
  67. if (!pBmonEntry) {
  68. return TRUE;
  69. }
  70. bRetval = FALSE;
  71. Lock();
  72. for (pCurrent = m_ListHead.Flink;
  73. pCurrent != &m_ListHead;
  74. pCurrent = pCurrent->Flink) {
  75. pBmonSet = CONTAINING_RECORD( pCurrent, ATQ_BMON_SET, m_SetList );
  76. if (pBmonSet->IsNotFull() && pBmonSet->AddEntry(pBmonEntry)) {
  77. bRetval = TRUE;
  78. break;
  79. }
  80. }
  81. if (!bRetval) {
  82. //
  83. // Couldn't find a set with space
  84. // so try to make a new one.
  85. //
  86. pBmonSet = new ATQ_BMON_SET;
  87. if (pBmonSet && pBmonSet->Initialize()) {
  88. InsertHeadList( &m_ListHead, &pBmonSet->m_SetList );
  89. bRetval = pBmonSet->AddEntry(pBmonEntry);
  90. }
  91. }
  92. Unlock();
  93. return bRetval;
  94. }
  95. BOOL
  96. ATQ_BACKLOG_MONITOR::RemoveEntry(
  97. ATQ_BMON_ENTRY * pBmonEntry
  98. )
  99. /*++
  100. Routine Description:
  101. Removes an entry from its containing ATQ_BMON_SET.
  102. If the set is empty it is removed from the list
  103. of sets.
  104. Arguments:
  105. pBmonEntry - The entry to be removed
  106. Return Values:
  107. TRUE on success
  108. --*/
  109. {
  110. ATQ_BMON_SET * pBmonSet;
  111. if (!pBmonEntry) {
  112. return TRUE;
  113. }
  114. DBG_ASSERT( pBmonEntry && pBmonEntry->CheckSignature() );
  115. pBmonSet = pBmonEntry->GetContainingBmonSet();
  116. DBG_ASSERT( pBmonSet );
  117. return pBmonSet->RemoveEntry(pBmonEntry);
  118. }
  119. BOOL
  120. ATQ_BACKLOG_MONITOR::PauseEntry(
  121. ATQ_BMON_ENTRY * pBmonEntry
  122. )
  123. /*++
  124. Routine Description:
  125. Pauses an entry in its containing ATQ_BMON_SET.
  126. The entry will remain in the set, but will
  127. not send notifications.
  128. Arguments:
  129. pBmonEntry - The entry to be paused
  130. Return Values:
  131. TRUE on success
  132. --*/
  133. {
  134. ATQ_BMON_SET * pBmonSet;
  135. if (!pBmonEntry) {
  136. return TRUE;
  137. }
  138. DBG_ASSERT( pBmonEntry && pBmonEntry->CheckSignature() );
  139. pBmonSet = pBmonEntry->GetContainingBmonSet();
  140. DBG_ASSERT( pBmonSet );
  141. return pBmonSet->PauseEntry(pBmonEntry);
  142. }
  143. BOOL
  144. ATQ_BACKLOG_MONITOR::ResumeEntry(
  145. ATQ_BMON_ENTRY * pBmonEntry
  146. )
  147. /*++
  148. Routine Description:
  149. Undoes PauseEntry. The entry in question
  150. will get notifications again
  151. Arguments:
  152. pBmonEntry - The entry to be resumed
  153. Return Values:
  154. TRUE on success
  155. --*/
  156. {
  157. ATQ_BMON_SET * pBmonSet;
  158. if (!pBmonEntry) {
  159. return TRUE;
  160. }
  161. DBG_ASSERT( pBmonEntry && pBmonEntry->CheckSignature() );
  162. pBmonSet = pBmonEntry->GetContainingBmonSet();
  163. DBG_ASSERT( pBmonSet );
  164. return pBmonSet->ResumeEntry(pBmonEntry);
  165. }
  166. ATQ_BMON_ENTRY::ATQ_BMON_ENTRY(
  167. SOCKET s
  168. )
  169. /*++
  170. Routine Description:
  171. Constructor sets up signature etc.
  172. Arguments:
  173. None
  174. --*/
  175. {
  176. DBG_ASSERT( s );
  177. m_Signature = ATQ_BMON_ENTRY_SIGNATURE;
  178. m_Socket = s;
  179. m_hAddRemoveEvent = NULL;
  180. m_BmonOpcode = BMON_INVALID;
  181. m_pBmonSet = NULL;
  182. m_dwErr = NO_ERROR;
  183. }
  184. ATQ_BMON_ENTRY::~ATQ_BMON_ENTRY(
  185. VOID
  186. )
  187. /*++
  188. Routine Description:
  189. Destructor sets up signature and closes event.
  190. Arguments:
  191. None
  192. --*/
  193. {
  194. DBG_ASSERT( CheckSignature() );
  195. DBG_ASSERT( m_Socket );
  196. m_Signature = ATQ_FREE_BMON_ENTRY_SIGNATURE;
  197. DBG_REQUIRE( CloseHandle( m_hAddRemoveEvent ) );
  198. }
  199. BOOL
  200. ATQ_BMON_ENTRY::InitEvent(
  201. VOID
  202. )
  203. /*++
  204. Routine Description:
  205. Sets up the AddRemove event that we use
  206. to synchronise adding and removing of entries.
  207. Arguments:
  208. None
  209. Return Values:
  210. TRUE on success
  211. --*/
  212. {
  213. DBG_ASSERT( CheckSignature() );
  214. DBG_ASSERT( m_hAddRemoveEvent == NULL );
  215. m_hAddRemoveEvent = CreateEvent(
  216. NULL, // default security
  217. FALSE, // do auto-reset
  218. FALSE, // init state false
  219. NULL // no name
  220. );
  221. if (m_hAddRemoveEvent == NULL) {
  222. m_dwErr = GetLastError();
  223. }
  224. return (m_hAddRemoveEvent != NULL);
  225. }
  226. VOID
  227. ATQ_BMON_ENTRY::SignalAddRemove(
  228. DWORD dwError
  229. )
  230. /*++
  231. Routine Description:
  232. Signals the AddRemove event. Clients adding or
  233. removing the entry will be blocked on its event.
  234. Arguments:
  235. None
  236. Return Values:
  237. None
  238. --*/
  239. {
  240. DBG_ASSERT( CheckSignature() );
  241. DBG_ASSERT( m_hAddRemoveEvent != NULL );
  242. m_dwErr = dwError;
  243. DBG_REQUIRE( SetEvent(m_hAddRemoveEvent) );
  244. }
  245. BOOL
  246. ATQ_BMON_ENTRY::WaitForAddRemove(
  247. VOID
  248. )
  249. /*++
  250. Routine Description:
  251. Call this function while waiting for
  252. the entry to be added to or removed from a set.
  253. Arguments:
  254. None
  255. Return Values:
  256. TRUE on success
  257. --*/
  258. {
  259. DWORD dwResult;
  260. DBG_ASSERT( CheckSignature() );
  261. DBG_ASSERT( m_hAddRemoveEvent != NULL );
  262. //
  263. // If the monitor thread dies, don't bother waiting for notification from
  264. // it regarding add/removal.
  265. //
  266. Retry:
  267. if ( m_pBmonSet && !m_pBmonSet->ThreadFinished() )
  268. {
  269. dwResult = WaitForSingleObject(m_hAddRemoveEvent, 10000 );
  270. if ( dwResult == WAIT_TIMEOUT )
  271. {
  272. goto Retry;
  273. }
  274. }
  275. else
  276. {
  277. dwResult = WAIT_OBJECT_0;
  278. }
  279. DBG_ASSERT( dwResult == WAIT_OBJECT_0 );
  280. return (dwResult == WAIT_OBJECT_0);
  281. }
  282. BOOL
  283. BMON_WAKEUP_ENTRY::Callback(
  284. VOID
  285. )
  286. /*++
  287. Routine Description:
  288. The sole purpose of the BMON_WAKEUP_ENTRY is to
  289. get the main thread to wake up and call
  290. SynchronizeSets. All we have to do here is
  291. do a read so that we can wake up again in
  292. the future.
  293. Arguments:
  294. None
  295. Return Values:
  296. TRUE if successful, else FALSE
  297. --*/
  298. {
  299. INT err;
  300. DWORD dwBuff;
  301. ATQ_BMON_SET * pBmonSet;
  302. SOCKADDR_IN sockAddr;
  303. int dwSize = sizeof(sockAddr);
  304. ZeroMemory( &sockAddr, sizeof(sockAddr) );
  305. DBG_ASSERT( CheckSignature() );
  306. //
  307. // do a read to clear the wakeup signal
  308. //
  309. err = recvfrom(
  310. GetSocket(), // our socket
  311. (PCHAR) &dwBuff, // read buffer
  312. sizeof(dwBuff), // buffer len
  313. 0, // flags
  314. (sockaddr *)&sockAddr, // src addr
  315. &dwSize // src addr len
  316. );
  317. if ( err == SOCKET_ERROR ) {
  318. DBGPRINTF((DBG_CONTEXT,
  319. "Error %d in recvfrom\n", WSAGetLastError()));
  320. return FALSE;
  321. } else {
  322. //
  323. // We expect 4 bytes representing ATQ_BMON_WAKEUP_MESSAGE
  324. // However it is possible that someone external
  325. // has sent datagram to our port
  326. //
  327. if ( ( err != sizeof( dwBuff ) ) ||
  328. ( dwBuff != ATQ_BMON_WAKEUP_MESSAGE) ) {
  329. //
  330. // check if returned source address structure is valid
  331. //
  332. if ( dwSize != sizeof(sockAddr) )
  333. {
  334. DBGPRINTF((DBG_CONTEXT,
  335. "Format of source address returned by recvfrom not recognized\n" ));
  336. DBG_ASSERT( FALSE );
  337. }
  338. else {
  339. //
  340. // Backlog monitor is using blocking select() calls and in order to
  341. // be able to unblock there is a wake up endpoint maintained
  342. // (listening on loopback address)
  343. // external programs running on the same computer may eventually
  344. // send random data to this this backlog monitor wakeup endpoint.
  345. // That by itself causes no harm, but we should be aware of it
  346. //
  347. DBGPRINTF((DBG_CONTEXT,
  348. "Warning: external source sent data to the BACKLOG monitor wakeup port\n" ));
  349. }
  350. }
  351. return TRUE;
  352. }
  353. }
  354. ATQ_BMON_SET::ATQ_BMON_SET(
  355. VOID
  356. )
  357. /*++
  358. Routine Description:
  359. Constructor sets up critsec and sets.
  360. Arguments:
  361. None
  362. --*/
  363. {
  364. INITIALIZE_CRITICAL_SECTION( &m_csLock );
  365. memset(m_apEntrySet, 0, sizeof(m_apEntrySet));
  366. FD_ZERO( &m_ListenSet );
  367. m_SetSize = 0;
  368. m_pWakeupEntry = NULL;
  369. m_fCleanup = FALSE;
  370. m_fDoSleep = FALSE;
  371. m_fThreadFinished = FALSE;
  372. m_dwError = NO_ERROR;
  373. }
  374. ATQ_BMON_SET::~ATQ_BMON_SET(
  375. VOID
  376. )
  377. /*++
  378. Routine Description:
  379. Destructor cleans up critsec.
  380. Arguments:
  381. None
  382. --*/
  383. {
  384. DBG_ASSERT( m_SetSize == 0 );
  385. //
  386. // get rid of the wakeup entry
  387. //
  388. DBG_REQUIRE( 0 == closesocket(m_pWakeupEntry->GetSocket()) );
  389. delete m_pWakeupEntry;
  390. DeleteCriticalSection(&m_csLock);
  391. }
  392. BOOL
  393. ATQ_BMON_SET::Initialize(
  394. VOID
  395. )
  396. /*++
  397. Routine Description:
  398. Sets up the Wakeup entry and starts
  399. our thread.
  400. Arguments:
  401. None
  402. Return Values:
  403. TRUE on success
  404. --*/
  405. {
  406. BOOL bRetval;
  407. SOCKET s = INVALID_SOCKET;
  408. SOCKET s2 = INVALID_SOCKET;
  409. SOCKADDR_IN sockAddr;
  410. BMON_WAKEUP_ENTRY * pWakeup = NULL;
  411. HANDLE hThread;
  412. DWORD dwError = NO_ERROR;
  413. bRetval = FALSE;
  414. ZeroMemory(&sockAddr, sizeof(sockAddr));
  415. sockAddr.sin_family = AF_INET;
  416. //
  417. // set up wakeup entry
  418. //
  419. // also create a second socket, bound to the non-loopback interfaces, and shut it down -
  420. // this will prevent another application from binding to the non-specific interface on
  421. // the same port.
  422. // this is done for compatibility with pre-.Net applications (ISA 2000) that
  423. // are using the same code, but are broken by IIS switching to the loopback address
  424. // in exclusive mode.
  425. //
  426. for (WORD wPort = ATQ_BMON_WAKEUP_PORT; wPort <= ATQ_BMON_WAKEUP_PORT_MAX; wPort++) {
  427. //
  428. // start with the non-specific socket
  429. //
  430. if (s2 == INVALID_SOCKET) {
  431. s2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  432. if (s2 == INVALID_SOCKET)
  433. goto failsearch;
  434. }
  435. sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  436. sockAddr.sin_port = htons(wPort);
  437. if (bind(s2, (PSOCKADDR)&sockAddr, sizeof(sockAddr)))
  438. {
  439. DWORD WsaError = WSAGetLastError();
  440. if ((WsaError != WSAEADDRINUSE) && (WsaError != WSAEACCES))
  441. goto failsearch;
  442. // go try another port
  443. continue;
  444. }
  445. //
  446. // now to the real wakeup socket
  447. //
  448. if (s == INVALID_SOCKET) {
  449. s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  450. if (s == INVALID_SOCKET)
  451. goto failsearch;
  452. //
  453. // set socket option for exclusive use of the port
  454. //
  455. BOOL bOpt = TRUE;
  456. if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (LPCSTR) &bOpt, sizeof(bOpt)))
  457. goto failsearch;
  458. }
  459. sockAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  460. if (bind(s, (PSOCKADDR)&sockAddr, sizeof(sockAddr))) {
  461. DWORD WsaError = WSAGetLastError();
  462. if ((WsaError != WSAEADDRINUSE) && (WsaError != WSAEACCES))
  463. goto failsearch;
  464. //
  465. // the loopback address is in use. try a new port. just close s2, as it is bound
  466. //
  467. closesocket(s2);
  468. s2 = INVALID_SOCKET;
  469. continue;
  470. }
  471. // connect the sockets to the loopback address so they cannon be hijacked.
  472. if (connect(s, (PSOCKADDR)&sockAddr, sizeof(sockAddr)))
  473. goto failsearch;
  474. if (connect(s2, (PSOCKADDR)&sockAddr, sizeof(sockAddr)))
  475. goto failsearch;
  476. //
  477. // shut down s2 to prevent activity.
  478. //
  479. if (shutdown(s2, SD_BOTH))
  480. goto failsearch;
  481. // success!
  482. break;
  483. failsearch:
  484. dwError = WSAGetLastError();
  485. goto exit;
  486. }
  487. if ( wPort > ATQ_BMON_WAKEUP_PORT_MAX ) {
  488. dwError = WSAEADDRINUSE;
  489. DBGERROR((DBG_CONTEXT,"Wakeup port search failed. Error %d\n", dwError));
  490. goto exit;
  491. }
  492. pWakeup = new BMON_WAKEUP_ENTRY(s, s2);
  493. if ( pWakeup == NULL )
  494. {
  495. dwError = ERROR_NOT_ENOUGH_MEMORY;
  496. goto exit;
  497. }
  498. s = INVALID_SOCKET;
  499. s2 = INVALID_SOCKET;
  500. if (!pWakeup->InitEvent()) {
  501. dwError = GetLastError();
  502. goto exit;
  503. }
  504. pWakeup->SetContainingBmonSet(this);
  505. pWakeup->SetOpcode(BMON_WAIT);
  506. m_pWakeupEntry = pWakeup;
  507. pWakeup = NULL;
  508. m_Port = wPort;
  509. //
  510. // just jam this entry into the lists
  511. //
  512. DBG_ASSERT(m_SetSize == 0);
  513. m_SetSize = 1;
  514. m_apEntrySet[0] = m_pWakeupEntry;
  515. FD_SET(m_pWakeupEntry->GetSocket(), &m_ListenSet);
  516. //
  517. // now set up our thread. from now on you
  518. // have to Lock before manipulating the
  519. // lists
  520. //
  521. m_hThread = CreateThread(
  522. NULL, // defualt security
  523. 0, // default stack
  524. ::BmonThreadFunc, // thread func
  525. this, // func parameter
  526. 0, // flags
  527. NULL // discard tid
  528. );
  529. if (m_hThread) {
  530. //
  531. // it worked!
  532. //
  533. bRetval = TRUE;
  534. } else {
  535. //
  536. // doh! clean up the wakeup entry
  537. //
  538. dwError = GetLastError();
  539. m_SetSize = 0;
  540. }
  541. exit:
  542. if (!bRetval) {
  543. if (s != INVALID_SOCKET) {
  544. closesocket(s);
  545. }
  546. if (s2 != INVALID_SOCKET) {
  547. closesocket(s2);
  548. }
  549. if (pWakeup) {
  550. delete pWakeup;
  551. }
  552. SetLastError(dwError);
  553. }
  554. return bRetval;
  555. }
  556. BOOL
  557. ATQ_BMON_SET::Cleanup(
  558. VOID
  559. )
  560. /*++
  561. Routine Description:
  562. Tells the select thread to clean up by
  563. removing the wakeup entry.
  564. Arguments:
  565. None
  566. Return Values:
  567. TRUE on success
  568. --*/
  569. {
  570. //
  571. // Cleanup is done when wakup entry
  572. // is removed.
  573. //
  574. // Don't use RemoveEntry, because the
  575. // other thread will delete the wakeup
  576. // entry.
  577. //
  578. DBG_ASSERT( m_pWakeupEntry && m_pWakeupEntry->CheckSignature() );
  579. m_pWakeupEntry->SetOpcode(BMON_REMOVE);
  580. Wakeup();
  581. //
  582. // Wait a reasonable amount of time for the thread to go away.
  583. //
  584. WaitForSingleObject( m_hThread, 10000 );
  585. CloseHandle( m_hThread );
  586. m_hThread = NULL;
  587. delete this;
  588. return TRUE;
  589. }
  590. BOOL
  591. ATQ_BMON_SET::IsEmpty(
  592. VOID
  593. )
  594. /*++
  595. Routine Description:
  596. This tells you if there are sockets in the
  597. set. Note that one socket is the wakeup
  598. socket, so a count of one means we're empty.
  599. Arguments:
  600. None
  601. Return Values:
  602. TRUE on empty
  603. --*/
  604. {
  605. BOOL bRetval;
  606. Lock();
  607. bRetval = (m_SetSize <= 1);
  608. DBG_ASSERT( m_SetSize <= FD_SETSIZE );
  609. Unlock();
  610. return bRetval;
  611. }
  612. BOOL
  613. ATQ_BMON_SET::IsNotFull(
  614. VOID
  615. )
  616. /*++
  617. Routine Description:
  618. This tells you if there is room for more sockets
  619. in the set. Note that one socket is the wakeup
  620. socket.
  621. Arguments:
  622. None
  623. Return Values:
  624. TRUE when space is available
  625. --*/
  626. {
  627. BOOL bRetval;
  628. Lock();
  629. bRetval = (m_SetSize < FD_SETSIZE);
  630. DBG_ASSERT( m_SetSize <= FD_SETSIZE );
  631. Unlock();
  632. return bRetval;
  633. }
  634. BOOL
  635. ATQ_BMON_SET::AddEntry(
  636. ATQ_BMON_ENTRY * pBmonEntry
  637. )
  638. /*++
  639. Routine Description:
  640. Add an entry to the set
  641. Arguments:
  642. pBmonEntry - the entry to be added
  643. Return Values:
  644. TRUE on success
  645. --*/
  646. {
  647. DWORD i;
  648. BOOL bAdded = FALSE;
  649. DWORD dwError;
  650. pBmonEntry->SetOpcode(BMON_ADD);
  651. Lock();
  652. for (i = 0; i < FD_SETSIZE; i++) {
  653. if (!m_apEntrySet[i]) {
  654. m_apEntrySet[i] = pBmonEntry;
  655. pBmonEntry->SetContainingBmonSet(this);
  656. bAdded = TRUE;
  657. m_SetSize++;
  658. DBG_ASSERT( m_SetSize <= FD_SETSIZE );
  659. break;
  660. }
  661. }
  662. Unlock();
  663. if (bAdded) {
  664. Wakeup();
  665. pBmonEntry->WaitForAddRemove();
  666. dwError = pBmonEntry->GetError();
  667. if (dwError) {
  668. //
  669. // other thread will remove from list
  670. //
  671. SetLastError(dwError);
  672. bAdded = FALSE;
  673. }
  674. }
  675. return bAdded;
  676. }
  677. BOOL
  678. ATQ_BMON_SET::RemoveEntry(
  679. ATQ_BMON_ENTRY * pBmonEntry
  680. )
  681. /*++
  682. Routine Description:
  683. Remove an entry from the set
  684. Arguments:
  685. pBmonEntry - the entry to be removed
  686. Return Values:
  687. TRUE on success
  688. --*/
  689. {
  690. DWORD i;
  691. BOOL bRemoved = FALSE;
  692. pBmonEntry->SetOpcode(BMON_REMOVE);
  693. Wakeup();
  694. pBmonEntry->WaitForAddRemove();
  695. return (pBmonEntry->GetError() == NO_ERROR);
  696. }
  697. BOOL
  698. ATQ_BMON_SET::PauseEntry(
  699. ATQ_BMON_ENTRY * pBmonEntry
  700. )
  701. /*++
  702. Routine Description:
  703. Pause an entry in the set. The entry's
  704. socket will be removed from the FD_SET,
  705. but the entry will stay.
  706. Arguments:
  707. pBmonEntry - the entry to be paused
  708. Return Values:
  709. TRUE on success
  710. --*/
  711. {
  712. DWORD i;
  713. BOOL bRemoved = FALSE;
  714. DBGPRINTF((DBG_CONTEXT,
  715. "Pausing backlog monitor entry %p\n",
  716. pBmonEntry));
  717. pBmonEntry->SetOpcode(BMON_PAUSE);
  718. Wakeup();
  719. //
  720. // We don't do the event stuff for pause and
  721. // resume. It's a pain because the client will
  722. // want to pause from within the callback
  723. // function.
  724. //
  725. return (TRUE);
  726. }
  727. BOOL
  728. ATQ_BMON_SET::ResumeEntry(
  729. ATQ_BMON_ENTRY * pBmonEntry
  730. )
  731. /*++
  732. Routine Description:
  733. Resume an entry in the set. The entry's
  734. socket will be added back to the FD_SET.
  735. Arguments:
  736. pBmonEntry - the entry to be resumed
  737. Return Values:
  738. TRUE on success
  739. --*/
  740. {
  741. DWORD i;
  742. BOOL bRemoved = FALSE;
  743. if (pBmonEntry->GetOpcode() == BMON_NOWAIT) {
  744. DBGPRINTF((DBG_CONTEXT,
  745. "Resuming backlog monitor entry %p\n",
  746. pBmonEntry));
  747. pBmonEntry->SetOpcode(BMON_RESUME);
  748. Wakeup();
  749. }
  750. //
  751. // We don't do the event stuff for pause and
  752. // resume. It's a pain because the client will
  753. // want to pause from within the callback
  754. // function.
  755. //
  756. return (TRUE);
  757. }
  758. VOID
  759. ATQ_BMON_SET::BmonThreadFunc(
  760. VOID
  761. )
  762. /*++
  763. Routine Description:
  764. This function is for the set's select thread.
  765. It calls accept with the listen set, and calls
  766. notification functions for all sockets that
  767. are ready.
  768. SynchronizeSets returns false when it's time
  769. to shut down.
  770. Arguments:
  771. None
  772. Return Values:
  773. None
  774. --*/
  775. {
  776. INT err;
  777. while (SynchronizeSets()) {
  778. err = select(
  779. 0, // junk
  780. &m_ListenSet, // readfds
  781. NULL, // writefds
  782. NULL, // exceptfds
  783. NULL // want to block
  784. );
  785. if (err != SOCKET_ERROR) {
  786. DBG_ASSERT(err > 0);
  787. if ( !NotifyEntries() )
  788. {
  789. //
  790. // If we couldn't notify the entries, stop doing our thing
  791. //
  792. m_dwError = GetLastError();
  793. m_dwError |= BMON_NOTIFY_ERROR;
  794. break;
  795. }
  796. } else {
  797. //
  798. // Actually let's take the general approach that the moment the
  799. // Backlog monitor sees trouble, it should stop. This avoids
  800. // low memory situations where the backlog monitor just spins,
  801. // thus becoming it's own denial of service attack.
  802. //
  803. m_dwError = WSAGetLastError();
  804. m_dwError |= BMON_SELECT_ERROR;
  805. break;
  806. DBGPRINTF(( DBG_CONTEXT,
  807. "Select failed with error %d\n",
  808. WSAGetLastError()
  809. ));
  810. }
  811. if ( m_fDoSleep )
  812. {
  813. //
  814. // Now sleep for a while. It will take time for unconnected to go away.
  815. // We don't want to spin
  816. //
  817. // Of course, this means we don't do useful work on any other endpoints
  818. // which may also be in trouble. Oh well.
  819. //
  820. Sleep( 5000 );
  821. m_fDoSleep = FALSE;
  822. }
  823. }
  824. m_fThreadFinished = TRUE;
  825. }
  826. VOID
  827. ATQ_BMON_SET::Wakeup(
  828. VOID
  829. )
  830. /*++
  831. Routine Description:
  832. We call this function when adding or removing
  833. an entry. Writing to the wakeup socket wakes
  834. up the select thread.
  835. Arguments:
  836. None
  837. Return Values:
  838. None
  839. --*/
  840. {
  841. SOCKADDR_IN sockAddr;
  842. INT err;
  843. DWORD dwBuf;
  844. ZeroMemory(&sockAddr, sizeof(sockAddr));
  845. sockAddr.sin_family = AF_INET;
  846. sockAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  847. sockAddr.sin_port = htons(m_Port);
  848. dwBuf = ATQ_BMON_WAKEUP_MESSAGE;
  849. err = sendto(
  850. m_pWakeupEntry->GetSocket(),
  851. (PCHAR)&dwBuf,
  852. sizeof(dwBuf),
  853. 0,
  854. (PSOCKADDR)&sockAddr,
  855. sizeof(sockAddr)
  856. );
  857. if ( err == SOCKET_ERROR ) {
  858. m_dwError = WSAGetLastError();
  859. m_dwError |= BMON_SENDTO_ERROR;
  860. DBGPRINTF((DBG_CONTEXT,
  861. "Error %d in sendto\n",WSAGetLastError()));
  862. }
  863. }
  864. BOOL
  865. ATQ_BMON_SET::SynchronizeSets(
  866. VOID
  867. )
  868. /*++
  869. Routine Description:
  870. This function updates our FD_SET to reflect
  871. what's in the entry set, and also notifies
  872. entries which have been added or removed.
  873. We also check to see if it's time to shut
  874. down (as indicated by the removal of the
  875. wakeup entry.
  876. Arguments:
  877. None
  878. Return Values:
  879. TRUE to continue operating
  880. FALSE on shutdown
  881. --*/
  882. {
  883. DWORD i;
  884. ATQ_BMON_ENTRY * pBmonEntry;
  885. BOOL bRetval;
  886. bRetval = TRUE;
  887. Lock();
  888. //
  889. // clear out whatever is there now
  890. //
  891. FD_ZERO(&m_ListenSet);
  892. //
  893. // put in everything we want
  894. //
  895. for (i = 0; i < FD_SETSIZE; i++) {
  896. pBmonEntry = m_apEntrySet[i];
  897. if (pBmonEntry) {
  898. DBG_ASSERT( pBmonEntry->CheckSignature() );
  899. switch(pBmonEntry->GetOpcode()) {
  900. case BMON_ADD:
  901. FD_SET(pBmonEntry->GetSocket(), &m_ListenSet);
  902. pBmonEntry->SetOpcode(BMON_WAIT);
  903. pBmonEntry->SignalAddRemove(NO_ERROR);
  904. break;
  905. case BMON_RESUME:
  906. FD_SET(pBmonEntry->GetSocket(), &m_ListenSet);
  907. pBmonEntry->SetOpcode(BMON_WAIT);
  908. break;
  909. case BMON_PAUSE:
  910. pBmonEntry->SetOpcode(BMON_NOWAIT);
  911. pBmonEntry->SignalAddRemove(NO_ERROR);
  912. break;
  913. case BMON_REMOVE:
  914. if (pBmonEntry == m_pWakeupEntry) {
  915. //
  916. // this means it's time to shut down
  917. //
  918. bRetval = FALSE;
  919. }
  920. m_apEntrySet[i] = NULL;
  921. m_SetSize--;
  922. pBmonEntry->SetContainingBmonSet(NULL);
  923. pBmonEntry->SignalAddRemove(NO_ERROR);
  924. break;
  925. case BMON_WAIT:
  926. FD_SET(pBmonEntry->GetSocket(), &m_ListenSet);
  927. break;
  928. case BMON_NOWAIT:
  929. //
  930. // this entry is paused, so don't do
  931. // anything
  932. //
  933. break;
  934. default:
  935. //
  936. // should never get here
  937. // remove the bad entry
  938. //
  939. DBGPRINTF((DBG_CONTEXT,
  940. "Invalid opcode in ATQ_BMON_ENTRY %p, %d\n",
  941. pBmonEntry, pBmonEntry->GetOpcode()));
  942. DBG_ASSERT(FALSE);
  943. m_apEntrySet[i] = NULL;
  944. break;
  945. }
  946. }
  947. }
  948. Unlock();
  949. return bRetval;
  950. }
  951. BOOL
  952. ATQ_BMON_SET::NotifyEntries(
  953. VOID
  954. )
  955. /*++
  956. Routine Description:
  957. This function looks through the entries
  958. to see who needs to be notified and calls
  959. their callback function.
  960. Arguments:
  961. None
  962. Return Values:
  963. TRUE if successful, else FALSE
  964. --*/
  965. {
  966. DWORD i;
  967. ATQ_BMON_ENTRY * pBmonEntry;
  968. BOOL fRet = TRUE;
  969. Lock();
  970. for (i = 0; i < FD_SETSIZE; i++) {
  971. pBmonEntry = m_apEntrySet[i];
  972. if (pBmonEntry) {
  973. if (!pBmonEntry->CheckSignature()) {
  974. DBGPRINTF(( DBG_CONTEXT,
  975. "ATQ_BMON_ENTRY(%p)::CheckSignature() failed. index = %d\n",
  976. pBmonEntry, i));
  977. DBG_ASSERT( pBmonEntry->CheckSignature() );
  978. }
  979. if ((pBmonEntry->GetOpcode() == BMON_WAIT)
  980. && (FD_ISSET(pBmonEntry->GetSocket(), &m_ListenSet))) {
  981. if ( !pBmonEntry->Callback() )
  982. {
  983. fRet = FALSE;
  984. break;
  985. }
  986. }
  987. }
  988. }
  989. Unlock();
  990. return fRet;
  991. }
  992. DWORD WINAPI
  993. BmonThreadFunc(
  994. LPVOID lpBmonSet
  995. )
  996. /*++
  997. Routine Description:
  998. This function starts the select thread
  999. of an ATQ_BMON_SET.
  1000. Arguments:
  1001. pBmonSet - the set to call
  1002. Return Values:
  1003. 0
  1004. --*/
  1005. {
  1006. ATQ_BMON_SET * pBmonSet = (ATQ_BMON_SET *) lpBmonSet;
  1007. pBmonSet->BmonThreadFunc();
  1008. return 0;
  1009. }
  1010. //
  1011. // atqbmon.cxx
  1012. //