/*++ Copyright (c) 1998 Microsoft Corporation Module Name: iphlpapi\rasmap.c Abstract: This module maps ras dial out and router names to friendly names. Revision History: AmritanR Created --*/ #include "inc.h" #pragma hdrstop #include LIST_ENTRY g_RasGuidHashTable[RAS_HASH_TABLE_SIZE]; LIST_ENTRY g_RasNameHashTable[RAS_HASH_TABLE_SIZE]; PRAS_INFO_TABLE g_pRasTable, g_pRouterTable; CRITICAL_SECTION g_RasTableLock; WCHAR g_rgwcRasServerIf[MAX_INTERFACE_NAME_LEN + 2]; ULONG g_ulRasServerIfSize; ULONG __inline RAS_NAME_HASH( IN PWCHAR pwszName ) { ULONG ulLen, ulNumChars, i, ulIndex = 0; ulLen = (ULONG)wcslen(pwszName); ulNumChars = ulLen < 6 ? ulLen : 6; ulLen--; for(i = 0; i < ulNumChars; i++) { ulIndex += pwszName[i]; ulIndex += pwszName[ulLen - i]; } return ulIndex % RAS_HASH_TABLE_SIZE; } DWORD InitRasNameMapper( VOID ) { ULONG i; for(i = 0; i < RAS_HASH_TABLE_SIZE; i ++) { InitializeListHead(&(g_RasNameHashTable[i])); InitializeListHead(&(g_RasGuidHashTable[i])); } __try { InitializeCriticalSection(&g_RasTableLock); } __except((GetExceptionCode() == STATUS_NO_MEMORY) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return ERROR_NOT_ENOUGH_MEMORY; } if(!LoadStringW(g_hModule, STRING_RAS_SERVER_INTERFACE, g_rgwcRasServerIf, MAX_INTERFACE_NAME_LEN + 1)) { return GetLastError(); } g_ulRasServerIfSize = (ULONG)(wcslen(g_rgwcRasServerIf) + 1) * sizeof(WCHAR); return NO_ERROR; } VOID DeinitRasNameMapper( VOID ) { ULONG i; for(i = 0; i < RAS_HASH_TABLE_SIZE; i ++) { while(!IsListEmpty(&(g_RasGuidHashTable[i]))) { PLIST_ENTRY pleNode; PRAS_NODE pRasNode; pleNode = RemoveHeadList(&(g_RasGuidHashTable[i])); pRasNode = CONTAINING_RECORD(pleNode, RAS_NODE, leGuidLink); RemoveEntryList(&(pRasNode->leNameLink)); HeapFree(g_hPrivateHeap, 0, pleNode); } } if(g_pRasTable) { HeapFree(g_hPrivateHeap, 0, g_pRasTable); g_pRasTable = NULL; } DeleteCriticalSection(&g_RasTableLock); } DWORD NhiGetPhonebookNameFromGuid( IN GUID *pGuid, OUT PWCHAR pwszBuffer, IN OUT PDWORD pdwBufferSize, IN BOOL bRefresh, IN BOOL bCache ) { DWORD dwResult, dwLength; PRAS_NODE pNode = NULL; WCHAR wszRouterPbk[MAX_PATH + RTL_NUMBER_OF(L"ras\router.pbk") + 2]; UNREFERENCED_PARAMETER(bCache); if(IsEqualGUID(pGuid, &GUID_IpRasServerInterface)) { if(*pdwBufferSize < g_ulRasServerIfSize) { *pdwBufferSize = g_ulRasServerIfSize; return ERROR_INSUFFICIENT_BUFFER; } wcscpy(pwszBuffer, g_rgwcRasServerIf); *pdwBufferSize = g_ulRasServerIfSize; return NO_ERROR; } // // Lock the table // EnterCriticalSection(&g_RasTableLock); // // Check if a refresh of the Ras Table is needed. // if((g_pRasTable is NULL) or bRefresh) { // // refresh the Ras Table cache // dwResult = RefreshRasCache(NULL, &g_pRasTable); // // Now lookup the table // pNode = LookupRasNodeByGuid(pGuid); } // // Check if a refresh of the Ras Router Table is needed. // if(((g_pRouterTable is NULL) and (pNode is NULL)) or bRefresh) { // // refresh the Router Table cache // ZeroMemory(wszRouterPbk, sizeof(wszRouterPbk)); GetSystemDirectoryW(wszRouterPbk, MAX_PATH + 1); wcscat(wszRouterPbk, L"\\ras\\router.pbk"); wszRouterPbk[MAX_PATH + 1] = 0; dwResult = RefreshRasCache(wszRouterPbk, &g_pRouterTable); // // Now lookup the table // pNode = LookupRasNodeByGuid(pGuid); } if(pNode is NULL) { LeaveCriticalSection(&g_RasTableLock); return ERROR_NOT_FOUND; } dwLength = (DWORD)(wcslen(pNode->rgwcName) + 1); if(*pdwBufferSize < dwLength) { *pdwBufferSize = dwLength; return ERROR_INSUFFICIENT_BUFFER; } wcscpy(pwszBuffer, pNode->rgwcName); LeaveCriticalSection(&g_RasTableLock); return NO_ERROR; } DWORD NhiGetGuidFromPhonebookName( IN PWCHAR pwszName, OUT GUID *pGuid, IN BOOL bRefresh, IN BOOL bCache ) { DWORD dwResult; PRAS_NODE pNode = NULL; UNREFERENCED_PARAMETER(bCache); if(_wcsicmp(pwszName, g_rgwcRasServerIf) == 0) { // // Structure copy // *pGuid = GUID_IpRasServerInterface; return NO_ERROR; } // // Lock the table // EnterCriticalSection(&g_RasTableLock); // // Check if a refresh of the Ras Table is needed. // if((g_pRasTable is NULL) or bRefresh) { // // refresh the Ras Table cache // dwResult = RefreshRasCache(NULL, &g_pRasTable); // // Now lookup the table // pNode = LookupRasNodeByGuid(pGuid); } // // Check if a refresh of the Ras Router Table is needed. // if(((g_pRouterTable is NULL) and (pNode is NULL)) or bRefresh) { // // refresh the Router Table cache // dwResult = RefreshRasCache(L"router.pbk", &g_pRouterTable); // // Now lookup the table // pNode = LookupRasNodeByGuid(pGuid); } if(pNode is NULL) { LeaveCriticalSection(&g_RasTableLock); return ERROR_NOT_FOUND; } *pGuid = pNode->Guid; LeaveCriticalSection(&g_RasTableLock); return NO_ERROR; } DWORD NhiGetPhonebookDescriptionFromGuid( IN GUID *pGuid, OUT PWCHAR pwszBuffer, IN OUT PULONG pulBufferSize, IN BOOL bCache, IN BOOL bRefresh ) { UNREFERENCED_PARAMETER(pGuid); UNREFERENCED_PARAMETER(pwszBuffer); UNREFERENCED_PARAMETER(pulBufferSize); UNREFERENCED_PARAMETER(bCache); UNREFERENCED_PARAMETER(bRefresh); return NO_ERROR; } DWORD RefreshRasCache( IN PWCHAR pwszPhonebook, IN OUT RAS_INFO_TABLE **ppTable ) /*++ Routine Description: This functions refreshes the ras cache for a given phonebook entry As a side effect, it also return the table of phonebook entries. It tries to overwrite the given table, if there is space, otherwise frees the given table and allocates a new table Locks: None needed. If the ppTable points to some global, then the function needs to be synchronized since it frees the table Arguments: pwszPhonebook ppTable Return Value: NO_ERROR ERROR_NOT_ENOUGH_MEMORY ERROR_CAN_NOT_COMPLETE --*/ { DWORD dwResult; ULONG ulSize; ULONG i, ulCount, ulCurrentCount; if(*ppTable is NULL) { // // If there is no table present, allocate the minimum // *ppTable = HeapAlloc(g_hPrivateHeap, 0, SIZEOF_RASTABLE(INIT_RAS_ENTRY_COUNT)); if(*ppTable is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } (*ppTable)->ulTotalCount = INIT_RAS_ENTRY_COUNT; } (*ppTable)->ulValidCount = 0; ulCurrentCount = (*ppTable)->ulTotalCount; i = 0; while(i < 3) { ulSize = (*ppTable)->ulTotalCount * sizeof(RASENUMENTRYDETAILS); (*ppTable)->rgEntries[0].dwSize = sizeof(RASENUMENTRYDETAILS); dwResult = DwEnumEntryDetails(pwszPhonebook, (*ppTable)->rgEntries, &ulSize, &ulCount); if(dwResult is NO_ERROR) { // // Things are good, update the hash table and move on // (*ppTable)->ulValidCount = ulCount; dwResult = UpdateRasLookupTable(*ppTable); if(dwResult isnot NO_ERROR) { // // Free the ras table so that we can try next time // HeapFree(g_hPrivateHeap, 0, *ppTable); *ppTable = NULL; return ERROR_CAN_NOT_COMPLETE; } break; } else { // // Free the old buffer // HeapFree(g_hPrivateHeap, 0, *ppTable); *ppTable = NULL; if(dwResult is ERROR_BUFFER_TOO_SMALL) { // // Go back and recalculate // See what size RAS required, add an overflow // ulCurrentCount += ulCount; *ppTable = HeapAlloc(g_hPrivateHeap, 0, SIZEOF_RASTABLE(ulCurrentCount)); if(*ppTable is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } (*ppTable)->ulTotalCount = ulCurrentCount; i++; } else { return dwResult; } } } return NO_ERROR; } DWORD UpdateRasLookupTable( IN PRAS_INFO_TABLE pTable ) /*++ Routine Description: Updates the fast lookup table for ras entries If even one fails, we bail out of the function Locks: Called with the RAS lock held Arguments: pTable Return Value: NO_ERROR --*/ { PRAS_NODE pNode; ULONG i; DWORD dwResult; // // Go through the entries in the phone book table and put them in // the hash table // for(i = 0; i < pTable->ulValidCount; i++) { pNode = LookupRasNodeByGuid(&(pTable->rgEntries[i].guidId)); if(!pNode) { dwResult = AddRasNode(&(pTable->rgEntries[i])); if(dwResult isnot NO_ERROR) { return dwResult; } } else { // // Node exists, if different remove and re-add // if(wcscmp(pNode->rgwcName, pTable->rgEntries[i].szEntryName) isnot 0) { RemoveRasNode(pNode); dwResult = AddRasNode(&(pTable->rgEntries[i])); if(dwResult isnot NO_ERROR) { return dwResult; } } } } return NO_ERROR; } PRAS_NODE LookupRasNodeByGuid( IN GUID *pGuid ) /*++ Routine Description: Looks up the ras node in the hash table Locks: Called with the ras table lock held Arguments: pGuid Guid for the node Return Value: RasNode if found NULL otherwise --*/ { ULONG ulIndex; PLIST_ENTRY pleNode; ulIndex = RAS_GUID_HASH(pGuid); for(pleNode = g_RasGuidHashTable[ulIndex].Flink; pleNode isnot &(g_RasGuidHashTable[ulIndex]); pleNode = pleNode->Flink) { PRAS_NODE pRasNode; pRasNode = CONTAINING_RECORD(pleNode, RAS_NODE, leGuidLink); if(IsEqualGUID(&(pRasNode->Guid), pGuid)) { return pRasNode; } } return NULL; } PRAS_NODE LookupRasNodeByName( IN PWCHAR pwszName ) /*++ Routine Description: Looks up the ras node in the hash table Locks: Called with the ras table lock held Arguments: pwszName Name of the phonebook entry Return Value: RasNode if found NULL otherwise --*/ { ULONG ulIndex; PLIST_ENTRY pleNode; ulIndex = RAS_NAME_HASH(pwszName); for(pleNode = g_RasNameHashTable[ulIndex].Flink; pleNode isnot &(g_RasNameHashTable[ulIndex]); pleNode = pleNode->Flink) { PRAS_NODE pRasNode; pRasNode = CONTAINING_RECORD(pleNode, RAS_NODE, leNameLink); if(_wcsicmp(pRasNode->rgwcName, pwszName) is 0) { return pRasNode; } } return NULL; } DWORD AddRasNode( IN LPRASENUMENTRYDETAILS pInfo ) /*++ Routine Description: Creates a node in the hash table for the given ras info Locks: Called with the RAS table lock held Arguments: pInfo Phonebook entry info Return Value: NO_ERROR ERROR_NOT_ENOUGH_MEMORY --*/ { ULONG ulGuidIndex, ulNameIndex; PRAS_NODE pRasNode; pRasNode = HeapAlloc(g_hPrivateHeap, 0, sizeof(RAS_NODE)); if(pRasNode is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pRasNode->Guid = pInfo->guidId; wcscpy(pRasNode->rgwcName, pInfo->szEntryName); ulGuidIndex = RAS_GUID_HASH(&(pInfo->guidId)); ulNameIndex = RAS_NAME_HASH(pInfo->szEntryName); InsertHeadList(&(g_RasGuidHashTable[ulGuidIndex]), &(pRasNode->leGuidLink)); InsertHeadList(&(g_RasNameHashTable[ulNameIndex]), &(pRasNode->leNameLink)); return NO_ERROR; } VOID RemoveRasNode( IN PRAS_NODE pNode ) /*++ Routine Description: Removes the given node from the hash tables Locks: Called with the RAS table lock held Arguments: pNode Node to remove Return Value: None --*/ { RemoveEntryList(&(pNode->leGuidLink)); RemoveEntryList(&(pNode->leNameLink)); }