windows-nt/Source/XPSP1/NT/net/tcpip/apis/iphlpapi/dll/rasmap.c
2020-09-26 16:20:57 +08:00

730 lines
14 KiB
C

/*++
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 <ifguid.h>
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 = 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]));
}
InitializeCriticalSection(&g_RasTableLock);
if(!LoadStringW(g_hModule,
STRING_RAS_SERVER_INTERFACE,
g_rgwcRasServerIf,
MAX_INTERFACE_NAME_LEN + 1))
{
return GetLastError();
}
g_ulRasServerIfSize = (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;
PRAS_NODE pNode = NULL;
WCHAR wszRouterPbk[MAX_PATH + 2];
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, (MAX_PATH + 2) * sizeof(WCHAR));
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;
}
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;
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
)
{
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));
}