523 lines
12 KiB
C++
523 lines
12 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1991 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
msgapi.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
The I_RpcSendReceive API used to send and receive messages as part of
|
|||
|
a remote procedure call lives here. This API is used by both clients
|
|||
|
(to make calls) and by servers (to make callbacks).
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Michael Montague (mikemon) 07-Nov-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
Mazhar Mohammed (mazharm) 09-11-95 added I_RpcReceive, I_RpcSend
|
|||
|
Mazhar Mohammed (mazharm) 03-31-96 added support for async RPC
|
|||
|
I_RpcAsyncSend and I_RpcAsyncReceive
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
|
|||
|
#define _SND_RECV_CALLED 0x100
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
I_RpcSendReceive (
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We do all of the protocol module independent work of making a remote
|
|||
|
procedure call; at least the part concerned with sending the request
|
|||
|
and receiving the response. The majority of the work is done by
|
|||
|
each rpc protocol module.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies and returns the information required to make
|
|||
|
the remote procedure call.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
RPC_S_OK - The operation completed successfully.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS retval;
|
|||
|
THREAD *Thread;
|
|||
|
|
|||
|
AssertRpcInitialized();
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
Thread = ThreadSelf();
|
|||
|
if (!Thread)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
|
|||
|
|
|||
|
MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
|
|||
|
|
|||
|
ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
|
|||
|
|
|||
|
ASSERT( Message->Buffer != 0 );
|
|||
|
ASSERT( !COMPLETE(Message) );
|
|||
|
|
|||
|
retval = MObject->SendReceive(Message);
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
// Insure that the buffer is aligned on an eight byte boundary.
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
|
|||
|
if ( retval == RPC_S_OK )
|
|||
|
{
|
|||
|
ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
|
|||
|
// uncomment this to check for 16 byte alignment on 64 bits
|
|||
|
// ASSERT( IsBufferAligned(Message->Buffer) );
|
|||
|
}
|
|||
|
|
|||
|
#endif // DEBUGRPC
|
|||
|
|
|||
|
return(retval);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
I_RpcSend (
|
|||
|
IN OUT PRPC_MESSAGE Message
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
This API is used in conjunction with pipes. This is used to send the marshalled
|
|||
|
parameters and the marshalled pipe data.
|
|||
|
|
|||
|
Client: If the RPC_BUFFER_PARTIAL bit is set in Message->RpcFlags,
|
|||
|
this routine returns as soon as the buffer is sent. If the
|
|||
|
bit is not set, this routine blocks until the first reply fragment arrives.
|
|||
|
|
|||
|
Server: The send always treated as a partial send.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the information required to send the request
|
|||
|
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
RPC_S_OK - The operation completed successfully.
|
|||
|
RPC_S_SEND_INCOMPLETE - The complete data wasn't sent, Message->Buffer
|
|||
|
points to the remaining data and Message->BufferLength indicates the length of the
|
|||
|
remaining data. Any additional data needs to be appended to the
|
|||
|
end of the buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS retval;
|
|||
|
THREAD *Thread;
|
|||
|
PVOID MessageBuffer;
|
|||
|
|
|||
|
AssertRpcInitialized();
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
Thread = ThreadSelf();
|
|||
|
if (!Thread)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
|
|||
|
|
|||
|
MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
|
|||
|
|
|||
|
ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
|
|||
|
|
|||
|
MessageBuffer = Message->Buffer;
|
|||
|
ASSERT( MessageBuffer != 0 );
|
|||
|
|
|||
|
if (ASYNC(Message))
|
|||
|
{
|
|||
|
retval = MObject->AsyncSend(Message);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
retval = MObject->Send(Message);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
// Insure that the buffer is aligned on an eight byte boundary.
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
|
|||
|
if ( retval == RPC_S_OK )
|
|||
|
{
|
|||
|
ASSERT( (((ULONG_PTR) MessageBuffer) % 8) == 0);
|
|||
|
// uncomment this to check for 16 byte alignment on 64 bits
|
|||
|
//ASSERT( IsBufferAligned(MessageBuffer) );
|
|||
|
}
|
|||
|
|
|||
|
#endif // DEBUGRPC
|
|||
|
|
|||
|
return(retval);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
I_RpcReceive (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN unsigned int Size
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
This routine is used in conjunction with pipes. If the RPC_BUFFER_PARTIAL bit
|
|||
|
is set in Message->RpcFlags, this call blocks until some data is received. Size is
|
|||
|
used as a hint of how much data the caller is requesting. If the partial bit is not set,
|
|||
|
this call blocks until the complete buffer is received.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the information required to make the receive
|
|||
|
Size - used as a hint to indicate the amount of data needed by the caller
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
RPC_S_OK - The operation completed successfully.
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
RPC_STATUS retval;
|
|||
|
THREAD *Thread;
|
|||
|
|
|||
|
AssertRpcInitialized();
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
Thread = ThreadSelf();
|
|||
|
if (!Thread)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
|
|||
|
|
|||
|
MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
|
|||
|
|
|||
|
ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
|
|||
|
|
|||
|
//
|
|||
|
// Temp hack
|
|||
|
// Need to get Ryszard to fix
|
|||
|
// the NDR engine to never ask for 0 bytes
|
|||
|
// We can then change this to an ASSERT
|
|||
|
// ASSERT(Size)
|
|||
|
//
|
|||
|
if (Size == 0)
|
|||
|
Size = 1;
|
|||
|
|
|||
|
if (ASYNC(Message))
|
|||
|
{
|
|||
|
retval = MObject->AsyncReceive(Message, Size);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
retval = MObject->Receive(Message, Size);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
// Insure that the buffer is aligned on an eight byte boundary.
|
|||
|
|
|||
|
#ifdef DEBUGRPC
|
|||
|
|
|||
|
if ( retval == RPC_S_OK )
|
|||
|
{
|
|||
|
ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
|
|||
|
// uncomment this to check for 16 byte alignment on 64 bits
|
|||
|
// ASSERT( IsBufferAligned(Message->Buffer) );
|
|||
|
}
|
|||
|
|
|||
|
#endif // DEBUGRPC
|
|||
|
|
|||
|
return(retval);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
I_RpcAsyncSetHandle (
|
|||
|
IN PRPC_MESSAGE Message,
|
|||
|
IN PRPC_ASYNC_STATE pAsync
|
|||
|
)
|
|||
|
/*++
|
|||
|
This API is called on the client and server side. If this API is called on the
|
|||
|
server, runtime assumes that the call is async
|
|||
|
we will add more params later.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS retval;
|
|||
|
|
|||
|
AssertRpcInitialized();
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
|
|||
|
|
|||
|
if (MObject->InvalidHandle(CALL_TYPE))
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
return (RPC_S_INVALID_BINDING);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!MObject->InvalidHandle(CCALL_TYPE))
|
|||
|
{
|
|||
|
// if we end up with invalid pAsync here, this means we were either
|
|||
|
// called by a private test, or COM. Both should know better. The
|
|||
|
// public APIs should pass through NDR and NDR already should have
|
|||
|
// validated the parameters.
|
|||
|
ASSERT((pAsync->Lock == 0) || (pAsync->Lock == 1));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
retval = MObject->SetAsyncHandle(pAsync);
|
|||
|
|
|||
|
if (retval == RPC_S_OK)
|
|||
|
{
|
|||
|
pAsync->RuntimeInfo = (void *) MObject;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(!RpcpCheckHeap());
|
|||
|
|
|||
|
return(retval);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
I_RpcAsyncAbortCall (
|
|||
|
IN PRPC_ASYNC_STATE pAsync,
|
|||
|
IN unsigned long ExceptionCode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
pAsync - the async handle being registered
|
|||
|
|
|||
|
Return Value:
|
|||
|
RPC_S_OK - the call succeeded.
|
|||
|
RPC_S_INVALID_HANDLE - the handle was bad.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) pAsync->RuntimeInfo;
|
|||
|
|
|||
|
if (!ThreadSelf())
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (MObject)
|
|||
|
{
|
|||
|
if (MObject->InvalidHandle(CALL_TYPE))
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
return (RPC_S_INVALID_BINDING);
|
|||
|
}
|
|||
|
|
|||
|
return ((CALL *) MObject)->AbortAsyncCall(pAsync, ExceptionCode);
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_INVALID_ASYNC_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef __cplusplus
|
|||
|
extern "C" {
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
I_RpcParseSecurity (
|
|||
|
IN RPC_CHAR * NetworkOptions,
|
|||
|
OUT SECURITY_QUALITY_OF_SERVICE * SecurityQualityOfService
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Parse a string of security options and build into the binary format
|
|||
|
required by the operating system. The network options must follow
|
|||
|
the following syntax. Case is not sensitive.
|
|||
|
|
|||
|
security=
|
|||
|
[anonymous|identification|impersonation|delegation]
|
|||
|
[dynamic|static]
|
|||
|
[true|false]
|
|||
|
|
|||
|
All three fields must be present. To specify impersonation
|
|||
|
with dynamic tracking and effective only, use the following
|
|||
|
string for the network options.
|
|||
|
|
|||
|
"security=impersonation dynamic true"
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NetworkOptions - Supplies the string containing the network options
|
|||
|
to be parsed.
|
|||
|
|
|||
|
SecurityQualityOfService - Returns the binary format of the network
|
|||
|
options.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The network options have been correctly parsed into binary
|
|||
|
format.
|
|||
|
|
|||
|
RPC_S_INVALID_NETWORK_OPTIONS - The network options are invalid and
|
|||
|
cannot be parsed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
ASSERT(NetworkOptions[0] != 0);
|
|||
|
|
|||
|
// We need to parse the security information from the network
|
|||
|
// options, and then stuff it into the object attributes. To
|
|||
|
// begin with, we check for "security=" at the beginning of
|
|||
|
// the network options.
|
|||
|
|
|||
|
if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("security="),
|
|||
|
sizeof("security=") - 1) != 0)
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
NetworkOptions += sizeof("security=") - 1;
|
|||
|
|
|||
|
// Ok, now we need to determine if the next field is one of
|
|||
|
// Anonymous, Identification, Impersonation, or Delegation.
|
|||
|
|
|||
|
if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("anonymous"),
|
|||
|
sizeof("anonymous") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->ImpersonationLevel = SecurityAnonymous;
|
|||
|
NetworkOptions += sizeof("anonymous") - 1;
|
|||
|
}
|
|||
|
else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("identification"),
|
|||
|
sizeof("identification") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->ImpersonationLevel = SecurityIdentification;
|
|||
|
NetworkOptions += sizeof("identification") - 1;
|
|||
|
}
|
|||
|
else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("impersonation"),
|
|||
|
sizeof("impersonation") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->ImpersonationLevel = SecurityImpersonation;
|
|||
|
NetworkOptions += sizeof("impersonation") - 1;
|
|||
|
}
|
|||
|
else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("delegation"),
|
|||
|
sizeof("delegation") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->ImpersonationLevel = SecurityDelegation;
|
|||
|
NetworkOptions += sizeof("delegation") - 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
if (*NetworkOptions != RPC_CONST_CHAR(' '))
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
NetworkOptions++;
|
|||
|
|
|||
|
// Next comes the context tracking field; it must be one of
|
|||
|
// dynamic or static.
|
|||
|
|
|||
|
if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("dynamic"),
|
|||
|
sizeof("dynamic") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->ContextTrackingMode =
|
|||
|
SECURITY_DYNAMIC_TRACKING;
|
|||
|
NetworkOptions += sizeof("dynamic") - 1;
|
|||
|
}
|
|||
|
else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("static"),
|
|||
|
sizeof("static") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->ContextTrackingMode =
|
|||
|
SECURITY_STATIC_TRACKING;
|
|||
|
NetworkOptions += sizeof("static") - 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
if (*NetworkOptions != RPC_CONST_CHAR(' '))
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
NetworkOptions++;
|
|||
|
|
|||
|
// Finally, comes the effective only flag. This must be one of
|
|||
|
// true or false.
|
|||
|
|
|||
|
if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("true"),
|
|||
|
sizeof("true") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->EffectiveOnly = TRUE;
|
|||
|
NetworkOptions += sizeof("true") - 1;
|
|||
|
}
|
|||
|
else if (RpcpStringNCompare(NetworkOptions, RPC_CONST_STRING("false"),
|
|||
|
sizeof("false") - 1) == 0)
|
|||
|
{
|
|||
|
SecurityQualityOfService->EffectiveOnly = FALSE;
|
|||
|
NetworkOptions += sizeof("false") - 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
if (*NetworkOptions != 0)
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_NETWORK_OPTIONS);
|
|||
|
}
|
|||
|
|
|||
|
SecurityQualityOfService->Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
#ifdef __cplusplus
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|