/*++ Copyright(c) 2001 Microsoft Corporation Module Name: NLB Manager File Name: nlbhost.cpp Abstract: Implementation of class NLBHost NLBHost is responsible for connecting to an NLB host and getting/setting its NLB-related configuration. History: 03/31/01 JosephJ Created --*/ #include "stdafx.h" #include "private.h" // // Static members of class NLBHost. // WSADATA NLBHost::s_WsaData; LONG NLBHost::s_InstanceCount; BOOL NLBHost::s_FatalError; BOOL NLBHost::s_WsaInitialized; BOOL NLBHost::s_ComInitialized; IWbemStatusCodeTextPtr NLBHost::s_sp_werr; // Smart pointer VOID NLBHost::mfn_Log( UINT ID, ... ) { WCHAR wszBuffer[1024]; LPCWSTR pwszMessage; CString FormatString; if (!FormatString.LoadString(ID)) { wsprintf(wszBuffer, L"Error loading string resource ID %d", ID); } else { try { va_list arglist; va_start (arglist, ID); int cch = vswprintf(wszBuffer, FormatString, arglist); va_end (arglist); } catch(...) { wsprintf(wszBuffer, L"Exception writing out log entry for resource ID %d", ID); } } m_pfnLogger(m_pLoggerContext, wszBuffer); } VOID NLBHost::mfn_LogHr( LPCWSTR pwszMessage, HRESULT hr ) { if (s_sp_werr) { BSTR bstr1 = 0; BSTR bstr2 = 0; SCODE sc; sc = s_sp_werr->GetFacilityCodeText( hr, 0, 0, &bstr1 ); if( sc != S_OK ) { bstr2 = L"Unknown Error"; } sc = s_sp_werr->GetErrorCodeText( hr, 0, 0, &bstr2 ); if( sc != S_OK ) { bstr2 = L"Unknown Code"; } mfn_Log( L"%s %s: %s(hr=0x%08lx)", pwszMessage, (LPCWSTR) bstr1, (LPCWSTR) bstr2, hr ); SysFreeString( bstr1 ); SysFreeString( bstr2 ); } else { mfn_Log( L"%s (hr=0x%08lx)", pwszMessage, hr ); } } VOID NLBHost::mfn_Log( LPCWSTR pwszMessage, ... ) { WCHAR wszBuffer[1024]; wszBuffer[0] = 0; va_list arglist; va_start (arglist, pwszMessage); int cch = vswprintf(wszBuffer, pwszMessage, arglist); va_end (arglist); m_pfnLogger(m_pLoggerContext, wszBuffer); } NLBHost::NLBHost( const WCHAR * pBindString, const WCHAR * pFriendlyName, PFN_LOGGER pfnLogger, PVOID pLoggerContext ) /*++ Routine Description: Constructor for NLBHost. The constructor does not initiate any connections to the host. Connections to the host are initiated on demand (based on method calls). Arguments: pBindString - String used to connect to the remote host. pFriendlyName - Descriptive name of the host. Used for logging. pfnLogger - Function called to log textual information. pLoggerContext - Caller's context, passed in calls to pfnLogger --*/ { m_BindString = pBindString; // implicit copy m_FriendlyName = pFriendlyName; // implicit copy m_pfnLogger = pfnLogger; m_pLoggerContext = pLoggerContext; if (InterlockedIncrement(&s_InstanceCount) == 1) { mfn_InitializeStaticFields(); } InitializeCriticalSection(&m_Lock); mfn_Log( L"NLBHost(BindString=%s, FriendlyName=%s) constructor succeeded.", (LPCWSTR) pBindString, (LPCWSTR) pFriendlyName ); } NLBHost::~NLBHost() /*++ Routine Description: Destructor for NLBHost. --*/ { mfn_Log(L"NLBHost distructor(%s).", (LPCWSTR) m_FriendlyName); ASSERT(m_fProcessing == FALSE); // Shouldn't be doing any processing when // calling the distructor. if (InterlockedDecrement(&s_InstanceCount)==0) { mfn_DeinitializeStaticFields(); } DeleteCriticalSection(&m_Lock); } UINT NLBHost::Ping( VOID ) { if (s_FatalError) return ERROR_INTERNAL_ERROR; return mfn_ping(); } UINT NLBHost::GetHostInformation( OUT HostInformation **ppHostInfo ) { UINT Status; HostInformation *pHostInfo = new HostInformation; BOOL fConnected = FALSE; NicInformation NicInfo; if (s_FatalError) return ERROR_INTERNAL_ERROR; pHostInfo = new HostInformation; if (pHostInfo == NULL) { Status = ERROR_OUTOFMEMORY; goto end; } // // Connect to the host. // Status = mfn_connect(); if (!NLBH_SUCCESS(Status)) goto end; fConnected = TRUE; #if 0 // // Now find the instance and execute the method to get the host info. // mfn_find_host_instance(); ... stuff parameters ... mfn_execute_method(); #endif // pHostInfo->MachineName = L"ACME-Machine-Name"; NicInfo.fullNicName = L"ACME Full Nic Name"; NicInfo.adapterGuid = L"8829d17b-b0b7-4ce8-ba50-71af38792a6f"; NicInfo.friendlyName = L"ACME Friendly Name"; pHostInfo->nicInformation.push_back(NicInfo); NicInfo.fullNicName = L"ACME2 Full Nic Name"; NicInfo.adapterGuid = L"fa770233-31c3-4475-aa96-1190058d326a"; NicInfo.friendlyName = L"ACME2 Friendly Name"; pHostInfo->nicInformation.push_back(NicInfo); end: if (fConnected) { mfn_disconnect(); } if (!NLBH_SUCCESS(Status)) { if (pHostInfo != NULL) { delete pHostInfo; } pHostInfo = NULL; } *ppHostInfo = pHostInfo; return Status; } // // Configuration operations: // UINT NLBHost::GetClusterConfiguration( IN const WCHAR* pNicGuid, OUT PMGR_RAW_CLUSTER_CONFIGURATION pClusterConfig, OUT UINT * pGenerationId ) { if (s_FatalError) return ERROR_INTERNAL_ERROR; mfn_Log( L"NLBHost -- getting cluster configuration on NIC (%s).", pNicGuid ); *pGenerationId = 1; return 0; } UINT NLBHost::SetClusterConfiguration( IN const WCHAR * pNicGuid, IN const PMGR_RAW_CLUSTER_CONFIGURATION pClusterConfig, IN UINT GenerationId, OUT UINT * pRequestId ) { if (s_FatalError) return ERROR_INTERNAL_ERROR; mfn_Log( L"NLBHost -- setting cluster configuration on NIC (%s).", pNicGuid ); *pRequestId = 123; return STATUS_PENDING; } UINT NLBHost::GetAsyncResult( IN UINT RequestId, OUT UINT * pGenerationId, OUT UINT * pResultCode, OUT _bstr_t * pResultText ) { if (s_FatalError) return ERROR_INTERNAL_ERROR; mfn_Log( L"NLBHost -- checking result of Async operation %d\n", RequestId ); *pGenerationId = 1; *pResultCode = 1; *pResultText = L"Result"; return 0; } UINT NLBHost::mfn_connect( VOID ) { UINT Status = ERROR_INTERNAL_ERROR; HRESULT hr; _bstr_t serverPath; hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &m_sp_pwl); if (FAILED(hr)) { mfn_LogHr(L"CoCreateInstance IWebmLocator failed", hr); m_sp_pwl = NULL; goto end; } // serverPath = _bstr_t(L"\\\\") + m_BindString + L"\\root\\microsoftnlb"; hr = m_sp_pwl->ConnectServer( serverPath, NULL, // strUser, NULL, // strPassword, NULL, 0, NULL, NULL, &m_sp_pws ); // these have been found to be special cases where retrying may help. if( ( hr == 0x800706bf ) || ( hr == 0x80070767 ) || ( hr == 0x80070005 ) ) { int delay = 250; // milliseconds int timesToRetry = 20; for( int i = 0; i < timesToRetry; ++i ) { Sleep(delay); mfn_Log(L"connectserver recoverable failure, retrying."); hr = m_sp_pwl->ConnectServer( serverPath, NULL, // strUser, NULL, // strPassword, NULL, 0, NULL, NULL, &m_sp_pws ); if( !FAILED( hr) ) { break; } } } else if ( hr == 0x80041064 ) { // trying to connect to local machine. Cannot use credentials. mfn_Log(L"Connecting to self. Retrying without using credentials"); hr = m_sp_pwl->ConnectServer( serverPath, NULL, NULL, 0, NULL, 0, 0, &m_sp_pws ); } if (FAILED(hr)) { mfn_LogHr(L"Error connecting to server", hr); m_sp_pws = NULL; goto end; } else { mfn_Log(L"Successfully connected to server %s", serverPath); } // Set the proxy so that impersonation of the client occurs. // hr = CoSetProxyBlanket( m_sp_pws, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_NAME, COLE_DEFAULT_PRINCIPAL, // NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, COLE_DEFAULT_AUTHINFO, // NULL, EOAC_DEFAULT // EOAC_NONE ); if (FAILED(hr)) { mfn_LogHr(L"Error setting proxy blanket", hr); goto end; } else { mfn_Log(L"Successfully set up proxy settings."); } Status = ERROR_SUCCESS; end: if (!NLBH_SUCCESS(Status)) { if (m_sp_pws != NULL) { // Smart pointer. m_sp_pws = NULL; } if (m_sp_pwl != NULL) { // Smart pointer. m_sp_pwl = NULL; } } return Status; } VOID NLBHost::mfn_disconnect( VOID ) { mfn_Log(L"Disconnecting from host %s", m_BindString); if (m_sp_pws != NULL) { // Smart pointer m_sp_pws = NULL; } if (m_sp_pwl != NULL) { // Smart pointer m_sp_pwl = NULL; } } VOID NLBHost::mfn_InitializeStaticFields( VOID ) { s_FatalError = TRUE; // Initialize com. // HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED); if ( FAILED(hr) ) { mfn_Log(L"Failed to initialize COM library (hr=0x%08lx)", hr); goto end; } s_ComInitialized = TRUE; // // Initialize Winsock // int err = WSAStartup(MAKEWORD(2,2), &s_WsaData); mfn_Log(L"Initializing Winsock"); err = WSAStartup(MAKEWORD(2,2), &s_WsaData); if (err) { mfn_Log(L"PING_WSASTARTUP_FAILED %d", GetLastError()); goto end; } s_WsaInitialized = TRUE; s_FatalError = FALSE; // // Get some WMI interface pointers... // SCODE sc = CoCreateInstance( CLSID_WbemStatusCodeText, 0, CLSCTX_INPROC_SERVER, IID_IWbemStatusCodeText, (LPVOID *) &s_sp_werr ); if( sc != S_OK ) { s_sp_werr = NULL; mfn_Log(L"CoCreateInstance IWbemStatusCodeText failure\n"); } end: if (s_FatalError) { mfn_DeinitializeStaticFields(); } } VOID NLBHost::mfn_DeinitializeStaticFields( VOID ) { if (s_sp_werr != NULL) { s_sp_werr = NULL; // Smart pointer } if (s_WsaInitialized) { mfn_Log(L"Deinitializing Winsock"); WSACleanup(); s_WsaInitialized = FALSE; } if (s_ComInitialized) { mfn_Log(L"Deinitializing COM"); CoUninitialize(); s_ComInitialized = FALSE; } }