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.

202 lines
5.4 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: addrrefresh.cxx
  4. //
  5. // Contents: Implements classes for handling dynamic TCP/IP address
  6. // changes
  7. //
  8. // Classes: CAddrRefreshMgr
  9. //
  10. // History: 26-Oct-00 jsimmons Created
  11. //
  12. //--------------------------------------------------------------------
  13. #include "act.hxx"
  14. // The single instance of this object
  15. CAddrRefreshMgr gAddrRefreshMgr;
  16. // Constructor
  17. CAddrRefreshMgr::CAddrRefreshMgr() :
  18. _hEventIPAddressChange(NULL),
  19. _hWaitObject(NULL),
  20. _IPChangeNotificationSocket(INVALID_SOCKET),
  21. _bWaitRegistered(FALSE),
  22. _bListenedOnTCP(FALSE),
  23. _bRegisteredForNotifications(FALSE)
  24. {
  25. ZeroMemory(&_WSAOverlapped, sizeof(_WSAOverlapped));
  26. }
  27. //
  28. // RegisterForAddressChanges
  29. //
  30. // Method to tell us to register with the network
  31. // stack to be notified of address changes. This is
  32. // a best-effort, if it fails we simply return; if
  33. // that happens, DCOM will not handle dynamic address
  34. // changes. Once this method succeeds, calling it
  35. // is a no-op until an address change notification
  36. // is signalled.
  37. //
  38. // Caller must be holding gpClientLock.
  39. //
  40. void CAddrRefreshMgr::RegisterForAddressChanges()
  41. {
  42. ASSERT(gpClientLock->HeldExclusive());
  43. // If we haven't yet listened on TCP, there is
  44. // no point in any of this
  45. if (!_bListenedOnTCP)
  46. return;
  47. if (!_hEventIPAddressChange)
  48. {
  49. _hEventIPAddressChange = CreateEvent(NULL, FALSE, FALSE, NULL);
  50. if (!_hEventIPAddressChange)
  51. return;
  52. }
  53. // We do not call WSAStartup, it is the responsibility of the caller
  54. // to make sure WSAStartup has already been been called successfully.
  55. // In practice, not calling this function until after we have
  56. // successfully listened on TCP satisfies this requirement.
  57. if (_IPChangeNotificationSocket == INVALID_SOCKET)
  58. {
  59. _IPChangeNotificationSocket = socket(AF_INET, SOCK_STREAM, 0);
  60. if (_IPChangeNotificationSocket == INVALID_SOCKET)
  61. {
  62. KdPrintEx((DPFLTR_DCOMSS_ID,
  63. DPFLTR_WARNING_LEVEL,
  64. "Failed to create notification socket\n"));
  65. return;
  66. }
  67. }
  68. // First make sure we have successfully registered for a
  69. // wait on the notification event with the NT thread pool
  70. if (!_bWaitRegistered)
  71. {
  72. _bWaitRegistered = RegisterWaitForSingleObject(
  73. &_hWaitObject,
  74. _hEventIPAddressChange,
  75. CAddrRefreshMgr::TimerCallbackFn,
  76. this,
  77. INFINITE,
  78. WT_EXECUTEINWAITTHREAD);
  79. if (!_bWaitRegistered)
  80. {
  81. KdPrintEx((DPFLTR_DCOMSS_ID,
  82. DPFLTR_WARNING_LEVEL,
  83. "RegisterWaitForSingleObject failed\n"));
  84. return;
  85. }
  86. }
  87. // Setup the notification again if we failed to register last time,
  88. // or if this is the first time we've ever been here
  89. if (!_bRegisteredForNotifications)
  90. {
  91. // Initialize overlapped structure
  92. ZeroMemory(&_WSAOverlapped, sizeof(_WSAOverlapped));
  93. _WSAOverlapped.hEvent = _hEventIPAddressChange;
  94. int err;
  95. DWORD dwByteCnt;
  96. err = WSAIoctl(
  97. _IPChangeNotificationSocket,
  98. SIO_ADDRESS_LIST_CHANGE,
  99. NULL,
  100. 0,
  101. NULL,
  102. 0,
  103. &dwByteCnt,
  104. &_WSAOverlapped,
  105. NULL
  106. );
  107. _bRegisteredForNotifications = (err == 0) || (WSAGetLastError() == WSA_IO_PENDING);
  108. if (!_bRegisteredForNotifications)
  109. {
  110. KdPrintEx((DPFLTR_DCOMSS_ID,
  111. DPFLTR_WARNING_LEVEL,
  112. "Failed to request ip change notification on socket (WSAGetLastError=%u)\n",
  113. WSAGetLastError()));
  114. return;
  115. }
  116. }
  117. // Success
  118. KdPrintEx((DPFLTR_DCOMSS_ID,
  119. DPFLTR_INFO_LEVEL,
  120. "DCOM: successfully registered for address change notifications\n"));
  121. return;
  122. }
  123. //
  124. // TimerCallbackFnHelper
  125. //
  126. // Helper function to handle address change notifications.
  127. //
  128. // Does the following tasks:
  129. // 1) re-registers for further address changes
  130. // 2) recomputes current resolver bindings
  131. // 3) pushes new bindings to currently running processes; note
  132. // that this is done async, so we don't tie up the thread.
  133. //
  134. void CAddrRefreshMgr::TimerCallbackFnHelper()
  135. {
  136. RPC_STATUS status;
  137. gpClientLock->LockExclusive();
  138. ASSERT(gpClientLock->HeldExclusive());
  139. // The fact that we we got this callback means that our
  140. // previous registration has been consumed. Remember
  141. // that fact so we can re-register down below.
  142. _bRegisteredForNotifications = FALSE;
  143. // re-register for address changes. The ordering of when
  144. // we do this and when we query for the new list is impt,
  145. // see docs for WSAIoctl that talk about proper ordering
  146. // of SIO_ADDRESS_LIST_CHANGE and SIO_ADDRESS_LIST_QUERY.
  147. RegisterForAddressChanges();
  148. // Tell machine address object that addresses have changed
  149. gpMachineName->IPAddrsChanged();
  150. // Compute new resolver bindings
  151. status = ComputeNewResolverBindings();
  152. // Release lock now, so we don't hold it across PushCurrentBindings
  153. ASSERT(gpClientLock->HeldExclusive());
  154. gpClientLock->UnlockExclusive();
  155. if (status == RPC_S_OK)
  156. {
  157. // Push new bindings to running processes
  158. PushCurrentBindings();
  159. }
  160. return;
  161. }
  162. //
  163. // TimerCallbackFn
  164. //
  165. // Static entry point that gets called by NT thread pool whenever
  166. // our notification event is signalled.
  167. //
  168. void CALLBACK CAddrRefreshMgr::TimerCallbackFn(void* pvParam, BOOLEAN TimerOrWaitFired)
  169. {
  170. ASSERT(!TimerOrWaitFired); // should always be FALSE, ie event was signalled
  171. CAddrRefreshMgr* pThis = (CAddrRefreshMgr*)pvParam;
  172. ASSERT(pThis == &gAddrRefreshMgr); // should always be ptr to the singleton
  173. pThis->TimerCallbackFnHelper();
  174. }