Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1582 lines
42 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995.
//
// File: Winschk.cxx
//
// Contents: Compares contents of replicating Wins Servers
//
// Classes:
//
// Functions:
//
// History: 09-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
#include <headers.hxx>
#pragma hdrstop
#define INET_ADDR_SIZE 51
#define DELTA 10
#define FIRST_GET 100
#define SUBSEQUENT_GET 30
#if 0
#define WINSCHK_TRACE printf
#define WINSCHK_WTRACE wprintf
#else
#define WINSCHK_TRACE nullfn
#define WINSCHK_WTRACE nullfn
inline void nullfn(...) {};
#endif
//+---------------------------------------------------------------------------
//
// Class: template < class T > class SortSet
//
// Synopsis: Maintains/manipulates sorted sets of objects of a particular
// type.
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
template <class T> class SortSet
{
public:
SortSet( void );
~SortSet( void );
void operator=(const SortSet &other);
BOOL Insert(const T &tItem);
BOOL Insert(const T *tItem);
BOOL Delete(const T &tItem);
BOOL Member(const T &tItem);
ULONG GetCount() { return _cItem; };
T &operator[]( ULONG index );
private:
BOOL _ReAlloc();
ULONG _cMax;
ULONG _cItem;
T *_tArray;
};
// Constructor
template <class T>
SortSet< T >::SortSet( void )
{
_cMax = 0;
_cItem = 0;
_tArray = NULL;
}
// Destructor
template <class T>
SortSet< T >::~SortSet( void )
{
if (0 != _cItem)
{
delete [] _tArray;
}
}
// Operator= Copies on assignment
template <class T>
void SortSet< T >::operator=(const SortSet &other)
{
if( this == &other)
return;
_cMax = other._cMax;
_cItem = other._cItem;
delete [] _tArray;
_tArray = new T [ _cMax ];
for (ULONG i = 0; i < _cMax; i++)
{
_tArray[i] = other._tArray[i];
}
}
// Operator[] Retrieves a reference to the Ith member of the
// Sorted set
template <class T>
T &SortSet< T >::operator[]( ULONG index )
{
return index<_cItem ? _tArray[index] : _tArray[0];
}
// ReAlloc Expands memory as needed.
template <class T>
BOOL SortSet< T >::_ReAlloc()
{
T *pTmp = new T [ _cMax + DELTA ];
if ( NULL == pTmp )
return FALSE;
_cMax += DELTA;
memset(pTmp, 0, _cMax * sizeof( T ));
if ( 0 != _cItem )
{
for (ULONG i = 0; i < _cItem; i++)
{
pTmp[ i ] = _tArray[ i ];
}
delete [] _tArray;
}
_tArray = pTmp;
return TRUE;
}
// Insert Inserts an item into the sortset
template <class T>
BOOL SortSet< T >::Insert(const T &tItem)
{
ULONG i, j;
int d;
if ( _cItem == _cMax )
{
if (FALSE == _ReAlloc())
return FALSE;
}
for (i = 0; i < _cItem; i++)
{
d = compare(_tArray[i], tItem);
if (0 == d)
{
return FALSE; // already a member
}
else if (d > 0)
{
break; // insert at _tArray[i]
}
}
for (j = _cItem; j > i; j--)
{
_tArray[j] = _tArray[j-1];
}
_tArray[i] = tItem;
_cItem++;
return TRUE;
}
// Insert An alternate interface for Insert
template <class T>
BOOL SortSet< T >::Insert(const T *tItem)
{
return Insert( *tItem );
}
// Member Test for membership
template <class T>
BOOL SortSet< T >::Member(const T &tItem)
{
for (ULONG i = 0; i < _cItem; i++)
{
if ( tItem == _tArray[i] )
{
return TRUE;
}
}
return FALSE;
}
typedef struct
{
WCHAR name[17];
SortSet < ULONG > *list;
} node;
//+---------------------------------------------------------------------------
//
// Function: compare (overloaded)
//
// Synopsis: The following set of overloaded functions provide ordering
// relations for objects needed to order elements of SortSets
// of their respective types.
//
// Arguments: Two objects to be tested by the ordering relation
//
// Returns: <0 if the first arg is less than the second
// 0 if the args are equal
// >0 if the first arg is greater than the second
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
int compare(const char *a, const char *b)
{
return strcmp(a, b);
}
int compare(const WCHAR *a, const WCHAR *b)
{
return wcscmp(a, b);
}
int compare(const ULONG a, const ULONG b)
{
return (a < b) ? -1 : (a > b) ? +1 : 0;
}
int compare(const node &a, const node &b)
{
return compare(a.name, b.name);
}
//+---------------------------------------------------------------------------
//
// Class: NameAndList
//
// Synopsis: An object to place in a sortable list.
// It consists of two parts, a name (the sortable part)
// And a list of servers where the associated name has been
// found NOT to exist (where it had been found at some other
// server).
//
// Arguments:
//
// Returns:
//
// History: 08-Feb-1996 CDermody Created
//
// Notes: This is the object that gets all of the information we expect
// to use from a record we get from GetDbRecsByName.
// BUGBUG -- this is the object we would have to expand if we
// want to process other information from that record, such as
// time stamp, version number, and owner address.
//
//----------------------------------------------------------------------------
class NameAndList
{
public:
NameAndList();
NameAndList(const char *name);
~NameAndList();
void operator=(const NameAndList &other);
int CompareAgainst(const NameAndList &other);
const char *GetNamePtr() { return _name; };
SortSet <ULONG> &GetULSet() { return *_pulset; };
private:
char _name[17];
SortSet < ULONG > *_pulset;
};
//
// Constructor
//
NameAndList::NameAndList()
{
memset(_name, 0, sizeof(_name));
_pulset = NULL;
}
//
// Default constructor
//
NameAndList::NameAndList(const char *name)
{
strncpy(_name, name, 17);
_pulset = new SortSet < ULONG >;
}
//
// Destructor
//
NameAndList::~NameAndList()
{
if(NULL != _pulset)
{
delete _pulset;
_pulset = NULL;
}
}
//
// Assignment operator
//
void NameAndList::operator=(const NameAndList &other)
{
if(this == &other)
return;
delete _pulset;
_pulset = new SortSet < ULONG >;
*_pulset = *(other._pulset);
memset(_name, 0, sizeof(_name));
strcpy(_name, other._name);
}
//
// CompareAgainst -- compares object with another
//
int NameAndList::CompareAgainst(const NameAndList &other)
{
return compare(_name, other._name);
}
//
// compare -- A helper function (relational operator)
// needed to define a SortSet on this object
//
int compare(NameAndList &a, const NameAndList &b)
{
return a.CompareAgainst( b );
}
//
// PrintSortSet -- dumps a SortSet of NameAndList objects
//
void PrintSortSet(SortSet < NameAndList > *pNLSS)
{
ULONG cTestSet = pNLSS->GetCount();
printf("%PRINT %d records in SortSet.\n", cTestSet);
for (ULONG m = 0; m < cTestSet; m++)
{
printf("%4d. %s\n", m, ((*pNLSS)[m]).GetNamePtr());
}
printf("END SortSet.\n");
}
//
// PrintSortSet -- a diagnostic function
//
void PrintRecords(PWINSINTF_RECS_T pRecs)
{
DWORD n;
PWINSINTF_RECORD_ACTION_T pRow = pRecs->pRow;
printf("PRINT Retrieved %d records\n", pRecs->NoOfRecs);
for(n=0; n<pRecs->NoOfRecs; n++)
{
DWORD s;
char *p;
s = pRow->State_e;
p = "TOMBSTONE";
if(WINSINTF_E_ACTIVE == s)
p = "ACTIVE";
if(WINSINTF_E_RELEASED == s)
p = "RELEASED";
printf("Name is (%s) "
"16th Char is (%x) "
"State is (%s)\n",
pRow->pName,
*(pRow->pName+15),
p);
pRow++;
}
printf("END Retrieved records.\n");
}
//
// PrintResults -- Outputs summary results -- a list, by name,
// of all the servers which are missing each name.
//
void PrintResults(SortSet <NameAndList> *pNLSSResult)
{
WINSCHK_TRACE("BEGIN PrintResults\n");
for (ULONG iName = 0; iName < pNLSSResult->GetCount(); iName++)
{
printf("Name <%s>\n", ((*pNLSSResult)[iName]).GetNamePtr());
for (ULONG iServer = 0;
iServer < ((*pNLSSResult)[iName]).GetULSet().GetCount();
iServer++)
{
struct in_addr TmpAddr;
TmpAddr.s_addr = ((*pNLSSResult)[iName]).GetULSet()[iServer];
printf(" Missing at %s\n", inet_ntoa(TmpAddr));
}
}
WINSCHK_TRACE("END PrintResults\n");
}
//+---------------------------------------------------------------------------
//
// Function: RecsToNLSortSet
//
// Synopsis: Copies records from the format gotten from WinsGetDbRecsByName
// to a sortset. Stores only names with sort order greater than
// that provided by the pszStartAfter parameter and through that
// provided by pszLimitName
//
// Arguments: pRecs information gotten from GetDbRecsByName.
// We use the pRow and NoOfRecs components.
//
// Returns: BUGBUG a status return would be appropriate
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
void RecsToNLSortSet(const PWINSINTF_RECS_T pRecs,
SortSet < NameAndList > *pNLSortSet,
const char *pszStartAfter,
const char *pszLimitName)
{
PWINSINTF_RECORD_ACTION_T pRow = pRecs->pRow;
for(DWORD i = 0; i < pRecs->NoOfRecs; i++, pRow++)
{
if (NULL != pszLimitName
&& strcmp((char *)pRow->pName, pszLimitName) > 0)
{
break;
}
if (WINSINTF_E_ACTIVE == pRow->State_e)
{
if (NULL != pszStartAfter
&& strcmp((char *)pRow->pName, pszStartAfter) <= 0)
{
WINSCHK_TRACE("%s is <= start name %s.\n",
pRow->pName,
pszStartAfter);
continue;
}
NameAndList nl((char *)pRow->pName);
pNLSortSet->Insert(nl);
}
}
}
//+---------------------------------------------------------------------------
//
// Function: CompareNLSortSets
//
// Synopsis: Compares a set to be tested against a reference set.
// Updates the reference set to reflect new names found in the
// test set but not previously in the reference set.
//
// Arguments: pnlssRef Reference NameAndList sortset
// pnlssTest Test NameAndList sortest
// pulssServersCompared a ULONG sortset containing the in_addr
// of each server used to build the
// reference set. If we find a new name,
// we use this to initialize the list of
// servers which do not have this object,
// since none of the servers in reference
// set have it.
// pin_addrThisServer the in_addr of the server represented
// by the sortset in pnlssTest
//
// Returns: BOOL - TRUE => success
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL CompareNLSortSets(SortSet < NameAndList > *pnlssRef,
SortSet < NameAndList > *pnlssTest,
SortSet < ULONG > *pulssServersCompared,
struct in_addr *pin_addrThisServer)
{
ULONG cRef = pnlssRef->GetCount();
ULONG cTest = pnlssTest->GetCount();
ULONG iRef = 0;
ULONG iTest = 0;
LONG delta = 0;
BOOL bResult = TRUE;
WINSCHK_TRACE("BEGIN Compare sort sets.\n");
while (iRef < cRef || iTest < cTest)
{
if (iRef == cRef)
{
bResult = FALSE;
WINSCHK_TRACE("%s at test server is beyond end of reference set.\n",
((*pnlssTest)[iTest]).GetNamePtr());
NameAndList nl((*pnlssTest)[iTest].GetNamePtr());
nl.GetULSet() = *pulssServersCompared;
pnlssRef->Insert(nl);
cRef++;
iRef++; // allow for the added a rec at reference
iTest++;
printf("BUGBUG! Violates assumption we not enumerate tested sever beyond what is in the reference data set.\n");
continue;
}
if (iTest == cTest)
{
bResult = FALSE;
WINSCHK_TRACE("%s at reference server is beyond end of test set.\n",
((*pnlssRef)[iRef]).GetNamePtr());
(*pnlssRef)[iRef].GetULSet().Insert(pin_addrThisServer->s_addr);
iRef++;
continue;
}
delta = strcmp(((*pnlssRef)[iRef].GetNamePtr()),
((*pnlssTest)[iTest].GetNamePtr()));
if (0 == delta)
{
WINSCHK_TRACE("Records %s MATCHED.\n", ((*pnlssTest)[iTest].GetNamePtr()));
iTest++;
iRef++;
}
else if (delta < 0)
{
bResult = FALSE;
WINSCHK_TRACE("Record %s does not appear at tested server.\n",
((*pnlssRef)[iRef].GetNamePtr()));
(*pnlssRef)[iRef].GetULSet().Insert(pin_addrThisServer->s_addr);
iRef++;
}
else
{
bResult = FALSE;
WINSCHK_TRACE("Record %s does not appear at reference server.\n",
((*pnlssTest)[iTest].GetNamePtr()));
NameAndList nl((*pnlssTest)[iTest].GetNamePtr());
nl.GetULSet() = *pulssServersCompared;
pnlssRef->Insert(nl);
cRef++;
iRef++; // allow for the added a rec at reference
iTest++;
}
}
WINSCHK_TRACE("END Compare sort sets.\n");
return bResult;
}
//
// CompareRecs -- used only for testing this program
//
BOOL CompareRecs(PWINSINTF_RECS_T pRecs1,
PWINSINTF_RECS_T pRecs2)
{
LONG delta;
BOOL bResult = TRUE;
DWORD i1 = 0;
DWORD i2 = 0;
DWORD max1 = pRecs1->NoOfRecs;
DWORD max2 = pRecs2->NoOfRecs;
PWINSINTF_RECORD_ACTION_T pRow1 = pRecs1->pRow;
PWINSINTF_RECORD_ACTION_T pRow2 = pRecs2->pRow;
printf("BEGIN CompareRecs.\n");
if (NULL == pRecs1 || NULL == pRecs2) return FALSE;
if (NULL == pRow1 || NULL == pRow2) return FALSE;
while (i1 < max1 || i2 < max2)
{
if (i1 < max1
&& WINSINTF_E_ACTIVE != pRow1->State_e)
{
printf("Record %s not active at reference server.\n", pRow1->pName);
pRow1++;
i1++;
continue;
}
if (i2 < max2
&& WINSINTF_E_ACTIVE != pRow2->State_e)
{
printf("Record %s not active at tested server.\n", pRow2->pName);
pRow2++;
i2++;
continue;
}
if (i1 == max1)
{
printf("Record %s past end at reference server.\n",
pRow2->pName);
pRow2++;
i2++;
bResult = FALSE;
continue;
}
if (i2 == max2)
{
printf("Record %s past end at tested server.\n",
pRow1->pName);
pRow1++;
i1++;
bResult = FALSE;
continue;
}
delta = strcmp((char *)pRow1->pName, (char *)pRow2->pName);
if (0 == delta)
{
printf("Records %s MATCHED.\n", pRow2->pName);
pRow1++;
pRow2++;
i1++;
i2++;
continue;
}
if (delta < 0)
{
printf("Record %s does not appear at tested server.\n",
pRow1->pName);
pRow1++;
i1++;
bResult = FALSE;
continue;
}
printf("Record %s does not appear at reference server.\n",
pRow2->pName);
pRow2++;
i2++;
bResult = FALSE;
continue;
}
printf("END CompareRecs.\n");
return bResult;
}
//+---------------------------------------------------------------------------
//
// Function: GetServerListFromSrv
//
// Synopsis: Given the address of the a Wins Server, return the list of
// its replica partners.
//
// Arguments: ulInAddr the address of the server to contact
// InAddrArray [out] a place to return the list of replicas
// cServers [out] a place to return the number of replicas,
// the number of items in InAddrArray.
//
// Returns: Status
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD GetServerListFromSrv(ULONG ulInAddr,
ULONG **InAddrArray,
ULONG *cServers)
{
WINSINTF_RESULTS_NEW_T ResultsN;
PWINSINTF_ADD_VERS_MAP_T pAddVersMaps = NULL;
WINSINTF_BIND_DATA_T BindData;
handle_t BindHdl;
WCHAR awszAddr[INET_ADDR_SIZE + 1];
ULONG *pTmp = NULL;
DWORD nOwners = 0;
ULONG index = 0;
DWORD Status = ERROR_SUCCESS;
struct in_addr InAddr;
InAddr.s_addr = ulInAddr;
memset(awszAddr, 0, sizeof(awszAddr));
mbstowcs(awszAddr, inet_ntoa(InAddr), INET_ADDR_SIZE);
BindData.fTcpIp = TRUE;
BindData.pServerAdd = (char *)awszAddr;
BindHdl = WinsBind(&BindData);
if (NULL == BindHdl)
return ERROR_FILE_NOT_FOUND; // BUGBUG - better status??
ResultsN.pAddVersMaps = NULL;
Status = WinsStatusNew(WINSINTF_E_CONFIG_ALL_MAPS, &ResultsN);
if (WINSINTF_SUCCESS != Status)
return Status;
nOwners = ResultsN.NoOfOwners;
pAddVersMaps = ResultsN.pAddVersMaps;
pTmp = new ULONG[ nOwners + 2 ];
if (NULL == pTmp)
return ERROR_OUTOFMEMORY;
memset(pTmp, 0, (nOwners + 2) * sizeof(ULONG));
index = 0;
pTmp[index++] = InAddr.s_addr;
for (DWORD i = 0; i < nOwners; i++, pAddVersMaps++)
{
if (MAXLONG == pAddVersMaps->VersNo.HighPart
&& MAXULONG == pAddVersMaps->VersNo.LowPart)
{
continue;
}
else if (0 == pAddVersMaps->VersNo.QuadPart)
{
continue;
}
else if (pTmp[0] == htonl(pAddVersMaps->Add.IPAdd))
{
continue; // Skip this! We already put the ref server first.
}
pTmp[index++] = htonl(pAddVersMaps->Add.IPAdd);
}
*InAddrArray = pTmp;
*cServers = index;
return ERROR_SUCCESS;
}
//+---------------------------------------------------------------------------
//
// Function: GetServerListFromReg
//
// Synopsis: Through information in the registry, try to find a set of
// replicating Wins Servers
//
// Arguments: InAddrArray [out] a place to put the array of servers
// cServers [out] a place to put the number of servers
//
// Returns: Status
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD GetServerListFromReg(ULONG **InAddrArray,
ULONG *cServers)
{
// First we must find a reference server,
// then all replica partners to that reference server,
// then we compare the names in each server against the referece.
// To find the reference server we enumerate the adapter cards from
// the registry key System\CurrentControlSet\Services\NetBT\Adapters
// in HKEY_LOCAL_MACHINE. We look in each, first for the subkey
// NameServer, then in each for NameServerBackup, DhcpNameSever and
// finally for DhcpNameServerBackup, until we find a server which will
// respond to WinsStatusNew, which gives us the replica partners.
LPWSTR alpwcsValueName[] =
{
L"NameServer",
L"NameServerBackup",
L"DhcpNameServer",
L"DhcpNameServerBackup"
};
LPWSTR lpwcsAdapters =
L"SYSTEM\\CurrentControlSet\\Services\\NetBT\\Adapters";
ULONG ulStatus = 0;
HKEY hk1, hk2;
WCHAR awszSubKey[MAX_PATH];
WCHAR awszData[MAX_PATH];
DWORD cchSubKey = 0;
DWORD cchValue = 0;
DWORD ccbData = 0;
DWORD dwType = 0;
FILETIME ft;
DWORD i, j, k, n;
DWORD Status;
DWORD nOwners = 0;
WINSINTF_BIND_DATA_T BindData;
WINSINTF_RESULTS_NEW_T ResultsN;
handle_t BindHdl;
PWINSINTF_ADD_VERS_MAP_T pAddVersMaps = NULL;
struct in_addr InAddr;
WCHAR awszAddr[50];
WINSINTF_RECS_T RefRecs;
SortSet < NameAndList > *pnlssRef;
SortSet < NameAndList > *pnlssTest;
SortSet < ULONG > ulssServersCompared;
RefRecs.pRow = NULL;
ulStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
lpwcsAdapters,
0,
KEY_READ,
&hk1);
if (ERROR_SUCCESS != ulStatus)
{
printf("Failed with %08lx opening key %ws\n", ulStatus, lpwcsAdapters);
exit(EXIT_FAILURE);
}
// Loop over keys
printf("Loop over keys.\n");
for (i = 0; i < sizeof(alpwcsValueName)/sizeof(alpwcsValueName[0]); i++)
{
// Enumerate adapters
for (j = 0; ; j++)
{
cchSubKey = MAX_PATH;
ulStatus = RegEnumKeyExW(hk1,
j,
awszSubKey,
&cchSubKey,
0, // reserved
0, // lpwszClass
0, // lpcchClass
&ft);
if (ERROR_NO_MORE_ITEMS == ulStatus)
{
printf("No more adapters.\n");
break; // j
}
else if (ERROR_SUCCESS != ulStatus)
{
printf("Adapter enumeration failed with %08lx.\n", ulStatus);
break; // j
}
else
{
printf("Adapter %ws, key %ws\n",
awszSubKey,
alpwcsValueName[i]);
ulStatus = RegOpenKeyExW(hk1,
awszSubKey,
0,
KEY_READ,
&hk2);
if (ERROR_SUCCESS != ulStatus)
{
printf("Could not open subkey %ws for adapter %ws.\n",
awszSubKey,
alpwcsValueName[i]);
continue; // j
}
dwType = 0;
ccbData = MAX_PATH;
ulStatus = RegQueryValueExW(hk2,
alpwcsValueName[i],
0,
&dwType,
(BYTE *)awszData,
&ccbData);
RegCloseKey(hk2);
if(ERROR_SUCCESS != ulStatus)
{
printf("Could not get %ws for adapter %ws.\n",
alpwcsValueName[i],
awszSubKey);
continue; // j
}
else
{
printf("%ws for adapter %ws is %ws\n",
alpwcsValueName[i],
awszSubKey,
awszData);
if (REG_SZ != dwType)
{
printf("Wrong key type for subkey %ws of adapter"
" %ws.\n",
awszSubKey,
alpwcsValueName);
}
else
{
// We seem to have a good one.
ULONG ulInAddr;
ULONG *aulInAddrs = NULL;
ULONG count;
char aszInAddr[INET_ADDR_SIZE];
printf("We have an address from registry.\n");
wcstombs(aszInAddr, awszData, INET_ADDR_SIZE);
ulInAddr = inet_addr(aszInAddr);
printf("Call GetServerListFromSrv with %s.\n",
aszInAddr);
Status = GetServerListFromSrv(ulInAddr,
&aulInAddrs,
&count);
if (ERROR_SUCCESS != Status)
continue;
*cServers = count;
*InAddrArray = aulInAddrs;
goto done;
} // type
} // query
} // enum
} // for j (adapters)
} // for i (keys)
done:
RegCloseKey(hk1);
return Status;
}
//+---------------------------------------------------------------------------
//
// Function: BuildNLSortSet
//
// Synopsis: Retrieve records from a server and return a condensation of
// their content in a NameAndList SortSet
//
// Arguments: ulInAddr The InAddr (in ULONG form) of the server to contact
// pszStartName Consider no records less that or equal to
// this in the sort order. If null, no limit.
// pszMaxName Consider no records beyond this in the sort order.
// If null, no limit.
//
// Returns: Status
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD BuildNLSortSet(ULONG ulInAddr,
char *pszStartName,
char *pszMaxName,
SortSet < NameAndList > **ppNLSortSet)
{
SortSet < NameAndList > *pNLSortSet;
struct in_addr InAddr;
WINSINTF_RECS_T Recs;
WINSINTF_BIND_DATA_T BindData;
handle_t BindHdl = 0;
WCHAR awszAddress[ INET_ADDR_SIZE ];
ULONG cRecords = 0;
ULONG cSortSet = 0;
DWORD Status = ERROR_SUCCESS;
char *pszQueryName = pszStartName;
char aszQueryName[MAX_PATH];
ULONG ulGet = 0;
InAddr.s_addr = ulInAddr;
WINSCHK_TRACE("BEGIN BuildNLSortSet for %s\n", inet_ntoa(InAddr));
if (NULL != pszStartName)
WINSCHK_TRACE("StartName is %s\n", pszStartName);
if (NULL != pszMaxName)
WINSCHK_TRACE("MaxName is %s\n", pszMaxName);
Recs.pRow = NULL;
pNLSortSet = new SortSet < NameAndList >;
if (NULL == pNLSortSet)
{
Status = ERROR_OUTOFMEMORY;
goto cleanup;
}
mbstowcs(awszAddress, inet_ntoa(InAddr), INET_ADDR_SIZE);
BindData.fTcpIp = TRUE;
BindData.pServerAdd = (char *) awszAddress;
BindHdl = WinsBind(&BindData);
if (NULL == BindHdl)
{
Status = ERROR_FILE_NOT_FOUND;
goto cleanup;
}
ulGet = FIRST_GET;
while (TRUE)
{
Recs.pRow = NULL;
WINSCHK_TRACE("The query name is <%s>.\n", pszQueryName);
Status = WinsGetDbRecsByName(
NULL,
WINSINTF_BEGINNING,
(LPBYTE)pszQueryName,
(NULL == pszQueryName)
? 0
: strlen(pszQueryName),
ulGet,
4,
&Recs);
ulGet = SUBSEQUENT_GET;
if (WINSINTF_SUCCESS != Status)
{
goto cleanup;
}
cRecords = Recs.NoOfRecs;
if (0 == cRecords)
{
// If we can't get any more records, whether limited by
// MaxName or not, we're done.
WINSCHK_TRACE("No more records. Done.\n");
Status = WINSINTF_SUCCESS;
goto cleanup;
}
WINSCHK_TRACE("The last name is %s\n", Recs.pRow[cRecords - 1].pName);
RecsToNLSortSet(&Recs, pNLSortSet, pszStartName, pszMaxName);
// BUGBUG -- should return status
if (WINSINTF_SUCCESS != Status)
{
goto cleanup;
}
cSortSet = pNLSortSet->GetCount();
if (NULL == pszMaxName && 0 != cSortSet)
{
// No MaxName => We are building the reference set
// && cSortSet > 0 => We have built one, return it.
WINSCHK_TRACE("EXITING -- we have records, no maxname.\n");
Status = WINSINTF_SUCCESS;
goto cleanup;
}
if (NULL != pszMaxName
&& strcmp((char *)Recs.pRow[cRecords - 1].pName, pszMaxName) >= 0)
{
// The last name we attempted to add to the sortset meets or
// exceeds the MaxName.
WINSCHK_TRACE("EXITING -- cut off by maxname %s.\n", pszMaxName);
Status = WINSINTF_SUCCESS;
goto cleanup;
}
if(NULL != pszStartName
&& 0 == strcmp(pszStartName, (char *)Recs.pRow[cRecords - 1].pName))
{
goto cleanup;
}
strcpy(aszQueryName, (char *)Recs.pRow[cRecords - 1].pName);
WINSCHK_TRACE("Query name is now %s\n", aszQueryName);
pszQueryName = aszQueryName;
WinsFreeMem(Recs.pRow);
Recs.pRow = NULL;
}
cleanup:
if (NULL != Recs.pRow)
{
WinsFreeMem(Recs.pRow);
}
if (NULL != BindHdl)
{
WinsUnbind(&BindData, BindHdl);
}
if (ERROR_SUCCESS == Status)
{
*ppNLSortSet = pNLSortSet;
}
else
{
delete pNLSortSet;
}
WINSCHK_TRACE("END BuildNLSortSet for %s\n", inet_ntoa(InAddr));
return Status;
}
//+---------------------------------------------------------------------------
//
// Function: AltMethod
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 08-Feb-1996 CDermody Created
//
// Notes: THIS ROUTINE IS USED ONLY IN TESTING THIS PROGRAM
// It is a simpler, but more burdensome algorithm for computing
// the same results. WARNING -- this routine can severely load
// a wins server, we currently limit it to retrieving 5000 records.
// Otherwise this does should return the same results as the main
// algorithm. It is left in for comparison and evaluation of the
// main algorithm of this program.
//
//----------------------------------------------------------------------------
void AltMethod()
{
DWORD Status = ERROR_SUCCESS;
ULONG *pulInAddrArray = NULL;
ULONG cServers = 0;
struct in_addr InAddrRef, InAddrTest;
SortSet < NameAndList > *pNLSSRef = 0;
SortSet < NameAndList > *pNLSSTest = 0;
WCHAR awszAddr[ INET_ADDR_SIZE ];
BOOL fSame = FALSE;
WINSINTF_RECS_T RefRecs;
WINSINTF_RECS_T TestRecs;
handle_t BindHdl;
WINSINTF_BIND_DATA_T BindData;
UINT k;
SortSet < ULONG > ulssServersCompared;
TestRecs.pRow = NULL;
RefRecs.pRow = NULL;
Status = GetServerListFromReg(&pulInAddrArray, &cServers);
printf("GetServerListFromReg status is %08lx. There are %d servers.\n",
Status,
cServers);
if (ERROR_SUCCESS != Status || 0 == cServers)
{
goto cleanup;
}
InAddrRef.s_addr = pulInAddrArray[ 0 ];
ulssServersCompared.Insert(InAddrRef.s_addr);
printf("Ref server address is %s.\n", inet_ntoa(InAddrRef));
mbstowcs(awszAddr, inet_ntoa(InAddrRef), INET_ADDR_SIZE);
BindData.fTcpIp = TRUE;
BindData.pServerAdd = (char *)awszAddr;
BindHdl = WinsBind(&BindData);
if (NULL == BindHdl)
{
printf("Could not bind to reference server %s.\n",
inet_ntoa(InAddrRef));
goto cleanup;
}
RefRecs.pRow = NULL;
Status = WinsGetDbRecsByName(NULL,
WINSINTF_BEGINNING,
NULL,
0,
5000,
4,
&RefRecs);
WinsUnbind(&BindData, BindHdl);
BindHdl = NULL;
if (WINSINTF_SUCCESS != Status)
{
printf("Reference WinsGetDbRecsByName failed with %08lx.\n");
goto cleanup;
}
pNLSSRef= new SortSet < NameAndList >;
if (NULL == pNLSSRef)
{
printf("Out of memory.\n");
goto cleanup;
}
RecsToNLSortSet(&RefRecs, pNLSSRef, NULL, NULL);
printf("This is the reference set.\n");
PrintRecords(&RefRecs);
PrintSortSet(pNLSSRef);
printf("End of reference set.\n");
for (k = 0; k < cServers; k++)
{
InAddrTest.s_addr = pulInAddrArray[ k ];
printf("Test server address is %s.\n", inet_ntoa(InAddrTest));
mbstowcs(awszAddr, inet_ntoa(InAddrTest), INET_ADDR_SIZE);
BindData.fTcpIp = TRUE;
BindData.pServerAdd = (char *)awszAddr;
BindHdl = WinsBind(&BindData);
if (NULL == BindHdl)
{
printf("Could not bind to test server %s.\n",
inet_ntoa(InAddrRef));
goto cleanup;
}
TestRecs.pRow = NULL;
Status = WinsGetDbRecsByName(NULL,
WINSINTF_BEGINNING,
NULL,
0,
5000,
4,
&TestRecs);
WinsUnbind(&BindData, BindHdl);
BindHdl = NULL;
if (WINSINTF_SUCCESS != Status)
{
printf("Test server WinsGetDbRecsByName failed with %08lx.\n");
goto cleanup;
}
pNLSSTest= new SortSet < NameAndList >;
if (NULL == pNLSSTest)
{
printf("Out of memory.\n");
goto cleanup;
}
RecsToNLSortSet(&TestRecs, pNLSSTest, NULL, NULL);
printf("This is the test set.\n");
PrintRecords(&TestRecs);
PrintSortSet(pNLSSTest);
printf("End of test set.\n");
CompareRecs(&RefRecs, &TestRecs);
fSame = CompareNLSortSets(pNLSSRef,
pNLSSTest,
&ulssServersCompared,
&InAddrTest);
ulssServersCompared.Insert(InAddrTest.s_addr);
PrintResults(pNLSSRef);
delete pNLSSTest;
pNLSSTest = 0;
WinsFreeMem(TestRecs.pRow);
TestRecs.pRow = 0;
}
cleanup:
delete pNLSSRef;
delete pNLSSTest;
if (NULL != TestRecs.pRow)
WinsFreeMem(TestRecs.pRow);
if (NULL != RefRecs.pRow)
WinsFreeMem(RefRecs.pRow);
if (NULL != BindHdl)
WinsUnbind(&BindData, BindHdl);
}
//+---------------------------------------------------------------------------
//
// Function: ProductionMethod
//
// Synopsis: Essentially, the main routine of this test program.
//
// Arguments:
//
// Returns:
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
void
_stdcall
ProductionMethod()
{
DWORD Status = ERROR_SUCCESS;
ULONG *pulInAddrArray = NULL;
ULONG cServers = 0;
struct in_addr InAddrRef, InAddrTest;
SortSet < NameAndList > *pNLSSRef = 0;
SortSet < NameAndList > *pNLSSTest = 0;
char aszRestartName[ MAX_PATH ];
char aszLimitName[ MAX_PATH ];
char *pszRestartName = 0;
char *pszLimitName = 0;
ULONG cRefNames = 0;
SortSet < ULONG > ulssServersCompared;
BOOL fSame = FALSE;
ULONG k;
Status = GetServerListFromReg(&pulInAddrArray, &cServers);
printf("GetServerListFromReg status is %08lx. There are %d servers.\n",
Status,
cServers);
if (ERROR_SUCCESS != Status || 0 == cServers)
{
goto done;
}
InAddrRef.s_addr = pulInAddrArray[ 0 ];
ulssServersCompared.Insert(InAddrRef.s_addr);
printf("Ref server address is %s.\n", inet_ntoa(InAddrRef));
while (TRUE)
{
Status = BuildNLSortSet(pulInAddrArray[ 0 ],
pszRestartName, // start
NULL, // limit
&pNLSSRef);
if (ERROR_SUCCESS != Status)
{
printf("Failed building reference sortset %08lx.\n", Status);
goto done;
}
cRefNames = pNLSSRef->GetCount();
WINSCHK_TRACE("%d reference set names\n", cRefNames);
if (0 == cRefNames)
{
pszLimitName = 0;
}
else
{
// Last name gotten from Ref Server becomes limit for
// test server request.
strcpy(aszLimitName, ((*pNLSSRef)[cRefNames - 1]).GetNamePtr());
pszLimitName = aszLimitName;
}
for (k = 0; k < cServers; k++)
{
InAddrTest.s_addr = pulInAddrArray[ k ];
WINSCHK_TRACE("Test server address is %s.\n", inet_ntoa(InAddrTest));
Status = BuildNLSortSet(pulInAddrArray[ k ],
pszRestartName,
pszLimitName,
&pNLSSTest);
if (ERROR_SUCCESS != Status)
{
printf("Failed building test server sortset %08lx.\n",
Status);
goto done;
}
fSame = CompareNLSortSets(pNLSSRef,
pNLSSTest,
&ulssServersCompared,
&InAddrTest);
cRefNames = pNLSSRef->GetCount();
WINSCHK_TRACE("%d reference set names\n", cRefNames);
ulssServersCompared.Insert(InAddrTest.s_addr);
delete pNLSSTest;
pNLSSTest = 0;
if (0 != cRefNames && NULL == pszLimitName)
{
// Last name gotten from Ref Server becomes limit for
// test server request.
// Ref set updating in CompareNLSortSets has essentially
// transfered this test set content to the ref set.
strcpy(aszLimitName,
((*pNLSSRef)[cRefNames - 1]).GetNamePtr());
pszLimitName = aszLimitName;
}
} // for k
cRefNames = pNLSSRef->GetCount();
WINSCHK_TRACE("%d members in reference set.\n", cRefNames);
PrintResults(pNLSSRef);
delete pNLSSRef;
pNLSSRef = 0;
if (0 == cRefNames)
{
printf("Done!\n");
goto done;
}
strcpy(aszRestartName, aszLimitName);
pszRestartName = aszRestartName;
} // while TRUE
done:
delete pNLSSTest;
delete pNLSSRef;
delete [] pulInAddrArray;
}
#ifdef __cplusplus
}
#endif
//+---------------------------------------------------------------------------
//
// Function: main
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 08-Feb-1996 CDermody Created
//
// Notes:
//
//----------------------------------------------------------------------------
/*
void _cdecl main(int argc, char **argv)
{
// First we must find a reference server,
// then all replica partners to that reference server,
// then we compare the names in each server against the referece.
// To find the reference server we enumerate the adapter cards from
// the registry key System\CurrentControlSet\Services\NetBT\Adapters
// in HKEY_LOCAL_MACHINE. We look in each, first for the subkey
// NameServer, then in each for NameServerBackup, DhcpNameSever and
// finally for DhcpNameServerBackup, until we find a server which will
// respond to WinsStatusNew, which gives us the replica partners.
DWORD k = 0;
#if 0
// for comparison and evaluation purposes only.
AltMethod();
for (k = 0; k < 20; k++) { printf("<*> "); } printf("\n");
#endif
ProductionMethod();
}
*/