windows-nt/Source/XPSP1/NT/com/rpc/runtime/trans/common/mq.cxx
2020-09-26 16:20:57 +08:00

2358 lines
68 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
mq.cxx
Abstract:
This is the code that actually makes Falcon API calls. It is
used by the Falcon/RPC transport (mqtrans.cxx)
Author:
Edward Reus (edwardr) 05-Jul-1997
Revision History:
--*/
#include <precomp.hxx>
#include <trans.hxx>
#include <dgtrans.hxx>
#include <wswrap.hxx>
#include <rpc.h>
#include <rpcdce.h>
#include <mqmgr.h>
#include "mqtrans.hxx"
static HINSTANCE g_hMqRt = 0;
FALCON_API *g_pMqApi = 0;
static CQueueMap *g_pQueueMap = 0;
char placeHolder[sizeof(MUTEX)]; // provide placeholder for the mutex
MUTEX *gp_csContext = (MUTEX *)placeHolder; // the mutex itself
#ifdef UNICODE
#define ptszVal pwszVal
#define VT_LPTSTR VT_LPWSTR
#else
#define ptszVal pszVal
#define VT_LPTSTR VT_LPSTR
#endif
static PCONTEXT_HANDLE g_pContext = 0;
// WARNING: the size and ordering of g_arszMqApis is dependent
// on the definition of the FALCON_API structure in mqtrans.hxx
// WARNING: When you are freeing Falcon allocated strings, do
// *not* use MQFreeMemory. Use MQFreeStringFromProperty. Otherwise
// you will break Win98 code.
const static char *g_arszMqApis[] = {
"MQLocateBegin",
"MQLocateNext",
"MQLocateEnd",
"MQInstanceToFormatName",
"MQOpenQueue",
"MQFreeMemory",
"MQSendMessage",
"MQReceiveMessage",
"MQCloseQueue",
"MQDeleteQueue",
"MQPathNameToFormatName",
"MQCreateQueue",
"MQGetMachineProperties",
"MQGetQueueProperties",
"MQSetQueueProperties",
NULL };
// Error mappings for MQ_MapStatusCode():
typedef struct _STATUS_MAPPING
{
HRESULT hr;
RPC_STATUS status;
} STATUS_MAPPING;
const static STATUS_MAPPING g_StatusMap[] =
{
{ MQ_OK, RPC_S_OK },
{ MQ_ERROR_IO_TIMEOUT, RPC_P_TIMEOUT },
{ MQ_ERROR_INSUFFICIENT_RESOURCES, RPC_S_OUT_OF_MEMORY },
{ MQ_ERROR_QUEUE_NOT_FOUND, RPC_S_SERVER_UNAVAILABLE },
{ MQ_ERROR, RPC_S_INTERNAL_ERROR },
{ MQMSG_CLASS_NACK_BAD_DST_Q, RPC_S_SERVER_UNAVAILABLE },
{ MQMSG_CLASS_NACK_PURGED, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_REACH_QUEUE_TIMEOUT, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_Q_EXCEED_QUOTA, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_ACCESS_DENIED, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_HOP_COUNT_EXCEEDED, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_BAD_SIGNATURE, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_BAD_ENCRYPTION, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_COULD_NOT_ENCRYPT, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_NOT_TRANSACTIONAL_Q, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_NOT_TRANSACTIONAL_MSG,RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_Q_DELETED, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_Q_PURGED, RPC_S_CALL_FAILED_DNE },
{ MQMSG_CLASS_NACK_RECEIVE_TIMEOUT, RPC_S_CALL_FAILED_DNE },
{ MQ_ERROR_ILLEGAL_QUEUE_PATHNAME, RPC_S_INVALID_ENDPOINT_FORMAT}
};
//----------------------------------------------------------------
// MQ_Initialize()
//
// Called by DG_TransportLoad() to initialize the ncadg_mq
// transport. This function does a dynamic load of the Falcon
// runtime DLL (MQRT.DLL) and creates a call table to access
// the Falcon API. If successful, return TRUE, else return
// FALSE.
//----------------------------------------------------------------
BOOL
MQ_Initialize()
{
BOOL fStatus = TRUE;
RPC_STATUS RpcStatus = RPC_S_OK;
// Make sure the function count is correct...
ASSERT( sizeof(g_arszMqApis)-sizeof(PVOID) == sizeof(FALCON_API) );
//
gp_csContext = new (gp_csContext) MUTEX(&RpcStatus);
if (RpcStatus != RPC_S_OK)
{
return FALSE;
}
// Get the MSMQ runtime library:
g_hMqRt = LoadLibrary(TEXT("mqrt.dll"));
if (!g_hMqRt)
{
fStatus = FALSE;
}
// Build up the MSMQ call table that we will use to access
// the MSMQ C API:
if (fStatus)
{
g_pMqApi = (FALCON_API*)I_RpcAllocate(sizeof(FALCON_API));
if (!g_pMqApi)
{
fStatus = FALSE;
}
}
if (fStatus)
{
FARPROC *ppFn = (FARPROC*)g_pMqApi;
int i = 0;
while (g_arszMqApis[i])
{
*ppFn = GetProcAddress(g_hMqRt,g_arszMqApis[i++]);
if (!*ppFn)
{
fStatus = FALSE;
break;
}
ppFn++;
}
}
if (fStatus)
{
g_pQueueMap = new CQueueMap;
if (!g_pQueueMap)
{
fStatus = FALSE;
}
else
{
fStatus = g_pQueueMap->Initialize();
}
}
if (!fStatus)
{
gp_csContext->Free();
if (g_hMqRt)
{
FreeLibrary(g_hMqRt);
g_hMqRt = 0;
}
if (g_pQueueMap)
{
delete g_pQueueMap;
g_pQueueMap = 0;
}
if (g_pMqApi)
{
I_RpcFree(g_pMqApi);
g_pMqApi = 0;
}
}
return fStatus;
}
//----------------------------------------------------------------
// MQ_MapStatusCode()
//
// Convert a MQ HRESULT status to a RPC_STATUS code.
//----------------------------------------------------------------
RPC_STATUS MQ_MapStatusCode( HRESULT hr, RPC_STATUS defaultStatus )
{
int iSize = sizeof(g_StatusMap)/sizeof(STATUS_MAPPING);
RPC_STATUS status = defaultStatus;
for (int i=0; i<iSize; i++)
{
if (hr == g_StatusMap[i].hr)
{
status = g_StatusMap[i].status;
break;
}
}
return status;
}
//----------------------------------------------------------------
// MQ_InitOptions()
//
// Initialize transport specific binding handle options structure.
//----------------------------------------------------------------
RPC_STATUS RPC_ENTRY MQ_InitOptions( IN void PAPI *pvTransportOptions )
{
RPC_STATUS status = RPC_S_OK;
MQ_OPTIONS *pOpts = (MQ_OPTIONS*)pvTransportOptions;
if (pOpts)
{
memset(pOpts,0,sizeof(MQ_OPTIONS));
pOpts->ulPriority = DEFAULT_PRIORITY;
pOpts->ulTimeToReachQueue = INFINITE;
pOpts->ulTimeToReceive = INFINITE;
}
else
{
status = RPC_S_OUT_OF_MEMORY;
}
return status;
}
//----------------------------------------------------------------
// MQ_SetOption()
//
// Set transport specific binding handle options.
//----------------------------------------------------------------
RPC_STATUS RPC_ENTRY MQ_SetOption( IN void PAPI *pvTransportOptions,
IN unsigned long option,
IN ULONG_PTR optionValue )
{
RPC_STATUS status = RPC_S_OK;
MQ_OPTIONS *pOpts = (MQ_OPTIONS*)pvTransportOptions;
switch (option)
{
case RPC_C_OPT_MQ_DELIVERY:
if ( (optionValue == RPC_C_MQ_EXPRESS)
|| (optionValue == RPC_C_MQ_RECOVERABLE) )
pOpts->ulDelivery = (unsigned long) optionValue;
else
status = RPC_S_INVALID_ARG;
break;
case RPC_C_OPT_MQ_PRIORITY:
if (optionValue <= MQ_MAX_PRIORITY)
pOpts->ulPriority = (unsigned long) optionValue;
else
pOpts->ulPriority = MQ_MAX_PRIORITY;
break;
case RPC_C_OPT_MQ_JOURNAL:
if ( (optionValue == RPC_C_MQ_JOURNAL_NONE)
|| (optionValue == RPC_C_MQ_JOURNAL_ALWAYS)
|| (optionValue == RPC_C_MQ_JOURNAL_DEADLETTER) )
pOpts->ulJournaling = (unsigned long) optionValue;
else
status = RPC_S_INVALID_ARG;
break;
case RPC_C_OPT_MQ_TIME_TO_REACH_QUEUE:
pOpts->ulTimeToReachQueue = (unsigned long) optionValue;
break;
case RPC_C_OPT_MQ_TIME_TO_BE_RECEIVED:
pOpts->ulTimeToReceive = (unsigned long) optionValue;
break;
case RPC_C_OPT_MQ_ACKNOWLEDGE:
pOpts->fAck = (optionValue != FALSE);
break;
case RPC_C_OPT_MQ_AUTHN_SERVICE:
if (optionValue == RPC_C_AUTHN_MQ)
{
status = RPC_S_OK;
}
else if (optionValue == RPC_C_AUTHN_NONE)
{
pOpts->fAuthenticate = FALSE;
pOpts->fEncrypt = FALSE;
status = RPC_S_OK;
}
else
{
status = RPC_S_UNKNOWN_AUTHN_SERVICE;
}
break;
case RPC_C_OPT_MQ_AUTHN_LEVEL:
if (optionValue > RPC_C_AUTHN_LEVEL_NONE)
{
pOpts->fAuthenticate = TRUE;
pOpts->fEncrypt = (optionValue == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)? TRUE : FALSE;
}
else
{
pOpts->fAuthenticate = FALSE;
pOpts->fEncrypt = FALSE;
}
break;
default:
status = RPC_S_CANNOT_SUPPORT;
break;
}
// The following is some code to make sure the RPC_C_xxx
// constants always have the correct values:
#if ( (RPC_C_MQ_EXPRESS != MQMSG_DELIVERY_EXPRESS) \
|| (RPC_C_MQ_RECOVERABLE != MQMSG_DELIVERY_RECOVERABLE) )
#error "RPC constants wrong"
#endif
#if ( (RPC_C_MQ_JOURNAL_NONE != MQMSG_JOURNAL_NONE) \
|| (RPC_C_MQ_JOURNAL_ALWAYS != MQMSG_JOURNAL) \
|| (RPC_C_MQ_JOURNAL_DEADLETTER != MQMSG_DEADLETTER) )
#error "RPC constants wrong"
#endif
return status;
}
//----------------------------------------------------------------
// MQ_InqOption()
//
// Get transport specific binding handle options.
//----------------------------------------------------------------
RPC_STATUS RPC_ENTRY MQ_InqOption( IN void PAPI *pvTransportOptions,
IN unsigned long option,
OUT ULONG_PTR *pOptionValue )
{
RPC_STATUS status = RPC_S_OK;
MQ_OPTIONS *pOpts = (MQ_OPTIONS*)pvTransportOptions;
switch (option)
{
case RPC_C_OPT_MQ_DELIVERY:
*pOptionValue = pOpts->ulDelivery;
break;
case RPC_C_OPT_MQ_PRIORITY:
*pOptionValue = pOpts->ulPriority;
break;
case RPC_C_OPT_MQ_JOURNAL:
*pOptionValue = pOpts->ulJournaling;
break;
case RPC_C_OPT_MQ_TIME_TO_REACH_QUEUE:
*pOptionValue = pOpts->ulTimeToReachQueue;
break;
case RPC_C_OPT_MQ_TIME_TO_BE_RECEIVED:
*pOptionValue = pOpts->ulTimeToReceive;
break;
case RPC_C_OPT_MQ_ACKNOWLEDGE:
*pOptionValue = pOpts->fAck;
break;
default:
status = RPC_S_INVALID_ARG;
*pOptionValue = 0;
break;
}
return status;
}
//----------------------------------------------------------------
// MQ_ImplementOptions()
//
// Apply transport specific binding handle options to the
// specified server.
//----------------------------------------------------------------
RPC_STATUS RPC_ENTRY MQ_ImplementOptions(
IN DG_TRANSPORT_ENDPOINT pvTransEndpoint,
IN void *pvTransportOptions )
{
RPC_STATUS Status = RPC_S_OK;
HRESULT hr;
MQ_OPTIONS *pOpts = (MQ_OPTIONS*)pvTransportOptions;
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)pvTransEndpoint;
pEndpoint->fAck = pOpts->fAck;
pEndpoint->ulDelivery = pOpts->ulDelivery;
pEndpoint->ulPriority = pOpts->ulPriority;
pEndpoint->ulJournaling = pOpts->ulJournaling;
pEndpoint->ulTimeToReachQueue = pOpts->ulTimeToReachQueue;
pEndpoint->ulTimeToReceive = pOpts->ulTimeToReceive;
pEndpoint->fAuthenticate = pOpts->fAuthenticate;
pEndpoint->fEncrypt = pOpts->fEncrypt;
//
// If the fAck flag is set, then we want to get an acknowledgement
// for each call (message) as it gets to the destination (server)
// queue. So, setup an admin queue to receive Falcon ACK messages.
//
if ( (pEndpoint->fAck) && (pEndpoint->hAdminQueue == 0) )
{
hr = SetupAdminQueue(pEndpoint);
Status = MQ_MapStatusCode(hr,RPC_S_INTERNAL_ERROR);
if (Status == RPC_S_OK)
{
MQ_RegisterQueueToDelete(pEndpoint->wsAdminQFormat,pEndpoint->wsMachine);
}
}
return Status;
}
//----------------------------------------------------------------
// MQ_BuildAddressVector()
//
//----------------------------------------------------------------
RPC_STATUS MQ_BuildAddressVector( OUT NETWORK_ADDRESS_VECTOR **ppVector )
{
DWORD dwSize;
RPC_CHAR wsMachine[MAX_COMPUTERNAME_LEN];
NETWORK_ADDRESS_VECTOR *pVector;
dwSize = sizeof(wsMachine)/sizeof(RPC_CHAR);
GetComputerName((RPC_SCHAR *)wsMachine,&dwSize);
*ppVector = 0;
pVector = new( sizeof(RPC_CHAR*)
+ sizeof(RPC_CHAR)*(1+RpcpStringLength(wsMachine)) )
NETWORK_ADDRESS_VECTOR;
if (!pVector)
{
return RPC_S_OUT_OF_MEMORY;
}
pVector->Count = 1;
pVector->NetworkAddresses[0] = (RPC_CHAR*)(&pVector->NetworkAddresses[1]);
RpcpStringCopy(pVector->NetworkAddresses[0],wsMachine);
*ppVector = pVector;
return RPC_S_OK;
}
//----------------------------------------------------------------
// MQ_FillInAddress()
//
//----------------------------------------------------------------
RPC_STATUS MQ_FillInAddress( MQ_ADDRESS *pAddress,
MQPROPVARIANT *pMsgProps )
{
pAddress->fAuthenticated = pMsgProps[I_AUTHENTICATED].bVal;
pAddress->ulPrivacyLevel = pMsgProps[I_PRIVACY_LEVEL].ulVal;
ParseQueuePathName( (RPC_CHAR *)pMsgProps[I_MESSAGE_LABEL].ptszVal,
pAddress->wsMachine,
pAddress->wsQName );
return RPC_S_OK;
}
#ifdef TRANSPORT_DLL
//----------------------------------------------------------------
// MIDL_user_allocate()
//
// Used by Mq_RegisterQueueToDelete().
//----------------------------------------------------------------
void __RPC_FAR * __RPC_USER MIDL_user_allocate( size_t len )
{
return (I_RpcAllocate(len));
}
//----------------------------------------------------------------
// MIDL_user_free()
//
// Used by Mq_RegisterQueueToDelete().
//----------------------------------------------------------------
void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
{
I_RpcFree(ptr);
}
#endif
//----------------------------------------------------------------
// MQ_RegisterQueueToDelete()
//
//----------------------------------------------------------------
RPC_STATUS MQ_RegisterQueueToDelete( RPC_CHAR *pwsQFormat,
RPC_CHAR *pwsMachine )
{
RPC_STATUS Status;
RPC_CHAR *pwsStringBinding;
RPC_BINDING_HANDLE hBinding = 0;
ASSERT(pwsQFormat);
gp_csContext->Request();
// This is a long critical section... but only for the first call.
if (!g_pContext)
{
Status = RpcStringBindingCompose( NULL,
Q_SVC_PROTSEQ,
pwsMachine,
Q_SVC_ENDPOINT,
NULL,
&pwsStringBinding );
if (RPC_S_OK == Status)
{
Status = RpcBindingFromStringBinding( pwsStringBinding,
&hBinding );
if (RPC_S_OK != Status)
{
gp_csContext->Clear();
return Status;
}
RpcStringFree(&pwsStringBinding);
RpcTryExcept
{
Status = MqGetContext(hBinding,&g_pContext);
Status = RpcBindingFree(&hBinding);
}
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
{
Status = RpcExceptionCode();
}
RpcEndExcept
}
}
gp_csContext->Clear();
if (g_pContext)
{
Status = MqRegisterQueue(g_pContext,pwsQFormat);
}
return Status;
}
//----------------------------------------------------------------
// ConstructQueuePathName()
//
// Return Value: TRUE on success.
// FALSE on fail (Path Name buffer too small).
//----------------------------------------------------------------
BOOL ConstructQueuePathName( IN RPC_CHAR *pwsMachine,
IN RPC_CHAR *pwsQName,
OUT RPC_CHAR *pwsPathName,
IN OUT DWORD *pdwSize )
{
BOOL status = TRUE;
DWORD len = sizeof(RPC_CHAR) * (1 + RpcpStringLength(pwsMachine)
+ RpcpStringLength(WS_SEPARATOR)
+ RpcpStringLength(pwsQName) );
if (*pdwSize < len)
{
status = FALSE;
}
else
{
RpcpStringCopy(pwsPathName,pwsMachine);
RpcpStringCat(pwsPathName,WS_SEPARATOR);
RpcpStringCat(pwsPathName,pwsQName);
}
*pdwSize = len;
return status;
}
//----------------------------------------------------------------
// ConstructPrivateQueuePathName()
//
// Return Value: TRUE on success.
// FALSE on fail (Path Name buffer too small).
//----------------------------------------------------------------
BOOL ConstructPrivateQueuePathName( IN RPC_CHAR *pwsMachine,
IN RPC_CHAR *pwsQName,
OUT RPC_CHAR *pwsPathName,
IN OUT DWORD *pdwSize )
{
BOOL status = TRUE;
DWORD dwSize = sizeof(RPC_CHAR) * (1 + RpcpStringLength(pwsMachine)
+ RpcpStringLength(WS_PRIVATE_DOLLAR)
+ RpcpStringLength(pwsQName) );
if (*pdwSize < dwSize)
{
status = FALSE;
}
else
{
RpcpStringCopy(pwsPathName,pwsMachine);
RpcpStringCat(pwsPathName,WS_PRIVATE_DOLLAR);
RpcpStringCat(pwsPathName,pwsQName);
}
*pdwSize = dwSize;
return status;
}
#ifdef USE_PRIVATE_QUEUES
//----------------------------------------------------------------
// ConstructPrivateDirectFormat()
//
// Return Value: TRUE on success.
// FALSE on fail (Path Name buffer too small).
//----------------------------------------------------------------
BOOL ConstructPrivateDirectFormat( IN RPC_CHAR *pwsMachine,
IN RPC_CHAR *pwsQName,
OUT RPC_CHAR *pwsPathName,
IN OUT DWORD *pdwSize )
{
BOOL status = TRUE;
DWORD dwSize = sizeof(RPC_CHAR) * (1 + RpcpStringLength(WS_DIRECT),
+ RpcpStringLength(pwsMachine)
+ RpcpStringLength(WS_PRIVATE_DOLLAR)
+ RpcpStringLength(pwsQName) );
if (*pdwSize < dwSize)
{
status = FALSE;
}
else
{
RpcpStringCopy(pwsPathName,WS_DIRECT);
RpcpStringCat(pwsPathName,pwsMachine);
RpcpStringCat(pwsPathName,WS_PRIVATE_DOLLAR);
RpcpStringCat(pwsPathName,pwsQName);
}
*pdwSize = dwSize;
return status;
}
#endif
#if FALSE
//----------------------------------------------------------------
// ConstructDirectFormat()
//
// Return Value: TRUE on success.
// FALSE on fail (Path Name buffer too small).
//----------------------------------------------------------------
BOOL ConstructDirectFormat( IN RPC_CHAR *pwsMachine,
IN RPC_CHAR *pwsQName,
OUT RPC_CHAR *pwsPathName,
IN OUT DWORD *pdwSize )
{
BOOL status = TRUE;
DWORD dwSize = sizeof(RPC_CHAR) * (1 + RpcpStringLength(WS_DIRECT)
+ RpcpStringLength(pwsMachine)
+ RpcpStringLength(WS_SEPARATOR)
+ RpcpStringLength(pwsQName) );
if (*pdwSize < dwSize)
{
status = FALSE;
}
else
{
RpcpStringCopy(pwsPathName,WS_DIRECT);
RpcpStringCat(pwsPathName,pwsMachine);
RpcpStringCat(pwsPathName,WS_SEPARATOR);
RpcpStringCat(pwsPathName,pwsQName);
}
*pdwSize = dwSize;
return status;
}
#endif
//----------------------------------------------------------------
// ParseQueuePathName()
//
// For RPC's use of MQ, a queue path name is of the form:
// "machine_name\queue_name" or "machine\PRIVATE$\queue_name".
// This routine extracts the machine name and queue name from
// a given queue path name.
//
// Return Value: TRUE on success.
// FALSE on fail (Can't find the "\" separator).
//----------------------------------------------------------------
BOOL ParseQueuePathName(
IN RPC_CHAR *pwsPathName,
OUT RPC_CHAR wsMachineName[MAX_COMPUTERNAME_LEN],
OUT RPC_CHAR wsQueueName[MQ_MAX_Q_NAME_LEN] )
{
BOOL status = TRUE;
RPC_CHAR *pSlash;
pSlash = (RPC_CHAR *)RpcpCharacter(pwsPathName,*(WS_SEPARATOR));
if (pSlash)
{
*pSlash = (RPC_CHAR)0;
RpcpStringCopy(wsMachineName,pwsPathName);
*pSlash = *(WS_SEPARATOR);
}
else
status = FALSE;
if (status)
{
pSlash = (RPC_CHAR *)RpcpCharacter(pwsPathName,*(WS_SEPARATOR));
if (pSlash)
{
RpcpStringCopy(wsQueueName,++pSlash);
}
else
status = FALSE;
}
return status;
}
//--------------------------------------------------------------------
// LocateQueueViaQName()
//
// Try to find a MQ queue of type specified by the Queue UUID (the
// queue type) with the specified queue name. The first one that is
// found (if any) is returned.
//--------------------------------------------------------------------
HRESULT LocateQueueViaQName( IN OUT MQ_ADDRESS *pAddress )
{
HRESULT hr = MQ_OK;
HANDLE hEnum;
int iSize;
DWORD dwSize;
DWORD cProps;
DWORD cQueue;
UUID QUuid;
QUEUEPROPID aqPropId[MAX_VAR];
MQPROPVARIANT aPropVar[MAX_VAR];
MQPROPERTYRESTRICTION aPropRestrict[MAX_VAR];
MQRESTRICTION restrict;
MQCOLUMNSET column;
RPC_CHAR wsMachine[MAX_COMPUTERNAME_LEN];
RPC_CHAR wsQName[MQ_MAX_Q_NAME_LEN];
if (RPC_S_OK != UuidFromString(SVR_QTYPE_UUID_STR,&QUuid))
{
return MQ_ERROR;
}
// Set up the restriction properties such that we will
// only find our queue (of type pQUuid):
cProps = 0;
aPropRestrict[cProps].rel = PREQ;
aPropRestrict[cProps].prop = PROPID_Q_TYPE;
aPropRestrict[cProps].prval.vt = VT_CLSID;
aPropRestrict[cProps].prval.puuid = &QUuid;
cProps++;
ASSERT(cProps < MAX_VAR);
restrict.cRes = cProps;
restrict.paPropRes = aPropRestrict;
cProps = 0;
aqPropId[cProps++] = PROPID_Q_INSTANCE;
aqPropId[cProps++] = PROPID_Q_PATHNAME;
ASSERT(cProps < MAX_VAR);
column.cCol = cProps;
column.aCol = aqPropId;
// Ok, do a locate enumeration:
hr = MQLocateBegin(NULL,&restrict,&column,NULL,&hEnum);
if (FAILED(hr))
{
return hr;
}
cQueue = cProps;
while (cQueue > 0)
{
hr = MQLocateNext( hEnum, &cQueue, aPropVar );
if (FAILED(hr))
{
MQLocateEnd(hEnum);
return hr;
}
if (cQueue > 0)
{
// Now extract the queue name from the path name:
if (ParseQueuePathName((RPC_CHAR *)(aPropVar[1].ptszVal),wsMachine,wsQName))
{
if (!RpcpStringCompare(pAddress->wsQName,wsQName))
{
// We have a match! Ok, get the format name,
// cleanup then return...
// Transform the queue instance UUID into a
// format name:
dwSize = sizeof(pAddress->wsQFormat);
hr = MQInstanceToFormatName( aPropVar[0].puuid, pAddress->wsQFormat, &dwSize);
if (FAILED(hr))
{
break;
}
// Free memory allocated by MQLocateNext():
MQFreeMemory(aPropVar[0].puuid); // From: PROPID_Q_INSTANCE
MQFreeStringFromProperty(&aPropVar[1]); // From: PROPID_Q_PATHNAME
// Machine name:
RpcpStringCopy(pAddress->wsMachine,wsMachine);
break;
}
}
// Free memory allocated by MQLocateNext():
MQFreeMemory(aPropVar[0].puuid); // From: PROPID_Q_INSTANCE
MQFreeStringFromProperty(&aPropVar[1]); // From: PROPID_Q_PATHNAME
}
}
MQLocateEnd(hEnum);
if (cQueue == 0)
{
return MQ_ERROR_QUEUE_NOT_FOUND;
}
return hr;
}
//----------------------------------------------------------------
// CreateQueue()
//
// Create a MQ queue of the specified path name.
//
// Return Value: MQ HRESULT value.
//
//----------------------------------------------------------------
HRESULT CreateQueue( IN SECURITY_DESCRIPTOR *pSecurityDescriptor,
IN UUID *pQueueUuid,
IN RPC_CHAR *pwsPathName,
IN RPC_CHAR *pwsQueueLabel,
IN ULONG ulQueueFlags,
OUT RPC_CHAR *pwsFormat,
IN OUT DWORD *pdwFormatSize )
{
HRESULT hr;
DWORD cProps;
DWORD dwSize;
MQQUEUEPROPS qProps;
MQPROPVARIANT aPropVar[MAX_VAR];
QUEUEPROPID aqPropId[MAX_VAR];
//
// Setup properties to create a queue on this machine:
//
cProps = 0;
// Set the PathName:
aqPropId[cProps] = PROPID_Q_PATHNAME;
aPropVar[cProps].vt = VT_LPTSTR;
aPropVar[cProps].ptszVal = (RPC_SCHAR *)pwsPathName;
cProps++;
// Set the type of the queue (this is a UUID).
// This can be used to locate RPC specific queues.
if (pQueueUuid)
{
aqPropId[cProps] = PROPID_Q_TYPE;
aPropVar[cProps].vt = VT_CLSID;
aPropVar[cProps].puuid = pQueueUuid;
cProps++;
}
// Do we want to force authentication of messages
// on the queue?
if (ulQueueFlags & RPC_C_MQ_AUTHN_LEVEL_PKT_INTEGRITY)
{
aqPropId[cProps] = PROPID_Q_AUTHENTICATE;
aPropVar[cProps].vt = VT_UI1;
aPropVar[cProps].bVal = TRUE;
cProps++;
}
// Do we want to force encrypted messages?
if (ulQueueFlags & RPC_C_MQ_AUTHN_LEVEL_PKT_PRIVACY)
{
aqPropId[cProps] = PROPID_Q_PRIV_LEVEL;
aPropVar[cProps].vt = VT_UI4;
aPropVar[cProps].ulVal = MQ_PRIV_LEVEL_BODY;
cProps++;
}
// Put a description to the queue.
// Useful for administration purposes (through the MSMQ admin tools).
aqPropId[cProps] = PROPID_Q_LABEL;
aPropVar[cProps].vt = VT_LPTSTR;
aPropVar[cProps].ptszVal = (RPC_SCHAR *)pwsQueueLabel;
cProps++;
ASSERT(cProps < MAX_VAR);
// Assemble the QUEUEPROPS structure:
qProps.cProp = cProps;
qProps.aPropID = aqPropId;
qProps.aPropVar = aPropVar;
qProps.aStatus = 0;
//-------------------------------------------------------
// Create the queue
hr = MQCreateQueue( pSecurityDescriptor,// Queue permissions.
&qProps, // Queue properties.
pwsFormat, // Format Name [out].
pdwFormatSize ); // Size of Format Name [in,out].
return hr;
}
//----------------------------------------------------------------
// ConnectToServerQueue()
//
//----------------------------------------------------------------
RPC_STATUS ConnectToServerQueue( MQ_ADDRESS *pAddress,
RPC_CHAR *pNetworkAddress,
RPC_CHAR *pEndpoint )
{
HRESULT hr;
DWORD dwSize;
RPC_CHAR wsQPathName[MAX_PATHNAME_LEN];
//
// First, check the end point:
//
if ( (pEndpoint == NULL)
|| (*pEndpoint == '\0')
|| (RpcpStringLength(pEndpoint) >= MQ_MAX_Q_NAME_LEN) )
{
return RPC_S_INVALID_ENDPOINT_FORMAT;
}
memset(pAddress,0,sizeof(MQ_ADDRESS));
RpcpStringCopy(pAddress->wsQName,pEndpoint);
//
// Now, if the server was specified, then use it as is,
// otherwise use the local machine name:
//
if ( (pNetworkAddress == NULL) || (*pNetworkAddress == '\0') )
{
dwSize = sizeof(pAddress->wsMachine);
GetComputerName((RPC_SCHAR *)pAddress->wsMachine,&dwSize);
}
else if (RpcpStringLength(pNetworkAddress) >= MAX_COMPUTERNAME_LEN)
{
return RPC_S_INVALID_ENDPOINT_FORMAT;
}
else
{
RpcpStringCopy(pAddress->wsMachine,pNetworkAddress);
}
//
// If the server name is a "*", then locate a server (andy) that
// has the specified queue name:
//
if (!RpcpStringCompare(pAddress->wsMachine,WS_ASTRISK))
{
hr = LocateQueueViaQName(pAddress);
if (FAILED(hr))
{
return RPC_S_SERVER_UNAVAILABLE;
}
}
#if FALSE
//
// Try to use a direct format to get to the server queue:
//
dwSize = sizeof(pAddress->wsQFormat);
if (!ConstructDirectFormat( pAddress->wsMachine,
pAddress->wsQName,
pAddress->wsQFormat,
&dwSize))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ConnectToServerQueue(): ConstructDirectFormat() failed.\n"));
return RPC_S_SERVER_UNAVAILABLE;
}
hr = MQOpenQueue( pAddress->wsQFormat,
MQ_SEND_ACCESS, 0, &(pAddress->hQueue) );
if (!FAILED(hr))
{
return RPC_S_OK;
}
#endif
//
// If we get here, then the direct format failed, so try using
// a lookup (MQPathNameToFormatName()):
//
dwSize = sizeof(wsQPathName);
if (!ConstructQueuePathName( pAddress->wsMachine,
pAddress->wsQName,
wsQPathName,
&dwSize ))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ConnectToServerQueue(): ConstructQueuePathName() failed.\n"));
return RPC_S_SERVER_UNAVAILABLE;
}
dwSize = sizeof(pAddress->wsQFormat);
hr = MQPathNameToFormatName( wsQPathName,
pAddress->wsQFormat,
&dwSize );
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL, RPCTRANS "ConnectToServerQueue(): MQPathNameToFormatName() failed: 0x%x\n",
hr));
return RPC_S_SERVER_UNAVAILABLE;
}
hr = MQOpenQueue( pAddress->wsQFormat,
MQ_SEND_ACCESS, 0, &(pAddress->hQueue) );
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ConnectToServerQueue(): MQOpenQueue() failed: 0x%x\n",
hr));
return RPC_S_SERVER_UNAVAILABLE;
}
return RPC_S_OK;
}
//----------------------------------------------------------------
// DisconnectFromServer()
//
//----------------------------------------------------------------
RPC_STATUS DisconnectFromServer( IN OUT MQ_ADDRESS *pAddress )
{
DWORD Status = NO_ERROR;
if ((pAddress) && (pAddress->hQueue))
{
MQCloseQueue(pAddress->hQueue);
pAddress->hQueue = 0;
}
return Status;
}
//----------------------------------------------------------------
// SetQueueProperties()
//
// Set the properties for an already existing queue. Currently
// the only two Falcon queue properties that need to be set are
// for forcing message authentication and encryption.
//
// Return Value: MQ HRESULT value.
//
//----------------------------------------------------------------
HRESULT SetQueueProperties( IN RPC_CHAR *pwsQFormat,
IN ULONG ulQueueFlags )
{
HRESULT hr = MQ_OK;
DWORD cProps = 0;
DWORD dwSize;
MQQUEUEPROPS qProps;
MQPROPVARIANT aPropVar[MAX_VAR];
QUEUEPROPID aqPropId[MAX_VAR];
HRESULT aStatus[MAX_VAR];
// Do we want to force authentication of messages
// on the queue?
if (ulQueueFlags & RPC_C_MQ_AUTHN_LEVEL_PKT_INTEGRITY)
{
aqPropId[cProps] = PROPID_Q_AUTHENTICATE;
aPropVar[cProps].vt = VT_UI1;
aPropVar[cProps].bVal = TRUE;
cProps++;
}
else
{
aqPropId[cProps] = PROPID_Q_AUTHENTICATE;
aPropVar[cProps].vt = VT_UI1;
aPropVar[cProps].bVal = FALSE;
cProps++;
}
// Do we want to force encrypted messages?
if (ulQueueFlags & RPC_C_MQ_AUTHN_LEVEL_PKT_PRIVACY)
{
aqPropId[cProps] = PROPID_Q_PRIV_LEVEL;
aPropVar[cProps].vt = VT_UI4;
aPropVar[cProps].ulVal = MQ_PRIV_LEVEL_BODY;
cProps++;
}
else
{
aqPropId[cProps] = PROPID_Q_PRIV_LEVEL;
aPropVar[cProps].vt = VT_UI4;
aPropVar[cProps].ulVal = MQ_PRIV_LEVEL_OPTIONAL;
cProps++;
}
// Assemble the QUEUEPROPS structure:
qProps.cProp = cProps;
qProps.aPropID = aqPropId;
qProps.aPropVar = aPropVar;
qProps.aStatus = 0;
// Set the new queue properties:
hr = MQSetQueueProperties(pwsQFormat,&qProps);
return hr;
}
//--------------------------------------------------------------------
// ClearQueue()
//
// Clear out all waiting messages from the specified queue (if
// any).
//
//--------------------------------------------------------------------
HRESULT ClearQueue( QUEUEHANDLE hQueue )
{
HRESULT hr;
DWORD cProps = 0;
MQMSGPROPS msgProps;
MSGPROPID aMsgPropID[MAX_RECV_VAR];
MQPROPVARIANT aMsgPropVar[MAX_RECV_VAR];
RPC_CHAR wsMsgLabel[MQ_MAX_MSG_LABEL_LEN];
//
// MQ doesn't seem to let me clear out the queue (by reading
// messages) unless we have at least one queue property.
//
aMsgPropID[cProps] = PROPID_M_LABEL;
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)wsMsgLabel;
cProps++;
aMsgPropID[cProps] = PROPID_M_LABEL_LEN;
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = sizeof(wsMsgLabel);
cProps++;
msgProps.cProp = cProps;
msgProps.aPropID = aMsgPropID;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = 0;
//
// pull up all pending MQ messages.
//
while (TRUE)
{
hr = MQReceiveMessage(hQueue,0,MQ_ACTION_RECEIVE,
&msgProps,NULL,NULL,NULL,NULL);
if (FAILED(hr))
break;
}
//
// A timeout means the queue is empty:
//
if (hr == MQ_ERROR_IO_TIMEOUT)
hr = MQ_OK;
return hr;
}
//----------------------------------------------------------------
// ClientSetupQueue()
//
// Called by MQ_CreateEndpoint() to create and initialize the
// client's message queue (to read server responses).
//
// pEP -- The structure that will hold information about
// the queue being created and setup.
//
// pwsMachine -- The machine to create the queue on.
//
// pwsEndpoint -- RPC_CHAR string name of the endpoint. This will
// be used as the queue name.
//
//----------------------------------------------------------------
HRESULT ClientSetupQueue( MQ_DATAGRAM_ENDPOINT *pEndpoint,
RPC_CHAR *pwsMachine,
RPC_CHAR *pwsEndpoint )
{
HRESULT hr;
DWORD dwSize;
// The computer name for the server process:
if (pEndpoint->wsMachine != pwsMachine)
{
RpcpStringCopy(pEndpoint->wsMachine,pwsMachine);
}
// The endpoint string (RPC_CHAR) is used as the queue name:
RpcpStringCopy(pEndpoint->wsQName,pwsEndpoint);
// Build the path name for the server queue:
dwSize = sizeof(pEndpoint->wsQPathName);
ConstructQueuePathName( pEndpoint->wsMachine, // [in]
pEndpoint->wsQName, // [in]
pEndpoint->wsQPathName, // [out]
&dwSize ); // [in,out]
// Try to create the client process's receive queue (for
// responses back from the RPC server):
UuidFromString( CLNT_QTYPE_UUID_STR, &(pEndpoint->uuidQType) );
dwSize = sizeof(pEndpoint->wsQFormat);
hr = CreateQueue( NULL, // [in] No security descriptor.
&(pEndpoint->uuidQType), // [in]
pEndpoint->wsQPathName, // [in]
pEndpoint->wsQName, // [in] Use QName as the QLabel.
0x00000000, // [in] Flags
pEndpoint->wsQFormat, // [out]
&dwSize ); // [in,out]
if ( (FAILED(hr)) && (hr != MQ_ERROR_QUEUE_EXISTS) )
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ClientSetupQueue(): CreateQueue(): 0x%x\n",
hr));
return hr;
}
//
// If the queue already exists, then locate it.
//
// NOTE: Currently client queues are temporary, but if cases
// are added in the future where client queues can be
// presistent, then this code will be needed.
//
if (hr == MQ_ERROR_QUEUE_EXISTS)
{
dwSize = sizeof(pEndpoint->wsQFormat);
hr = MQPathNameToFormatName( pEndpoint->wsQPathName,
pEndpoint->wsQFormat,
&dwSize );
if (FAILED(hr))
return hr;
}
//
// Ok, open the receive queue:
//
hr = MQOpenQueue( pEndpoint->wsQFormat, MQ_RECEIVE_ACCESS, 0, &(pEndpoint->hQueue));
#if FALSE
if (!FAILED(hr))
{
pEndpoint->fInitialized = TRUE;
}
#endif
#ifdef DBG
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ClientSetupQueue(): MQOpenQueueFailed(): 0x%x\n",
hr));
}
#endif
return hr;
}
//----------------------------------------------------------------
// ClientCloseQueue()
//
//----------------------------------------------------------------
HRESULT ClientCloseQueue( MQ_DATAGRAM_ENDPOINT *pEndpoint )
{
ASSERT(pEndpoint);
if (pEndpoint->hQueue)
{
MQCloseQueue(pEndpoint->hQueue);
pEndpoint->hQueue = 0;
}
g_pQueueMap->Remove(pEndpoint->wsQFormat);
MQDeleteQueue(pEndpoint->wsQFormat);
return MQ_OK;
}
//----------------------------------------------------------------
// QueryQM()
//
//----------------------------------------------------------------
HRESULT QueryQM( RPC_CHAR *pwsMachine,
DWORD *pdwSize )
{
DWORD cProps = 0;
HRESULT hr;
MQQMPROPS msgProps;
MSGPROPID aMsgPropID[MAX_RECV_VAR];
MQPROPVARIANT aMsgPropVar[MAX_RECV_VAR];
aMsgPropID[cProps] = PROPID_QM_PATHNAME; // 0
aMsgPropVar[cProps].vt = VT_NULL;
cProps++;
ASSERT( cProps < MAX_RECV_VAR );
msgProps.cProp = cProps;
msgProps.aPropID = aMsgPropID;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = 0;
// The following receive should always fail, we're just calling
// it to get the size of the message body:
hr = MQGetMachineProperties( NULL, NULL, &msgProps );
if (FAILED(hr))
{
return hr;
}
RpcpStringCopy(pwsMachine,aMsgPropVar[0].pwszVal);
MQFreeStringFromProperty(&aMsgPropVar[0]);
#ifdef MAJOR_DBG
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "QueryQM(): wsMachine: %S\n",
pwsMachine));
#endif
return hr;
}
//----------------------------------------------------------------
// ServerSetupQueue()
//
// Called by MQ_CreateEndpoint() to create and initialize the
// server process's message queue (endpoint).
//
// pEP -- The struct to hold information about the queue
// that is being set up.
//
// pwsMachine -- The machine to create the queue on. For RPC this
// is always the machine that the server process is
// running on.
//
// pwsEndpoint - The name of the endpoint. This will be used as
// the queue name.
//
// pSecurityDescriptor -- User may specify a security descriptor
// to apply to this queue (may be NULL).
//
// dwEndpointFlags -- Flags to control queue properties.
//
//----------------------------------------------------------------
HRESULT ServerSetupQueue( MQ_DATAGRAM_ENDPOINT *pEndpoint,
RPC_CHAR *pwsMachine,
RPC_CHAR *pwsEndpoint,
void *pSecurityDescriptor,
DWORD dwEndpointFlags )
{
HRESULT hr;
DWORD dwSize;
// The computer name for the server process:
if (pEndpoint->wsMachine != pwsMachine)
{
RpcpStringCopy(pEndpoint->wsMachine,pwsMachine);
}
// The endpoint string (RPC_CHAR) is used as the queue name:
if (pEndpoint->wsQName != pwsEndpoint)
{
RpcpStringCopy(pEndpoint->wsQName,pwsEndpoint);
}
// Build the path name for the server queue:
dwSize = sizeof(pEndpoint->wsQPathName);
if (!ConstructQueuePathName( pEndpoint->wsMachine, // [in]
pEndpoint->wsQName, // [in]
pEndpoint->wsQPathName, // [out]
&dwSize )) // [in,out]
{
return MQ_ERROR_ILLEGAL_QUEUE_PATHNAME;
}
// Try to create the server process receive queue;
UuidFromString( SVR_QTYPE_UUID_STR, &(pEndpoint->uuidQType) );
dwSize = sizeof(pEndpoint->wsQFormat);
hr = CreateQueue( (SECURITY_DESCRIPTOR*)pSecurityDescriptor,
&(pEndpoint->uuidQType), // [in]
pEndpoint->wsQPathName, // [in]
pEndpoint->wsQName, // [in] Use QName as the QLabel.
dwEndpointFlags, // [in]
pEndpoint->wsQFormat, // [out]
&dwSize ); // [in,out]
// If the queue already exists, then locate it:
if (hr == MQ_ERROR_QUEUE_EXISTS)
{
dwSize = sizeof(pEndpoint->wsQFormat);
hr = MQPathNameToFormatName( pEndpoint->wsQPathName,
pEndpoint->wsQFormat,
&dwSize );
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ServerSetupQueue(): MQPathNameToFormatName() failed: 0x%x\n",
hr));
return hr;
}
if ( !(dwEndpointFlags & RPC_C_MQ_USE_EXISTING_SECURITY) )
{
hr = SetQueueProperties(pEndpoint->wsQFormat,dwEndpointFlags);
if (FAILED(hr))
{
return hr;
}
}
}
else if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ServerSetupQueue(): CreateQueue() failed: 0x%x\n",
hr));
return hr;
}
//
// Ok, open the receive queue:
//
hr = MQOpenQueue( pEndpoint->wsQFormat, MQ_RECEIVE_ACCESS, 0, &(pEndpoint->hQueue));
//
// Does the user want to make sure the queue is empty (in case it
// was a perminent queue):
//
if ( (hr == MQ_OK) && (dwEndpointFlags & RPC_C_MQ_CLEAR_ON_OPEN) )
{
hr = ClearQueue(pEndpoint->hQueue);
}
#ifdef DBG
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "ServerSetupQueue(): MQOpenQueue() failed: 0x%x\n",
hr));
}
#endif
return hr;
}
//----------------------------------------------------------------
// ServerCloseQueue()
//
//----------------------------------------------------------------
HRESULT ServerCloseQueue( MQ_DATAGRAM_ENDPOINT *pEndpoint )
{
ASSERT(pEndpoint);
if (pEndpoint->hQueue)
{
MQCloseQueue(pEndpoint->hQueue);
pEndpoint->hQueue = 0;
}
// MQDeleteQueue(pEndpoint->wsQFormat);
return MQ_OK;
}
//----------------------------------------------------------------
// AsyncPeekQueue()
//
//----------------------------------------------------------------
HRESULT AsyncPeekQueue( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
IN MQ_OVERLAPPED *pOl )
{
DWORD cProps = 0;
HRESULT hr;
pOl->aMsgPropID[cProps] = PROPID_M_BODY_SIZE;
pOl->aMsgPropVar[cProps].vt = VT_UI4;
pOl->aMsgPropVar[cProps].ulVal = 0;
cProps++;
ASSERT( cProps < MAX_RECV_VAR );
pOl->msgProps.cProp = cProps;
pOl->msgProps.aPropID = pOl->aMsgPropID;
pOl->msgProps.aPropVar = pOl->aMsgPropVar;
pOl->msgProps.aStatus = pOl->aStatus;
hr = MQReceiveMessage( pEndpoint->hQueue,
INFINITE,
MQ_ACTION_PEEK_CURRENT,
&pOl->msgProps,
&pOl->ol, // Asynchronous.
NULL, // No callback.
NULL, // Message filter.
NULL ); // Transaction object.
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "AsyncPeekQueue() failed: 0x%x\n",
hr));
}
return hr;
}
//----------------------------------------------------------------
// AsyncReadQueue()
//
//----------------------------------------------------------------
HRESULT AsyncReadQueue( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
IN MQ_OVERLAPPED *pOl,
OUT MQ_ADDRESS *pAddress,
OUT UCHAR *pBuffer,
IN DWORD dwBufferSize )
{
DWORD cProps = 0;
HRESULT hr;
pOl->aMsgPropID[cProps] = PROPID_M_BODY; // [0]
pOl->aMsgPropVar[cProps].vt = (VT_UI1 | VT_VECTOR);
pOl->aMsgPropVar[cProps].caub.cElems = dwBufferSize;
pOl->aMsgPropVar[cProps].caub.pElems = pBuffer;
cProps++;
ASSERT(cProps == I_MESSAGE_SIZE);
pOl->aMsgPropID[cProps] = PROPID_M_BODY_SIZE; // [1]
pOl->aMsgPropVar[cProps].vt = VT_UI4;
cProps++;
ASSERT(cProps == I_MESSAGE_LABEL);
pOl->aMsgPropID[cProps] = PROPID_M_LABEL; // [2]
pOl->aMsgPropVar[cProps].vt = VT_LPWSTR;
pOl->aMsgPropVar[cProps].pwszVal = (WCHAR *)pAddress->wsMsgLabel;
cProps++;
pOl->aMsgPropID[cProps] = PROPID_M_LABEL_LEN; // [3]
pOl->aMsgPropVar[cProps].vt = VT_UI4;
pOl->aMsgPropVar[cProps].ulVal = sizeof(pAddress->wsMsgLabel);
cProps++;
pOl->aMsgPropID[cProps] = PROPID_M_RESP_QUEUE; // [4]
pOl->aMsgPropVar[cProps].vt = VT_LPWSTR;
pOl->aMsgPropVar[cProps].pwszVal = (WCHAR *)pAddress->wsQFormat;
cProps++;
pOl->aMsgPropID[cProps] = PROPID_M_RESP_QUEUE_LEN; // [5]
pOl->aMsgPropVar[cProps].vt = VT_UI4;
pOl->aMsgPropVar[cProps].ulVal = sizeof(pAddress->wsQFormat);
cProps++;
//
// These message properties are for authentication and privacy:
//
ASSERT(cProps == I_AUTHENTICATED);
pOl->aMsgPropID[cProps] = PROPID_M_AUTHENTICATED; // [6]
pOl->aMsgPropVar[cProps].vt = VT_UI1;
pOl->aMsgPropVar[cProps].bVal = 0;
cProps++;
ASSERT(cProps == I_PRIVACY_LEVEL);
pOl->aMsgPropID[cProps] = PROPID_M_PRIV_LEVEL; // [7]
pOl->aMsgPropVar[cProps].vt = VT_UI4;
pOl->aMsgPropVar[cProps].ulVal = 0;
cProps++;
//
// WARNING: these always need to be the last two properties
// in the arrays (see the while loop below):
//
pOl->aMsgPropID[cProps] = PROPID_M_SENDERID_TYPE; // [8]
pOl->aMsgPropVar[cProps].vt = VT_UI4;
pOl->aMsgPropVar[cProps].ulVal = 0;
cProps++;
pOl->aMsgPropID[cProps] = PROPID_M_SENDERID; // [9]
pOl->aMsgPropVar[cProps].vt = (VT_UI1 | VT_VECTOR);
pOl->aMsgPropVar[cProps].caub.cElems = sizeof(pAddress->aSidBuffer);
pOl->aMsgPropVar[cProps].caub.pElems = pAddress->aSidBuffer;
cProps++;
ASSERT( cProps < MAX_RECV_VAR );
pOl->msgProps.cProp = cProps;
pOl->msgProps.aPropID = pOl->aMsgPropID;
pOl->msgProps.aPropVar = pOl->aMsgPropVar;
pOl->msgProps.aStatus = pOl->aStatus;
hr = MQReceiveMessage( pEndpoint->hQueue,
INFINITE,
MQ_ACTION_RECEIVE,
&pOl->msgProps,
&pOl->ol, // Asynchronous.
NULL, // No callback.
NULL, // Message filter.
NULL ); // Transaction object.
#ifdef DBG
if ( (hr != MQ_OK)
&& (hr != MQ_INFORMATION_OPERATION_PENDING)
&& (hr != MQ_ERROR_BUFFER_OVERFLOW) )
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "AsyncReadQueue() failed: 0x%x\n",
hr));
}
#endif
return hr;
}
//----------------------------------------------------------------
// MQ_SendToQueue()
//
// Send a PDU to somebody (specified by pAddress).
//
// pEndpoint -- My (endpoint) for responses.
//
// pAddress -- The destination queue.
//
// pBuffer -- The data PDU to send.
//
// dwBufferSize The size of the PDU (bytes).
//
//----------------------------------------------------------------
HRESULT MQ_SendToQueue( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
IN MQ_ADDRESS *pAddress,
IN UCHAR *pBuffer,
IN DWORD dwBufferSize )
{
HRESULT hr;
DWORD cProps = 0;
MQMSGPROPS msgProps;
MSGPROPID aMsgPropID[MAX_SEND_VAR];
MQPROPVARIANT aMsgPropVar[MAX_SEND_VAR];
HRESULT aStatus[MAX_SEND_VAR];
// NOTE: If you add MQ properties to be sent, make sure that
// MAX_SEND_VAR is large enough...
// Message body contains the packet being sent:
aMsgPropID[cProps] = PROPID_M_BODY;
aMsgPropVar[cProps].vt = (VT_UI1 | VT_VECTOR);
aMsgPropVar[cProps].caub.cElems = dwBufferSize;
aMsgPropVar[cProps].caub.pElems = pBuffer;
cProps++;
// The size of the packet:
#if FALSE
aMsgPropID[cProps] = PROPID_M_BODY_SIZE;
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = dwBufferSize;
cProps++;
#endif
// Pass the sender (me) as the queue label. The queue label
// holds the my Queue Path Name:
aMsgPropID[cProps] = PROPID_M_LABEL;
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)pEndpoint->wsQPathName;
cProps++;
// Delivery (express or recoverable):
aMsgPropID[cProps] = PROPID_M_DELIVERY;
aMsgPropVar[cProps].vt = VT_UI1;
aMsgPropVar[cProps].bVal = (unsigned char)(pEndpoint->ulDelivery);
cProps++;
// Priority (MQ_MIN_PRIORITY to MQ_MAX_PRIORITY):
aMsgPropID[cProps] = PROPID_M_PRIORITY;
aMsgPropVar[cProps].vt = VT_UI1;
aMsgPropVar[cProps].bVal = (unsigned char)(pEndpoint->ulPriority);
cProps++;
// Journaling (none, deadletter or journal):
aMsgPropID[cProps] = PROPID_M_JOURNAL;
aMsgPropVar[cProps].vt = VT_UI1;
aMsgPropVar[cProps].bVal = (unsigned char)(pEndpoint->ulJournaling);
cProps++;
// Time limit to reach destination queue (seconds):
aMsgPropID[cProps] = PROPID_M_TIME_TO_REACH_QUEUE;
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = pEndpoint->ulTimeToReachQueue;
cProps++;
// Time limit for call to be received (seconds):
aMsgPropID[cProps] = PROPID_M_TIME_TO_BE_RECEIVED;
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = pEndpoint->ulTimeToReceive;
cProps++;
// Response Queue:
aMsgPropID[cProps] = PROPID_M_RESP_QUEUE;
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)pEndpoint->wsQFormat;
cProps++;
// Authentication:
aMsgPropID[cProps] = PROPID_M_AUTH_LEVEL;
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = (pEndpoint->fAuthenticate)? MQMSG_AUTH_LEVEL_ALWAYS : MQMSG_AUTH_LEVEL_NONE;
cProps++;
// Encryption:
aMsgPropID[cProps] = PROPID_M_PRIV_LEVEL;
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = (pEndpoint->fEncrypt)? MQMSG_PRIV_LEVEL_BODY : MQMSG_PRIV_LEVEL_NONE;
cProps++;
// Call (message) acknowledgment:
if (pEndpoint->fAck)
{
aMsgPropID[cProps] = PROPID_M_ACKNOWLEDGE;
aMsgPropVar[cProps].vt = VT_UI1;
aMsgPropVar[cProps].bVal = MQMSG_ACKNOWLEDGMENT_FULL_REACH_QUEUE;
cProps++;
aMsgPropID[cProps] = PROPID_M_ADMIN_QUEUE;
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)pEndpoint->wsAdminQFormat;
cProps++;
}
ASSERT( cProps < MAX_SEND_VAR );
msgProps.cProp = cProps;
msgProps.aPropID = aMsgPropID;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = aStatus;
if ( (!pAddress->hQueue)
&& !(pAddress->hQueue = g_pQueueMap->Lookup(pAddress->wsQFormat)) )
{
hr = MQOpenQueue( pAddress->wsQFormat,
MQ_SEND_ACCESS, 0, &(pAddress->hQueue) );
if (FAILED(hr))
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "MQ_SendToQueue(): MQOpenQueue() failed: 0x%x\n",
hr));
return hr;
}
if (!g_pQueueMap->Add(pAddress->wsQFormat, pAddress->hQueue))
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
}
hr = MQSendMessage( pAddress->hQueue, &msgProps, NULL );
if ( (!FAILED(hr)) && (pEndpoint->fAck) )
{
hr = WaitForAck(pEndpoint);
if (hr == MQ_ERROR_QUEUE_NOT_FOUND)
{
MQCloseQueue(pEndpoint->hQueue);
pEndpoint->hQueue = 0;
}
}
#ifdef DBG
if (hr != MQ_OK)
{
TransDbgPrint((DPFLTR_RPCPROXY_ID,
DPFLTR_WARNING_LEVEL,
RPCTRANS "MQ_SendToQueue(): MQSendMessage() failed: 0x%x\n",
hr));
}
#endif
return hr;
}
//----------------------------------------------------------------
// ReadQueue()
//
// Blocking read of the next message from the queue in pEndpoint.
// If there is no pending message on the queue, wait around for
// timeoutMsec.
//
// pInfo -- Holds information about the queue that we are
// doing a read on.
//
// timeoutMsec -- How long to wait around if there are no messages
// pending.
//
// pAddress -- Where to replace information about the queue to
// respond queue (who sent the message).
//
// pBuffer -- The MQ message body is returned in the memory
// pointed to by pBuffer. This is the RPC packet.
//
// pdwBufferSize On entry it is passed in as the total size of
// pBuffer, and it is returned with the actual
// number of bytes in the message.
//
//----------------------------------------------------------------
HRESULT ReadQueue( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
IN DWORD timeoutMsec,
OUT MQ_ADDRESS *pAddress,
OUT UCHAR *pBuffer,
IN OUT DWORD *pdwBufferSize )
{
DWORD cProps = 0;
HRESULT hr;
MQMSGPROPS msgProps;
MSGPROPID aMsgPropID[MAX_RECV_VAR];
MQPROPVARIANT aMsgPropVar[MAX_RECV_VAR];
HRESULT aStatus[MAX_RECV_VAR];
aMsgPropID[cProps] = PROPID_M_BODY; // [0]
aMsgPropVar[cProps].vt = (VT_UI1 | VT_VECTOR);
aMsgPropVar[cProps].caub.cElems = *pdwBufferSize;
aMsgPropVar[cProps].caub.pElems = pBuffer;
cProps++;
ASSERT(cProps == I_MESSAGE_SIZE);
aMsgPropID[cProps] = PROPID_M_BODY_SIZE; // [1]
aMsgPropVar[cProps].vt = VT_UI4;
cProps++;
ASSERT(cProps == I_MESSAGE_LABEL);
aMsgPropID[cProps] = PROPID_M_LABEL; // [2]
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)pAddress->wsMsgLabel;
cProps++;
aMsgPropID[cProps] = PROPID_M_LABEL_LEN; // [3]
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = sizeof(pAddress->wsMsgLabel);
cProps++;
aMsgPropID[cProps] = PROPID_M_RESP_QUEUE; // [4]
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)pAddress->wsQFormat;
cProps++;
aMsgPropID[cProps] = PROPID_M_RESP_QUEUE_LEN; // [5]
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = MAX_FORMAT_LEN;
cProps++;
//
// These message properties are for authentication and privacy:
//
ASSERT(cProps == I_AUTHENTICATED);
aMsgPropID[cProps] = PROPID_M_AUTHENTICATED; // [6]
aMsgPropVar[cProps].vt = VT_UI1;
aMsgPropVar[cProps].bVal = 0;
cProps++;
ASSERT(cProps == I_PRIVACY_LEVEL);
aMsgPropID[cProps] = PROPID_M_PRIV_LEVEL; // [7]
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = 0;
cProps++;
aMsgPropID[cProps] = PROPID_M_SENDERID_TYPE; // [8]
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = 0;
cProps++;
aMsgPropID[cProps] = PROPID_M_SENDERID; // [9]
aMsgPropVar[cProps].vt = (VT_UI1 | VT_VECTOR);
aMsgPropVar[cProps].caub.cElems = sizeof(pAddress->aSidBuffer);
aMsgPropVar[cProps].caub.pElems = pAddress->aSidBuffer;
cProps++;
ASSERT( cProps < MAX_RECV_VAR );
msgProps.cProp = cProps;
msgProps.aPropID = aMsgPropID;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = aStatus;
hr = MQReceiveMessage( pEndpoint->hQueue,
timeoutMsec,
MQ_ACTION_RECEIVE,
&msgProps,
NULL, // No overlap (synchronous).
NULL, // No callback.
NULL, // Message filter.
NULL ); // Transaction object.
#ifdef DBG
if ( (hr != MQ_OK) && (hr != MQ_ERROR_IO_TIMEOUT) )
{
DbgPrint("ReadQueue(): ERROR: hr: 0x%x\n",hr);
}
#endif
if (!FAILED(hr))
{
pAddress->hQueue = 0;
*pdwBufferSize = msgProps.aPropVar[I_MESSAGE_SIZE].ulVal;
}
return hr;
}
//----------------------------------------------------------------
// PeekQueue()
//
// Do a peek on the queue for the specified endpoint in order to
// find out how big the next message is. If there are no messages
// in the queue, wait around for dwTimeoutMsec. Return the size
// of the message in *pdwSize.
//
//----------------------------------------------------------------
HRESULT PeekQueue( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
IN DWORD dwTimeoutMsec,
OUT DWORD *pdwSize )
{
DWORD cProps = 0;
BOOL bSuccess;
HRESULT hr;
MQMSGPROPS msgProps;
MSGPROPID aMsgPropID[MAX_RECV_VAR];
MQPROPVARIANT aMsgPropVar[MAX_RECV_VAR];
RPC_CHAR wsMsgLabel[MQ_MAX_MSG_LABEL_LEN];
aMsgPropID[cProps] = PROPID_M_BODY; // 0
aMsgPropVar[cProps].vt = (VT_UI1 | VT_VECTOR);
aMsgPropVar[cProps].caub.cElems = 0;
aMsgPropVar[cProps].caub.pElems = NULL;
cProps++;
aMsgPropID[cProps] = PROPID_M_BODY_SIZE; // 1
aMsgPropVar[cProps].vt = VT_UI4;
cProps++;
aMsgPropID[cProps] = PROPID_M_LABEL; // 2
aMsgPropVar[cProps].vt = VT_LPTSTR;
aMsgPropVar[cProps].ptszVal = (RPC_SCHAR *)wsMsgLabel;
cProps++;
aMsgPropID[cProps] = PROPID_M_LABEL_LEN; // 3
aMsgPropVar[cProps].vt = VT_UI4;
aMsgPropVar[cProps].ulVal = sizeof(wsMsgLabel);
cProps++;
ASSERT( cProps < MAX_RECV_VAR );
msgProps.cProp = cProps;
msgProps.aPropID = aMsgPropID;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = 0;
// The following receive should always fail, we're just calling
// it to get the size of the message body:
hr = MQReceiveMessage( pEndpoint->hQueue,
dwTimeoutMsec,
MQ_ACTION_RECEIVE,
&msgProps,
NULL, // No overlap (synchronous).
NULL, // No callback.
NULL, // Message filter.
NULL ); // Transaction object.
if (hr == MQ_ERROR_BUFFER_OVERFLOW)
{
*pdwSize = aMsgPropVar[1].ulVal;
hr = MQ_OK;
}
else
*pdwSize = 0;
#ifdef DBG
if ( (hr != MQ_OK) && (hr != MQ_ERROR_IO_TIMEOUT) )
{
DbgPrint("ClntPeekQueue(): ERROR: hr: 0x%x (%d)\n",hr,hr);
}
#endif
return hr;
}
//----------------------------------------------------------------
// EvaluateAckMessage()
//
//----------------------------------------------------------------
HRESULT EvaluateAckMessage( IN USHORT msgClass )
{
HRESULT hr = msgClass;
switch (msgClass)
{
case MQMSG_CLASS_ACK_REACH_QUEUE:
case MQMSG_CLASS_ACK_RECEIVE:
hr = MQ_OK;
break;
case MQMSG_CLASS_NACK_BAD_DST_Q:
hr = MQ_ERROR_QUEUE_NOT_FOUND;
break;
// All other cases are handled in MQ_MapStatusCode()...
}
return hr;
}
//----------------------------------------------------------------
// ClntWaitForAck()
//
// Used by the client side to wait for a MQ acknowledgement when
// ClntSendToQueue() sends a call. An ACK is sent when the call
// message reaches the destination (server) queue.
//
//----------------------------------------------------------------
HRESULT WaitForAck( IN MQ_DATAGRAM_ENDPOINT *pEndpoint )
{
HRESULT hr;
DWORD cProps = 0;
UCHAR msgClass;
MQMSGPROPS msgProps;
MSGPROPID aMsgPropID[MAX_RECV_VAR];
MQPROPVARIANT aMsgPropVar[MAX_RECV_VAR];
HRESULT aMsgHr[MAX_RECV_VAR];
RPC_CHAR wsMsgLabel[MQ_MAX_MSG_LABEL_LEN];
// The message class will tell us the message acknowledgement:
aMsgPropID[cProps] = PROPID_M_CLASS;
aMsgPropVar[cProps].vt = VT_UI2;
aMsgPropVar[cProps].uiVal = 0;
aMsgHr[cProps] = MQ_OK;
cProps++;
ASSERT( cProps < MAX_RECV_VAR );
msgProps.cProp = cProps;
msgProps.aPropID = aMsgPropID;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = aMsgHr;
hr = MQReceiveMessage( pEndpoint->hAdminQueue,
INFINITE,
MQ_ACTION_RECEIVE,
&msgProps,
NULL, NULL, NULL, NULL );
if (!FAILED(hr))
{
hr = EvaluateAckMessage( aMsgPropVar[0].uiVal );
}
# ifdef DBG
else
{
DbgPrint("WaitForAck(): FAILED: hr: 0x%x aMsgHr[0]: 0x%x\n", hr, aMsgHr[0] );
}
# endif
return hr;
}
//----------------------------------------------------------------
// SetupAdminQueue()
//
//
//----------------------------------------------------------------
HRESULT SetupAdminQueue( MQ_DATAGRAM_ENDPOINT *pEndpoint )
{
HRESULT hr;
DWORD dwSize;
UUID uuidQType;
RPC_CHAR wsQName[MQ_MAX_Q_NAME_LEN];
RPC_CHAR wsQPathName[MAX_PATHNAME_LEN];
RpcpStringCopy(wsQName,TEXT("Admin"));
RpcpStringCat(wsQName,pEndpoint->wsQName);
// Build the path name for the admin queue (NOTE: that this
// is a private queue):
dwSize = sizeof(pEndpoint->wsQPathName);
ConstructPrivateQueuePathName( pEndpoint->wsMachine, // [in]
wsQName, // [in]
wsQPathName, // [out]
&dwSize ); // [in,out]
// Try to create the server process receive queue;
UuidFromString( CLNT_ADMIN_QTYPE_UUID_STR, &uuidQType );
dwSize = sizeof(pEndpoint->wsAdminQFormat);
hr = CreateQueue( NULL, // [in] No security descriptor.
&uuidQType, // [in]
wsQPathName, // [in]
wsQName, // [in] Use QName as the QLabel.
0x00000000, // [in] Flags
pEndpoint->wsAdminQFormat, // [out]
&dwSize ); // [in,out]
if ( (FAILED(hr)) && (hr != MQ_ERROR_QUEUE_EXISTS) )
{
#ifdef DBG
DbgPrint("SetupAdminQueue(): %S FAILED: 0x%x (%d)\n", wsQPathName, hr, hr );
#endif
return hr;
}
//
// If the queue already exists, then locate it.
//
if (hr == MQ_ERROR_QUEUE_EXISTS)
{
dwSize = sizeof(pEndpoint->wsQPathName);
hr = MQPathNameToFormatName( pEndpoint->wsQPathName,
pEndpoint->wsQFormat,
&dwSize );
if (FAILED(hr))
{
#ifdef DBG
DbgPrint("SetupAdminQueue(): %S FAILED: 0x%x (%d)\n", wsQPathName, hr, hr );
#endif
return hr;
}
}
//
// Ok, open the admin queue for receive:
//
hr = MQOpenQueue( pEndpoint->wsAdminQFormat,
MQ_RECEIVE_ACCESS, 0, &(pEndpoint->hAdminQueue));
#ifdef DBG
if (FAILED(hr))
{
DbgPrint("SetupAdminQueue(): %S FAILED: 0x%x (%d)\n", wsQPathName, hr, hr );
}
#endif
return hr;
}
//----------------------------------------------------------------
// Debug test code -- DG_DbgPrintPacket().
//----------------------------------------------------------------
#ifdef MAJOR_DBG
const static char *packetTypeStrs[] =
{
"REQUEST",
"PING ",
"RESP ",
"FAULT ",
"WORKING",
"NOCALL ",
"REJECT ",
"ACK ",
"QUIT ",
"FACK ",
"QUACK ",
"Unknown",
};
const static char asciiByteChars[] =
{
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
};
#define HIGH_NIBBLE(uc) ((uc) >> 4)
#define LOW_NIBBLE(uc) ((uc) & 0x0f)
//----------------------------------------------------------------
// DbgPacketType()
//
//----------------------------------------------------------------
static char *DbgPacketType( unsigned char *pPacket )
{
if ( (pPacket[1] >= 0) && (pPacket[1] < 11) )
return packetTypeStrs[pPacket[1]];
else
return packetTypeStrs[11];
}
//----------------------------------------------------------------
// DbgUuidToStr()
//
//----------------------------------------------------------------
static char *DbgUuidToStr( unsigned char *pUuidArg, char *pszUuid )
{
int i = 0;
int j;
GUID uuid;
unsigned char *pUuid;
// Work with local copy of the UUID:
pUuid = (unsigned char*)&uuid;
CopyMemory(pUuid,pUuidArg,sizeof(GUID));
// Assume this is intel and byte-swap it...
uuid.Data1 = RpcpByteSwapLong(uuid.Data1);
uuid.Data2 = RpcpByteSwapShort(uuid.Data2);
uuid.Data3 = RpcpByteSwapShort(uuid.Data3);
for (j=0; j<16; j++)
{
pszUuid[i++] = asciiByteChars[HIGH_NIBBLE(pUuid[j])];
pszUuid[i++] = asciiByteChars[LOW_NIBBLE(pUuid[j])];
if ( (j==3)||(j==5)||(j==7)||(j==9) )
pszUuid[i++] = '-';
}
pszUuid[i] = '\0';
return pszUuid;
}
//----------------------------------------------------------------
// DbgPrintPacket()
//
//----------------------------------------------------------------
void DG_DbgPrintPacket( unsigned char *pPacket )
{
char szIf[50];
char szAct[50];
ULONG ulSequenceNumber;
if (pPacket)
{
ulSequenceNumber = *((unsigned long*)(&(pPacket[56])));
ulSequenceNumber = RpcpByteSwapLong(ulSequenceNumber);
DbgPrint(" Type: %s:0x%x:0x%x:0x%x:0x%x\n Intferface: %s\n Activity : %s\n SequenceNumber: %d\n",
DbgPacketType(pPacket),
pPacket[0], pPacket[1], pPacket[2], pPacket[3],
DbgUuidToStr(&(pPacket[24]),szIf),
DbgUuidToStr(&(pPacket[40]),szAct),
ulSequenceNumber );
}
else
{
DbgPrint(" NULL Packet.\n" );
}
}
#endif