|
|
/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
ipname.cxx
Abstract:
Miscellaneous helper routines to resolve names to IP Addresses.
Author:
Gopal Parupudi <GopalP>
Notes:
a. Class IP_ADDRESS_RESOLVER cloned from RPC Runtime Transport sources (rpc\runtime\trans\winnt\common\wstrans.cxx).
Revision History:
GopalP 10/13/1997 Start.
--*/
#include <precomp.hxx>
#define BACKSLASH ((SENS_CHAR) '\\')
#define HTTP_PREFIX1 (SENS_STRING("http://"))
#define HTTP_PREFIX2 (SENS_STRING("http:\\\\"))
#define HTTP_PREFIX_LEN 7
BOOL GetNetBIOSName( IN TCHAR *ActualName, IN OUT TCHAR *SanitizedName, IN SIZE_T cchName ) /*++
Routine Description:
Sanitize the name of the destination to make it more suitable for name resolution.
Arguments:
ActualName - Original Name of the destination.
SanitizedName - On return, this contains the sanitized version of the Actual Name. Memory is allocated by the caller.
Return Value:
TRUE, if successful.
FALSE, if the address if the address in invalid.
--*/ { TCHAR *pchTemp;
//
// Remove the leading \\ characters, if present.
//
pchTemp = ActualName; if (*pchTemp == BACKSLASH) { // Check for another slash
if (*++pchTemp == BACKSLASH) { if (NULL != _tcschr(++pchTemp, BACKSLASH)) { // Found yet another slash!
return FALSE; }
StringCchCopy(SanitizedName, cchName, pchTemp);
return TRUE; } else { return FALSE; } }
//
// Remove the "http://" prefix, if present.
//
pchTemp = ActualName; if ( (_tcsnicmp(HTTP_PREFIX1, ActualName, HTTP_PREFIX_LEN) == 0) || (_tcsnicmp(HTTP_PREFIX2, ActualName, HTTP_PREFIX_LEN) == 0)) { StringCchCopy(SanitizedName, cchName, (pchTemp + HTTP_PREFIX_LEN));
return TRUE; }
StringCchCopy(SanitizedName, cchName, pchTemp);
return TRUE; }
DWORD ResolveName( IN TCHAR *lpszDestination, OUT LPDWORD lpdwIpAddr ) /*++
Routine Description:
Resolve the destination name to its IP Address.
Arguments:
lpszDestination - Name of the destination of interest.
lpdwIpAddr - On success, this contains the IP Address of the destination.
Note:
Since this function depends on Winsock2 being loaded, there are 2 different implementations - one for Win9x and one for NT.
Return Value:
ERROR_SUCCESS, if successful
Error code from GetLastError(), otherwise
--*/ { RPC_STATUS status; TCHAR *lpszSanitizedName; DWORD dwReturnCode; DWORD bufsize; PVOID buf; BOOL bSuccess;
if ( (lpdwIpAddr == NULL) || (lpszDestination == NULL)) { return ERROR_INVALID_PARAMETER; }
*lpdwIpAddr = 0x0; lpszSanitizedName = NULL; dwReturnCode = ERROR_HOST_UNREACHABLE; bSuccess = FALSE;
lpszSanitizedName = new TCHAR[_tcslen(lpszDestination)+1]; if (!lpszSanitizedName) { return (ERROR_OUTOFMEMORY); }
bSuccess = GetNetBIOSName(lpszDestination, lpszSanitizedName, _tcslen(lpszDestination)+1); if (bSuccess == FALSE) { SensPrint(SENS_INFO, (SENS_STRING("Bad format for destination name - %s\n"), lpszDestination)); delete lpszSanitizedName; return (ERROR_INVALID_PARAMETER); }
SensPrint(SENS_INFO, (SENS_STRING("Actual Name - [%s]\n"), lpszDestination)); SensPrint(SENS_INFO, (SENS_STRING("Sanitized Name - [%s]\n"), lpszSanitizedName));
bufsize = sizeof(WSAQUERYSET) + IP_BUFFER_SIZE; buf = (PVOID) new char[bufsize]; if (NULL == buf) { delete lpszSanitizedName; return (ERROR_OUTOFMEMORY); }
IP_ADDRESS_RESOLVER resolver(lpszSanitizedName, bufsize, buf);
status = resolver.NextAddress(lpdwIpAddr);
switch (status) { case RPC_S_OK: dwReturnCode = ERROR_SUCCESS; break;
case RPC_S_OUT_OF_MEMORY: dwReturnCode = ERROR_OUTOFMEMORY; break;
case RPC_S_SERVER_UNAVAILABLE: default: //
// Should we return HOST_NOT_FOUND in some cases depending
// upon the WSAGetLastError() value? Maybe. But, the error
// ERROR_HOST_UNREACHABLE is pretty close enough.
//
dwReturnCode = ERROR_HOST_UNREACHABLE; break; }
//
// Cleanup
//
if (NULL != lpszSanitizedName) { delete lpszSanitizedName; } if (NULL != buf) { delete buf; }
return (dwReturnCode); }
#if !defined(SENS_CHICAGO)
RPC_STATUS IP_ADDRESS_RESOLVER::NextAddress( OUT LPDWORD lpdwIpAddr ) /*++
Routine Description:
Returns the next IP address associated with the Name parameter to the constructor.
During the first call if check for loopback and for dotted numeric IP address formats. If these fail then it begins a complex lookup (WSALookupServiceBegin) and returns the first available address.
During successive calls in which a complex lookup was started it returns sucessive addressed returned by WSALookupServiceNext().
Arguments:
lpdwIpAddr - If successful, the member is set to an IP address.
Return Value:
RPC_S_OK - lpdwIpAddr points to a new IP address
RPC_S_SERVER_UNAVAILABLE - Unable to find any more addresses
RPC_S_OUT_OF_MEMORY - otherwise
--*/ { int err; RPC_STATUS status;
*lpdwIpAddr = 0x0;
// If this is the first call, _Name will be non-NULL and
// we need to start the lookup process.
if (_Name) { TCHAR *Name = _Name; _Name = 0;
// Check for loopback first.
if (! *Name) { // Loopback - assign result of htonl(INADDR_LOOPBACK)
// Little-endian dependence.
*lpdwIpAddr = 0x0100007F; return(RPC_S_OK); }
// Assume dot address since this is faster to check.
int size = sizeof(SOCKADDR_IN); SOCKADDR_IN addr; err = WSAStringToAddress(Name, AF_INET, 0, (PSOCKADDR)&addr, &size);
if (err != SOCKET_ERROR) { *lpdwIpAddr = addr.sin_addr.s_addr; return(RPC_S_OK); }
ASSERT(GetLastError() == WSAEINVAL);
// Start a complex query operation
const static AFPROTOCOLS aIpProtocols[2] = { {AF_INET, IPPROTO_UDP}, {AF_INET, IPPROTO_TCP} };
const static GUID guidHostAddressByName = SVCID_INET_HOSTADDRBYNAME; WSAQUERYSET wsqs;
memset(&wsqs, 0, sizeof(wsqs)); wsqs.dwSize = sizeof(WSAQUERYSET); // wsqs.dwNameSpace = NS_ALL;
ASSERT(NS_ALL == 0); wsqs.lpszServiceInstanceName = Name; wsqs.lpServiceClassId = (GUID *)&guidHostAddressByName; wsqs.dwNumberOfProtocols = 2; wsqs.lpafpProtocols = (PAFPROTOCOLS)&aIpProtocols[0];
err = WSALookupServiceBegin(&wsqs, LUP_RETURN_ADDR, &_hRnr);
if (err == SOCKET_ERROR) { SensPrintA(SENS_INFO, ("WSALookupServiceBegin() failed: %d\n", GetLastError())); return(RPC_S_SERVER_UNAVAILABLE); }
_index = 0;
if (_pwsqs) { _pwsqs->dwNumberOfCsAddrs = 0; } } else { if (!_hRnr) { // First call finished but didn't start a complex query. Abort now.
return(RPC_S_SERVER_UNAVAILABLE); } }
// A complex query has been started.
ASSERT(_hRnr);
// If the cached query structure is empty, call WSALookupNext to get
// more addresses.
if (!_pwsqs || (_index >= _pwsqs->dwNumberOfCsAddrs)) {
DWORD needed = _size;
// Loop needed to realloc a larger _pwsqs buffer.
for(;;) { err = WSALookupServiceNext(_hRnr, 0, // flags
&needed, _pwsqs);
// Success, break out of the loop.
if (err != SOCKET_ERROR) { ASSERT(_pwsqs->dwNumberOfCsAddrs > 0); ASSERT(_pwsqs->lpcsaBuffer);
// Reset to start of new result set.
_index = 0; break; }
status = GetLastError();
// WSAEFAULT means the buffer was too small.
if (status != WSAEFAULT) { // WSA_E_NO_MORE means all matching address have
// already been returned.
VALIDATE(status) { WSA_E_NO_MORE, WSANO_DATA, WSASERVICE_NOT_FOUND, WSAHOST_NOT_FOUND, WSATRY_AGAIN, WSANO_RECOVERY, WSANO_DATA, WSAEINVAL // In response to out of resources scenarios.
} END_VALIDATE;
SensPrintA(SENS_ERR, ("WSALookupServiceNext() failed: %d\n", status));
return(RPC_S_SERVER_UNAVAILABLE); }
// Allocate a larger buffer.
if (needed <= _size) { ASSERT(needed > _size); return(RPC_S_SERVER_UNAVAILABLE); }
if (_fFree) { delete _pwsqs; }
_pwsqs = (PWSAQUERYSET) new char[needed]; //_pwsqs = new WSAQUERYSETW[(needed - sizeof(WSAQUERYSETW))];
//_pwsqs = (PWSAQUERYSETW) new char(needed - sizeof(WSAQUERYSETW));
if (!_pwsqs) { return(RPC_S_OUT_OF_MEMORY); }
_fFree = TRUE; _pwsqs->dwNumberOfCsAddrs = 0; _size = needed;
#if DBG
// On retail we start with enough space for two addresses during the
// first call. If this debug print gets hit too much we can increase the
// starting size (IP_BUFFER_SIZE).
if (_size > sizeof(WSAQUERYSET) + IP_RETAIL_BUFFER_SIZE) { SensPrintA(SENS_ERR, ("WSALookupServerNext(): sizeof(WSAQUERYSETW) - %d\n" "WSALookupServerNext(): IP_RETAIL_BUFFER_SIZE - %d\n", sizeof(WSAQUERYSETW), IP_RETAIL_BUFFER_SIZE)); SensPrintA(SENS_ERR, ("WSALookupServerNext() wants %d bytes. Make this the " "default?\n", _size)); } #endif
} }
ASSERT(_pwsqs); ASSERT(_index < _pwsqs->dwNumberOfCsAddrs);
LPCSADDR_INFO pInfo = &_pwsqs->lpcsaBuffer[_index]; _index++;
*lpdwIpAddr = ((SOCKADDR_IN *)pInfo->RemoteAddr.lpSockaddr)->sin_addr.s_addr;
return(RPC_S_OK); }
IP_ADDRESS_RESOLVER::~IP_ADDRESS_RESOLVER() { if (_hRnr) { WSALookupServiceEnd(_hRnr); }
if (_fFree) { delete _pwsqs; } }
#endif // SENS_CHICAGO
|