|
|
//+-------------------------------------------------------------------
//
// File: addrrefresh.cxx
//
// Contents: Implements classes for handling dynamic TCP/IP address
// changes
//
// Classes: CAddrRefreshMgr
//
// History: 26-Oct-00 jsimmons Created
//
//--------------------------------------------------------------------
#include "act.hxx"
// The single instance of this object
CAddrRefreshMgr gAddrRefreshMgr;
// Constructor
CAddrRefreshMgr::CAddrRefreshMgr() : _hEventIPAddressChange(NULL), _hWaitObject(NULL), _IPChangeNotificationSocket(INVALID_SOCKET), _bWaitRegistered(FALSE), _bListenedOnTCP(FALSE), _bRegisteredForNotifications(FALSE) { ZeroMemory(&_WSAOverlapped, sizeof(_WSAOverlapped)); }
//
// RegisterForAddressChanges
//
// Method to tell us to register with the network
// stack to be notified of address changes. This is
// a best-effort, if it fails we simply return; if
// that happens, DCOM will not handle dynamic address
// changes. Once this method succeeds, calling it
// is a no-op until an address change notification
// is signalled.
//
// Caller must be holding gpClientLock.
//
void CAddrRefreshMgr::RegisterForAddressChanges() { ASSERT(gpClientLock->HeldExclusive()); // If we haven't yet listened on TCP, there is
// no point in any of this
if (!_bListenedOnTCP) return;
if (!_hEventIPAddressChange) { _hEventIPAddressChange = CreateEvent(NULL, FALSE, FALSE, NULL); if (!_hEventIPAddressChange) return; }
// We do not call WSAStartup, it is the responsibility of the caller
// to make sure WSAStartup has already been been called successfully.
// In practice, not calling this function until after we have
// successfully listened on TCP satisfies this requirement.
if (_IPChangeNotificationSocket == INVALID_SOCKET) { _IPChangeNotificationSocket = socket(AF_INET, SOCK_STREAM, 0); if (_IPChangeNotificationSocket == INVALID_SOCKET) { KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_WARNING_LEVEL, "Failed to create notification socket\n")); return; } }
// First make sure we have successfully registered for a
// wait on the notification event with the NT thread pool
if (!_bWaitRegistered) { _bWaitRegistered = RegisterWaitForSingleObject( &_hWaitObject, _hEventIPAddressChange, CAddrRefreshMgr::TimerCallbackFn, this, INFINITE, WT_EXECUTEINWAITTHREAD); if (!_bWaitRegistered) { KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_WARNING_LEVEL, "RegisterWaitForSingleObject failed\n")); return; } } // Setup the notification again if we failed to register last time,
// or if this is the first time we've ever been here
if (!_bRegisteredForNotifications) { // Initialize overlapped structure
ZeroMemory(&_WSAOverlapped, sizeof(_WSAOverlapped)); _WSAOverlapped.hEvent = _hEventIPAddressChange;
int err; DWORD dwByteCnt; err = WSAIoctl( _IPChangeNotificationSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &dwByteCnt, &_WSAOverlapped, NULL ); _bRegisteredForNotifications = (err == 0) || (WSAGetLastError() == WSA_IO_PENDING); if (!_bRegisteredForNotifications) { KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_WARNING_LEVEL, "Failed to request ip change notification on socket (WSAGetLastError=%u)\n", WSAGetLastError())); return; } }
// Success
KdPrintEx((DPFLTR_DCOMSS_ID, DPFLTR_INFO_LEVEL, "DCOM: successfully registered for address change notifications\n"));
return; }
//
// TimerCallbackFnHelper
//
// Helper function to handle address change notifications.
//
// Does the following tasks:
// 1) re-registers for further address changes
// 2) recomputes current resolver bindings
// 3) pushes new bindings to currently running processes; note
// that this is done async, so we don't tie up the thread.
//
void CAddrRefreshMgr::TimerCallbackFnHelper() { RPC_STATUS status;
gpClientLock->LockExclusive(); ASSERT(gpClientLock->HeldExclusive());
// The fact that we we got this callback means that our
// previous registration has been consumed. Remember
// that fact so we can re-register down below.
_bRegisteredForNotifications = FALSE;
// re-register for address changes. The ordering of when
// we do this and when we query for the new list is impt,
// see docs for WSAIoctl that talk about proper ordering
// of SIO_ADDRESS_LIST_CHANGE and SIO_ADDRESS_LIST_QUERY.
RegisterForAddressChanges();
// Tell machine address object that addresses have changed
gpMachineName->IPAddrsChanged();
// Compute new resolver bindings
status = ComputeNewResolverBindings();
// Release lock now, so we don't hold it across PushCurrentBindings
ASSERT(gpClientLock->HeldExclusive()); gpClientLock->UnlockExclusive();
if (status == RPC_S_OK) { // Push new bindings to running processes
PushCurrentBindings(); }
return; }
//
// TimerCallbackFn
//
// Static entry point that gets called by NT thread pool whenever
// our notification event is signalled.
//
void CALLBACK CAddrRefreshMgr::TimerCallbackFn(void* pvParam, BOOLEAN TimerOrWaitFired) { ASSERT(!TimerOrWaitFired); // should always be FALSE, ie event was signalled
CAddrRefreshMgr* pThis = (CAddrRefreshMgr*)pvParam;
ASSERT(pThis == &gAddrRefreshMgr); // should always be ptr to the singleton
pThis->TimerCallbackFnHelper(); }
|