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

523 lines
12 KiB
C++
Raw 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, 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