362 lines
9.1 KiB
C++
362 lines
9.1 KiB
C++
/*++
|
||
|
||
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);
|
||
}
|
||
|