#include #include #include #include #include #include #include #include #include #include #include #define NM_WCSLEN(_string) ((lstrlenW(_string) + 1) * sizeof(WCHAR)) CLNET_CONFIG_LISTS ConfigLists; LPWSTR NodeName = L"TestComputer"; LPWSTR NodeId = L"1"; #if 0 #include #include HKEY DmpRoot; LIST_ENTRY KeyList; CRITICAL_SECTION KeyLock; HDMKEY DmClusterParametersKey; HDMKEY DmResourcesKey; HDMKEY DmResourceTypesKey; HDMKEY DmGroupsKey; HDMKEY DmNodesKey; HDMKEY DmNetworksKey; HDMKEY DmNetInterfacesKey; HDMKEY DmQuorumKey; HANDLE ghQuoLogOpenEvent=NULL; typedef struct _DMP_KEY_DEF { HDMKEY *pKey; LPWSTR Name; } DMP_KEY_DEF; DMP_KEY_DEF DmpKeyTable[] = { {&DmResourcesKey, CLUSREG_KEYNAME_RESOURCES}, {&DmResourceTypesKey, CLUSREG_KEYNAME_RESOURCE_TYPES}, {&DmQuorumKey, CLUSREG_KEYNAME_QUORUM}, {&DmGroupsKey, CLUSREG_KEYNAME_GROUPS}, {&DmNodesKey, CLUSREG_KEYNAME_NODES}, {&DmNetworksKey, CLUSREG_KEYNAME_NETWORKS}, {&DmNetInterfacesKey, CLUSREG_KEYNAME_NETINTERFACES}}; #endif VOID ClNetPrint( IN ULONG LogLevel, IN PCHAR FormatString, ... ) { CHAR buffer[256]; DWORD bytes; va_list argList; va_start(argList, FormatString); bytes = FormatMessageA( FORMAT_MESSAGE_FROM_STRING, FormatString, 0, 0, buffer, sizeof(buffer), &argList ); va_end(argList); if (bytes != 0) { printf("%s", buffer); } return; } // ClNetPrint VOID ClNetLogEvent( IN DWORD LogLevel, IN DWORD MessageId ) { return; } // ClNetLogEvent VOID ClNetLogEvent1( IN DWORD LogLevel, IN DWORD MessageId, IN LPCWSTR Arg1 ) { return; } // ClNetLogEvent1 VOID ClNetLogEvent2( IN DWORD LogLevel, IN DWORD MessageId, IN LPCWSTR Arg1, IN LPCWSTR Arg2 ) { return; } // ClNetLogEvent2 VOID ClNetLogEvent3( IN DWORD LogLevel, IN DWORD MessageId, IN LPCWSTR Arg1, IN LPCWSTR Arg2, IN LPCWSTR Arg3 ) { return; } // ClNetLogEvent3 void PrintConfigEntry( PCLNET_CONFIG_ENTRY ConfigEntry ) { PNM_NETWORK_INFO Network = &(ConfigEntry->NetworkInfo); PNM_INTERFACE_INFO Interface = &(ConfigEntry->InterfaceInfo); printf("\t*************\n"); printf("\tNet Id\t\t%ws\n", Network->Id); printf("\tName\t\t%ws\n", Network->Name); printf("\tDesc\t\t%ws\n", Network->Description); printf("\tRole\t\t%u\n", Network->Role); printf("\tPriority\t%u\n", Network->Priority); printf("\tTransport\t%ws\n", Network->Transport); printf("\tAddress\t\t%ws\n", Network->Address); printf("\tMask\t\t%ws\n", Network->AddressMask); printf("\tIf Id\t\t%ws\n", Interface->Id); printf("\tName\t\t%ws\n", Interface->Name); printf("\tDesc\t\t%ws\n", Interface->Description); printf("\tNodeId\t\t%ws\n", Interface->NodeId); printf("\tAdapter\t\t%ws\n", Interface->Adapter); printf("\tAddress\t\t%ws\n", Interface->Address); printf("\tEndpoint\t%ws\n", Interface->ClusnetEndpoint); printf("\tState\t\t%u\n\n", Interface->State); return; } void PrintResults(void) { PCLNET_CONFIG_ENTRY configEntry; PLIST_ENTRY listEntry; printf("Renamed interface list:\n"); for ( listEntry = ConfigLists.RenamedInterfaceList.Flink; listEntry != &ConfigLists.RenamedInterfaceList; listEntry = listEntry->Flink ) { configEntry = CONTAINING_RECORD( listEntry, CLNET_CONFIG_ENTRY, Linkage ); PrintConfigEntry(configEntry); } printf("Deleted interface list:\n"); for ( listEntry = ConfigLists.DeletedInterfaceList.Flink; listEntry != &ConfigLists.DeletedInterfaceList; listEntry = listEntry->Flink ) { configEntry = CONTAINING_RECORD( listEntry, CLNET_CONFIG_ENTRY, Linkage ); PrintConfigEntry(configEntry); } printf("Updated interface list:\n"); for ( listEntry = ConfigLists.UpdatedInterfaceList.Flink; listEntry != &ConfigLists.UpdatedInterfaceList; listEntry = listEntry->Flink ) { configEntry = CONTAINING_RECORD( listEntry, CLNET_CONFIG_ENTRY, Linkage ); PrintConfigEntry(configEntry); } printf("Created interface list:\n"); for ( listEntry = ConfigLists.CreatedInterfaceList.Flink; listEntry != &ConfigLists.CreatedInterfaceList; listEntry = listEntry->Flink ) { configEntry = CONTAINING_RECORD( listEntry, CLNET_CONFIG_ENTRY, Linkage ); PrintConfigEntry(configEntry); } printf("Created network list:\n"); for ( listEntry = ConfigLists.CreatedNetworkList.Flink; listEntry != &ConfigLists.CreatedNetworkList; listEntry = listEntry->Flink ) { configEntry = CONTAINING_RECORD( listEntry, CLNET_CONFIG_ENTRY, Linkage ); PrintConfigEntry(configEntry); } printf("Unchanged interface list:\n"); for ( listEntry = ConfigLists.InputConfigList.Flink; listEntry != &ConfigLists.InputConfigList; listEntry = listEntry->Flink ) { configEntry = CONTAINING_RECORD( listEntry, CLNET_CONFIG_ENTRY, Linkage ); PrintConfigEntry(configEntry); } return; } void ConsolidateLists( PLIST_ENTRY MasterList, PLIST_ENTRY OtherList ) { PLIST_ENTRY entry; while (!IsListEmpty(OtherList)) { entry = RemoveHeadList(OtherList); InsertTailList(MasterList, entry); } return; } #if 0 DWORD DmpOpenKeys( IN REGSAM samDesired ) /*++ Routine Description: Opens all the standard cluster registry keys. If any of the keys are already opened, they will be closed and reopened. Arguments: samDesired - Supplies the access that the keys will be opened with. Return Value: ERROR_SUCCESS if successful. Win32 error code otherwise. --*/ { DWORD i; DWORD status; status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Cluster", 0, samDesired, &ClusterRegKey); if ( status == ERROR_SUCCESS ) { for (i=0; iName) + 1 + lstrlenW(lpSubKey) + 1)*sizeof(WCHAR); Key = LocalAlloc(LMEM_FIXED, sizeof(DMKEY)+NameLength); if (Key == NULL) { Status = ERROR_NOT_ENOUGH_MEMORY; CL_UNEXPECTED_ERROR(Status); goto FnExit; } // // Open the key on the local machine. // Status = RegOpenKeyEx(Parent->hKey, lpSubKey, 0, samDesired, &Key->hKey); if (Status != ERROR_SUCCESS) { goto FnExit; } // // Create the key name // lstrcpyW(Key->Name, Parent->Name); if (Key->Name[0] != UNICODE_NULL) { lstrcatW(Key->Name, L"\\"); } lstrcatW(Key->Name, lpSubKey); Key->GrantedAccess = samDesired; EnterCriticalSection(&KeyLock); InsertHeadList(&KeyList, &Key->ListEntry); InitializeListHead(&Key->NotifyList); LeaveCriticalSection(&KeyLock); FnExit: if (Status != ERROR_SUCCESS) { if (Key) LocalFree(Key); SetLastError(Status); return(NULL); } else return((HDMKEY)Key); } DWORD NmpQueryString( IN HDMKEY Key, IN LPCWSTR ValueName, IN DWORD ValueType, IN LPWSTR *StringBuffer, IN OUT LPDWORD StringBufferSize, OUT LPDWORD StringSize ) /*++ Routine Description: Reads a REG_SZ or REG_MULTI_SZ registry value. If the StringBuffer is not large enough to hold the data, it is reallocated. Arguments: Key - Open key for the value to be read. ValueName - Unicode name of the value to be read. ValueType - REG_SZ or REG_MULTI_SZ. StringBuffer - Buffer into which to place the value data. StringBufferSize - Pointer to the size of the StringBuffer. This parameter is updated if StringBuffer is reallocated. StringSize - The size of the data returned in StringBuffer, including the terminating null character. Return Value: The status of the registry query. --*/ { DWORD status; DWORD valueType; WCHAR *temp; DWORD oldBufferSize = *StringBufferSize; BOOL noBuffer = FALSE; if (*StringBufferSize == 0) { noBuffer = TRUE; } *StringSize = *StringBufferSize; status = DmQueryValue( Key, ValueName, &valueType, (LPBYTE) *StringBuffer, StringSize ); if (status == NO_ERROR) { if (!noBuffer ) { if (valueType == ValueType) { return(NO_ERROR); } else { return(ERROR_INVALID_PARAMETER); } } status = ERROR_MORE_DATA; } if (status == ERROR_MORE_DATA) { temp = MIDL_user_allocate(*StringSize); if (temp == NULL) { *StringSize = 0; return(ERROR_NOT_ENOUGH_MEMORY); } if (!noBuffer) { MIDL_user_free(*StringBuffer); } *StringBuffer = temp; *StringBufferSize = *StringSize; status = DmQueryValue( Key, ValueName, &valueType, (LPBYTE) *StringBuffer, StringSize ); if (status == NO_ERROR) { if (valueType == ValueType) { return(NO_ERROR); } else { *StringSize = 0; return(ERROR_INVALID_PARAMETER); } } } return(status); } // NmpQueryString DWORD NmpGetNetworkDefinition( IN LPWSTR NetworkId, OUT PNM_NETWORK_INFO NetworkInfo ) /*++ Routine Description: Reads information about a defined cluster network from the cluster database and fills in a structure describing it. Arguments: NetworkId - A pointer to a unicode string containing the ID of the network to query. NetworkInfo - A pointer to the network info structure to fill in. Return Value: ERROR_SUCCESS if the routine succeeds. A Win32 error code otherwise. --*/ { DWORD status; HDMKEY networkKey = NULL; DWORD valueLength, valueSize; DWORD i; PNM_INTERFACE_ENUM interfaceEnum; ZeroMemory(NetworkInfo, sizeof(NM_NETWORK_INFO)); // // Open the network's key. // networkKey = DmOpenKey(DmNetworksKey, NetworkId, KEY_READ); if (networkKey == NULL) { status = GetLastError(); ClNetPrint(LOG_CRITICAL, "[NM] Failed to open network key, status %1!u!\n", status ); goto error_exit; } // // Copy the ID value. // NetworkInfo->Id = MIDL_user_allocate(NM_WCSLEN(NetworkId)); if (NetworkInfo->Id == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto error_exit; } wcscpy(NetworkInfo->Id, NetworkId); // // Read the network's name. // valueLength = 0; status = NmpQueryString( networkKey, CLUSREG_NAME_NET_NAME, REG_SZ, &(NetworkInfo->Name), &valueLength, &valueSize ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of name value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } // // Read the description value. // valueLength = 0; status = NmpQueryString( networkKey, CLUSREG_NAME_NET_DESC, REG_SZ, &(NetworkInfo->Description), &valueLength, &valueSize ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of description value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } // // Read the role value. // status = DmQueryDword( networkKey, CLUSREG_NAME_NET_ROLE, &(NetworkInfo->Role), NULL ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of role value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } // // Read the priority value. // status = DmQueryDword( networkKey, CLUSREG_NAME_NET_PRIORITY, &(NetworkInfo->Priority), NULL ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of priority value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } // // Read the address value. // valueLength = 0; status = NmpQueryString( networkKey, CLUSREG_NAME_NET_ADDRESS, REG_SZ, &(NetworkInfo->Address), &valueLength, &valueSize ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of address value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } // // Read the address mask. // valueLength = 0; status = NmpQueryString( networkKey, CLUSREG_NAME_NET_ADDRESS_MASK, REG_SZ, &(NetworkInfo->AddressMask), &valueLength, &valueSize ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of address mask value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } // // Read the transport name. // valueLength = 0; status = NmpQueryString( networkKey, CLUSREG_NAME_NET_TRANSPORT, REG_SZ, &(NetworkInfo->Transport), &valueLength, &valueSize ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Query of transport value failed for network %1!ws!, status %2!u!.\n", NetworkId, status ); goto error_exit; } error_exit: if (status != ERROR_SUCCESS) { ClNetFreeNetworkInfo(NetworkInfo); } if (networkKey != NULL) { DmCloseKey(networkKey); } return(status); } // NmpGetNetworkDefinition DWORD NmpEnumNetworkDefinitions( OUT PNM_NETWORK_ENUM * NetworkEnum ) /*++ Routine Description: Reads information about defined cluster networks from the cluster database. and builds an enumeration structure to hold the information. Arguments: NetworkEnum - A pointer to the variable into which to place a pointer to the allocated network enumeration. Return Value: ERROR_SUCCESS if the routine succeeds. A Win32 error code otherwise. --*/ { DWORD status; PNM_NETWORK_ENUM networkEnum = NULL; PNM_NETWORK_INFO networkInfo; WCHAR networkId[CS_NETWORK_ID_LENGTH + 1]; DWORD i; DWORD valueLength; DWORD numNetworks; DWORD ignored; FILETIME fileTime; *NetworkEnum = NULL; // // First count the number of networks. // status = DmQueryInfoKey( DmNetworksKey, &numNetworks, &ignored, // MaxSubKeyLen &ignored, // Values &ignored, // MaxValueNameLen &ignored, // MaxValueLen &ignored, // lpcbSecurityDescriptor &fileTime ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Failed to query Networks key information, status %1!u!\n", status ); return(status); } if (numNetworks == 0) { valueLength = sizeof(NM_NETWORK_ENUM); } else { valueLength = sizeof(NM_NETWORK_ENUM) + (sizeof(NM_NETWORK_INFO) * (numNetworks-1)); } valueLength = sizeof(NM_NETWORK_ENUM) + (sizeof(NM_NETWORK_INFO) * (numNetworks-1)); networkEnum = MIDL_user_allocate(valueLength); if (networkEnum == NULL) { ClNetPrint(LOG_CRITICAL, "[NM] Failed to allocate memory.\n"); return(ERROR_NOT_ENOUGH_MEMORY); } ZeroMemory(networkEnum, valueLength); for (i=0; i < numNetworks; i++) { networkInfo = &(networkEnum->NetworkList[i]); valueLength = sizeof(networkId); status = DmEnumKey( DmNetworksKey, i, &(networkId[0]), &valueLength, NULL ); if (status != ERROR_SUCCESS) { ClNetPrint(LOG_CRITICAL, "[NM] Failed to enumerate network key, status %1!u!\n", status ); goto error_exit; } status = NmpGetNetworkDefinition(networkId, networkInfo); if (status != ERROR_SUCCESS) { goto error_exit; } networkEnum->NetworkCount++; } *NetworkEnum = networkEnum; return(ERROR_SUCCESS); error_exit: if (networkEnum != NULL) { ClNetFreeNetworkEnum(networkEnum); } return(status); } DWORD ReadRegData( IN PCLNET_CONFIG_LISTS Lists ) /*++ Read the cluster registry data and bulid up an input list similar to what happens in the cluster service. --*/ { DWORD status; PNM_NETWORK_ENUM * networkEnum; PNM_INTERFACE_ENUM * interfaceEnum; LPWSTR localNodeId; status = DmpOpenKeys(MAXIMUM_ALLOWED); if (status != ERROR_SUCCESS) { CL_UNEXPECTED_ERROR( status ); return(status); } status = ClNetConvertEnumsToConfigList(networkEnum, interfaceEnum, localNodeId, &Lists->InputConfigList); return status; } #endif int _cdecl main( int argc, char** argv ) { DWORD status; DWORD i; WSADATA wsaData; WORD versionRequested; int err; SOCKET s; DWORD bytesReturned; DWORD matchedNetworkCount; DWORD newNetworkCount; ClNetInitialize( ClNetPrint, ClNetLogEvent, ClNetLogEvent1, ClNetLogEvent2, ClNetLogEvent3 ); ClNetInitializeConfigLists(&ConfigLists); // ReadRegData( &ConfigLists ); versionRequested = MAKEWORD(2,0); err = WSAStartup(versionRequested, &wsaData); if (err != 0) { status = WSAGetLastError(); printf("wsastartup failed, %u\n", status); return(1); } s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { status = WSAGetLastError(); printf("socket failed, %u\n", status); return(1); } // // Init COM // status = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED ); if ( !SUCCEEDED( status )) { printf("Couldn't init COM %08X\n", status ); return 1; } for (i=0; ; i++) { printf("\nIteration #%u\n\n", i); status = ClNetConfigureNetworks( NodeId, NodeName, L"4303", TRUE, &ConfigLists, &matchedNetworkCount, &newNetworkCount ); if (status != ERROR_SUCCESS) { printf("Config failed, status %u\n", status); return(1); } printf("Config succeeded - matched Networks = %u, new Networks = %u\n\n", matchedNetworkCount, newNetworkCount); PrintResults(); ClNetFreeConfigList(&ConfigLists.RenamedInterfaceList); ClNetFreeConfigList(&ConfigLists.DeletedInterfaceList); ConsolidateLists( &ConfigLists.InputConfigList, &ConfigLists.UpdatedInterfaceList ); ConsolidateLists( &ConfigLists.InputConfigList, &ConfigLists.CreatedInterfaceList ); ConsolidateLists( &ConfigLists.InputConfigList, &ConfigLists.CreatedNetworkList ); printf("Waiting for PnP event\n"); err = WSAIoctl( s, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &bytesReturned, NULL, NULL ); if (err != 0) { status = WSAGetLastError(); printf("wsastartup failed, %u\n", status); return(1); } printf("PnP notification received\n"); } CoUninitialize(); return(0); }