1499 lines
39 KiB
C++
1499 lines
39 KiB
C++
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1997 - 1999
|
||
|
||
Module Name:
|
||
|
||
mqtrans.cxx
|
||
|
||
Abstract:
|
||
|
||
Support for MSMQ (Falcon) datagram transport. Based on MarioGo's
|
||
DG transport code (dgtrans.cxx).
|
||
|
||
Author:
|
||
|
||
Edward Reus (edwardr) 04-Jul-1997
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include <precomp.hxx>
|
||
#include <trans.hxx>
|
||
#include <dgtrans.hxx>
|
||
#include <wswrap.hxx>
|
||
#include "mqtrans.hxx"
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// MSMQ datagram routines.
|
||
//
|
||
|
||
//----------------------------------------------------------------
|
||
RPC_STATUS
|
||
MQ_SubmitReceive( IN MQ_DATAGRAM_ENDPOINT *pEndpoint,
|
||
IN MQ_DATAGRAM *pDatagram )
|
||
/*++
|
||
|
||
Arguments:
|
||
|
||
pEndpoint - The endpoint on which the receive should be posted.
|
||
pDatagram - The datagram object to manage the receive.
|
||
|
||
Return Value:
|
||
|
||
RPC_P_IO_PENDING - OK
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
|
||
--*/
|
||
|
||
{
|
||
RPC_STATUS status;
|
||
BOOL fRetry = TRUE;
|
||
DWORD dwBytes = 0;
|
||
DWORD dwStatus;
|
||
HRESULT hr;
|
||
|
||
|
||
while (fRetry)
|
||
{
|
||
if (pDatagram->pPacket == 0)
|
||
{
|
||
pDatagram->dwPacketSize = dwBytes;
|
||
status = I_RpcTransDatagramAllocate2( pEndpoint,
|
||
(BUFFER *)&pDatagram->pPacket,
|
||
(PUINT) &pDatagram->dwPacketSize,
|
||
(PVOID *) &pDatagram->pAddress);
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
ASSERT( pDatagram->pPacket );
|
||
|
||
memset(pDatagram->pAddress,0,sizeof(MQ_ADDRESS));
|
||
}
|
||
|
||
pDatagram->cRecvAddr = sizeof(MQ_ADDRESS);
|
||
|
||
ASSERT(*(PDWORD)pDatagram->pPacket = 0xDEADF00D);
|
||
|
||
hr = AsyncReadQueue( pEndpoint,
|
||
&pDatagram->Read,
|
||
pDatagram->pAddress,
|
||
pDatagram->pPacket,
|
||
pDatagram->dwPacketSize );
|
||
|
||
if (!FAILED(hr))
|
||
{
|
||
return RPC_P_IO_PENDING;
|
||
}
|
||
|
||
if (hr == MQ_ERROR_BUFFER_OVERFLOW)
|
||
{
|
||
// This can happen if there is already a large sized call on the queue.
|
||
dwBytes = pDatagram->Read.aMsgPropVar[1].ulVal;
|
||
|
||
dwStatus = I_RpcTransDatagramFree( pEndpoint,
|
||
(BUFFER)pDatagram->pPacket,
|
||
(PVOID) pDatagram->pAddress);
|
||
pDatagram->pPacket = 0;
|
||
pDatagram->dwPacketSize = 0;
|
||
if (dwStatus != RPC_S_OK)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "MQ_SubmitReceive(): I_RpcTransDatagram() failed: %d\n",
|
||
dwStatus));
|
||
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
fRetry = FALSE;
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "MQ_SubmitReceive(): AsyncReadQueue() failed: 0x%x\n",
|
||
hr));
|
||
}
|
||
}
|
||
|
||
return RPC_S_OUT_OF_RESOURCES;
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
void
|
||
MQ_SubmitReceives(
|
||
BASE_ADDRESS *ThisEndpoint
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Helper function called when the pending IO count
|
||
on an address is too low.
|
||
|
||
Arguments:
|
||
|
||
ThisEndpoint - The address to submit IOs on.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PMQ_DATAGRAM pDg;
|
||
PMQ_DATAGRAM_ENDPOINT pEndpoint = (PMQ_DATAGRAM_ENDPOINT)ThisEndpoint;
|
||
|
||
if ( (!pEndpoint->fAllowReceives) || (!pEndpoint->hQueue) )
|
||
{
|
||
return;
|
||
}
|
||
|
||
do
|
||
{
|
||
BOOL fIoSubmitted;
|
||
|
||
fIoSubmitted = FALSE;
|
||
|
||
// Only one thread should be trying to submit IOs at a time.
|
||
// This saves locking each DATAGRAM object.
|
||
|
||
// Simple lock - but requires a loop. See the comment at the end
|
||
// of the loop.
|
||
|
||
if (pEndpoint->fSubmittingIos != 0)
|
||
break;
|
||
|
||
if (InterlockedIncrement(&pEndpoint->fSubmittingIos) != 1)
|
||
break;
|
||
|
||
// Submit new IOs on all the idle datagram objects
|
||
|
||
for (int i = 0; i < pEndpoint->cMaximumIos; i++)
|
||
{
|
||
pDg = &pEndpoint->aDatagrams[i];
|
||
|
||
if (pDg->Busy)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// Must be all set for the IO to complete before trying
|
||
// to submit the IO.
|
||
InterlockedIncrement(&pEndpoint->cPendingIos);
|
||
pDg->Busy = TRUE;
|
||
|
||
if (MQ_SubmitReceive(pEndpoint, pDg) == RPC_P_IO_PENDING)
|
||
{
|
||
fIoSubmitted = TRUE;
|
||
}
|
||
else
|
||
{
|
||
pDg->Busy = FALSE;
|
||
InterlockedDecrement(&pEndpoint->cPendingIos);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Release the "lock" on the endpoint object.
|
||
pEndpoint->fSubmittingIos = 0;
|
||
|
||
if (!fIoSubmitted && pEndpoint->cPendingIos == 0)
|
||
{
|
||
// It appears that no IO is pending on the endpoint.
|
||
COMMON_AddressManager(pEndpoint);
|
||
return;
|
||
}
|
||
|
||
// Even if we submitted new IOs, they may all have completed
|
||
// already. Which means we may need to loop and submit more
|
||
// IOs. This is needed since the thread which completed the
|
||
// last IO may have run into our lock and returned.
|
||
}
|
||
while (pEndpoint->cPendingIos == 0);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
BOOL RPC_ENTRY MQ_AllowReceives(
|
||
IN DG_TRANSPORT_ENDPOINT pvTransEndpoint,
|
||
IN BOOL fAllowReceives,
|
||
IN BOOL fCancelPendingIos )
|
||
{
|
||
BOOL fPrevAllowReceives;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)pvTransEndpoint;
|
||
|
||
fPrevAllowReceives = pEndpoint->fAllowReceives;
|
||
pEndpoint->fAllowReceives = fAllowReceives;
|
||
|
||
if (!pEndpoint->cPendingIos)
|
||
{
|
||
MQ_SubmitReceives(pEndpoint);
|
||
}
|
||
|
||
ASSERT( !fCancelPendingIos ); // Not implemented yet.
|
||
|
||
return fPrevAllowReceives;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
MQ_SendPacket(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
IN DG_TRANSPORT_ADDRESS pvAddress,
|
||
IN BUFFER pHeader,
|
||
IN unsigned cHeader,
|
||
IN BUFFER pBody,
|
||
IN unsigned cBody,
|
||
IN BUFFER pTrailer,
|
||
IN unsigned cTrailer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends a packet to an address.
|
||
|
||
The routine will send a packet built out of the three buffers supplied.
|
||
All the buffers are optional, the actual packet sent will be built from
|
||
all the buffers actually supplied. In each call at least buffer should
|
||
NOT be null.
|
||
|
||
Arguments:
|
||
|
||
ThisEndpoint - Endpoint to send from.
|
||
pAddress - Address to send to.
|
||
|
||
pHeader - First data buffer
|
||
cHeader - Size of the first data buffer or 0.
|
||
|
||
pBody - Second data buffer
|
||
cBody - Size of the second data buffer or 0.
|
||
|
||
pTrailer - Third data buffer.
|
||
cTrailer - Size of the third data buffer or 0.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_P_SEND_FAILED
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
|
||
MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pvAddress;
|
||
UCHAR *pBuffer;
|
||
UCHAR *pTemp;
|
||
DWORD dwBytes = cHeader + cBody + cTrailer;
|
||
HRESULT hr;
|
||
BOOL fNeedToFree = FALSE;
|
||
|
||
|
||
ASSERT(dwBytes);
|
||
|
||
//
|
||
// Buffer assembly. I get the data PDU as up to three separate pieces,
|
||
// so it needs to be assembled before being sent. For Falcon (which can't
|
||
// do scatter/gather) this is expensive (allocate() + memcpy()'s). We try
|
||
// to be cheap and avoid the allocation, or do an _alloca() off the stack
|
||
// instead of the heap.
|
||
//
|
||
if ( (cHeader==0) && (cBody > 0) && (cTrailer == 0) )
|
||
{
|
||
pBuffer = pBody;
|
||
}
|
||
else if ( ((cBody == 0) && (cTrailer == 0))
|
||
|| ((pHeader+cHeader == pBody) && (pTrailer == 0)) )
|
||
{
|
||
pBuffer = pHeader;
|
||
}
|
||
else
|
||
{
|
||
pBuffer = (UCHAR*)I_RpcAllocate(dwBytes);
|
||
fNeedToFree = TRUE;
|
||
|
||
if (!pBuffer)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
pTemp = pBuffer;
|
||
if (cHeader)
|
||
{
|
||
memcpy(pTemp,pHeader,cHeader);
|
||
pTemp += cHeader;
|
||
}
|
||
|
||
if (cBody)
|
||
{
|
||
memcpy(pTemp,pBody,cBody);
|
||
pTemp += cBody;
|
||
}
|
||
|
||
if (cTrailer)
|
||
{
|
||
memcpy(pTemp,pTrailer,cTrailer);
|
||
}
|
||
|
||
ASSERT(pTemp != pBuffer);
|
||
}
|
||
|
||
#ifdef MAJOR_DBG
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "MQ_SendPacket():\n"));
|
||
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
" To: %S: %S\n",
|
||
pAddress->wsMachine,
|
||
pAddress->wsQName));
|
||
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
" Size: %d\n",
|
||
dwBytes));
|
||
|
||
DG_DbgPrintPacket(pBuffer);
|
||
#endif
|
||
|
||
hr = MQ_SendToQueue( pEndpoint, pAddress, pBuffer, dwBytes );
|
||
Status = MQ_MapStatusCode(hr,RPC_P_SEND_FAILED);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
if (fNeedToFree)
|
||
{
|
||
I_RpcFree(pBuffer);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
if ( (pEndpoint->cMinimumIos)
|
||
&& (pEndpoint->cPendingIos <= pEndpoint->cMaximumIos) )
|
||
{
|
||
MQ_SubmitReceives(pEndpoint);
|
||
}
|
||
|
||
if (fNeedToFree)
|
||
{
|
||
I_RpcFree(pBuffer);
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
MQ_ForwardPacket(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
IN BUFFER pHeader,
|
||
IN unsigned cHeader,
|
||
IN BUFFER pBody,
|
||
IN unsigned cBody,
|
||
IN BUFFER pTrailer,
|
||
IN unsigned cTrailer,
|
||
IN CHAR * pszPort
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends a packet to the server it was originally destined for (that
|
||
is, the client had a dynamic endpoint it wished the enpoint mapper
|
||
to resolve and forward the packet to).
|
||
|
||
Arguments:
|
||
|
||
ThisEndpoint - The endpoint to forward the packet from.
|
||
|
||
// Buffer like DG_SendPacket
|
||
|
||
pszPort - Pointer to the server port num to forward to.
|
||
This is in an Ansi string.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_CANT_CREATE_ENDPOINT - pEndpoint invalid.
|
||
|
||
results of MQ_SendPacket().
|
||
|
||
--*/
|
||
|
||
{
|
||
PMQ_DATAGRAM_ENDPOINT pEndpoint = (PMQ_DATAGRAM_ENDPOINT)ThisEndpoint;
|
||
MQ_ADDRESS Address;
|
||
MQ_ADDRESS *pAddress = &Address;
|
||
RPC_CHAR wsPort[MQ_MAX_Q_NAME_LEN];
|
||
UNICODE_STRING UnicodePort;
|
||
ANSI_STRING AsciiPort;
|
||
DWORD Status;
|
||
NTSTATUS NtStatus;
|
||
|
||
//
|
||
// Convert pszPort to Unicode:
|
||
//
|
||
RtlInitAnsiString(&AsciiPort, pszPort);
|
||
|
||
UnicodePort.Buffer = wsPort;
|
||
UnicodePort.Length = 0;
|
||
UnicodePort.MaximumLength = MQ_MAX_Q_NAME_LEN * sizeof(RPC_CHAR);
|
||
|
||
NtStatus = RtlAnsiStringToUnicodeString(&UnicodePort,
|
||
&AsciiPort,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
return RPC_S_CANT_CREATE_ENDPOINT;
|
||
}
|
||
|
||
//
|
||
// Try to connect to the server (to forward the packet to):
|
||
//
|
||
Status = ConnectToServerQueue(pAddress, NULL, wsPort );
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return RPC_S_CANT_CREATE_ENDPOINT;
|
||
}
|
||
|
||
|
||
//
|
||
// Forward the packet on:
|
||
//
|
||
Status = MQ_SendPacket(ThisEndpoint,
|
||
pAddress,
|
||
pHeader,
|
||
cHeader,
|
||
pBody,
|
||
cBody,
|
||
pTrailer,
|
||
cTrailer );
|
||
|
||
//
|
||
// Release the connection, we shouldn't need it any more:
|
||
//
|
||
DisconnectFromServer(pAddress);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
MQ_ResizePacket(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
OUT DG_TRANSPORT_ADDRESS *pReplyAddress,
|
||
OUT PUINT pBufferLength,
|
||
OUT BUFFER *pBuffer
|
||
)
|
||
{
|
||
RPC_STATUS Status = RPC_P_TIMEOUT;
|
||
DWORD dwBytes = 0;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
|
||
MQ_DATAGRAM *pDatagram = &pEndpoint->aDatagrams[0];
|
||
|
||
|
||
dwBytes = pDatagram->Read.aMsgPropVar[1].ulVal;
|
||
|
||
ASSERT(dwBytes);
|
||
|
||
#ifdef DBG
|
||
DbgPrint("MQ_ResizePacket(): dwBytes: %d\n",dwBytes);
|
||
#endif
|
||
|
||
if ( (pDatagram->pPacket) && (pDatagram->dwPacketSize < dwBytes) )
|
||
{
|
||
Status = I_RpcTransDatagramFree( pEndpoint,
|
||
(BUFFER)pDatagram->pPacket,
|
||
(PVOID) pDatagram->pAddress);
|
||
pDatagram->pPacket = 0;
|
||
pDatagram->dwPacketSize = 0;
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
|
||
if (!pDatagram->pPacket)
|
||
{
|
||
pDatagram->dwPacketSize = dwBytes;
|
||
Status = I_RpcTransDatagramAllocate2( pEndpoint,
|
||
(BUFFER *)&pDatagram->pPacket,
|
||
(PUINT) &pDatagram->dwPacketSize,
|
||
(PVOID *) &pDatagram->pAddress);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
pDatagram->cRecvAddr = sizeof(MQ_ADDRESS);
|
||
|
||
ASSERT( pDatagram->pPacket );
|
||
}
|
||
|
||
#ifdef DBG
|
||
DbgPrint("MQ_ResizePacket(): Ok\n");
|
||
#endif
|
||
|
||
return RPC_P_TIMEOUT;
|
||
}
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
MQ_ReceivePacket(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
OUT DG_TRANSPORT_ADDRESS *pReplyAddress,
|
||
OUT PUINT pBufferLength,
|
||
OUT BUFFER *pBuffer,
|
||
IN LONG Timeout
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Used to wait for a datagram from a server. Returns the data
|
||
returned and the address of the machine which replied.
|
||
|
||
This is a blocking API. It should only be called during sync
|
||
client RPC threads.
|
||
|
||
Arguments:
|
||
|
||
Endpoint - The endpoint to receive from.
|
||
ReplyAddress - Contain the source address of the datagram if
|
||
successful.
|
||
BufferLength - The size of Buffer on input, the size of the
|
||
datagram received on output.
|
||
Timeout - Milliseconds to wait for a datagram.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
RPC_P_OVERSIZE_PACKET - Datagram > BufferLength arrived,
|
||
first BufferLength bytes of Buffer contain the partial datagram.
|
||
|
||
RPC_P_RECEIVE_FAILED
|
||
|
||
RPC_P_TIMEOUT
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = RPC_P_TIMEOUT;
|
||
DWORD dwBytes;
|
||
BOOL fRetry = TRUE;
|
||
HRESULT hr;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
|
||
MQ_DATAGRAM *pDatagram = &pEndpoint->aDatagrams[0];
|
||
|
||
ASSERT((pEndpoint->type & TYPE_MASK) == CLIENT);
|
||
ASSERT(pEndpoint->aDatagrams[0].Read.ol.hEvent);
|
||
|
||
#if TRUE
|
||
while (fRetry)
|
||
{
|
||
fRetry = FALSE;
|
||
|
||
if (pDatagram->Busy == 0)
|
||
{
|
||
Status = MQ_SubmitReceive(pEndpoint,pDatagram);
|
||
if (Status != RPC_P_IO_PENDING)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
pDatagram->Busy = TRUE;
|
||
}
|
||
else
|
||
{
|
||
ASSERT(pDatagram->Busy);
|
||
ASSERT(pDatagram->pPacket);
|
||
|
||
Status = RPC_P_IO_PENDING;
|
||
}
|
||
|
||
|
||
if (Status == RPC_P_IO_PENDING)
|
||
{
|
||
Status = WaitForSingleObjectEx(pDatagram->Read.ol.hEvent,
|
||
Timeout,
|
||
TRUE);
|
||
|
||
if (Status != STATUS_WAIT_0)
|
||
{
|
||
// In the timeout case we just want to return.
|
||
if (Status == WAIT_IO_COMPLETION)
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "MQ_ReceivePacket() cancelled.\n"));
|
||
}
|
||
else
|
||
{
|
||
ASSERT(Status == STATUS_TIMEOUT);
|
||
}
|
||
|
||
ASSERT(pDatagram->Busy);
|
||
|
||
return RPC_P_TIMEOUT;
|
||
}
|
||
}
|
||
|
||
|
||
MQ_FillInAddress(pDatagram->pAddress,pDatagram->Read.aMsgPropVar);
|
||
}
|
||
|
||
ASSERT((Status == RPC_S_OK)||(Status == RPC_P_OVERSIZE_PACKET));
|
||
|
||
ASSERT(pDatagram->Busy);
|
||
ASSERT(pDatagram->pPacket);
|
||
// ASSERT(dwBytes <= pDatagram->dwPacketSize);
|
||
|
||
*pBuffer = (BUFFER)pDatagram->pPacket;
|
||
*pBufferLength = pDatagram->Read.aMsgPropVar[1].ulVal;
|
||
// dwBytes;
|
||
*pReplyAddress = pDatagram->pAddress;
|
||
|
||
pDatagram->pPacket = 0;
|
||
pDatagram->dwPacketSize = 0;
|
||
pDatagram->Busy = 0;
|
||
|
||
return Status;
|
||
|
||
#else
|
||
if (pDatagram->Busy == 0)
|
||
{
|
||
hr = PeekQueue( pEndpoint, Timeout, &dwBytes );
|
||
|
||
Status = MQ_MapStatusCode(hr,RPC_P_RECEIVE_FAILED);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
if ( (pDatagram->pPacket) && (pDatagram->dwPacketSize < dwBytes) )
|
||
{
|
||
Status = I_RpcTransDatagramFree( pEndpoint,
|
||
(BUFFER)pDatagram->pPacket,
|
||
(PVOID) pDatagram->pAddress);
|
||
pDatagram->pPacket = 0;
|
||
pDatagram->dwPacketSize = 0;
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
|
||
if (!pDatagram->pPacket)
|
||
{
|
||
pDatagram->dwPacketSize = dwBytes;
|
||
Status = I_RpcTransDatagramAllocate2( pEndpoint,
|
||
(BUFFER *)&pDatagram->pPacket,
|
||
(PUINT) &pDatagram->dwPacketSize,
|
||
(PVOID *) &pDatagram->pAddress);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
pDatagram->cRecvAddr = sizeof(MQ_ADDRESS);
|
||
|
||
ASSERT( pDatagram->pPacket );
|
||
}
|
||
|
||
pDatagram->Busy = TRUE;
|
||
dwBytes = pDatagram->dwPacketSize;
|
||
hr = ReadQueue( pEndpoint, Timeout, pDatagram->pAddress, pDatagram->pPacket, &dwBytes );
|
||
Status = MQ_MapStatusCode(hr,RPC_P_RECEIVE_FAILED);
|
||
if (FAILED(hr))
|
||
{
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "ReadQueue() failed: 0x%x\n",
|
||
hr));
|
||
|
||
pDatagram->Busy = FALSE;
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
#ifdef MAJOR_DBG
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "MQ_ReceivePacket():\n"));
|
||
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
" Receive on: %S\n",
|
||
pEndpoint->wsQName));
|
||
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
" From: %S\n",
|
||
pDatagram->pAddress->wsQName));
|
||
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
" Size: %d\n",
|
||
dwBytes));
|
||
|
||
DG_DbgPrintPacket(pDatagram->pPacket);
|
||
#endif
|
||
|
||
ASSERT((Status == RPC_S_OK)||(Status == RPC_P_OVERSIZE_PACKET));
|
||
|
||
ASSERT(pDatagram->Busy);
|
||
ASSERT(pDatagram->pPacket);
|
||
ASSERT(dwBytes <= pDatagram->dwPacketSize);
|
||
|
||
*pBuffer = (BUFFER)pDatagram->pPacket;
|
||
*pBufferLength = dwBytes;
|
||
*pReplyAddress = pDatagram->pAddress;
|
||
|
||
pDatagram->pPacket = 0;
|
||
pDatagram->dwPacketSize = 0;
|
||
pDatagram->Busy = 0;
|
||
|
||
return Status;
|
||
#endif
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
MQ_CreateEndpoint(
|
||
OUT MQ_DATAGRAM_ENDPOINT *pEndpoint,
|
||
IN MQ_ADDRESS *pAddress,
|
||
IN void *pSecurityDescriptor,
|
||
IN DWORD dwEndpointFlags,
|
||
IN PROTOCOL_ID id,
|
||
IN BOOL fClient,
|
||
IN BOOL fAsync
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a new endpoint.
|
||
|
||
Arguments:
|
||
|
||
pEndpoint - The runtime allocated endpoint structure to
|
||
filled in.
|
||
|
||
pSockAddr - An initialized sockaddr with the correct
|
||
(or no) endpoint.
|
||
|
||
id - The id of the protocol to use in creating the address.
|
||
|
||
fClient - If TRUE this is a client endpoint
|
||
|
||
fAsync - If TRUE this endpoint is "async" which means that
|
||
a) It should be added to the IO completion port and
|
||
b) that the transport should pend a number of receives
|
||
on the endpoint automatically.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_CANT_CREATE_ENDPOINT
|
||
RPC_S_DUPLICATE_ENDPOINT
|
||
|
||
--*/
|
||
{
|
||
MQ_DATAGRAM *pDatagram;
|
||
int i;
|
||
int err;
|
||
int length;
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
HRESULT hr;
|
||
UUID uuid;
|
||
DWORD dwSize;
|
||
RPC_CHAR *pwsUuid;
|
||
RPC_CHAR wsQName[MQ_MAX_Q_NAME_LEN];
|
||
RPC_CHAR wsMachine[MAX_COMPUTERNAME_LEN];
|
||
|
||
|
||
pEndpoint->type = DATAGRAM | ADDRESS;
|
||
pEndpoint->id = id;
|
||
pEndpoint->pAddressVector = 0;
|
||
pEndpoint->SubmitListen = MQ_SubmitReceives;
|
||
pEndpoint->InAddressList = NotInList;
|
||
pEndpoint->pNext = 0;
|
||
pEndpoint->fSubmittingIos = 0;
|
||
pEndpoint->cPendingIos = 0;
|
||
pEndpoint->cMinimumIos = 0;
|
||
pEndpoint->cMaximumIos = 0;
|
||
pEndpoint->aDatagrams = 0;
|
||
pEndpoint->pFirstAddress = pEndpoint;
|
||
pEndpoint->pNextAddress = 0;
|
||
|
||
pEndpoint->hQueue = 0;
|
||
pEndpoint->hAdminQueue = 0;
|
||
|
||
// If we're told not to listen, then we won't allow receives
|
||
// until we are specifically told to do so...
|
||
#ifdef RPC_C_MQ_DONT_LISTEN
|
||
pEndpoint->fAllowReceives = !(dwEndpointFlags & RPC_C_MQ_DONT_LISTEN);
|
||
#else
|
||
pEndpoint->fAllowReceives = TRUE;
|
||
#endif
|
||
|
||
pEndpoint->fAck = FALSE;
|
||
pEndpoint->ulDelivery = RPC_C_MQ_EXPRESS;
|
||
pEndpoint->ulPriority = DEFAULT_PRIORITY;
|
||
pEndpoint->ulJournaling = RPC_C_MQ_JOURNAL_NONE;
|
||
pEndpoint->ulTimeToReachQueue = INFINITE;
|
||
pEndpoint->ulTimeToReceive = INFINITE;
|
||
|
||
pEndpoint->fAuthenticate = FALSE;
|
||
pEndpoint->fEncrypt = FALSE;
|
||
pEndpoint->ulPrivacyLevel = 0;
|
||
|
||
// Machine name:
|
||
dwSize = sizeof(wsMachine);
|
||
if (!GetComputerName((RPC_SCHAR *)wsMachine,&dwSize))
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
// Get the name of the machine that the QM (mqsvc.exe)
|
||
// is running on:
|
||
dwSize = sizeof(pEndpoint->wsMachine);
|
||
hr = QueryQM(pEndpoint->wsMachine,&dwSize);
|
||
if (FAILED(hr))
|
||
{
|
||
Status = MQ_MapStatusCode(hr,RPC_S_CANT_CREATE_ENDPOINT);
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// See if this is a call from an RPC server or RPC client:
|
||
//
|
||
if (fClient)
|
||
{
|
||
pEndpoint->type |= CLIENT;
|
||
|
||
// Queue name (a unique string...):
|
||
Status = UuidCreate(&uuid);
|
||
if ((Status != RPC_S_OK) && (Status != RPC_S_UUID_LOCAL_ONLY))
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
if (UuidToString(&uuid,&pwsUuid) != RPC_S_OK)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
RpcpStringCopy(wsQName,TEXT("RpcCl-"));
|
||
RpcpStringCat(wsQName,pwsUuid);
|
||
|
||
// Function UuidCreate() allocated a string, free it:
|
||
RpcStringFree(&pwsUuid);
|
||
|
||
//
|
||
// Create the queue for this endpoint:
|
||
//
|
||
hr = ClientSetupQueue( pEndpoint, pEndpoint->wsMachine, wsQName );
|
||
Status = MQ_MapStatusCode(hr,RPC_S_CANT_CREATE_ENDPOINT);
|
||
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
MQ_RegisterQueueToDelete(pEndpoint->wsQFormat,wsMachine);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pEndpoint->type |= SERVER;
|
||
|
||
//
|
||
// Create the queue for this server endpoint:
|
||
//
|
||
hr = ServerSetupQueue( pEndpoint,
|
||
pEndpoint->wsMachine,
|
||
pEndpoint->wsQName,
|
||
pSecurityDescriptor,
|
||
dwEndpointFlags );
|
||
|
||
Status = MQ_MapStatusCode(hr,RPC_S_CANT_CREATE_ENDPOINT);
|
||
|
||
//
|
||
// Check to see if this queue is temporary. If so, then
|
||
// register it with RPCSS to delete.
|
||
//
|
||
if ((Status == RPC_S_OK) && !(RPC_C_MQ_PERMANENT & dwEndpointFlags))
|
||
{
|
||
MQ_RegisterQueueToDelete(pEndpoint->wsQFormat,wsMachine);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the endpoint is going to async initialize async part
|
||
// and add the socket to the IO completion port.
|
||
//
|
||
|
||
if (Status == RPC_S_OK)
|
||
{
|
||
int cMaxIos;
|
||
int cMinIos;
|
||
|
||
ASSERT(fAsync || fClient);
|
||
|
||
// Step one, figure out the high and low mark for ios.
|
||
|
||
if (fAsync)
|
||
{
|
||
// PERF REVIEW these parameters.
|
||
cMaxIos = 2
|
||
+ (gfServerPlatform == TRUE) * 2
|
||
+ (fClient == FALSE) * gNumberOfProcessors;
|
||
|
||
// This should be larger than zero so that we'll generally submit new
|
||
// recvs during idle time rather then just after receiving a datagram.
|
||
cMinIos = 1 + (fClient == FALSE ) * (gNumberOfProcessors/2);
|
||
|
||
cMinIos = 1;
|
||
cMaxIos = 1;
|
||
}
|
||
else
|
||
{
|
||
// For sync endpoints we need to allocate a single datagram
|
||
// object for the receive.
|
||
cMinIos = 0;
|
||
cMaxIos = 1;
|
||
}
|
||
|
||
// ASSERT(cMinIos < cMaxIos); Not currently true...
|
||
|
||
pEndpoint->cMinimumIos = cMinIos;
|
||
pEndpoint->cMaximumIos = cMaxIos;
|
||
|
||
// Allocate a chunk on memory to hold the array of datagrams
|
||
|
||
// PERF: For clients, allocate larger array but don't submit all
|
||
// the IOs unless we determine that the port is "really" active.
|
||
|
||
pEndpoint->aDatagrams = new MQ_DATAGRAM[cMaxIos];
|
||
|
||
if (pEndpoint->aDatagrams)
|
||
{
|
||
UINT type;
|
||
type = DATAGRAM | RECEIVE;
|
||
type |= (fClient) ? CLIENT : SERVER;
|
||
|
||
for (i = 0; i < cMaxIos; i++)
|
||
{
|
||
pDatagram = &pEndpoint->aDatagrams[i];
|
||
|
||
pDatagram->id = id;
|
||
pDatagram->type = type;
|
||
pDatagram->pEndpoint = pEndpoint;
|
||
pDatagram->Busy = 0;
|
||
pDatagram->pPacket = 0;
|
||
pDatagram->dwPacketSize = 0;
|
||
memset(&pDatagram->Read, 0, sizeof(pDatagram->Read));
|
||
pDatagram->Read.pAsyncObject = pDatagram;
|
||
}
|
||
|
||
if (fAsync)
|
||
{
|
||
Status = COMMON_PrepareNewHandle((HANDLE)pEndpoint->hQueue);
|
||
}
|
||
else
|
||
{
|
||
// The receive operation on sync endpoints will may span
|
||
// several receives. This means it can't use the thread
|
||
// event, so allocate an event for the receive.
|
||
HANDLE hEvent = CreateEvent(0, TRUE, FALSE, 0);
|
||
if (!hEvent)
|
||
{
|
||
Status = RPC_S_OUT_OF_RESOURCES;
|
||
}
|
||
else
|
||
{
|
||
ASSERT(pDatagram == &pEndpoint->aDatagrams[0]);
|
||
pDatagram->Read.ol.hEvent = hEvent;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
}
|
||
|
||
// If adding a new failure case here, add code to close the sync receive event.
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
delete pEndpoint->aDatagrams;
|
||
|
||
return Status;
|
||
}
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
void RPC_ENTRY
|
||
MQ_ServerAbortListen(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Callback after DG_CreateEndpoint has completed successfully
|
||
but the runtime for some reason is not going to be able to
|
||
listen on the endpoint.
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
|
||
|
||
#ifdef MAJOR_DBG
|
||
TransDbgPrint((DPFLTR_RPCPROXY_ID,
|
||
DPFLTR_WARNING_LEVEL,
|
||
RPCTRANS "MQ_ServerAbortListen(): %S\n",
|
||
pEndpoint->wsQName));
|
||
#endif
|
||
|
||
ASSERT(pEndpoint->cPendingIos == 0);
|
||
ASSERT(pEndpoint->hQueue);
|
||
ASSERT(pEndpoint->pNext == 0);
|
||
ASSERT(pEndpoint->type & SERVER);
|
||
|
||
if (pEndpoint->pAddressVector)
|
||
{
|
||
delete pEndpoint->pAddressVector;
|
||
}
|
||
|
||
if (pEndpoint->aDatagrams)
|
||
{
|
||
delete pEndpoint->aDatagrams;
|
||
}
|
||
|
||
hr = ServerCloseQueue(pEndpoint);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
MQ_ClientCloseEndpoint(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called on sync client endpoints when they are no longer needed.
|
||
|
||
Arguments:
|
||
|
||
ThisEndpoint
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
PMQ_DATAGRAM_ENDPOINT pEndpoint = (PMQ_DATAGRAM_ENDPOINT)ThisEndpoint;
|
||
PMQ_DATAGRAM pDatagram = &pEndpoint->aDatagrams[0];
|
||
|
||
ASSERT((pEndpoint->type & TYPE_MASK) == CLIENT);
|
||
ASSERT(pEndpoint->hQueue); // MQOpenQueue must have worked
|
||
ASSERT(pEndpoint->cMinimumIos == 0);
|
||
ASSERT(pEndpoint->cMaximumIos == 1); // Must not be async!
|
||
ASSERT(pEndpoint->aDatagrams);
|
||
// ASSERT(pEndpoint->Endpoint == 0);
|
||
ASSERT(pEndpoint->pAddressVector == 0);
|
||
// ASSERT(pEndpoint->pNext == 0);
|
||
|
||
// Close & delete the client queue:
|
||
hr = ClientCloseQueue(pEndpoint);
|
||
|
||
// Free the receive buffer if allocated
|
||
if (pDatagram->pPacket)
|
||
{
|
||
I_RpcTransDatagramFree(pEndpoint,
|
||
(BUFFER)pDatagram->pPacket,
|
||
pDatagram->pAddress
|
||
);
|
||
}
|
||
|
||
if (pDatagram->Read.ol.hEvent)
|
||
{
|
||
CloseHandle(pDatagram->Read.ol.hEvent);
|
||
}
|
||
|
||
delete pDatagram;
|
||
|
||
pEndpoint->aDatagrams = 0;
|
||
|
||
return(RPC_S_OK);
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
MQ_ServerListen(
|
||
IN OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
IN RPC_CHAR *NetworkAddress,
|
||
IN OUT RPC_CHAR **ppEndpoint,
|
||
IN void *pSecurityDescriptor,
|
||
IN ULONG EndpointFlags,
|
||
IN ULONG NICFlags,
|
||
OUT NETWORK_ADDRESS_VECTOR **ppNetworkAddressVector
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a server endpoint object to receive packets. New
|
||
packets won't actually arrive until CompleteListen is
|
||
called.
|
||
|
||
Arguments:
|
||
|
||
ThisEndpoint - Storage for the server endpoint object.
|
||
ppEndpoint - The RPC_CHAR name of the endpoint to listen
|
||
on or a pointer to 0 if the transport should choose
|
||
the address. Contains the endpoint listened to on
|
||
output. The caller should free this.
|
||
EndpointFlags - Application flags passed into RPC via
|
||
RpcServerUseProtseq*Ex.
|
||
NICFlags - Application flags passed into RPC via
|
||
RpcServerUseProtseq*Ex.
|
||
pNetworkAddresses - A vector of the network addresses
|
||
listened on by this call. This vector does
|
||
not need to be freed.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_CANT_CREATE_ENDPOINT
|
||
RPC_S_INVALID_ENDPOINT_FORMAT
|
||
RPC_S_DUPLICATE_ENDPOINT
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
DWORD dwSize;
|
||
UUID uuid;
|
||
RPC_CHAR *pUuidStr;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
|
||
|
||
|
||
*ppNetworkAddressVector = 0;
|
||
|
||
if (*ppEndpoint)
|
||
{
|
||
// Known Endpoint:
|
||
RpcpStringCopy(pEndpoint->wsQName,*ppEndpoint);
|
||
}
|
||
else
|
||
{
|
||
// Dynamic Endpoint:
|
||
Status = UuidCreate(&uuid);
|
||
if ((Status != RPC_S_OK) && (Status != RPC_S_UUID_LOCAL_ONLY))
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
Status = UuidToString(&uuid,&pUuidStr);
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
RpcpStringCopy(pEndpoint->wsQName,TEXT("RpcSvr-"));
|
||
RpcpStringCat(pEndpoint->wsQName,pUuidStr);
|
||
RpcStringFree(&pUuidStr);
|
||
|
||
dwSize = (1+RpcpStringLength(pEndpoint->wsQName))*(sizeof(RPC_CHAR));
|
||
*ppEndpoint = (RPC_CHAR*)I_RpcAllocate(dwSize);
|
||
if (!*ppEndpoint)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
RpcpStringCopy(*ppEndpoint,pEndpoint->wsQName);
|
||
}
|
||
|
||
//
|
||
// Actually create the endpoint
|
||
//
|
||
Status = MQ_CreateEndpoint( pEndpoint,
|
||
NULL,
|
||
pSecurityDescriptor,
|
||
EndpointFlags,
|
||
MSMQ,
|
||
FALSE, // Server
|
||
TRUE ); // Async
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
Status = MQ_BuildAddressVector(&pEndpoint->pAddressVector);
|
||
|
||
if (Status != RPC_S_OK)
|
||
{
|
||
MQ_ServerAbortListen(ThisEndpoint);
|
||
return Status;
|
||
}
|
||
|
||
*ppNetworkAddressVector = pEndpoint->pAddressVector;
|
||
|
||
#if FALSE
|
||
// If needed, figure out the dynamically allocated endpoint.
|
||
|
||
if (!*pPort)
|
||
{
|
||
*pPort = new RPC_CHAR[IP_MAXIMUM_ENDPOINT];
|
||
if (!*pPort)
|
||
{
|
||
MQ_ServerAbortListen(ThisEndpoint);
|
||
return(RPC_S_OUT_OF_MEMORY);
|
||
}
|
||
|
||
port = ntohs(addr.inetaddr.sin_port);
|
||
|
||
PortNumberToEndpoint(port, *pPort);
|
||
}
|
||
|
||
// Figure out the network addresses
|
||
|
||
status = IP_BuildAddressVector(&pEndpoint->pAddressVector);
|
||
|
||
if (status != RPC_S_OK)
|
||
{
|
||
MQ_ServerAbortListen(ThisEndpoint);
|
||
return(status);
|
||
}
|
||
|
||
*ppNetworkAddressVector = pEndpoint->pAddressVector;
|
||
#endif
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
MQ_QueryEndpoint
|
||
(
|
||
IN void * pOriginalEndpoint,
|
||
OUT RPC_CHAR * pClientEndpoint
|
||
)
|
||
{
|
||
MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pOriginalEndpoint;
|
||
|
||
if (!RpcpStringLength(pAddress->wsQName))
|
||
{
|
||
ParseQueuePathName(pAddress->wsMsgLabel,
|
||
pAddress->wsMachine,
|
||
pAddress->wsQName);
|
||
}
|
||
|
||
RpcpStringCopy(pClientEndpoint,pAddress->wsQName);
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
MQ_QueryAddress
|
||
(
|
||
IN void * pOriginalEndpoint,
|
||
OUT RPC_CHAR * pClientAddress
|
||
)
|
||
{
|
||
MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pOriginalEndpoint;
|
||
|
||
if (!RpcpStringLength(pAddress->wsMachine))
|
||
{
|
||
ParseQueuePathName(pAddress->wsMsgLabel,
|
||
pAddress->wsMachine,
|
||
pAddress->wsQName);
|
||
}
|
||
|
||
RpcpStringCopy(pClientAddress,pAddress->wsMachine);
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
MQ_ClientInitializeAddress
|
||
(
|
||
OUT DG_TRANSPORT_ADDRESS pvAddress,
|
||
IN RPC_CHAR *pNetworkAddress,
|
||
IN RPC_CHAR *pEndpoint,
|
||
IN BOOL fUseCache,
|
||
IN BOOL fBroadcast
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initializes a address object for sending to a server.
|
||
|
||
Arguments:
|
||
|
||
pvAddress - Storage for the address
|
||
pNetworkAddress - The address of the server or 0 if local
|
||
pEndpoint - The endpoint of the server
|
||
fUseCache - If TRUE then the transport may use a cached
|
||
value from a previous call on the same NetworkAddress.
|
||
fBroadcast - If TRUE, NetworkAddress is ignored and a broadcast
|
||
address is used.
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Success, name resolved and, optionally, added to cache.
|
||
RPC_P_FOUND_IN_CACHE - Success, returned only if fUseCache is TRUE
|
||
and the was name found in local cache.
|
||
RPC_P_MATCHED_CACHE - Partial success, fUseCache is FALSE and the
|
||
result of the lookup was the same as the value previously
|
||
in the cache.
|
||
|
||
RPC_S_OUT_OF_MEMORY
|
||
RPC_S_OUT_OF_RESOURCES
|
||
RPC_S_INVALID_ENDPOINT_FORMAT
|
||
RPC_S_SERVER_UNAVAILABLE
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
MQ_ADDRESS *pAddress = (MQ_ADDRESS*)pvAddress;
|
||
|
||
ASSERT(pvAddress);
|
||
|
||
Status = ConnectToServerQueue(pAddress,pNetworkAddress,pEndpoint);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
MQ_ClientOpenEndpoint(
|
||
OUT DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
IN BOOL fAsync,
|
||
DWORD Flags
|
||
)
|
||
{
|
||
RPC_STATUS Status;
|
||
MQ_DATAGRAM_ENDPOINT *pEndpoint = (MQ_DATAGRAM_ENDPOINT*)ThisEndpoint;
|
||
|
||
Status = MQ_CreateEndpoint(pEndpoint, NULL, NULL, 0, MSMQ, TRUE, fAsync);
|
||
|
||
return Status;
|
||
}
|
||
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
MQ_GetEndpointStats(
|
||
IN DG_TRANSPORT_ENDPOINT ThisEndpoint,
|
||
OUT DG_ENDPOINT_STATS * pStats
|
||
)
|
||
{
|
||
pStats->PreferredPduSize = MQ_PREFERRED_PDU_SIZE;
|
||
pStats->MaxPduSize = MQ_MAX_PDU_SIZE;
|
||
pStats->MaxPacketSize = MQ_MAX_PACKET_SIZE;
|
||
pStats->ReceiveBufferSize = MQ_RECEIVE_BUFFER_SIZE;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
//----------------------------------------------------------------
|
||
// MQ_InquireAuthClient()
|
||
//
|
||
// Fill out security information for the transport.
|
||
//
|
||
// NOTE: The returned SID (ppSid) is a pointer to the one in the
|
||
// client endpoint. The caller can't free it and should make
|
||
// its own copy...
|
||
//----------------------------------------------------------------
|
||
RPC_STATUS
|
||
RPC_ENTRY
|
||
MQ_InquireAuthClient( void *pvClientEndpoint,
|
||
RPC_CHAR **ppPrincipal,
|
||
SID **ppSid,
|
||
ULONG *pulAuthnLevel,
|
||
ULONG *pulAuthnService,
|
||
ULONG *pulAuthzService )
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
MQ_ADDRESS *pClientEndpoint = (MQ_ADDRESS*)(pvClientEndpoint);
|
||
SID *pClientSid;
|
||
DWORD dwSize;
|
||
|
||
ASSERT(pulAuthnLevel);
|
||
ASSERT(pulAuthnService);
|
||
ASSERT(pulAuthzService);
|
||
|
||
if (pClientEndpoint)
|
||
{
|
||
*ppPrincipal = NULL;
|
||
*pulAuthnService = RPC_C_AUTHN_MQ;
|
||
*pulAuthzService = RPC_C_AUTHZ_NONE;
|
||
|
||
//
|
||
// The authentication level:
|
||
//
|
||
if (pClientEndpoint->fAuthenticated)
|
||
{
|
||
if (pClientEndpoint->ulPrivacyLevel == MQMSG_PRIV_LEVEL_BODY)
|
||
*pulAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
|
||
else
|
||
*pulAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
|
||
}
|
||
else if (pClientEndpoint->ulPrivacyLevel == MQMSG_PRIV_LEVEL_BODY)
|
||
{
|
||
*pulAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
|
||
}
|
||
else
|
||
{
|
||
*pulAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
|
||
}
|
||
|
||
if ( IsValidSid((PSID)(pClientEndpoint->aSidBuffer)) )
|
||
*ppSid = (SID*)(pClientEndpoint->aSidBuffer);
|
||
else
|
||
*ppSid = NULL;
|
||
|
||
}
|
||
else
|
||
Status = RPC_S_BINDING_HAS_NO_AUTH;
|
||
|
||
return Status;
|
||
}
|
||
|