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

362 lines
8.7 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:
bufapi.cxx
Abstract:
The two APIs used to allocate and free buffers used to make remote
procedure calls reside in this file. These APIs are used by both
the client and server in caller and callee stubs.
Author:
Michael Montague (mikemon) 07-Nov-1991
Revision History:
Connie Hoppe (connieh) 26-Jul-1993 I_RpcGetBuffer
Kamen Moutafov (kamenm) Jan 2000 - Multiple transfer syntax support
--*/
#include <precomp.hxx>
inline RPC_STATUS CheckHandleValidity (IN OUT RPC_MESSAGE __RPC_FAR * Message)
{
if (((GENERIC_OBJECT *) (Message->Handle))->InvalidHandle(
CALL_TYPE | BINDING_HANDLE_TYPE))
return(RPC_S_INVALID_BINDING);
else
return RPC_S_OK;
}
RPC_STATUS
EnterBufApiPartial (
IN OUT RPC_MESSAGE __RPC_FAR * Message
)
{
THREAD *Thread;
AssertRpcInitialized();
ASSERT(!RpcpCheckHeap());
Thread = ThreadSelf();
if (!Thread)
{
return RPC_S_OUT_OF_MEMORY;
}
RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
// for WIN64, these are never set
#if !defined(_WIN64)
// this is used to workaround a MIDL 1.0 bug
// which didn't initialize the RpcFlags. MIDL 2.0 initializes the
// flags correctly, and in addition sets this bit in the ProcNum
// to indicate the flags are set correctly.
if (Message->ProcNum & RPC_FLAGS_VALID_BIT)
{
#endif
// Flags are valid, clear the bit.
Message->ProcNum &= ~(RPC_FLAGS_VALID_BIT);
#if !defined(_WIN64)
}
else
{
// Flags are invalid, set to zero.
Message->RpcFlags = 0;
}
#endif
return RPC_S_OK;
}
RPC_STATUS
EnterBufApiFull (
IN OUT RPC_MESSAGE __RPC_FAR * Message
)
{
RPC_STATUS Status;
Status = EnterBufApiPartial(Message);
if (Status == RPC_S_OK)
Status = CheckHandleValidity (Message);
return Status;
}
RPCRTAPI
RPC_STATUS
RPC_ENTRY
I_RpcNegotiateTransferSyntax (
IN OUT RPC_MESSAGE __RPC_FAR * Message
)
/*++
Routine Description:
NDR calls this routine to get the transfer syntax to be used in marshalling.
Stubs that are multiple transfer syntax aware (starting with the 64 bit release
of Win2000) will set the RPCFLG_HAS_MULTI_SYNTAXES in RPC_CLIENT_INTERFACE
to indicate they have properly initialized the InterpreterInfo field. Legacy
stubs will not have this flag initialized, and will call I_RpcGetBuffer[WithObject]
directly. The runtime has to be prepared to deal with this. Stubs that
support only NDR2.0 are free to behave as legacy stubs.
Arguments:
Message - Supplies the information necessary to allocate the buffer,
and returns the allocated buffer. This function assumes that
the handle passed in Message->Handle is a binding handle. It also
assumes Message->TransferSyntax is valid.
Return Value:
RPC_S_OK - The operation completed successfully.
--*/
{
RPC_STATUS Status;
MESSAGE_OBJECT *MessageObject;
// validate and transorm some input parameters
Status = EnterBufApiFull(Message);
MessageObject = (MESSAGE_OBJECT *)Message->Handle;
if (Status != RPC_S_OK)
return Status;
return MessageObject->NegotiateTransferSyntax(Message);
}
RPC_STATUS RPC_ENTRY
I_RpcGetBufferWithObject (
IN OUT PRPC_MESSAGE Message,
IN UUID * ObjectUuid
)
/*++
Routine Description:
In this API, we do all of the rpc protocol module independent work of
allocating a buffer to be used in making a remote procedure call. This
consists of validating the handle, and then calling the rpc protocol
module to do the real work.
Arguments:
Message - Supplies the information necessary to allocate the buffer,
and returns the allocated buffer.
Return Value:
RPC_S_OK - The operation completed successfully.
--*/
{
RPC_STATUS Status;
RPC_CLIENT_INTERFACE *ClientInterface;
BOOL fObjectIsSCall;
MESSAGE_OBJECT *MessageObject;
Status = CheckHandleValidity (Message);
if (Status)
return Status;
MessageObject = (MESSAGE_OBJECT *)Message->Handle;
fObjectIsSCall = MessageObject->Type(SCALL_TYPE);
// in all fairness, this could very well be a server interface, but
// they have the same layout, and the Flags field is in the same place,
// so we can test the Flags field as if this is a client interface
ClientInterface = (RPC_CLIENT_INTERFACE *)Message->RpcInterfaceInformation;
// check whether this is a client stub that supports multiple transfer
// syntaxes if yes, it should have called I_RpcNegotiateTransferSyntax
// by now
if (!fObjectIsSCall && DoesInterfaceSupportMultipleTransferSyntaxes(ClientInterface))
{
// if this interface supports multiple transfer syntaxes
// the stub should have called already I_RpcNegotiateTransferSyntax
// and this cannot be an OSF_BINDING_HANDLE
ASSERT(!MessageObject->Type(OSF_BINDING_HANDLE_TYPE));
ASSERT(!MessageObject->Type(LRPC_BINDING_HANDLE_TYPE));
if (ObjectUuid && ((RPC_UUID *) ObjectUuid)->IsNullUuid())
{
ObjectUuid = 0;
}
Status = MessageObject->GetBuffer(Message, ObjectUuid);
}
else
{
// if not, this is either a legacy stub, a new stub that supports
// one transfer syntax only, or a server side call
// validate the input parameters
Status = EnterBufApiPartial(Message);
if (Status != RPC_S_OK)
return Status;
if (!fObjectIsSCall)
{
// this applies only on the client side
Status = MessageObject->NegotiateTransferSyntax(Message);
if (Status != RPC_S_OK)
return Status;
MessageObject = (MESSAGE_OBJECT *)Message->Handle;
if (ObjectUuid && ((RPC_UUID *) ObjectUuid)->IsNullUuid())
{
ObjectUuid = 0;
}
}
// by now this should not be a binding handle object
ASSERT(!MessageObject->Type(OSF_BINDING_HANDLE_TYPE));
ASSERT(!MessageObject->Type(LRPC_BINDING_HANDLE_TYPE));
Status = MessageObject->GetBuffer(Message, ObjectUuid);
}
#ifdef DEBUGRPC
if ( Status == RPC_S_OK )
{
// Ensure that the buffer is aligned
ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
// Uncomment this to check for 16 byte alignment on 64 bit
// ASSERT( IsBufferAligned(Message->Buffer) );
}
#endif // DEBUGRPC
return(Status);
}
RPC_STATUS RPC_ENTRY
I_RpcGetBuffer (
IN OUT PRPC_MESSAGE Message
)
{
return I_RpcGetBufferWithObject (Message, 0);
}
RPC_STATUS RPC_ENTRY
I_RpcFreeBuffer (
IN PRPC_MESSAGE Message
)
/*++
Routine Description:
The stubs free buffers using the API. The buffer must have been
obtained from I_RpcGetBuffer or I_RpcSendReceive, or as an argument
to a callee stub.
Arguments:
Message - Supplies the buffer to be freed and handle information
about who owns the buffer.
Return Value:
RPC_S_OK - The operation completed successfully.
--*/
{
AssertRpcInitialized();
ASSERT(!RpcpCheckHeap());
ASSERT( ((GENERIC_OBJECT *) Message->Handle)->InvalidHandle(CALL_TYPE) == 0 );
((MESSAGE_OBJECT *) (Message->Handle))->FreeBuffer(Message);
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
I_RpcFreePipeBuffer (
IN PRPC_MESSAGE Message
)
/*++
Routine Description:
Free the buffer that was either implicitly or explicitly allocated for use
in conjunction with pipes
Arguments:
Message - Supplies the buffer to be freed and handle information
about who owns the buffer.
Return Value:
RPC_S_OK - The operation completed successfully.
--*/
{
AssertRpcInitialized();
ASSERT(!RpcpCheckHeap());
ASSERT( ((GENERIC_OBJECT *) Message->Handle)->InvalidHandle(CALL_TYPE) == 0 );
((MESSAGE_OBJECT *) (Message->Handle))->FreePipeBuffer(Message);
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
I_RpcReallocPipeBuffer (
IN PRPC_MESSAGE Message,
IN unsigned int NewSize
)
/*++
Routine Description:
Realloc a buffer, this is API is used in conjunction with pipes
Arguments:
Message - Supplies the buffer to be freed and handle information
about who owns the buffer.
Return Value:
RPC_S_OK - The operation completed successfully.
--*/
{
AssertRpcInitialized();
ASSERT(!RpcpCheckHeap());
ASSERT( ((GENERIC_OBJECT *) Message->Handle)->InvalidHandle(CALL_TYPE) == 0 );
if (!ThreadSelf())
{
return RPC_S_OUT_OF_MEMORY;
}
RpcpPurgeEEInfo();
return ((MESSAGE_OBJECT *) (Message->Handle))->ReallocPipeBuffer(Message, NewSize);
}