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.
1206 lines
28 KiB
1206 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
String.cxx
|
|
|
|
Abstract:
|
|
|
|
Methods of construction of various kinds of DUALSTRINGARRAYs.
|
|
|
|
Author:
|
|
|
|
Mario Goertzel [MarioGo]
|
|
|
|
Revision History:
|
|
|
|
MarioGo 04-01-95 Bits 'n pieces
|
|
MarioGO 01-??-96 STRINGARRAYs replaced by DUALSTRINGARRAYs
|
|
|
|
--*/
|
|
|
|
#include <or.hxx>
|
|
#include <mach.hxx>
|
|
|
|
static CONST WCHAR aCallbackSecurity[] = L"Security=Identification Dynamic True";
|
|
static CONST DWORD dwCallbackSecurityLength = sizeof(aCallbackSecurity)/sizeof(WCHAR);
|
|
|
|
|
|
HRESULT dsaAllocateAndCopy(DUALSTRINGARRAY** ppdsaDest, DUALSTRINGARRAY* pdsaSrc)
|
|
{
|
|
ASSERT(ppdsaDest);
|
|
ASSERT(pdsaSrc);
|
|
ASSERT(dsaValid(pdsaSrc));
|
|
|
|
*ppdsaDest = NULL;
|
|
|
|
DWORD dwDSASize = sizeof(USHORT) +
|
|
sizeof(USHORT) +
|
|
(pdsaSrc->wNumEntries * sizeof(WCHAR));
|
|
|
|
*ppdsaDest = (DUALSTRINGARRAY*)MIDL_user_allocate(dwDSASize);
|
|
if (*ppdsaDest)
|
|
{
|
|
// copy in the string bindings
|
|
memcpy(*ppdsaDest, pdsaSrc, dwDSASize);
|
|
ASSERT(dsaValid(*ppdsaDest));
|
|
return S_OK;
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
RPC_BINDING_HANDLE
|
|
GetBinding(
|
|
IN PWSTR pCompressedBinding
|
|
)
|
|
{
|
|
ASSERT(pCompressedBinding);
|
|
|
|
PWSTR pwstrStringBinding;
|
|
PWSTR pwstrProtseq = GetProtseq(*pCompressedBinding);
|
|
PWSTR pwstrT;
|
|
RPC_STATUS Status;
|
|
RPC_BINDING_HANDLE bhReturn;
|
|
BOOL fLocal = FALSE;
|
|
|
|
if (!pwstrProtseq)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
size_t size = OrStringLen(pwstrProtseq) + OrStringLen(pCompressedBinding);
|
|
|
|
if (*pCompressedBinding == ID_LPC)
|
|
{
|
|
fLocal = TRUE;
|
|
size += dwCallbackSecurityLength + 1; // +1 for ','
|
|
}
|
|
|
|
pwstrStringBinding = (PWSTR) alloca(size * sizeof(USHORT));
|
|
if (!pwstrStringBinding)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
OrStringCopy(pwstrStringBinding, pwstrProtseq);
|
|
pwstrT = OrStringSearch(pwstrStringBinding, 0);
|
|
*pwstrT = L':';
|
|
pwstrT++;
|
|
*pwstrT = 0;
|
|
OrStringCopy(pwstrT, pCompressedBinding + 1);
|
|
|
|
if (fLocal)
|
|
{
|
|
// We assume we have an endpoint.
|
|
|
|
pwstrT = OrStringSearch(pwstrT, 0);
|
|
pwstrT--;
|
|
if (*pwstrT != L']')
|
|
{
|
|
KdPrintEx((DPFLTR_DCOMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"OR: Local string binding missing endpoint %S\n",
|
|
pwstrStringBinding));
|
|
|
|
ASSERT(0);
|
|
return(0);
|
|
}
|
|
|
|
*pwstrT = L',';
|
|
pwstrT++;
|
|
OrStringCopy(pwstrT, aCallbackSecurity);
|
|
pwstrT = OrStringSearch(pwstrT, 0);
|
|
*pwstrT = L']';
|
|
*(pwstrT + 1) = 0;
|
|
}
|
|
|
|
Status =
|
|
RpcBindingFromStringBinding( pwstrStringBinding,
|
|
&bhReturn);
|
|
|
|
if (Status != RPC_S_OK)
|
|
{
|
|
KdPrintEx((DPFLTR_DCOMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"OR: Unable to create binding for %S = %d\n",
|
|
pwstrStringBinding,
|
|
Status));
|
|
|
|
bhReturn = NULL;
|
|
}
|
|
|
|
return(bhReturn);
|
|
}
|
|
|
|
|
|
RPC_BINDING_HANDLE
|
|
GetBindingToOr(
|
|
IN PWSTR pwstrCompressedBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets an RPC binding to a remote object resolver given
|
|
a compressed string binding to the remote object resolver.
|
|
|
|
Arguments:
|
|
|
|
pwstrCompressedBinding - a compressed string binding without an endpoint.
|
|
|
|
Return Value:
|
|
|
|
0 - failed to allocate memory or RpcBindingFromStringBinding failed.
|
|
|
|
non-NULL - completed okay
|
|
|
|
--*/
|
|
{
|
|
PWSTR protseq, endpoint;
|
|
PWSTR strbinding;
|
|
size_t len;
|
|
RPC_BINDING_HANDLE bh = 0;
|
|
|
|
ASSERT(pwstrCompressedBinding);
|
|
ASSERT(*pwstrCompressedBinding != 0);
|
|
|
|
protseq = GetProtseq(*pwstrCompressedBinding);
|
|
endpoint = GetEndpoint(*pwstrCompressedBinding);
|
|
|
|
if (0 == protseq || 0 == endpoint)
|
|
{
|
|
ASSERT(0);
|
|
return(0);
|
|
}
|
|
|
|
len = 4; // ':' '[' ']' and '\0'
|
|
len += OrStringLen(protseq);
|
|
len += OrStringLen(endpoint);
|
|
len += OrStringLen(&pwstrCompressedBinding[1]);
|
|
|
|
strbinding = new USHORT[len];
|
|
|
|
if (strbinding)
|
|
{
|
|
PWSTR pwstrT;
|
|
|
|
OrStringCopy(strbinding, protseq); // protseq
|
|
|
|
pwstrT = OrStringSearch(strbinding, 0); // :
|
|
*pwstrT = L':';
|
|
pwstrT++;
|
|
*pwstrT = 0;
|
|
|
|
OrStringCat(strbinding, &pwstrCompressedBinding[1]); // network address
|
|
|
|
pwstrT = OrStringSearch(strbinding, 0); // [
|
|
*pwstrT = L'[';
|
|
pwstrT++;
|
|
*pwstrT = 0;
|
|
|
|
OrStringCat(strbinding, endpoint); // endpoint
|
|
|
|
pwstrT = OrStringSearch(strbinding, 0); // ]
|
|
*pwstrT = L']';
|
|
pwstrT++;
|
|
*pwstrT = 0;
|
|
|
|
RPC_STATUS status = RpcBindingFromStringBinding(strbinding, &bh);
|
|
|
|
ASSERT(bh == 0 || status == RPC_S_OK);
|
|
|
|
delete strbinding;
|
|
}
|
|
|
|
if (bh == 0)
|
|
{
|
|
KdPrintEx((DPFLTR_DCOMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"OR: Unable to bind to %S\n",
|
|
pwstrCompressedBinding + 1));
|
|
}
|
|
|
|
return(bh);
|
|
}
|
|
|
|
|
|
DUALSTRINGARRAY *
|
|
GetStringBinding(
|
|
IN PWSTR pwstrCompressed,
|
|
IN PWSTR pwstrSecurityBindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts the compressed string binding into an expanded
|
|
string binding. An enpoint maybe optionally specified.
|
|
|
|
Arguments:
|
|
|
|
pwstrCompressed - a compressed string binding
|
|
|
|
pwstrSecurityBindings - optional security bindings
|
|
too be tacked onto the end of the expanded string binding.
|
|
Terminated by two nulls.
|
|
|
|
Return Value:
|
|
|
|
NULL - out of memory
|
|
|
|
non-NULL - a string binding. Allocated with MIDL_user_allocate.
|
|
--*/
|
|
{
|
|
DUALSTRINGARRAY *pT;
|
|
PWSTR protseq;
|
|
USHORT seccount;
|
|
|
|
PWSTR t = pwstrSecurityBindings;
|
|
if (t && *t)
|
|
{
|
|
seccount = 0;
|
|
do
|
|
{
|
|
seccount++;
|
|
t++;
|
|
|
|
if (*t == 0)
|
|
{
|
|
seccount++;
|
|
t++;
|
|
}
|
|
}
|
|
while (*t);
|
|
|
|
seccount++; // final NULL
|
|
}
|
|
else
|
|
{
|
|
// Two nulls only.
|
|
seccount = 2;
|
|
}
|
|
|
|
protseq = GetProtseq(*pwstrCompressed);
|
|
if (!protseq)
|
|
return NULL; // not out of memory -- means bindings contained bogus tower id
|
|
|
|
size_t l = OrStringLen(pwstrCompressed) + OrStringLen(protseq) + seccount + 1 + 1;
|
|
|
|
pT =(DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY) + l * sizeof(WCHAR));
|
|
|
|
if (!pT)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
pT->wNumEntries = (USHORT) l;
|
|
OrStringCopy(pT->aStringArray, protseq);
|
|
OrStringCat(pT->aStringArray, L":");
|
|
OrStringCat(pT->aStringArray, pwstrCompressed + 1);
|
|
|
|
if (pwstrSecurityBindings)
|
|
{
|
|
PWSTR t = pT->aStringArray;
|
|
t = OrStringSearch(t, 0);
|
|
t++;
|
|
*t = 0; // Second NULL on string bindings.
|
|
t++;
|
|
OrMemoryCopy(t, pwstrSecurityBindings, seccount*sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
// Add three NULLs, total of four.
|
|
PWSTR t = pT->aStringArray;
|
|
t = OrStringSearch(t, 0);
|
|
t[1] = 0;
|
|
t[2] = 0;
|
|
t[3] = 0;
|
|
}
|
|
|
|
pT->wSecurityOffset = pT->wNumEntries - seccount;
|
|
|
|
ASSERT(dsaValid(pT));
|
|
|
|
return(pT);
|
|
}
|
|
|
|
|
|
ORSTATUS
|
|
ConvertToRemote(
|
|
IN DUALSTRINGARRAY *pdsaLocal,
|
|
OUT DUALSTRINGARRAY **ppdsaRemote
|
|
)
|
|
/* ++
|
|
|
|
Parameters:
|
|
pdsaLocal - An array of string bindings with compressed protseqs.
|
|
|
|
ppdsaRemote - Will contain only those string bindings in pdsaLocal
|
|
which are not "IsLocal()".
|
|
|
|
Note: *ppdsaRemote maybe used as a flag, don't set it to non-NULL
|
|
until it is valid.
|
|
|
|
-- */
|
|
{
|
|
USHORT iTotalSize;
|
|
USHORT iSize;
|
|
USHORT *p1, *p2;
|
|
DUALSTRINGARRAY *pdsaT;
|
|
|
|
// Size remote array
|
|
|
|
// Final null terminator
|
|
iSize = 1;
|
|
|
|
p1 = pdsaLocal->aStringArray;
|
|
|
|
while (*p1)
|
|
{
|
|
if (! IsLocal(*p1) )
|
|
{
|
|
iSize += (USHORT) OrStringLen(p1) + 1;
|
|
}
|
|
p1 = OrStringSearch(p1, 0) + 1;
|
|
}
|
|
|
|
if (iSize == 1)
|
|
{
|
|
iSize = 2; // No non-local strings, need two terminators.
|
|
}
|
|
|
|
iTotalSize = iSize + (pdsaLocal->wNumEntries - pdsaLocal->wSecurityOffset);
|
|
|
|
pdsaT = new(iTotalSize * sizeof(WCHAR)) DUALSTRINGARRAY;
|
|
|
|
if (!pdsaT)
|
|
{
|
|
return(OR_NOMEM);
|
|
}
|
|
|
|
pdsaT->wNumEntries = iTotalSize;
|
|
pdsaT->wSecurityOffset = iSize;
|
|
|
|
p2 = pdsaT->aStringArray;
|
|
|
|
// Copy security bindings
|
|
OrMemoryCopy(p2 + iSize,
|
|
pdsaLocal->aStringArray + pdsaLocal->wSecurityOffset,
|
|
(iTotalSize - iSize) * sizeof(WCHAR));
|
|
|
|
if (iSize == 2)
|
|
{
|
|
// No non-local strings, fill in terminators and return.
|
|
*p2 = 0;
|
|
*(p2 + 1) = 0;
|
|
*ppdsaRemote = pdsaT;
|
|
|
|
ASSERT(dsaValid(pdsaT));
|
|
return(OR_OK);
|
|
}
|
|
|
|
p1 = pdsaLocal->aStringArray;
|
|
|
|
while (*p1)
|
|
{
|
|
if ( ! IsLocal(*p1) )
|
|
{
|
|
OrStringCopy(p2, p1);
|
|
p2 = OrStringSearch(p2, 0) + 1;
|
|
}
|
|
|
|
p1 = OrStringSearch(p1, 0) + 1;
|
|
}
|
|
|
|
*p2 = 0; // Second terminator.
|
|
|
|
*ppdsaRemote = pdsaT;
|
|
|
|
ASSERT(dsaValid(pdsaT));
|
|
return(OR_OK);
|
|
}
|
|
|
|
|
|
DUALSTRINGARRAY *
|
|
CompressStringArrayAndAddIPAddrs(
|
|
IN DUALSTRINGARRAY *pdsaExpanded
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a stringarray of regular string bindings into a
|
|
compressed (protseq's replaced with WORD id's) array of
|
|
string bindings.
|
|
|
|
Arguments:
|
|
|
|
pdsaExpanded - the string array to compress.
|
|
Security information is copied.
|
|
|
|
Return Value:
|
|
|
|
0 - failed to allocate memory.
|
|
|
|
non-0 - compressed string array.
|
|
|
|
--*/
|
|
{
|
|
size_t i, size;
|
|
USHORT *p1, *p2, *p3;
|
|
PWSTR pwstr;
|
|
DUALSTRINGARRAY *pdsaCompressed;
|
|
CIPAddrs* pIPAddrs = gpMachineName->GetIPAddrs();
|
|
ULONG cIPAddrs = 0;
|
|
|
|
// Possible for gpMachineName->GetIPAddrs to return NULL.
|
|
if (pIPAddrs)
|
|
{
|
|
ASSERT(pIPAddrs->_pIPAddresses);
|
|
cIPAddrs = pIPAddrs->_pIPAddresses->Count;
|
|
}
|
|
|
|
// Compute size of result.
|
|
|
|
p1 = pdsaExpanded->aStringArray;
|
|
|
|
size = pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset;
|
|
|
|
if (*p1 == 0)
|
|
{
|
|
size += 2; // two null terminators ONLY.
|
|
}
|
|
else
|
|
{
|
|
size += 1; // last null terminator
|
|
}
|
|
|
|
while (*p1)
|
|
{
|
|
size_t sizeT = OrStringLen(p1);
|
|
|
|
p2 = OrStringSearch(p1, L':'); // ':' is not valid in protseq.
|
|
if (p2)
|
|
{
|
|
// proseq len (p2 - p1) become 1 for Id.
|
|
size_t newLen = (sizeT + 1 - (size_t)(p2 - p1));
|
|
size += newLen;
|
|
|
|
*p2 = 0; // subst NULL just for the compare
|
|
if ((lstrcmpW(L"ncacn_ip_tcp", p1) == 0) ||
|
|
(lstrcmpW(L"ncadg_ip_udp", p1) == 0) ||
|
|
(lstrcmpW(L"ncacn_http", p1) == 0))
|
|
{
|
|
if (pIPAddrs)
|
|
{
|
|
size += pIPAddrs->_pIPAddresses->StringBufferSpace;
|
|
}
|
|
}
|
|
*p2 = L':'; // put the colon back in
|
|
|
|
p1 = OrStringSearch(p2, 0) + 1;
|
|
}
|
|
else
|
|
{
|
|
// Prefix bug: if we got here, this would mean we found a binding
|
|
// that did not have a colon, and we would then have passed a NULL
|
|
// p2 to OrStringSearch. This code is so old I doubt that this
|
|
// case ever has been or will be hit, but better to do the right thing.
|
|
ASSERT(0 && "Malformed binding");
|
|
if (pIPAddrs)
|
|
pIPAddrs->DecRefCount();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
pdsaCompressed = new(size * sizeof(WCHAR)) DUALSTRINGARRAY;
|
|
|
|
if (0 == pdsaCompressed)
|
|
{
|
|
if (pIPAddrs)
|
|
pIPAddrs->DecRefCount();
|
|
return(0);
|
|
}
|
|
|
|
p3 = pdsaCompressed->aStringArray;
|
|
*p3 = 0;
|
|
|
|
p1 = pdsaExpanded->aStringArray;
|
|
|
|
if (*p1 == 0)
|
|
{
|
|
// Loop won't be entered, point p3 to second null terminator
|
|
p3++;
|
|
}
|
|
|
|
while (*p1)
|
|
{
|
|
p2 = OrStringSearch(p1, L':');
|
|
if (p2)
|
|
{
|
|
USHORT TowerId;
|
|
|
|
*p2 = 0;
|
|
*p3 = TowerId = GetProtseqId(p1);
|
|
*p2 = L':';
|
|
if (*p3 != 0)
|
|
{
|
|
p3++;
|
|
p1 = p2 + 1; // Just after ':'
|
|
OrStringCopy(p3, p1);
|
|
// Move p3 to start of next string if any.
|
|
p3 = OrStringSearch(p3, 0) + 1;
|
|
|
|
//
|
|
// add in IP addresses for TCP/IP and UDP/IP
|
|
//
|
|
|
|
if ((TowerId == ID_TCP) || (TowerId == ID_UDP) || (ID_DCOMHTTP == TowerId))
|
|
{
|
|
ULONG i;
|
|
p2 = OrStringSearch(p1, L'[');
|
|
if (p2)
|
|
{
|
|
for (i=0; i<cIPAddrs; i++)
|
|
{
|
|
// do not include the loopback address in server bindings
|
|
if (lstrcmpW(L"127.0.0.1", pIPAddrs->_pIPAddresses->NetworkAddresses[i]) != 0)
|
|
{
|
|
*p3 = TowerId;
|
|
p3++;
|
|
|
|
// copy in IP address
|
|
OrStringCopy(p3, pIPAddrs->_pIPAddresses->NetworkAddresses[i]);
|
|
p3 = OrStringSearch(p3, 0);
|
|
|
|
// copy in rest of string binding
|
|
OrStringCopy(p3, p2);
|
|
|
|
// Move p3 to start of next string if any.
|
|
p3 = OrStringSearch(p3, 0) + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Move p1 to start of next string if any.
|
|
p1 = OrStringSearch(p1, 0) + 1;
|
|
}
|
|
|
|
// Second terminator, p3 already points to it.
|
|
*p3 = 0;
|
|
|
|
pdsaCompressed->wSecurityOffset = (USHORT) (p3 + 1 - pdsaCompressed->aStringArray );
|
|
pdsaCompressed->wNumEntries = pdsaCompressed->wSecurityOffset +
|
|
(pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset);
|
|
|
|
// Copy security bindings
|
|
OrMemoryCopy(p3 + 1,
|
|
pdsaExpanded->aStringArray + pdsaExpanded->wSecurityOffset,
|
|
(pdsaExpanded->wNumEntries - pdsaExpanded->wSecurityOffset) * sizeof(WCHAR));
|
|
|
|
ASSERT(dsaValid(pdsaCompressed));
|
|
|
|
if (pIPAddrs)
|
|
pIPAddrs->DecRefCount();
|
|
|
|
return(pdsaCompressed);
|
|
}
|
|
|
|
|
|
USHORT
|
|
FindMatchingProtseq(
|
|
IN USHORT cClientProtseqs,
|
|
IN USHORT aClientProtseqs[],
|
|
IN PWSTR pwstrServerBindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the first protseq id in aClientProtseqs which appears in any of
|
|
the server bindings.
|
|
|
|
Arguments:
|
|
|
|
cClientProtseqs - the number of entries in aClientProtseqs.
|
|
aClientProtseqs - Protseq tower id's support by the client.
|
|
pwstrServerBindings - compressed array of bindings supported by the server
|
|
terminated by two NULLs.
|
|
|
|
Return Value:
|
|
|
|
0 - no match found.
|
|
non-0 - the matching protseq id.
|
|
|
|
--*/
|
|
|
|
// Called by server oxid's and processes when checking for lazy use protseq.
|
|
{
|
|
ULONG i;
|
|
|
|
if (0 == cClientProtseqs)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
while (*pwstrServerBindings)
|
|
{
|
|
for (i = 0; i < cClientProtseqs; i++)
|
|
{
|
|
if (aClientProtseqs[i] == *pwstrServerBindings)
|
|
{
|
|
return(aClientProtseqs[i]);
|
|
}
|
|
}
|
|
pwstrServerBindings = OrStringSearch(pwstrServerBindings, 0) + 1;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
PWSTR
|
|
FindMatchingProtseq(
|
|
IN USHORT protseq,
|
|
IN PWSTR pwstrCompressedBindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches a compressed string array for an entry which
|
|
matches a particular protseq.
|
|
|
|
|
|
Arguments:
|
|
|
|
protseq - The protseq to search for.
|
|
|
|
pwstrCompressedBindings - The bindings to search.
|
|
|
|
Return Value:
|
|
|
|
0 - not found
|
|
|
|
non-0 - a pointer into the pwstrCompressedBindings
|
|
|
|
--*/
|
|
{
|
|
ASSERT(pwstrCompressedBindings);
|
|
|
|
while (*pwstrCompressedBindings)
|
|
{
|
|
if (*pwstrCompressedBindings == protseq)
|
|
{
|
|
return(pwstrCompressedBindings);
|
|
}
|
|
pwstrCompressedBindings = OrStringSearch(pwstrCompressedBindings, 0) + 1;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
PWSTR
|
|
FindMatchingProtseq(
|
|
IN PWSTR pMachineName,
|
|
IN USHORT protseq,
|
|
IN PWSTR pwstrCompressedBindings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches a compressed string array for an entry which
|
|
matches a particular protseq and machine
|
|
|
|
|
|
Arguments:
|
|
|
|
protseq - The protseq to search for.
|
|
|
|
pMachine - the machine name to search for.
|
|
|
|
pwstrCompressedBindings - The bindings to search.
|
|
|
|
Return Value:
|
|
|
|
0 - not found
|
|
|
|
non-0 - a pointer into the pwstrCompressedBindings
|
|
|
|
--*/
|
|
{
|
|
ASSERT(pwstrCompressedBindings);
|
|
|
|
while (*pwstrCompressedBindings)
|
|
{
|
|
if (*pwstrCompressedBindings == protseq)
|
|
{
|
|
PWSTR pwstrMachineNameTemp = pMachineName;
|
|
|
|
WCHAR* pwstrT = pwstrCompressedBindings + 1;
|
|
BOOL fSkip = FALSE;
|
|
while (*pwstrT && *pwstrMachineNameTemp && ((*pwstrT != L'[') || fSkip))
|
|
{
|
|
fSkip = (*pwstrT == L'\\') && !fSkip;
|
|
|
|
if (towupper(*pwstrMachineNameTemp) != towupper(*pwstrT))
|
|
{
|
|
break;
|
|
}
|
|
pwstrT++;
|
|
pwstrMachineNameTemp++;
|
|
}
|
|
|
|
if (!*pwstrMachineNameTemp && (!*pwstrT || (*pwstrT == L'[')))
|
|
{
|
|
return pwstrCompressedBindings;
|
|
}
|
|
}
|
|
|
|
pwstrCompressedBindings = OrStringSearch(pwstrCompressedBindings, 0) + 1;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
WCHAR *
|
|
ExtractMachineName(WCHAR *pSB)
|
|
{
|
|
|
|
pSB++;
|
|
WCHAR* pwstrT = pSB;
|
|
|
|
BOOL fSkip = FALSE;
|
|
while (*pwstrT && ((*pwstrT != L'[') || fSkip))
|
|
{
|
|
fSkip = (*pwstrT == L'\\') && !fSkip;
|
|
pwstrT++;
|
|
}
|
|
ULONG len = (ULONG)(pwstrT - pSB);
|
|
if (len)
|
|
{
|
|
WCHAR* pMachineName;
|
|
pMachineName = new WCHAR[len + 1];
|
|
if (pMachineName)
|
|
{
|
|
memcpy(pMachineName, pSB, (UINT)((pwstrT - pSB) * sizeof(WCHAR)));
|
|
pMachineName[len] = 0;
|
|
return pMachineName;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
RPC_BINDING_HANDLE
|
|
TestBindingGetHandle(
|
|
IN PWSTR pwstrCompressedBinding
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tests that an OR can be found on the machine identified by the
|
|
compressed binding.
|
|
|
|
Arguments:
|
|
|
|
pwstrCompressedBiding - A compressed stringing binding to the
|
|
server in question. May include an endpoint to something
|
|
other then the endpoint mapper.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PWSTR pwstrT;
|
|
PWSTR pwstrCopy = (PWSTR)alloca( (OrStringLen(pwstrCompressedBinding) + 1)
|
|
* sizeof(WCHAR) );
|
|
|
|
if (pwstrCopy == 0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
OrStringCopy(pwstrCopy, pwstrCompressedBinding);
|
|
|
|
// We need to wack the endpoint out of the string binding.
|
|
// Go read the runtime's string parsing stuff if you're not
|
|
// sure what this is doing. Note: on Win9x this needs to
|
|
// be DBCS enabled...
|
|
|
|
#ifndef NTENV
|
|
#message "Error: string.cxx(): this won't work"
|
|
#endif
|
|
pwstrT = pwstrCopy;
|
|
|
|
while (*pwstrT && *pwstrT != L'[')
|
|
pwstrT++;
|
|
|
|
if (*pwstrT)
|
|
{
|
|
ASSERT(*pwstrT == L'[');
|
|
*pwstrT = 0;
|
|
// Endpoint gone.
|
|
}
|
|
|
|
return GetBindingToOr(pwstrCopy);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CDualStringArray methods
|
|
//
|
|
|
|
DWORD CDualStringArray::AddRef()
|
|
{
|
|
ASSERT(_cRef != 0);
|
|
DWORD cRef = InterlockedIncrement(&_cRef);
|
|
return cRef;
|
|
}
|
|
|
|
DWORD CDualStringArray::Release()
|
|
{
|
|
ASSERT(_cRef > 0);
|
|
DWORD cRef = InterlockedDecrement(&_cRef);
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
return cRef;
|
|
}
|
|
|
|
CDualStringArray::~CDualStringArray()
|
|
{
|
|
ASSERT(_cRef == 0);
|
|
|
|
// free the dual string array
|
|
MIDL_user_free( _pdsa );
|
|
}
|
|
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
RPC_STATUS CParallelPing::Ping()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls ServerAlive2 on all supplied bindings asyncronously. First binding
|
|
that completles succesfully is chosen. Remaining calls are cancelled.
|
|
|
|
Arguments:
|
|
|
|
None;
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK
|
|
RPC_S_CALL_FAILED
|
|
|
|
--*/
|
|
{
|
|
ULONG cHandlesMax = 0;
|
|
const ULONG cBlockSize = 10;
|
|
|
|
_cCalls = 0;
|
|
_cReceived = 0;
|
|
_arAsyncCallInfo = NULL;
|
|
|
|
//
|
|
// First ping that succeeds sets _ndxWinner to it's index + 1
|
|
//
|
|
_ndxWinner = 0;
|
|
|
|
//
|
|
// send off all the calls
|
|
//
|
|
|
|
RPC_STATUS sc;
|
|
|
|
ULONG i;
|
|
for (i=0; _ndxWinner == 0; i++)
|
|
{
|
|
|
|
//
|
|
// allocate/resize arrays to hold call state
|
|
//
|
|
|
|
if (i >= cHandlesMax)
|
|
{
|
|
REALLOC(MIDL_user_allocate, MIDL_user_free,
|
|
PRPC_ASYNC_STATE,
|
|
_arAsyncCallInfo, cHandlesMax, cHandlesMax+cBlockSize, sc)
|
|
if (FAILED(sc))
|
|
{
|
|
break;
|
|
}
|
|
memset(_arAsyncCallInfo+cHandlesMax, 0, (sizeof(PRPC_ASYNC_STATE) * cBlockSize));
|
|
|
|
cHandlesMax += cBlockSize;
|
|
}
|
|
if (i >= _cProtseqMax)
|
|
{
|
|
REALLOC(MIDL_user_allocate, MIDL_user_free,
|
|
PROTSEQINFO, _pProtseqInfo,
|
|
_cProtseqMax, _cProtseqMax+cBlockSize, sc)
|
|
if (FAILED(sc))
|
|
{
|
|
break;
|
|
}
|
|
_cProtseqMax += cBlockSize;
|
|
}
|
|
|
|
if (i == _cHandles)
|
|
{
|
|
// get more handles
|
|
if (!NextCall(_pProtseqInfo+i))
|
|
{
|
|
// no more, so we're done
|
|
break;
|
|
}
|
|
|
|
_cHandles++;
|
|
|
|
//
|
|
// turn off serialization
|
|
//
|
|
|
|
sc = RpcBindingSetOption(_pProtseqInfo[i].hRpc, RPC_C_OPT_BINDING_NONCAUSAL, TRUE);
|
|
if (sc != RPC_S_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Initialize the COM version, to the minimum (so if the call
|
|
// fails with RPC_S_PROCNUM_OUT_OF_RANGE, we know the right
|
|
// answer.
|
|
//
|
|
_pProtseqInfo[i].comVersion.MajorVersion = 5;
|
|
_pProtseqInfo[i].comVersion.MinorVersion = 1;
|
|
}
|
|
|
|
if (_pProtseqInfo[i].hRpc == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
_arAsyncCallInfo[i] = (PRPC_ASYNC_STATE) MIDL_user_allocate(sizeof(RPC_ASYNC_STATE));
|
|
if (_arAsyncCallInfo[i] == NULL)
|
|
{
|
|
sc = RPC_S_OUT_OF_MEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// set up async information
|
|
//
|
|
|
|
sc = RpcAsyncInitializeHandle(_arAsyncCallInfo[i],
|
|
sizeof(RPC_ASYNC_STATE));
|
|
//
|
|
// If this succeeds we pass the ownership of _arAsyncCallInfo[i] to the callback
|
|
//
|
|
if (sc != RPC_S_OK)
|
|
{
|
|
MIDL_user_free(_arAsyncCallInfo[i]);
|
|
_arAsyncCallInfo[i] = NULL;
|
|
break;
|
|
}
|
|
_arAsyncCallInfo[i]->NotificationType = RpcNotificationTypeApc;
|
|
_arAsyncCallInfo[i]->u.APC.NotificationRoutine = ServerAliveAPC;
|
|
_arAsyncCallInfo[i]->u.APC.hThread = 0;
|
|
_arAsyncCallInfo[i]->UserInfo = (void *)this;
|
|
|
|
|
|
_cCalls++;
|
|
//
|
|
// begin the call
|
|
//
|
|
|
|
RPC_STATUS ret = ServerAlive2( _arAsyncCallInfo[i],
|
|
_pProtseqInfo[i].hRpc,
|
|
&(_pProtseqInfo[i].comVersion),
|
|
&_tmpOrBindings,
|
|
&_tmpReserved );
|
|
|
|
if (ret != RPC_S_OK)
|
|
{
|
|
ServerAliveWork(_arAsyncCallInfo[i], ret);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// stagger the calls
|
|
//
|
|
|
|
SleepEx(PARALLEL_PING_STAGGER_TIME, TRUE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// wait for successful ping or for all calls to
|
|
// return
|
|
//
|
|
|
|
while ( (_ndxWinner == 0) && ((_cCalls - _cReceived) > 0) )
|
|
{
|
|
SleepEx(INFINITE, TRUE);
|
|
}
|
|
|
|
//
|
|
// Cancel the calls left outstanding if there are any
|
|
//
|
|
|
|
if ((_cCalls - _cReceived) > 0)
|
|
{
|
|
for (i = 0; i<_cHandles; i++)
|
|
{
|
|
if (_arAsyncCallInfo[i] != NULL)
|
|
{
|
|
// we purposely ignore the return code here. Even if it failed
|
|
// there wouldn't be much we could do.
|
|
RPC_STATUS retDontCare = RpcAsyncCancelCall(_arAsyncCallInfo[i], TRUE);
|
|
if (retDontCare != RPC_S_OK)
|
|
{
|
|
KdPrintEx((DPFLTR_DCOMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"OR: RpcAsyncCancelCall failed - this is non-fatal; ret=%d\n",
|
|
retDontCare));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// wait for cancelled calls to return
|
|
//
|
|
|
|
while ( (_cCalls - _cReceived) > 0)
|
|
{
|
|
SleepEx(INFINITE, TRUE);
|
|
}
|
|
}
|
|
|
|
// Free call infos
|
|
if (_arAsyncCallInfo)
|
|
{
|
|
#if DBG
|
|
for (i=0; i < cHandlesMax; ++i)
|
|
{
|
|
ASSERT(_arAsyncCallInfo[i] == NULL);
|
|
}
|
|
#endif
|
|
MIDL_user_free(_arAsyncCallInfo);
|
|
}
|
|
|
|
//
|
|
// return results
|
|
//
|
|
|
|
_arAsyncCallInfo = NULL;
|
|
|
|
if (_ndxWinner != 0)
|
|
{
|
|
_pWinner = _pProtseqInfo + _ndxWinner - 1;
|
|
return RPC_S_OK;
|
|
}
|
|
else
|
|
{
|
|
_pWinner = NULL;
|
|
|
|
//
|
|
// give precedence to failure which occured while attempting
|
|
// to make calls.
|
|
//
|
|
|
|
if (sc != RPC_S_OK)
|
|
{
|
|
return sc;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(_sc != RPC_S_OK);
|
|
return _sc;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServerAliveAPC( IN PRPC_ASYNC_STATE pAsyncState,
|
|
IN void *Context,
|
|
IN RPC_ASYNC_EVENT Flags)
|
|
{
|
|
CParallelPing *pParallelPing = (CParallelPing *)pAsyncState->UserInfo;
|
|
|
|
pParallelPing->ServerAliveWork(pAsyncState, RPC_S_OK);
|
|
}
|
|
|
|
|
|
void CParallelPing::ServerAliveWork( PRPC_ASYNC_STATE pAsyncState, RPC_STATUS scBegin)
|
|
{
|
|
RPC_STATUS tmpStatus;
|
|
_tmpOrBindings = NULL;
|
|
|
|
if (scBegin == RPC_S_OK)
|
|
{
|
|
_sc = RpcAsyncCompleteCall(pAsyncState, &tmpStatus);
|
|
}
|
|
else
|
|
{
|
|
_sc = scBegin;
|
|
}
|
|
|
|
// If there are no saved bindings, save these.
|
|
if (_pdsaOrBindings == NULL && dsaValid(_tmpOrBindings))
|
|
{
|
|
_pdsaOrBindings = _tmpOrBindings;
|
|
_tmpOrBindings = NULL;
|
|
}
|
|
else
|
|
{
|
|
MIDL_user_free( _tmpOrBindings );
|
|
_tmpOrBindings = NULL;
|
|
}
|
|
|
|
_cReceived++;
|
|
|
|
ULONG uMyIndex = 0;
|
|
|
|
for (uMyIndex=0; uMyIndex < _cHandles; ++uMyIndex)
|
|
{
|
|
if (_arAsyncCallInfo[uMyIndex] == pAsyncState)
|
|
{
|
|
MIDL_user_free(pAsyncState);
|
|
_arAsyncCallInfo[uMyIndex] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (uMyIndex == _cHandles)
|
|
{
|
|
ASSERT(uMyIndex < _cHandles);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// First protocol to succeed is the winner
|
|
//
|
|
if (_ndxWinner == 0)
|
|
{
|
|
if ((_sc == RPC_S_OK) || (_sc == RPC_S_PROCNUM_OUT_OF_RANGE))
|
|
{
|
|
_ndxWinner = uMyIndex + 1;
|
|
_sc = RPC_S_OK;
|
|
}
|
|
}
|
|
}
|