/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1999-2000 Microsoft Corporation Module Name : mulsyntx.cxx Abstract : This file contains multiple transfer syntaxes negotiation related code Author : Yong Qu yongqu September 1999. Revision History : ---------------------------------------------------------------------*/ #include "ndrp.h" #define CINTERFACE #include "ndrole.h" #include "rpcproxy.h" #include "mulsyntx.h" #include "hndl.h" #include "auxilary.h" #include "pipendr.h" #include "ndr64tkn.h" const extern PMARSHALL_ROUTINE MarshallRoutinesTable[]; const extern PUNMARSHALL_ROUTINE UnmarshallRoutinesTable[]; const extern PSIZE_ROUTINE SizeRoutinesTable[]; const extern PMEM_SIZE_ROUTINE MemSizeRoutinesTable[]; const extern PFREE_ROUTINE FreeRoutinesTable[]; //const extern PWALKIP_ROUTINE WalkIPRoutinesTable[]; // TODO: move this to ndrpall.h after Preview. #define MIDL_VERSION_6_0_322 ((6UL << 24) | (0UL << 16) | 322UL) void RPC_ENTRY NdrpClientInit(MIDL_STUB_MESSAGE * pStubMsg, void * pReturnValue ) { PFORMAT_STRING pFormatParam; ulong ProcNum; BOOL fRaiseExcFlag; ulong n; uchar * pArg; INTERPRETER_FLAGS InterpreterFlags; PPARAM_DESCRIPTION Params; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *) pStubMsg->pContext; INTERPRETER_OPT_FLAGS OptFlags = pContext->NdrInfo.pProcDesc->Oi2Flags; PFORMAT_STRING pTypeFormat; // When this routine is called from ndrclientcall2, we don't have MIDL_SYNTAX_INFO, // so we need to read it from MIDL_STUB_DESC; // Note: we need to conenct StubDesc to pStubMsg before calling into here. if ( NULL == pContext->pSyntaxInfo ) pContext->DceTypeFormatString = pStubMsg->StubDesc->pFormatTypes; else pContext->DceTypeFormatString = pContext->pSyntaxInfo->TypeString; InterpreterFlags = pContext->NdrInfo.InterpreterFlags; Params = ( PPARAM_DESCRIPTION )pContext->Params; pTypeFormat = pContext->DceTypeFormatString; if ( InterpreterFlags.FullPtrUsed ) pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit( 0, XLAT_CLIENT ); else pStubMsg->FullPtrXlatTables = 0; if ( InterpreterFlags.RpcSsAllocUsed ) NdrRpcSmSetClientToOsf( pStubMsg ); // Set Rpc flags after the call to client initialize. pStubMsg->RpcMsg->RpcFlags = pContext->RpcFlags; if ( OptFlags.HasPipes ) NdrpPipesInitialize32( pStubMsg, &pContext->AllocateContext, (PFORMAT_STRING) pContext->Params, ( char * )pContext->StartofStack, pContext->NumberParams ); // Must do this before the sizing pass! pStubMsg->StackTop = pContext->StartofStack; if ( OptFlags.HasExtensions ) { pStubMsg->fHasExtensions = 1; pStubMsg->fHasNewCorrDesc = pContext->NdrInfo.pProcDesc->NdrExts.Flags2.HasNewCorrDesc; if ( pContext->NdrInfo.pProcDesc->NdrExts.Flags2.ClientCorrCheck ) { ulong *pCache = (ulong*)NdrpAlloca(&pContext->AllocateContext, NDR_DEFAULT_CORR_CACHE_SIZE ); NdrCorrelationInitialize( pStubMsg, pCache, NDR_DEFAULT_CORR_CACHE_SIZE, 0 /* flags */ ); } } // // Get the compile time computed buffer size. // pStubMsg->BufferLength = pContext->NdrInfo.pProcDesc->ClientBufferSize; // // Check ref pointers and do object proc [out] zeroing. // fRaiseExcFlag = FALSE; for ( n = 0; n < pContext->NumberParams; n++ ) { if ( Params[n].ParamAttr.IsReturn ) pArg = (uchar *) &pReturnValue; else pArg = pContext->StartofStack + Params[n].StackOffset; if ( Params[n].ParamAttr.IsSimpleRef && !Params[n].ParamAttr.IsReturn ) { // We cannot raise the exception here, // as some out args may not be zeroed out yet. if ( ! *((uchar **)pArg) ) { fRaiseExcFlag = TRUE; continue; } } // if top level point is FC_RP and the arg is NULL, we'll catch this // before the call goes to server. // We wouldn't catch all the null ref pointer here, but we should be able // to catch the most obvious ones. // This code is called from sync & raw async code; in async dcom, // we only go through outinit in finish routine so we can't do anything anyhow. if ( Params[n].ParamAttr.IsOut && ! Params[n].ParamAttr.IsBasetype ) { pFormatParam = pTypeFormat + Params[n].TypeOffset; if ( * pFormatParam == FC_RP && !*((uchar **)pArg) ) { fRaiseExcFlag = TRUE; continue; } } // // In object procs and complex return types we have to zero // out all [out] parameters. We do the basetype check to // cover the [out] simple ref to basetype case. // if ( ( InterpreterFlags.ObjectProc && ! pContext->IsAsync && ( Params[n].ParamAttr.IsPartialIgnore || ( ! Params[n].ParamAttr.IsIn && ! Params[n].ParamAttr.IsReturn && ! Params[n].ParamAttr.IsPipe ) ) ) || ( pContext->HasComplexReturn && Params[n].ParamAttr.IsReturn ) ) { if ( Params[n].ParamAttr.IsBasetype ) { // [out] only arg can only be ref, we checked that above. MIDL_memset( *(uchar **)pArg, 0, (size_t)SIMPLE_TYPE_MEMSIZE( Params[n].SimpleType.Type )); } else { pFormatParam = pTypeFormat + Params[n].TypeOffset; NdrClientZeroOut( pStubMsg, pFormatParam, *(uchar **)pArg ); } } } if ( fRaiseExcFlag ) RpcRaiseException( RPC_X_NULL_REF_POINTER ); if ( OptFlags.ClientMustSize ) { // Compiler prevents variable size non-pipe args for NT v.4.0. if ( OptFlags.HasPipes ) RpcRaiseException( RPC_X_WRONG_PIPE_VERSION ); } else pContext->pfnSizing = (PFNSIZING)NdrpNoopSizing; } void RPC_ENTRY NdrpNoopSizing( MIDL_STUB_MESSAGE * pStubMsg, BOOL IsClient ) { return; } void RPC_ENTRY NdrpSizing( MIDL_STUB_MESSAGE * pStubMsg, BOOL IsClient ) { PFORMAT_STRING pFormatParam; ulong n; uchar * pArg; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; PPARAM_DESCRIPTION Params = ( PPARAM_DESCRIPTION )pContext->Params; PFORMAT_STRING pTypeFormat = pContext->DceTypeFormatString; // // Skip buffer size pass if possible. // for ( n = 0; n < pContext->NumberParams; n++ ) { if ( !SAMEDIRECTION(IsClient, Params[n]) || ! Params[n].ParamAttr.MustSize ) continue; if ( IsClient && Params[n].ParamAttr.IsPartialIgnore ) { LENGTH_ALIGN( pStubMsg->BufferLength, 0x3 ); pStubMsg->BufferLength += PTR_WIRE_SIZE; continue; } // // Note : Basetypes will always be factored into the // constant buffer size emitted by in the format strings. // pFormatParam = pTypeFormat + Params[n].TypeOffset; pArg = pContext->StartofStack + Params[n].StackOffset; if ( ! Params[n].ParamAttr.IsByValue ) pArg = *((uchar **)pArg); (*SizeRoutinesTable[ROUTINE_INDEX(*pFormatParam)]) ( pStubMsg, pArg, pFormatParam ); } } void RPC_ENTRY NdrpClientMarshal( MIDL_STUB_MESSAGE * pStubMsg, BOOL IsObject ) { ulong n; uchar * pArg; PFORMAT_STRING pFormatParam; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION ) pContext->Params; PFORMAT_STRING pTypeFormat = pContext->DceTypeFormatString; // // ---------------------------------------------------------- // Marshall Pass. // ---------------------------------------------------------- // for ( n = 0; n < pContext->NumberParams; n++ ) { if (!Params[n].ParamAttr.IsIn || Params[n].ParamAttr.IsPipe ) continue; if ( Params[n].ParamAttr.IsPartialIgnore ) { pArg = pContext->StartofStack + Params[n].StackOffset; ALIGN( pStubMsg->Buffer, 0x3 ); *(ulong*)pStubMsg->Buffer = *(void**)pArg ? 1 : 0; pStubMsg->Buffer += PTR_WIRE_SIZE; continue; } pArg = pContext->StartofStack + Params[n].StackOffset; if ( Params[n].ParamAttr.IsBasetype ) { // // Check for pointer to basetype. // if ( Params[n].ParamAttr.IsSimpleRef ) pArg = *((uchar **)pArg); else { #ifdef _IA64_ if ( !IsObject && Params[n].SimpleType.Type == FC_FLOAT ) { // Due to the fact that NdrClientCall2 is called with the // parameters in ... arguments, floats get promoted to doubles. // This is not true for DCOM since an assembly langauge wrapper // is used that saves the floats as floats. // // BUG, BUG. IA64 passes byval structures that consist // entirely of float fields with each field in a separate register. // We do not handle this case properly. *((float *) pArg) = (float) *((double *)pArg); } #endif } if ( Params[n].SimpleType.Type == FC_ENUM16 ) { if ( *((int *)pArg) & ~((int)0x7fff) ) RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); } ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( Params[n].SimpleType.Type ) ); RpcpMemoryCopy( pStubMsg->Buffer, pArg, (uint)SIMPLE_TYPE_BUFSIZE(Params[n].SimpleType.Type) ); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( Params[n].SimpleType.Type ); continue; } pFormatParam = pTypeFormat + Params[n].TypeOffset; if ( ! Params[n].ParamAttr.IsByValue ) pArg = *((uchar **)pArg); (* MarshallRoutinesTable[ROUTINE_INDEX(*pFormatParam)] ) ( pStubMsg, pArg, pFormatParam ); } if ( pStubMsg->RpcMsg->BufferLength < (uint)(pStubMsg->Buffer - (uchar *)pStubMsg->RpcMsg->Buffer) ) { NDR_ASSERT( 0, "NdrpClientMarshal marshal: buffer overflow!" ); RpcRaiseException( RPC_X_BAD_STUB_DATA ); } } void RPC_ENTRY NdrpServerMarshal( MIDL_STUB_MESSAGE * pStubMsg, BOOL IsObject ) { ulong n; uchar * pArg; PFORMAT_STRING pFormatParam; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION ) pContext->Params; PFORMAT_STRING pTypeFormat = pContext->DceTypeFormatString; // // ---------------------------------------------------------- // Marshall Pass. // ---------------------------------------------------------- // for ( n = 0; n < pContext->NumberParams; n++ ) { if (!Params[n].ParamAttr.IsOut || Params[n].ParamAttr.IsPipe ) continue; pArg = pContext->StartofStack + Params[n].StackOffset; if ( Params[n].ParamAttr.IsBasetype ) { // // Check for pointer to basetype. // if ( Params[n].ParamAttr.IsSimpleRef ) pArg = *((uchar **)pArg); if ( Params[n].SimpleType.Type == FC_ENUM16 ) { if ( *((int *)pArg) & ~((int)0x7fff) ) RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); } ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( Params[n].SimpleType.Type ) ); RpcpMemoryCopy( pStubMsg->Buffer, pArg, (uint)SIMPLE_TYPE_BUFSIZE(Params[n].SimpleType.Type) ); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( Params[n].SimpleType.Type ); continue; } pFormatParam = pTypeFormat + Params[n].TypeOffset; if ( ! Params[n].ParamAttr.IsByValue ) pArg = *((uchar **)pArg); (* MarshallRoutinesTable[ROUTINE_INDEX(*pFormatParam)] ) ( pStubMsg, pArg, pFormatParam ); } if ( pStubMsg->RpcMsg->BufferLength < (uint)(pStubMsg->Buffer - (uchar *)pStubMsg->RpcMsg->Buffer) ) { NDR_ASSERT( 0, "NdrpServerMarshal marshal: buffer overflow!" ); RpcRaiseException( RPC_X_BAD_STUB_DATA ); } } /* From: To: Marshall: User Exception: Cleanup:Rundown: context handle: ---------- ---------------------------------- -------------------------------- Any NULL Y N/A No No INVALID_HANDLE from the server !NULL Same value Any Any No No Same as before !NULL Different Any Any No No New context on the server !NULL Any N/A Y No No No new context handle is created NULL ANY N/A Y Yes No INVALID_HANDLE from the server NULL !NULL Y N Yes Yes INVALID_HANDLE from the server NULL !NULL N N Yes Yes INVALID_HANDLE from the server !NULL NULL N N Yes No No new context handle is created NULL NULL N N Yes No No new context handle is created In the OUT only context handle case: To: Marshall: User Exception: Cleanup:Rundown: context handle: -------------------------------------------------------------------------------------- Any N/A Y N N No new context handle is created NULL N N N N No new context handle is created NULL Y N N N No new context handle is created !NULL N N N Y No new context handle is created !NULL Y N Y Y No new context handle is created */ void NdrpEmergencyContextCleanup( MIDL_STUB_MESSAGE * pStubMsg, PNDR_CONTEXT_HANDLE_ARG_DESC pCtxtDesc, void * pArg, BOOL fManagerRoutineException ) { int RtnIndex = pCtxtDesc->RundownRtnIndex; NDR_RUNDOWN pfnRundown = pStubMsg->StubDesc->apfnNdrRundownRoutines[ RtnIndex ]; NDR_SCONTEXT SContext = pStubMsg->SavedContextHandles[ pCtxtDesc->ParamOrdinal ]; void * NewHandle = pArg; // if runtime failes during marshalling context handle, we shouldn't call into // cleanup routine since it's already cleanup by runtime. if ( SContext == (NDR_SCONTEXT )CONTEXT_HANDLE_BEFORE_MARSHAL_MARKER ) return; if ( fManagerRoutineException ) { // NDR_ASSERT( SContext != NULL || pCtxtDesc->Flags.IsReturn , // "only return context handle can have null scontext in exception" ); // if we failed somewhere during unmarshalling, or this is a return context handle, // we don't need to cleanup if ( SContext == NULL ) return; // in NdrServerOutInit, we initialize the scontext for regular [out] parameters, // and runtime has already allocated some memory. But for return context handle, // we initialize the scontext during marshalling and saved context is NULL till // just before marshalling. } else { // haven't unmarshalled yet. if ( SContext == NULL ) { if ( NULL == NewHandle ) return; else { // note : what if the context handle is both return and viaptr? NDR_ASSERT( pCtxtDesc->Flags.IsReturn, "has to be return context handle" ); } } else if ( SContext == (NDR_SCONTEXT )CONTEXT_HANDLE_AFTER_MARSHAL_MARKER ) { // this particular context handle has been marshalled; the exception happens // during marshalling other parameters after this one. // After marshalling is done, the runtime will release the user context if new context // handle is NULL, so we can't reference to the user context at this point. NewHandle = NULL; } else { if ( pCtxtDesc->Flags.IsViaPtr ) NewHandle = *((void * UNALIGNED *)pArg); } // if this is a regular [in,out] or [out] context handle, and it hasn't been marshalled // yet, we need to call into runtime to cleanup. } // Kamen volunteer to process the logic of calling runtime or not. In NDR we just // don't call into the routine when it isn't supposed to. NDRSContextEmergencyCleanup( pStubMsg->RpcMsg->Handle, SContext, pfnRundown, NewHandle, fManagerRoutineException ); } void NdrpCleanupServerContextHandles( MIDL_STUB_MESSAGE * pStubMsg, uchar * pStartOfStack, BOOL fManagerRoutineException ) { ulong n; uchar * pArg; PFORMAT_STRING pFormatParam; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION ) pContext->Params; PFORMAT_STRING pTypeFormat = pContext->DceTypeFormatString; // // ------------------------------------------------------------------------ // Context handle loop: clean up out context handles to prevent leaks. // // Note, this routine handles only the handles that may have been dropped // due to the NDR engine raising exception between a clean return from // the manager routine and end of marshaling back of the parameters. // This addresses a situation where handles get dropped by NDR without being // registered with the runtime and so the server leaks because the rundown // routine is never called on the dropped handles. // ------------------------------------------------------------------------ // for ( n = 0; n < pContext->NumberParams; n++ ) { if (!Params[n].ParamAttr.IsOut || Params[n].ParamAttr.IsPipe ) continue; pArg = pContext->StartofStack + Params[n].StackOffset; if ( Params[n].ParamAttr.IsBasetype ) { // // Check for pointer to basetype. // continue; } pFormatParam = pTypeFormat + Params[n].TypeOffset; if ( ! Params[n].ParamAttr.IsByValue ) pArg = *((uchar **)pArg); // Context handle have their own "via pointer" flag to mark dereference. if ( *pFormatParam == FC_BIND_CONTEXT ) { NdrpEmergencyContextCleanup( pStubMsg, (PNDR_CONTEXT_HANDLE_ARG_DESC) pFormatParam, pArg, fManagerRoutineException ); } } // parameter loop } void RPC_ENTRY NdrpClientUnMarshal ( MIDL_STUB_MESSAGE * pStubMsg, void * pReturnValue ) { ulong n; uchar * pArg; uchar ** ppArg; PFORMAT_STRING pFormatParam, pFormat; NDR_PROC_CONTEXT * pContext = ( NDR_PROC_CONTEXT *) pStubMsg->pContext; PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION)pContext->Params; PFORMAT_STRING pTypeFormat = pContext->DceTypeFormatString; // we only need to do conversion in NDR32 now: we cut off endian // conversion in NDR64. // Do endian/floating point conversions if necessary. // if ( (pStubMsg->RpcMsg->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) { NdrConvert2( pStubMsg, (PFORMAT_STRING) Params, pContext->NumberParams ); } // // ---------------------------------------------------------- // Unmarshall Pass. // ---------------------------------------------------------- // for ( n = 0; n < pContext->NumberParams; n++ ) { if ( Params[n].ParamAttr.IsPipe ) continue; if ( !Params[n].ParamAttr.IsOut ) { if ( !Params[n].ParamAttr.IsIn && !Params[n].ParamAttr.IsReturn ) { // If a param is not [in], [out], or a return value, // then it is a "hidden" client-side only status // paramater. It will get set below if an exception // happens. If everything is ok we need to zero it // out here. NDR_ASSERT( Params[n].ParamAttr.IsSimpleRef && Params[n].ParamAttr.IsBasetype && FC_ERROR_STATUS_T == Params[n].SimpleType.Type, "Apparently not a hidden status param" ); pArg = pContext->StartofStack + Params[n].StackOffset; ** (error_status_t **) pArg = RPC_S_OK; } continue; } if ( Params[n].ParamAttr.IsReturn ) pArg = (uchar *) pReturnValue; else pArg = pContext->StartofStack + Params[n].StackOffset; // // This is for returned basetypes and for pointers to // basetypes. // if ( Params[n].ParamAttr.IsBasetype ) { // // Check for a pointer to a basetype. // if ( Params[n].ParamAttr.IsSimpleRef ) pArg = *((uchar **)pArg); ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT(Params[n].SimpleType.Type) ); #if defined(__RPC_WIN64__) // Special case for int3264. if ( Params[n].SimpleType.Type == FC_INT3264 || Params[n].SimpleType.Type == FC_UINT3264 ) { if ( Params[n].SimpleType.Type == FC_INT3264 ) *((INT64 *)pArg) = *((long * &)pStubMsg->Buffer)++; else *((UINT64 *)pArg) = *((ulong * &)pStubMsg->Buffer)++; continue; } #endif if ( Params[n].SimpleType.Type == FC_ENUM16 ) { *((int *)(pArg)) = *((int *)pArg) & ((int)0x7fff) ; } RpcpMemoryCopy( pArg, pStubMsg->Buffer, (uint)SIMPLE_TYPE_BUFSIZE(Params[n].SimpleType.Type) ); pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( Params[n].SimpleType.Type ); continue; } ppArg = Params[n].ParamAttr.IsByValue ? &pArg : (uchar **)pArg; pFormatParam = pTypeFormat + Params[n].TypeOffset; // // Transmit/Represent as can be passed as [out] only, thus // the IsByValue check. // (* UnmarshallRoutinesTable[ROUTINE_INDEX(*pFormatParam)] ) ( pStubMsg, ppArg, pFormatParam, FALSE ); } if ( pStubMsg->pCorrInfo ) NdrCorrelationPass( pStubMsg ); return ; } void RPC_ENTRY NdrpServerUnMarshal ( MIDL_STUB_MESSAGE * pStubMsg ) { ulong n; uchar * pArg; uchar ** ppArg; PFORMAT_STRING pFormatParam, pFormat; NDR_PROC_CONTEXT * pContext = ( NDR_PROC_CONTEXT *) pStubMsg->pContext; PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION)pContext->Params; PFORMAT_STRING pTypeFormat = pContext->DceTypeFormatString; // we only need to do conversion in NDR32 now: we cut off endian // conversion in NDR64. // Do endian/floating point conversions if necessary. // if ( ( pStubMsg->RpcMsg->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) { NdrConvert2( pStubMsg, (PFORMAT_STRING) Params, (long) pContext->NumberParams ); } // -------------------------------- // Unmarshall all of our parameters. // -------------------------------- for ( n = 0; n < pContext->NumberParams; n++ ) { if ( ! Params[n].ParamAttr.IsIn || Params[n].ParamAttr.IsPipe ) continue; if ( Params[n].ParamAttr.IsPartialIgnore ) { pArg = pContext->StartofStack + Params[n].StackOffset; ALIGN( pStubMsg->Buffer, 0x3 ); *(void**)pArg = *(ulong*)pStubMsg->Buffer ? (void*)1 : (void*)0; pStubMsg->Buffer += PTR_WIRE_SIZE; continue; } pArg = pContext->StartofStack + Params[n].StackOffset; if ( Params[n].ParamAttr.IsBasetype ) { // // Check for a pointer to a basetype. Set the arg pointer // at the correct buffer location and you're done. // Except darn int3264 if ( Params[n].ParamAttr.IsSimpleRef ) { ALIGN( pStubMsg->Buffer, SIMPLE_TYPE_ALIGNMENT( Params[n].SimpleType.Type ) ); #if defined(__RPC_WIN64__) // Special case for a ref pointer to int3264. if ( Params[n].SimpleType.Type == FC_INT3264 || Params[n].SimpleType.Type == FC_UINT3264 ) { *((void **)pArg) = NdrpAlloca( &pContext->AllocateContext, 8 ); if ( Params[n].SimpleType.Type == FC_INT3264 ) *(*(INT64**)pArg) = *((long * &)pStubMsg->Buffer)++; else *(*(UINT64**)pArg)= *((ulong * &)pStubMsg->Buffer)++; continue; } #endif *((uchar **)pArg) = pStubMsg->Buffer; pStubMsg->Buffer += SIMPLE_TYPE_BUFSIZE( Params[n].SimpleType.Type ); } else { NdrUnmarshallBasetypeInline( pStubMsg, pArg, Params[n].SimpleType.Type ); } continue; } // IsBasetype // // This is an initialization of [in] and [in,out] ref pointers // to pointers. These can not be initialized to point into the // rpc buffer and we want to avoid doing a malloc of 4 bytes! // 32b: a ref pointer to any pointer, we allocate the pointee pointer. // if ( Params[n].ParamAttr.ServerAllocSize != 0 ) { *((void **)pArg) = NdrpAlloca(& pContext->AllocateContext, PTR_MEM_SIZE ); // Triple indirection - cool! **((void ***)pArg) = 0; } pStubMsg->ReuseBuffer = Params[n].ParamAttr.IsForceAllocate; ppArg = Params[n].ParamAttr.IsByValue ? &pArg : (uchar **)pArg; pFormatParam = pTypeFormat + Params[n].TypeOffset; (*UnmarshallRoutinesTable[ROUTINE_INDEX(*pFormatParam)]) ( pStubMsg, ppArg, pFormatParam, Params[n].ParamAttr.IsForceAllocate && !Params[n].ParamAttr.IsByValue ); pStubMsg->ReuseBuffer = FALSE; } if ( pStubMsg->pCorrInfo ) NdrCorrelationPass( pStubMsg ); return ; } void RPC_ENTRY NdrpDcomClientExceptionHandling( MIDL_STUB_MESSAGE * pStubMsg, ulong ProcNum, RPC_STATUS ExceptionCode, CLIENT_CALL_RETURN * pReturnValue ) { ulong NumberParams; PPARAM_DESCRIPTION Params; PFORMAT_STRING pTypeFormat; ulong n; uchar * pArg; PFORMAT_STRING pFormatParam; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; pReturnValue->Simple = NdrProxyErrorHandler(ExceptionCode); if( pStubMsg->dwStubPhase != PROXY_UNMARSHAL) return; NumberParams = pContext->NumberParams; Params = ( PPARAM_DESCRIPTION )pContext->Params; // alert: this can't be directly called from ndrclientcall2: we don't have pSyntaxInfo. pTypeFormat = pContext->DceTypeFormatString; // // In OLE, since they don't know about error_status_t and wanted to // reinvent the wheel, check to see if we need to map the exception. // In either case, set the return value and then try to free the // [out] params, if required. // pStubMsg->BufferStart = 0; pStubMsg->BufferEnd = 0; for ( n = 0; n < pContext->NumberParams; n++ ) { // // Skip everything but [out] only parameters. We make // the basetype check to cover [out] simple ref pointers // to basetypes. // if ( !Params[n].ParamAttr.IsPartialIgnore ) { if ( Params[n].ParamAttr.IsIn || Params[n].ParamAttr.IsReturn || Params[n].ParamAttr.IsBasetype || Params[n].ParamAttr.IsPipe ) continue; } pArg = pContext->StartofStack + Params[n].StackOffset; pFormatParam = pTypeFormat + Params[n].TypeOffset; NdrClearOutParameters( pStubMsg, pFormatParam, *((uchar **)pArg) ); } return ; } void RPC_ENTRY NdrpClientExceptionHandling( MIDL_STUB_MESSAGE * pStubMsg, ulong ProcNum, RPC_STATUS ExceptionCode, CLIENT_CALL_RETURN * pReturnValue ) { NDR_PROC_CONTEXT * pContext = ( NDR_PROC_CONTEXT * ) pStubMsg->pContext; NDR_ASSERT( pContext->NdrInfo.InterpreterFlags.HasCommOrFault, " must have comm or fault to catch" ); NdrClientMapCommFault( pStubMsg, ProcNum, ExceptionCode, (ULONG_PTR*)&pReturnValue->Simple ); return ; } void RPC_ENTRY NdrpAsyncClientExceptionHandling( MIDL_STUB_MESSAGE * pStubMsg, ulong ProcNum, RPC_STATUS ExceptionCode, CLIENT_CALL_RETURN * pReturnValue ) { NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; if ( pContext->NdrInfo.InterpreterFlags.HasCommOrFault ) { NdrClientMapCommFault( pStubMsg, ProcNum, ExceptionCode, (ULONG_PTR*)&pReturnValue->Simple ); if ( ExceptionCode == RPC_S_ASYNC_CALL_PENDING ) { // If the call is just pending, force the pending error code // to show up in the return value of RpcAsyncCallComplete. pReturnValue->Simple = RPC_S_ASYNC_CALL_PENDING; } } else { RpcRaiseException(ExceptionCode); } return ; } void RPC_ENTRY NdrpClientFinally( PMIDL_STUB_MESSAGE pStubMsg, void * pThis ) { NDR_PROC_CONTEXT * pContext = ( NDR_PROC_CONTEXT * ) pStubMsg->pContext; NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables); NdrCorrelationFree( pStubMsg ); // // Free the RPC buffer. // if ( pThis ) { NdrProxyFreeBuffer( pThis, pStubMsg ); } else { NdrFreeBuffer( pStubMsg ); // // Unbind if generic handle used. We do this last so that if the // the user's unbind routine faults, then all of our internal stuff // will already have been freed. // if ( pContext->SavedGenericHandle ) GenericHandleUnbind( pStubMsg->StubDesc, pContext->StartofStack, pContext->pHandleFormatSave, (pContext->HandleType) ? IMPLICIT_MASK : 0, &pContext->SavedGenericHandle ); } NdrpAllocaDestroy( & pContext->AllocateContext ); } void NdrpServerInit( PMIDL_STUB_MESSAGE pStubMsg, RPC_MESSAGE * pRpcMsg, PMIDL_STUB_DESC pStubDesc, void * pThis, IRpcChannelBuffer * pChannel, PNDR_ASYNC_MESSAGE pAsyncMsg ) { NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *) pStubMsg->pContext; uchar * pArg; uchar * pArgBuffer = pContext->StartofStack; if ( pContext->pSyntaxInfo == NULL ) pContext->DceTypeFormatString = pStubDesc->pFormatTypes; else pContext->DceTypeFormatString = pContext->pSyntaxInfo->TypeString; if ( ! pContext->HandleType ) { // // For a handle_t parameter we must pass the handle field of // the RPC message to the server manager. // if ( *pContext->pHandleFormatSave == FC_BIND_PRIMITIVE ) { pArg = pArgBuffer + *((ushort *)&pContext->pHandleFormatSave[2]); if ( IS_HANDLE_PTR(pContext->pHandleFormatSave[1]) ) pArg = *((uchar **)pArg); *((handle_t *)pArg) = pRpcMsg->Handle; } } // // If OLE, put pThis in first dword of stack. // if ( pThis ) { *((void **)pArgBuffer) = (void *)((CStdStubBuffer *)pThis)->pvServerObject; } // // Initialize the Stub message. // if ( ! pChannel ) { if ( ! pContext->NdrInfo.pProcDesc->Oi2Flags.HasPipes ) { NdrServerInitializeNew( pRpcMsg, pStubMsg, pStubDesc ); } else NdrServerInitializePartial( pRpcMsg, pStubMsg, pStubDesc, pContext->NdrInfo.pProcDesc->ClientBufferSize ); } else { // pipe is not supported in obj interface. NDR_ASSERT( ! pContext->HasPipe, "Pipe is not supported in dcom" ); NdrStubInitialize( pRpcMsg, pStubMsg, pStubDesc, pChannel ); } if ( pAsyncMsg ) { pStubMsg->pAsyncMsg = pAsyncMsg; pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC; } if ( pContext->NdrInfo.InterpreterFlags.FullPtrUsed ) pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit( 0, XLAT_SERVER ); else pStubMsg->FullPtrXlatTables = NULL; // // Set StackTop AFTER the initialize call, since it zeros the field // out. // pStubMsg->StackTop = pArgBuffer; if ( pContext->NdrInfo.pProcDesc->Oi2Flags.HasPipes ) { NdrpPipesInitialize32( pStubMsg, &pContext->AllocateContext, (PFORMAT_STRING) pContext->Params, (char*)pArgBuffer, pContext->NumberParams ); } // // We must make this check AFTER the call to ServerInitialize, // since that routine puts the stub descriptor alloc/dealloc routines // into the stub message. // if ( pContext->NdrInfo.InterpreterFlags.RpcSsAllocUsed ) NdrRpcSsEnableAllocate( pStubMsg ); if ( pContext->NdrInfo.pProcDesc->Oi2Flags.HasExtensions ) { pStubMsg->fHasExtensions = 1; pStubMsg->fHasNewCorrDesc = pContext->NdrInfo.pProcDesc->NdrExts.Flags2.HasNewCorrDesc; if ( pContext->NdrInfo.pProcDesc->NdrExts.Flags2.ServerCorrCheck ) { void * pCorr = NdrpAlloca( &pContext->AllocateContext, NDR_DEFAULT_CORR_CACHE_SIZE ); NdrCorrelationInitialize( pStubMsg, pCorr, NDR_DEFAULT_CORR_CACHE_SIZE, 0 /* flags */ ); } } } void NdrpServerOutInit( PMIDL_STUB_MESSAGE pStubMsg ) { ulong n; NDR_PROC_CONTEXT * pContext = (NDR_PROC_CONTEXT *)pStubMsg->pContext; PPARAM_DESCRIPTION Params = ( PPARAM_DESCRIPTION ) pContext->Params; PFORMAT_STRING pFormatTypes = pContext->DceTypeFormatString; uchar * pArgBuffer = pContext->StartofStack; uchar * pArg; PFORMAT_STRING pFormatParam; for ( n = 0; n < pContext->NumberParams; n++ ) { if ( !Params[n].ParamAttr.IsPartialIgnore ) { if ( Params[n].ParamAttr.IsIn || ( Params[n].ParamAttr.IsReturn && !pContext->HasComplexReturn ) || Params[n].ParamAttr.IsPipe ) continue; pArg = pArgBuffer + Params[n].StackOffset; } else { pArg = pArgBuffer + Params[n].StackOffset; if ( !*(void**)pArg ) continue; } // // Check if we can initialize this parameter using some of our // stack. // if ( Params[n].ParamAttr.ServerAllocSize != 0 ) { *((void **)pArg) = NdrpAlloca( &pContext->AllocateContext, Params[n].ParamAttr.ServerAllocSize * 8); MIDL_memset( *((void **)pArg), 0, Params[n].ParamAttr.ServerAllocSize * 8 ); continue; } else if ( Params[n].ParamAttr.IsBasetype ) { *((void **)pArg) = NdrpAlloca( &pContext->AllocateContext, 8 ); MIDL_memset( *((void **)pArg), 0, 8 ); continue; }; pFormatParam = pFormatTypes + Params[n].TypeOffset; NdrOutInit( pStubMsg, pFormatParam, (uchar **)pArg ); } } #if defined( BUILD_NDR64 ) BOOL IsServerSupportNDR64( MIDL_SERVER_INFO *pServerInfo ) { if ( ( pServerInfo->pStubDesc->Version > NDR_VERSION ) || ( pServerInfo->pStubDesc->Version < NDR_VERSION_6_0 ) || ( pServerInfo->pStubDesc->MIDLVersion < MIDL_VERSION_6_0_322 ) || ! ( pServerInfo->pStubDesc->mFlags & RPCFLG_HAS_MULTI_SYNTAXES ) ) return FALSE; return TRUE; } #endif RPC_STATUS RPC_ENTRY NdrClientGetSupportedSyntaxes( IN RPC_CLIENT_INTERFACE * pInf, OUT ulong * pCount, MIDL_SYNTAX_INFO ** pArr ) { MIDL_SYNTAX_INFO *pSyntaxInfo; NDR_ASSERT( pInf->Flags & RPCFLG_HAS_MULTI_SYNTAXES, "invalid clientif" ); if ( pInf->Flags & RPCFLG_HAS_CALLBACK ) { // interpreter info is MIDL_SERVER_INFO MIDL_SERVER_INFO * pServerInfo = ( MIDL_SERVER_INFO *) pInf->InterpreterInfo; *pCount = ( ulong ) pServerInfo->nCount ; *pArr = pServerInfo->pSyntaxInfo; } else { MIDL_STUBLESS_PROXY_INFO * pProxyInfo = ( MIDL_STUBLESS_PROXY_INFO *) pInf->InterpreterInfo; *pCount = ( ulong ) pProxyInfo->nCount ; *pArr = pProxyInfo->pSyntaxInfo; } return RPC_S_OK; } RPC_STATUS RPC_ENTRY NdrServerGetSupportedSyntaxes( IN RPC_SERVER_INTERFACE * pInf, OUT ulong * pCount, MIDL_SYNTAX_INFO ** pArr, OUT ulong * pPrefer) { NDR_ASSERT( pInf->Flags & RPCFLG_HAS_MULTI_SYNTAXES,"invalid serverif" ); MIDL_SERVER_INFO *pServerInfo = ( MIDL_SERVER_INFO *) pInf->InterpreterInfo; *pCount = ( ulong ) pServerInfo->nCount; *pArr = pServerInfo->pSyntaxInfo; NdrpGetPreferredSyntax( ( ulong )pServerInfo->nCount, pServerInfo->pSyntaxInfo, pPrefer ); return RPC_S_OK; } RPC_STATUS RPC_ENTRY NdrCreateServerInterfaceFromStub( IN IRpcStubBuffer* pStub, IN OUT RPC_SERVER_INTERFACE *pServerIf ) { #if !defined( BUILD_NDR64 ) return S_OK; #else CInterfaceStubVtbl * pStubVTable; PMIDL_SERVER_INFO pServerInfo; IRpcStubBuffer * pv = NULL; RpcTryExcept { // filter out non-ndr stub first. if ( S_OK != pStub->lpVtbl->QueryInterface(pStub, IID_IPrivStubBuffer, (void **)& pv ) ) return S_OK; pv->lpVtbl->Release(pv); pStubVTable = (CInterfaceStubVtbl *) (*((uchar **)pStub) - sizeof(CInterfaceStubHeader)); pServerInfo = (PMIDL_SERVER_INFO) pStubVTable->header.pServerInfo; // In /Os mode, we don't have pServerInfo. if ( pServerInfo && IsServerSupportNDR64( pServerInfo ) ) { memcpy ( &pServerIf->TransferSyntax, pServerInfo->pTransferSyntax, sizeof( RPC_SYNTAX_IDENTIFIER ) ); pServerIf->Flags |= RPCFLG_HAS_MULTI_SYNTAXES; pServerIf->InterpreterInfo = pServerInfo; } } RpcExcept( 1 ) { } RpcEndExcept #endif return S_OK; } /*++ Routine Description : Read the proc header for different transfer syntax. We need to return proc number in dce because for stubs compiled with DCE only, proc header is the only place to get the procnum. This rountine being called from both client and server. The difference is that client side we are reading from the default one; server side we are reading from the selected one. Arguments : Return : none. Raise exception if something goes wrong. We can't recovered from here because we don't have enough information about how the stub looks like if we don't have valid proc header. --*/ ulong RPC_ENTRY MulNdrpInitializeContextFromProc ( SYNTAX_TYPE SyntaxType, PFORMAT_STRING pFormat, NDR_PROC_CONTEXT * pContext, uchar * StartofStack, BOOLEAN IsReset ) { ulong RpcFlags; ulong ProcNum = 0; if ( !IsReset ) NdrpInitializeProcContext( pContext ); pContext->pProcFormat = pFormat; pContext->StartofStack = StartofStack; if ( SyntaxType == XFER_SYNTAX_DCE ) { PPARAM_DESCRIPTION Params; INTERPRETER_FLAGS InterpreterFlags; PFORMAT_STRING pNewProcDescr; INTERPRETER_OPT_FLAGS OptFlags; pContext->CurrentSyntaxType = XFER_SYNTAX_DCE; pContext->HandleType = *pFormat++ ; pContext->UseLocator = (FC_AUTO_HANDLE == pContext->HandleType); pContext->NdrInfo.InterpreterFlags = *((PINTERPRETER_FLAGS)pFormat++); InterpreterFlags = pContext->NdrInfo.InterpreterFlags; if ( InterpreterFlags.HasRpcFlags ) RpcFlags = *(( UNALIGNED ulong* &)pFormat)++; else RpcFlags = 0; ProcNum = *(ushort *)pFormat; pFormat += 2; pContext->StackSize = *(ushort *)pFormat; pFormat += 2; pContext->pHandleFormatSave = pFormat; pNewProcDescr = pFormat; if ( ! pContext->HandleType ) { // explicit handle pNewProcDescr += ((*pFormat == FC_BIND_PRIMITIVE) ? 4 : 6); } pContext->NdrInfo.pProcDesc = (NDR_PROC_DESC *)pNewProcDescr; OptFlags = ( (NDR_PROC_DESC *)pNewProcDescr )->Oi2Flags; pContext->NumberParams = pContext->NdrInfo.pProcDesc->NumberParams; // // Parameter descriptions are nicely spit out by MIDL. // If there is no extension, Params is in the position of extensions. // Params = (PPARAM_DESCRIPTION) &( pContext->NdrInfo.pProcDesc->NdrExts ); // Proc header extentions, from NDR ver. 5.2. // Params must be set correctly here because of exceptions. if ( OptFlags.HasExtensions ) { pContext->HasComplexReturn = pContext->NdrInfo.pProcDesc->NdrExts.Flags2.HasComplexReturn; Params = (PPARAM_DESCRIPTION)((uchar*)Params + pContext->NdrInfo.pProcDesc->NdrExts.Size); #if defined(_AMD64_) || defined(_IA64_) PNDR_PROC_HEADER_EXTS64 pExts = (PNDR_PROC_HEADER_EXTS64 )&pContext->NdrInfo.pProcDesc->NdrExts; pContext->FloatDoubleMask = pExts->FloatArgMask; #endif // defined(_AMD64_) || defined(_IA64_) } pContext->Params = Params; pContext->IsAsync = OptFlags.HasAsyncUuid ; pContext->IsObject = InterpreterFlags.ObjectProc; pContext->HasPipe = OptFlags.HasPipes; pContext->ExceptionFlag = ! ( InterpreterFlags.IgnoreObjectException ) && ( pContext->IsObject || InterpreterFlags.HasCommOrFault ); } // XFER_SYNTAX_DCE #if defined(BUILD_NDR64) else if ( SyntaxType == XFER_SYNTAX_NDR64 ) { NDR64_PROC_FLAGS * pProcFlags; pContext->CurrentSyntaxType = XFER_SYNTAX_NDR64; pContext->Ndr64Header = (NDR64_PROC_FORMAT *)pFormat; pContext->HandleType = NDR64MAPHANDLETYPE( NDR64GETHANDLETYPE( &pContext->Ndr64Header->Flags ) ); pContext->UseLocator = (FC64_AUTO_HANDLE == pContext->HandleType); RpcFlags = pContext->Ndr64Header->RpcFlags; #if defined(_AMD64_) || defined(_IA64_) pContext->FloatDoubleMask = pContext->Ndr64Header->FloatDoubleMask; #endif // defined(_AMD64_) || defined(_IA64_) pContext->NumberParams = pContext->Ndr64Header->NumberOfParams; pContext->Params = (NDR64_PROC_FORMAT *)( (char *) pFormat + sizeof( NDR64_PROC_FORMAT ) + pContext->Ndr64Header->ExtensionSize ); pContext->StackSize = pContext->Ndr64Header->StackSize; pProcFlags = (NDR64_PROC_FLAGS *) &pContext->Ndr64Header->Flags; pContext->HasComplexReturn = pProcFlags->HasComplexReturn; pContext->IsAsync = pProcFlags->IsAsync; pContext->IsObject = pProcFlags->IsObject; pContext->HasPipe = pProcFlags->UsesPipes; pContext->ExceptionFlag = pContext->IsObject || pProcFlags->HandlesExceptions; } // XFER_SYNTAX_NDR64 #endif else NDR_ASSERT( 0, "Invalid transfer syntax."); // setup the pipe flag before negotiation. if ( pContext->HasPipe ) { RpcFlags &= ~RPC_BUFFER_COMPLETE; RpcFlags |= RPC_BUFFER_PARTIAL; } pContext->RpcFlags = RpcFlags; // We need to cleanup the resend flag during initialization in preparation // for retry later. pContext->NeedsResend = FALSE; return ProcNum; }