mirror of https://github.com/lianthony/NT4.0
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.
857 lines
16 KiB
857 lines
16 KiB
|
|
/*++
|
|
|
|
Microsoft Windows NT RPC Name Service
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.cxx
|
|
|
|
Abstract:
|
|
|
|
This module contains definitions of miscellaneous utility functions.
|
|
|
|
Author:
|
|
|
|
Satish Thatte (SatishT) 09/20/95 Created all the code below except where
|
|
otherwise indicated.
|
|
|
|
--*/
|
|
|
|
#include <objects.hxx>
|
|
#include <api.hxx>
|
|
#include <var.hxx>
|
|
#include <loctoloc.h>
|
|
#include <simpleLL.hxx>
|
|
|
|
|
|
BOOL
|
|
hasWhacksInMachineName(
|
|
STRING_T szName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if machine name has "\\" at the beginning.
|
|
|
|
Returns:
|
|
|
|
TRUE if "\\" present, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
if ((*szName == L'\\') && (*(szName+1) == L'\\')) return TRUE;
|
|
else return FALSE;
|
|
}
|
|
|
|
|
|
|
|
unsigned long
|
|
CurrentTime (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the current time in seconds.
|
|
|
|
Returns:
|
|
|
|
The time.
|
|
|
|
--*/
|
|
{
|
|
ULONG time;
|
|
|
|
// QUERY the current time; and return the time since service start in seconds.
|
|
|
|
time = GetCurrentTime();
|
|
|
|
return((time-StartTime)/1000);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsStillCurrent(
|
|
ULONG ulCacheTime,
|
|
ULONG ulTolerance
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if a cache creation time is still "current" based on a tolerance
|
|
level for staleness. All time values are in seconds.
|
|
|
|
Arguments:
|
|
|
|
ulCacheTime - cache creation time
|
|
ulTolerance - staleness tolerance
|
|
|
|
Returns:
|
|
|
|
TRUE if current, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG ulCurrent = CurrentTime();
|
|
|
|
DBGOUT(UTIL, "IsStillCurrent: ulCacheTime = " << ulCacheTime << WNL);
|
|
DBGOUT(UTIL, "IsStillCurrent: ulTolerance = " << ulTolerance << WNL);
|
|
DBGOUT(UTIL, "IsStillCurrent: ulCurrent = " << ulCurrent << "\n\n");
|
|
|
|
/* the next statement is basically a kludge to get around the fact that
|
|
rpc_c_ns_default_exp_age is -1 which, as a ULONG is 0xffffffff
|
|
so that ulTolerance + CACHE_GRACE wraps around to CACHE_GRACE - 1
|
|
for the default tolerance!
|
|
*/
|
|
|
|
if (ulTolerance + CACHE_GRACE < CACHE_GRACE) // ulTolerance wrap around
|
|
return TRUE;
|
|
|
|
if (
|
|
(ulCurrent - ulCacheTime) > (ulTolerance + CACHE_GRACE) ||
|
|
((long)ulCurrent - (long)ulCacheTime) < 0 // ulCurrent wrap around
|
|
)
|
|
|
|
return FALSE;
|
|
|
|
else {
|
|
DBGOUT(UTIL, "IsStillCurrent: YES!\n\n");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
AssertHeap()
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks the state of the current process heap, or of a single
|
|
block in the heap if a non-null block address is provided.
|
|
|
|
--*/
|
|
{
|
|
BOOL valid = HeapValidate(
|
|
hHeapHandle,
|
|
0, // default: serialize heap access
|
|
NULL // default: validate the entire heap
|
|
);
|
|
|
|
if (!valid) Raise(NSI_S_HEAP_TRASHED);
|
|
|
|
}
|
|
|
|
RPC_BINDING_HANDLE
|
|
MakeDClocTolocHandle(
|
|
STRING_T pszDCName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an RPC binding handle for a locator on the given server
|
|
|
|
Arguments:
|
|
|
|
pszDCName - name of the server machine
|
|
|
|
Returns:
|
|
|
|
A binding handle.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
STRING_T pszTempBinding;
|
|
|
|
STRING_T pszNetworkAddr = catenate(TEXT("\\\\"),pszDCName);
|
|
|
|
Status = RpcStringBindingCompose(
|
|
NULL,
|
|
TEXT("ncacn_np"),
|
|
pszNetworkAddr,
|
|
TEXT("\\pipe\\locator"),
|
|
NULL,
|
|
&pszTempBinding
|
|
);
|
|
|
|
if (Status != RPC_S_OK) Raise(NSI_S_DC_BINDING_FAILURE);
|
|
|
|
RPC_BINDING_HANDLE hResult;
|
|
|
|
Status = RpcBindingFromStringBinding(
|
|
pszTempBinding,
|
|
&hResult
|
|
);
|
|
|
|
if (Status != RPC_S_OK) Raise(NSI_S_DC_BINDING_FAILURE);
|
|
|
|
UINT Timeout;
|
|
|
|
Status = RpcMgmtInqComTimeout( // BUGBUG: does this have any effect?
|
|
hResult,
|
|
&Timeout
|
|
);
|
|
|
|
|
|
delete pszNetworkAddr;
|
|
RpcStringFree(&pszTempBinding);
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
STRING_T
|
|
catenate(
|
|
STRING_T pszPrefix,
|
|
STRING_T pszSuffix
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Concatenate the two given strings into a new string
|
|
|
|
Arguments:
|
|
|
|
pszPrefix - prefix of result
|
|
|
|
pszSuffix - suffix of result
|
|
|
|
Returns:
|
|
|
|
A newly allocated string.
|
|
|
|
--*/
|
|
{
|
|
long prefixLen = wcslen(pszPrefix);
|
|
long suffixLen = wcslen(pszSuffix);
|
|
|
|
STRING_T pszResult = new WCHAR[(prefixLen+suffixLen+1)*sizeof(WCHAR)];
|
|
wcscpy(pszResult,pszPrefix);
|
|
wcscpy(pszResult+prefixLen,pszSuffix);
|
|
return pszResult;
|
|
}
|
|
|
|
|
|
NSI_SERVER_BINDING_VECTOR_T *
|
|
BVTtoSBVT(
|
|
NSI_BINDING_VECTOR_T * pbvt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reformulates a NSI_BINDING_VECTOR_T as a
|
|
NSI_SERVER_BINDING_VECTOR_T but does not make copies of
|
|
the string bindings in the process.
|
|
|
|
--*/
|
|
{
|
|
NSI_SERVER_BINDING_VECTOR_T *
|
|
psbvt = (NSI_SERVER_BINDING_VECTOR_T *)
|
|
new char [ sizeof(UNSIGNED32) +
|
|
sizeof(NSI_STRING_BINDING_T)*(pbvt->count)
|
|
];
|
|
|
|
psbvt->count = pbvt->count;
|
|
for (UNSIGNED32 i = 0; i < pbvt->count; i++) {
|
|
psbvt->string[i] = pbvt->binding[i].string;
|
|
}
|
|
|
|
return psbvt;
|
|
}
|
|
|
|
|
|
|
|
STRING_T
|
|
makeBindingStringWithObject(
|
|
STRING_T binding,
|
|
STRING_T object
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Take an existing binding string and replace the object part
|
|
before returning. The string returned is allocated by RPC
|
|
and must be freed by calling RpcStringFree unless it is an
|
|
out parameter for an RPC call (or a part of such a returned
|
|
value) in which case it is freed by the RPC runtime.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS Status;
|
|
|
|
/* variables to receive binding decomposition */
|
|
|
|
STRING_T ProtSeq;
|
|
STRING_T EndPoint;
|
|
STRING_T NetworkAddr;
|
|
STRING_T NetworkOptions;
|
|
|
|
Status = RpcStringBindingParse(
|
|
binding,
|
|
NULL, // don't need current Object ID
|
|
&ProtSeq,
|
|
&NetworkAddr,
|
|
&EndPoint, // Don't need endpoint
|
|
&NetworkOptions);
|
|
|
|
if (Status != RPC_S_OK) // corrupted entry?
|
|
Raise(NSI_S_INVALID_STRING_BINDING);
|
|
|
|
// The following allocates and creates a new string
|
|
|
|
// BUGBUG: for now we keep the endpoint to be compatible with
|
|
// the old locator, but the endpoint really should be removed
|
|
|
|
STRING_T tempBinding = NULL;
|
|
|
|
Status = RpcStringBindingCompose(
|
|
object,
|
|
ProtSeq,
|
|
NetworkAddr,
|
|
EndPoint,
|
|
NetworkOptions,
|
|
&tempBinding
|
|
);
|
|
|
|
if (Status != RPC_S_OK) // must be out of memory
|
|
Raise(NSI_S_OUT_OF_MEMORY);
|
|
|
|
RpcStringFree(&ProtSeq);
|
|
RpcStringFree(&EndPoint);
|
|
RpcStringFree(&NetworkAddr);
|
|
RpcStringFree(&NetworkOptions);
|
|
|
|
return tempBinding;
|
|
|
|
}
|
|
|
|
|
|
void
|
|
I_NSI_NS_HANDLE_T_rundown(
|
|
IN NSI_NS_HANDLE_T InqContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup after an a lookup operation. Internal version.
|
|
|
|
Arguments:
|
|
|
|
InqContext - Context to cleanup
|
|
|
|
--*/
|
|
{
|
|
CContextHandle *pHandle = (CContextHandle *) InqContext;
|
|
|
|
__try {
|
|
|
|
pHandle->rundown();
|
|
}
|
|
__finally {
|
|
|
|
delete pHandle;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void NSI_NS_HANDLE_T_done(
|
|
/* [out][in] */ NSI_NS_HANDLE_T __RPC_FAR *inq_context,
|
|
/* [out] */ UNSIGNED16 __RPC_FAR *status)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A generalized version of the "done" operation for NS context handles.
|
|
|
|
Arguments:
|
|
|
|
inq_context - context handle the client is done with
|
|
|
|
status - status is returned here
|
|
|
|
--*/
|
|
{
|
|
*status = NSI_S_OK;
|
|
|
|
if (*inq_context)
|
|
|
|
__try {
|
|
|
|
I_NSI_NS_HANDLE_T_rundown(*inq_context);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
*status = (UNSIGNED16) GetExceptionCode();
|
|
}
|
|
|
|
*inq_context = NULL;
|
|
}
|
|
|
|
|
|
void __RPC_API
|
|
NSI_NS_HANDLE_T_rundown(
|
|
IN NSI_NS_HANDLE_T InqContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup after an aborted lookup operation.
|
|
This is the one called directly by RPC runtime when needed.
|
|
|
|
Arguments:
|
|
|
|
InqContext - Context to cleanup
|
|
|
|
--*/
|
|
{
|
|
DBGOUT(MEM1,"RPC Called Rundown\n\n");
|
|
|
|
I_NSI_NS_HANDLE_T_rundown(InqContext);
|
|
}
|
|
|
|
|
|
|
|
RPC_BINDING_HANDLE
|
|
ConnectToMasterLocator(
|
|
ULONG& Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Contains the logic for connecting to a master locator, whether in a
|
|
workgroup or domain. Tries to use the cached list of masters in the
|
|
locator object, and if there are none then in a workgroup environment
|
|
tries a broadcast for master locators in the workgroup. When a name
|
|
for a machine with a master is found, the locator is pinged to ensure
|
|
that it is actually alive.
|
|
|
|
Returns:
|
|
|
|
A binding handle to a live master locator, if any. NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
RPC_BINDING_HANDLE hCurrentMaster = NULL;
|
|
|
|
int fHandleWorked = FALSE;
|
|
|
|
TGSLString *pMasters = myRpcLocator->getMasters();
|
|
|
|
if ((pMasters->size() == 0) && (myRpcLocator->IsInWorkgroup()))
|
|
{
|
|
myRpcLocator->TryBroadcastingForMasterLocator();
|
|
pMasters = myRpcLocator->getMasters();
|
|
}
|
|
|
|
TGSLStringIter iterDCs(*pMasters);
|
|
|
|
|
|
CStringW * pPrimaryDCName = myRpcLocator->getPDC();
|
|
|
|
RpcImpersonateClient(0);
|
|
|
|
for (CStringW * pSWcurrentDC = pPrimaryDCName ? pPrimaryDCName : iterDCs.next();
|
|
pSWcurrentDC != NULL;
|
|
pSWcurrentDC = iterDCs.next()
|
|
)
|
|
{
|
|
hCurrentMaster = MakeDClocTolocHandle(*pSWcurrentDC);
|
|
|
|
RpcTryExcept {
|
|
CLIENT_I_nsi_ping_locator(
|
|
hCurrentMaster,
|
|
&Status
|
|
);
|
|
}
|
|
|
|
RpcExcept (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
RpcBindingFree(&hCurrentMaster);
|
|
hCurrentMaster = NULL;
|
|
Status = RpcExceptionCode();
|
|
|
|
if (Status == RPC_S_ACCESS_DENIED)
|
|
Status = NSI_S_NO_NS_PRIVILEGE;
|
|
|
|
/* Unnecessary to set it here
|
|
|
|
if (Status == RPC_S_SERVER_TOO_BUSY)
|
|
Status = NSI_S_NAME_SERVICE_UNAVAILABLE;
|
|
*/
|
|
}
|
|
RpcEndExcept;
|
|
|
|
if (Status != RPC_S_OK) continue;
|
|
|
|
fHandleWorked = TRUE;
|
|
break;
|
|
}
|
|
|
|
RpcRevertToSelf();
|
|
|
|
if (!fHandleWorked) {
|
|
|
|
hCurrentMaster = NULL;
|
|
|
|
if (Status != NSI_S_NO_NS_PRIVILEGE)
|
|
Status = NSI_S_NAME_SERVICE_UNAVAILABLE;
|
|
}
|
|
|
|
return hCurrentMaster;
|
|
}
|
|
|
|
|
|
|
|
NSI_UUID_VECTOR_T *
|
|
getVector(CObjectInqHandle *pInqHandle)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a handle for object lookup, extract all the objects in it
|
|
and format them into a standard object vector. This function
|
|
is always used in creating ObjectInqHandles
|
|
|
|
Arguments:
|
|
|
|
pInqHandle - a context handle for object inquiry
|
|
|
|
Returns:
|
|
|
|
A standard object vector
|
|
--*/
|
|
{
|
|
// we have no idea how many we will have, so we use a simple
|
|
// linked list to gather the UUIDs before setting up the vector
|
|
|
|
int fDone = FALSE;
|
|
|
|
CSimpleLinkList GuidList;
|
|
|
|
while (!fDone) {
|
|
|
|
__try {
|
|
GUID * pGUID = pInqHandle->next();
|
|
if (pGUID) GuidList.insert(pGUID);
|
|
else fDone = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
fDone = TRUE;
|
|
}
|
|
}
|
|
|
|
ULONG ulSize = GuidList.size();
|
|
|
|
NSI_UUID_VECTOR_T *pUuidVector = (NSI_UUID_VECTOR_T *)
|
|
midl_user_allocate(
|
|
sizeof(UNSIGNED32) +
|
|
sizeof(GUID*) * ulSize
|
|
);
|
|
|
|
pUuidVector->count = ulSize;
|
|
|
|
for (ULONG i = 0; i < ulSize; i++)
|
|
pUuidVector->uuid[i] = (GUID*) GuidList.pop();
|
|
|
|
return pUuidVector;
|
|
}
|
|
|
|
|
|
void *new_handler(size_t)
|
|
/* this is just in case we use the standard "new" operation, which we don't */
|
|
{
|
|
Raise(NSI_S_OUT_OF_MEMORY);
|
|
|
|
return NULL; // just to keep the compiler happy, never used
|
|
}
|
|
|
|
|
|
|
|
void
|
|
parseEntryName(
|
|
CONST_STRING_T fullName,
|
|
CStringW * &pswDomainName,
|
|
CStringW * &pswEntryName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses a given entry name into its domain and entry name parts.
|
|
Deals with both global and relative (local) entry name syntax.
|
|
|
|
Arguments:
|
|
|
|
fullName - the name to parse
|
|
|
|
pswDomainName - the domain name (if the input was a global name) is
|
|
returned here. For a local name, NULL is returned.
|
|
|
|
pswEntryName - the relative entry name is returned here.
|
|
|
|
Remarks:
|
|
|
|
The returned values are newly allocated string objects.
|
|
|
|
--*/
|
|
{
|
|
if (memcmp(RelativePrefix, fullName,
|
|
RelativePrefixLength * sizeof(WCHAR))
|
|
== 0) {
|
|
|
|
pswDomainName = NULL;
|
|
pswEntryName = new CStringW(fullName + RelativePrefixLength);
|
|
}
|
|
|
|
else if (memcmp(GlobalPrefix, fullName,
|
|
GlobalPrefixLength * sizeof(WCHAR))
|
|
== 0) {
|
|
|
|
// make a copy starting after the prefix
|
|
|
|
STRING_T domainBegin = CStringW::copyString(fullName + GlobalPrefixLength);
|
|
|
|
for (STRING_T psz = domainBegin;
|
|
(*psz != NSnameDelimiter) && (*psz != WStringTerminator);
|
|
psz++);
|
|
|
|
if (*psz == WStringTerminator) { // no entry name at all
|
|
delete [] domainBegin;
|
|
Raise(NSI_S_INCOMPLETE_NAME);
|
|
}
|
|
|
|
else
|
|
{
|
|
*psz = 0; // the NULL character
|
|
pswDomainName = new CStringW(domainBegin);
|
|
pswEntryName = new CStringW(psz+1);
|
|
delete [] domainBegin;
|
|
}
|
|
|
|
}
|
|
|
|
else // neither relative nor global prefix found
|
|
Raise(NSI_S_UNSUPPORTED_NAME_SYNTAX);
|
|
|
|
}
|
|
|
|
STRING_T
|
|
makeGlobalName(
|
|
const STRING_T szDomainName,
|
|
const STRING_T szEntryName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Formats a global entry name from domain and relative name parts.
|
|
|
|
Arguments:
|
|
|
|
szDomainName - the domain name
|
|
|
|
pswEntryName - the relative entry name
|
|
|
|
Returns
|
|
|
|
A newly allocated global name string
|
|
|
|
--*/
|
|
{
|
|
STRING_T psz1, psz2;
|
|
|
|
psz1 = catenate(TEXT("/"),szEntryName);
|
|
psz2 = catenate(szDomainName,psz1);
|
|
delete [] psz1;
|
|
psz1 = catenate(GlobalPrefix,psz2);
|
|
delete [] psz2;
|
|
return psz1;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
IsNormalCode(
|
|
IN ULONG StatusCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A test to see if a status code is a normal status to return or signifies
|
|
some error of purely internal interest.
|
|
|
|
Arguments:
|
|
|
|
StatusCode - the code to test
|
|
|
|
Returns
|
|
|
|
TRUE if normal, FALSE if internal error (such as failure to connect to master locator).
|
|
|
|
--*/
|
|
{
|
|
return
|
|
(StatusCode < NSI_S_STATUS_MAX) &&
|
|
(StatusCode != NSI_S_NAME_SERVICE_UNAVAILABLE) &&
|
|
(StatusCode != NSI_S_NO_NS_PRIVILEGE) &&
|
|
(StatusCode != NSI_S_OUT_OF_MEMORY) &&
|
|
(StatusCode != NSI_S_NO_MASTER_LOCATOR);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
StripObjectsFrom(
|
|
NSI_BINDING_VECTOR_P_T * BindingVectorOut
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The vector of binding handles normally returned from a lookup handle
|
|
contains binding strings with objects (if objects are present).
|
|
However, this is not usable in locator-to-locator communication
|
|
because the old (Steve Zeck's) locator expects objectless
|
|
strings and simply attaches objects in front of the strings it gets
|
|
from a master. We therefore strip the objects from these strings
|
|
when they are meant to be returned to another locator. This also
|
|
gives us an opportunity to eliminate duplicates, which is important
|
|
because an object inquiry must be done via RPC for every binding
|
|
string returned to the inquiring locator as a result of the weakness
|
|
of the current locator-to-locator interface.
|
|
|
|
Arguments:
|
|
|
|
StatusCode - the code to test
|
|
|
|
Returns
|
|
|
|
TRUE if normal, FALSE if internal error (such as failure to connect to master locator).
|
|
|
|
--*/
|
|
{
|
|
if (!*BindingVectorOut) return;
|
|
|
|
NSI_BINDING_VECTOR_P_T pbvtGivenVector = *BindingVectorOut;
|
|
|
|
TCSafeSkipList<CNSBinding> SSLwinnow;
|
|
|
|
for (ULONG i = 0; i < pbvtGivenVector->count; i++)
|
|
{
|
|
STRING_T pszOld = pbvtGivenVector->binding[i].string;
|
|
STRING_T pszNew = makeBindingStringWithObject(pszOld,NULL);
|
|
pbvtGivenVector->binding[i].string = CStringW::copyMIDLstring(pszNew);
|
|
midl_user_free(pszOld);
|
|
RpcStringFree(&pszNew);
|
|
|
|
CNSBinding *pNSB = new CNSBinding(pbvtGivenVector->binding[i]);
|
|
if (Duplicate == SSLwinnow.insert(pNSB)) delete pNSB;
|
|
}
|
|
|
|
ULONG ulBVcount = SSLwinnow.size();
|
|
|
|
NSI_BINDING_VECTOR_P_T pbvtNewVector =
|
|
(NSI_BINDING_VECTOR_T *)
|
|
midl_user_allocate(sizeof(UNSIGNED32) + sizeof(NSI_BINDING_T)*ulBVcount);
|
|
|
|
pbvtNewVector->count = ulBVcount;
|
|
|
|
TCSafeSkipListIterator<CNSBinding> nsbIter(SSLwinnow);
|
|
|
|
CNSBinding* pNSB = nsbIter.next();
|
|
|
|
for (ULONG j=0; j < ulBVcount; j++)
|
|
{
|
|
pNSB->copyBinding(pbvtNewVector->binding[j]);
|
|
pNSB = nsbIter.next();
|
|
}
|
|
|
|
CBVWrapper destructor(pbvtGivenVector); // wrap to release
|
|
destructor.rundown(); // run down the pbvtGivenVector
|
|
|
|
SSLwinnow.wipeOut(); // release CNSBinding objects
|
|
|
|
*BindingVectorOut = pbvtNewVector;
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
RandomBit(
|
|
unsigned long *pState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generates a "random" bit.
|
|
|
|
Using the MASK32 polynomial this function will have a period of exactly
|
|
2^32-1.
|
|
|
|
A more complete description of this algorithm can be found in "Numerical
|
|
Recipes In C: The Art of Scientific Computation"
|
|
|
|
Never generates a sequence of the same value longer more then 31. This
|
|
doesn't affect the odds much since a more general algorithm would generate
|
|
such a sequence only every 2^31*(32/2) sequences.
|
|
|
|
Arguments:
|
|
|
|
pState - Pointer to a dword of State. This should
|
|
be initalized to a random value (GetTickCount())
|
|
before the first call. It should be unmodified
|
|
between future calls. Must not be zero.
|
|
|
|
Return Value:
|
|
|
|
0 or 1
|
|
|
|
Author: MarioGo
|
|
|
|
--*/
|
|
{
|
|
#define B1 (1)
|
|
#define B2 (1<<1)
|
|
#define B3 (1<<2)
|
|
#define B4 (1<<3)
|
|
#define B5 (1<<4)
|
|
#define B6 (1<<5)
|
|
#define B7 (1<<6)
|
|
#define B32 (1<<31)
|
|
|
|
// Selected polynomial's from table in Numerical Recipes In C.
|
|
|
|
#define MASK30 (B1 + B4 + B6) // for 30,6,4,1,0 polynomial
|
|
|
|
#define MASK32 (B1 + B2 + B3 + B5 + B7) // for 32,7,5,3,2,1,0 polynomial
|
|
|
|
if (*pState & B32)
|
|
{
|
|
*pState = ((*pState ^ MASK32) << 1) | 1;
|
|
return(1);
|
|
}
|
|
|
|
*pState <<= 1;
|
|
return(0);
|
|
}
|
|
|