/// <summary>
        /// Expect to receive a call.
        /// </summary>
        /// <param name="timeout">Timeout of expecting a call.</param>
        /// <param name="sessionContext">Session Context of the received call.</param>
        /// <param name="opnum">Operation number of the method invoked.</param>
        /// <returns>Received a byte array of the request stub from a client.</returns>
        /// <exception cref="InvalidOperationException">
        /// Thrown when receive error from server.
        /// </exception>
        public virtual byte[] ExpectCall(
            TimeSpan timeout,
            out RpceServerSessionContext sessionContext,
            out ushort opnum)
        {
            sessionContext = null;

            RpcePdu          receivedPdu = ReceiveAndReassemblePdu(timeout, ref sessionContext);
            RpceCoRequestPdu requestPdu  = receivedPdu as RpceCoRequestPdu;

            if (requestPdu == null)
            {
                throw new InvalidOperationException("Expect request_pdu, but received others.");
            }

            opnum = requestPdu.opnum;

            byte[] stub = requestPdu.stub;
            if (stub == null)
            {
                stub = new byte[0];
            }

            return(stub);
        }
예제 #2
0
        /// <summary>
        /// Send request to RPCE server.
        /// </summary>
        /// <param name="opnum">
        /// The opnum of a method.
        /// </param>
        /// <param name="requestStub">
        /// A byte array of the request stub of a method.<para/>
        /// RpceStubEncoder can be used to NDR marshal parameters to a byte array.
        /// </param>
        /// <param name="callId">
        /// The identifier of this call.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when requestStub is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when receive error from server or RPC connection has not been established.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when this transport has been used as an synchronous transport.
        /// </exception>
        public virtual void SendRequest(
            ushort opnum,
            byte[] requestStub,
            out uint callId)
        {
            if (requestStub == null)
            {
                throw new ArgumentNullException("requestStub");
            }
            if (rpceClient.IsDisposed)
            {
                throw new InvalidOperationException("RPC connection has not been established.");
            }

            RpceCoRequestPdu requestPdu = rpceClient.CreateCoRequestPdu(
                opnum,
                requestStub);

            if (rpceClient.Context.AuthenticationType == RpceAuthenticationType.RPC_C_AUTHN_WINNT &&
                rpceClient.Context.AuthenticationLevel == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
            {
                verification_trailer_t verificationTrailer = requestPdu.CreateVerificationTrailer(
                    SEC_VT_COMMAND.SEC_VT_COMMAND_BITMASK_1,
                    SEC_VT_COMMAND.SEC_VT_COMMAND_HEADER2,
                    SEC_VT_COMMAND.SEC_VT_COMMAND_PCONTEXT | SEC_VT_COMMAND.SEC_VT_COMMAND_END);
                requestPdu.AppendVerificationTrailerToStub(verificationTrailer);
            }

            FragmentAndSendPdu(requestPdu);

            lock (responseLock)
            {
                callId = requestPdu.call_id;
                outstandingCallIds.Add(callId);
            }
        }
예제 #3
0
        /// <summary>
        /// update context on sending PDU.
        /// </summary>
        /// <param name="pdu">PDU to send.</param>
        internal void UpdateContextOnSendingPdu(RpcePdu pdu)
        {
            RpceCoPdu coPdu = pdu as RpceCoPdu;

            if (coPdu == null)
            {
                return;
            }

            this.RpcVersionMajor = coPdu.rpc_vers;
            this.RpcVersionMinor = coPdu.rpc_vers_minor;
            if (coPdu.PTYPE == RpcePacketType.Bind ||
                coPdu.PTYPE == RpcePacketType.BindAck ||
                coPdu.PTYPE == RpcePacketType.AlterContext ||
                coPdu.PTYPE == RpcePacketType.AlterContextResp)
            {
                this.SupportsHeaderSign
                    = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN)
                      == RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN;
            }

            this.SupportsConcurrentMultiplexing
                = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_CONC_MPX)
                  == RpceCoPfcFlags.PFC_CONC_MPX;
            this.PackedDataRepresentationFormat = coPdu.packed_drep.dataRepFormat;

            if (coPdu.PTYPE != RpcePacketType.Request)
            {
                this.outstandingCalls.Remove(coPdu.call_id);
            }

            switch (coPdu.PTYPE)
            {
            case RpcePacketType.BindAck:
                RpceCoBindAckPdu bindAckPdu = coPdu as RpceCoBindAckPdu;
                if (bindAckPdu != null)
                {
                    UpdateContextOnSendingBindAckPdu(bindAckPdu);
                }
                break;

            case RpcePacketType.Request:
                RpceCoRequestPdu requestPdu = coPdu as RpceCoRequestPdu;
                if (requestPdu != null)
                {
                    this.ContextIdentifier = requestPdu.p_cont_id;
                }
                break;

            case RpcePacketType.Response:
                RpceCoResponsePdu responsePdu = coPdu as RpceCoResponsePdu;
                if (responsePdu != null)
                {
                    this.ContextIdentifier = responsePdu.p_cont_id;
                }
                break;

            case RpcePacketType.BindNak:
            case RpcePacketType.AlterContextResp:
            case RpcePacketType.Fault:
            case RpcePacketType.Shutdown:
            default:
                //default situation should do nothing.
                //This is just update the context, if we cannot recognize the PDU, ignore it.
                break;
            }
        }
예제 #4
0
        /// <summary>
        /// update context on receiving PDU.
        /// </summary>
        /// <param name="pdu">PDU to receive.</param>
        /// <exception cref="ArgumentNullException">Thrown when pdu is null.</exception>
        internal void UpdateContextOnReceivingPdu(RpcePdu pdu)
        {
            RpceCoPdu coPdu = pdu as RpceCoPdu;

            if (coPdu == null)
            {
                return;
            }

            this.RpcVersionMajor = coPdu.rpc_vers;
            this.RpcVersionMinor = coPdu.rpc_vers_minor;
            if (coPdu.PTYPE == RpcePacketType.Bind ||
                coPdu.PTYPE == RpcePacketType.BindAck)
            {
                //TDI:
                //TD said PFC_SUPPORT_HEADER_SIGN is meanful in Bind and AltContext.
                //But when using Kerberos, AltContext doesn't have this flag,
                //if server or client read this flag according to AltContext, Sign/Encrypt will fail.
                this.SupportsHeaderSign
                    = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN)
                      == RpceCoPfcFlags.PFC_SUPPORT_HEADER_SIGN;
                this.SupportsConcurrentMultiplexing
                    = (coPdu.pfc_flags & RpceCoPfcFlags.PFC_CONC_MPX)
                      == RpceCoPfcFlags.PFC_CONC_MPX;
            }

            this.PackedDataRepresentationFormat = coPdu.packed_drep.dataRepFormat;
            this.CurrentCallId = coPdu.call_id;
            if (coPdu.PTYPE != RpcePacketType.Response && coPdu.PTYPE != RpcePacketType.Auth3)
            {
                this.outstandingCalls.Add(coPdu.call_id);
            }

            switch (coPdu.PTYPE)
            {
            case RpcePacketType.Bind:
                RpceCoBindPdu bindPdu = coPdu as RpceCoBindPdu;
                if (bindPdu != null)
                {
                    UpdateContextOnReceivingBindPdu(bindPdu);
                }
                break;

            case RpcePacketType.Request:
                RpceCoRequestPdu requestPdu = coPdu as RpceCoRequestPdu;
                if (requestPdu != null)
                {
                    this.ContextIdentifier = requestPdu.p_cont_id;
                }
                break;

            case RpcePacketType.Response:
                RpceCoResponsePdu responsePdu = coPdu as RpceCoResponsePdu;
                if (responsePdu != null)
                {
                    this.ContextIdentifier = responsePdu.p_cont_id;
                }
                break;

            case RpcePacketType.Auth3:
            case RpcePacketType.AlterContext:
            case RpcePacketType.CoCancel:
            case RpcePacketType.Orphaned:
            default:
                //default situation should do nothing.
                //This is just update the context, if we cannot recognize the PDU, ignore it.
                break;
            }

            this.SecurityContextNeedContinueProcessing = coPdu.securityContextNeedContinueProcessing;
        }
예제 #5
0
        public static RpceCoPdu DecodeCoPdu(
            RpceContext context,
            byte[] pduBytes)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (pduBytes == null)
            {
                throw new ArgumentNullException("pduBytes");
            }

            RpceCoPdu pdu;

            //#2 byte is PTYPE
            RpcePacketType packageType = (RpcePacketType)pduBytes[2];
            //#3 byte is PFC_*** flags
            RpceCoPfcFlags pfcFlags = (RpceCoPfcFlags)pduBytes[3];

            RpceCoPfcFlags pfcFlagsNoFragment = RpceCoPfcFlags.PFC_FIRST_FRAG | RpceCoPfcFlags.PFC_LAST_FRAG;

            if (((pfcFlags & pfcFlagsNoFragment) != pfcFlagsNoFragment) &&
                (packageType == RpcePacketType.Bind ||
                 packageType == RpcePacketType.BindAck ||
                 packageType == RpcePacketType.AlterContext ||
                 packageType == RpcePacketType.AlterContextResp ||
                 packageType == RpcePacketType.Auth3))
            {
                //If it's a fragment and PTYPE is bind/bind_ack/alter_context/alter_context_resp
                //Windows RPC support version 5.0 only.
                //Bind fragment requires RPC ver 5.1.
                //We don't support it.
                throw new NotSupportedException("bind/bind_ack/alt_context/alt_context_resp/auth3 PDU fragment are not supported.");
            }
            else
            {
                switch (packageType)
                {
                case RpcePacketType.Bind:
                    pdu = new RpceCoBindPdu(context, pduBytes);
                    break;

                case RpcePacketType.BindAck:
                    pdu = new RpceCoBindAckPdu(context, pduBytes);
                    break;

                case RpcePacketType.BindNak:
                    pdu = new RpceCoBindNakPdu(context, pduBytes);
                    break;

                case RpcePacketType.AlterContext:
                    pdu = new RpceCoAlterContextPdu(context, pduBytes);
                    break;

                case RpcePacketType.AlterContextResp:
                    pdu = new RpceCoAlterContextRespPdu(context, pduBytes);
                    break;

                case RpcePacketType.Auth3:
                    pdu = new RpceCoAuth3Pdu(context, pduBytes);
                    break;

                case RpcePacketType.Request:
                    pdu = new RpceCoRequestPdu(context, pduBytes);
                    break;

                case RpcePacketType.Response:
                    pdu = new RpceCoResponsePdu(context, pduBytes);
                    break;

                case RpcePacketType.Fault:
                    pdu = new RpceCoFaultPdu(context, pduBytes);
                    break;

                case RpcePacketType.CoCancel:
                    pdu = new RpceCoCancelPdu(context, pduBytes);
                    break;

                case RpcePacketType.Orphaned:
                    pdu = new RpceCoOrphanedPdu(context, pduBytes);
                    break;

                case RpcePacketType.Shutdown:
                    pdu = new RpceCoShutdownPdu(context, pduBytes);
                    break;

                default:
                    throw new InvalidOperationException(
                              string.Format("Receive invalid packet - {0}.", packageType));
                }
            }

            return(pdu);
        }
예제 #6
0
        /// <summary>
        /// Reassemble several fragment PDUs to one PDU.<para/>
        /// Must call after decrypt/verify.
        /// </summary>
        /// <param name="context">RpceContext to Reassemble PDU.</param>
        /// <param name="pdus">Fragment PDUs to be reassembled.</param>
        /// <returns>A ressembled PDU.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when pdus is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown when pdus is invalid.
        /// </exception>
        /// <exception cref="InvalidOperationException">Thrown when Speicified PDU doesn't
        /// support fragment and reassemble.</exception>
        public static RpceCoPdu ReassemblePdu(RpceContext context, params RpceCoPdu[] pdus)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (pdus == null)
            {
                throw new ArgumentNullException("pdus");
            }

            if (pdus.Length == 0)
            {
                throw new ArgumentException("There's no PDU to reassemble.", "pdus");
            }

            //verify if the fisrt pdu has the valid PFC_FIRST_FRAG.
            if ((pdus[0].pfc_flags & RpceCoPfcFlags.PFC_FIRST_FRAG) == 0)
            {
                throw new ArgumentException("First PDU doesn't have PFC_FIRST_FRAG flag.", "pdus");
            }

            //verify if fragments end expected.
            for (int i = 0; i < pdus.Length - 1; i++)
            {
                if ((pdus[i].pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) != 0)
                {
                    throw new ArgumentException("Fragments ended unexpected.", "pdus");
                }
            }

            if ((pdus[pdus.Length - 1].pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) == 0)
            {
                throw new ArgumentException("Fragments is not ended.", "pdus");
            }

            //All PTYPEs should be the same.
            for (int i = 1; i < pdus.Length; i++)
            {
                if (pdus[i].PTYPE != pdus[0].PTYPE)
                {
                    throw new ArgumentException("PDUs' PTYPE are different.", "pdus");
                }
            }

            if (pdus.Length == 1)
            {
                return(pdus[0]);
            }

            RpceCoPdu reassembledPdu;

            switch (pdus[0].PTYPE)
            {
            case RpcePacketType.Request:
                RpceCoRequestPdu requestPdu = pdus[0] as RpceCoRequestPdu;

                if (requestPdu == null)
                {
                    throw new ArgumentException("The PDU is not a valid RpceCoRequestPdu");
                }

                for (int i = 1; i < pdus.Length; i++)
                {
                    requestPdu.stub = ArrayUtility.ConcatenateArrays(
                        requestPdu.stub,
                        ((RpceCoRequestPdu)pdus[i]).stub);
                }

                requestPdu.pfc_flags    |= RpceCoPfcFlags.PFC_LAST_FRAG;
                requestPdu.frag_length   = (ushort)(requestPdu.GetSize() + requestPdu.stub.Length);
                requestPdu.auth_length   = 0;
                requestPdu.auth_verifier = null;
                reassembledPdu           = requestPdu;
                break;

            case RpcePacketType.Response:
                RpceCoResponsePdu responsePdu = pdus[0] as RpceCoResponsePdu;

                if (responsePdu == null)
                {
                    throw new ArgumentException("The PDU is not a valid RpceCoResponsePdu");
                }

                for (int i = 1; i < pdus.Length; i++)
                {
                    responsePdu.stub = ArrayUtility.ConcatenateArrays(
                        responsePdu.stub,
                        ((RpceCoResponsePdu)pdus[i]).stub);
                }

                responsePdu.pfc_flags    |= RpceCoPfcFlags.PFC_LAST_FRAG;
                responsePdu.frag_length   = (ushort)(responsePdu.GetSize() + responsePdu.stub.Length);
                responsePdu.auth_length   = 0;
                responsePdu.auth_verifier = null;
                reassembledPdu            = responsePdu;
                break;

            case RpcePacketType.Bind:
            case RpcePacketType.BindAck:
            case RpcePacketType.AlterContext:
            case RpcePacketType.AlterContextResp:
            case RpcePacketType.Auth3:
                //Windows RPC support version 5.0 only.
                //Bind fragment requires RPC ver 5.1.
                //We don't support it.
                throw new NotSupportedException("bind/bind_ack/alt_context/alt_context_resp/auth3 PDU fragment are not supported.");

            default:
                throw new InvalidOperationException("Speicified PDU doesn't support fragment and reassemble.");
            }

            return(reassembledPdu);
        }
예제 #7
0
        /// <summary>
        /// Fragment a PDU into several PDUs by max_xmit_frag field.<para/>
        /// Only bind, bind_ack, alter_context, alter_context_response,
        /// request and response PDUs will be fragmented.<para/>
        /// Must call before sign/encrypt.
        /// </summary>
        /// <param name="context">RpceContext to fragment PDU</param>
        /// <param name="pdu">
        /// A PDU to be fragmented.
        /// Only bind, bind_ack, alter_context, alter_context_response,
        /// request and response PDUs will be fragmented.
        /// </param>
        /// <returns>Fragmented PDUs.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when pdu or context is null.
        /// </exception>
        /// <exception cref="NotSupportedException">Thrown when PDU PacketType isn't supported.</exception>
        public static RpceCoPdu[] FragmentPdu(RpceContext context, RpceCoPdu pdu)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (pdu == null)
            {
                throw new ArgumentNullException("pdu");
            }

            if (pdu.frag_length > context.MaxTransmitFragmentSize)
            {
                int    headerAndTrailerSize;
                byte[] stub;

                switch (pdu.PTYPE)
                {
                case RpcePacketType.Request:

                    //Get stub of request PDU
                    RpceCoRequestPdu requestPdu = pdu as RpceCoRequestPdu;

                    if (requestPdu == null)
                    {
                        throw new ArgumentException("The pdu is not a valid RpceCoRequestPdu.");
                    }

                    headerAndTrailerSize = requestPdu.GetSize();

                    if (requestPdu.auth_verifier != null)
                    {
                        //length of auth_verifier
                        headerAndTrailerSize += RpceUtility.AUTH_VERIFIER_SIZE;
                        headerAndTrailerSize += requestPdu.auth_verifier.Value.auth_value.Length;

                        //To keep stub always be padded to 16 bytes, and pdu doesnot exceed max transmit frag size.
                        int stubLength = context.MaxTransmitFragmentSize - headerAndTrailerSize;
                        headerAndTrailerSize +=
                            RpceUtility.Align(stubLength, RpceUtility.AUTH_PAD_LENGTH) - stubLength;

                        //The beginning of the verification_trailer header MUST be 4-byte aligned
                        //with respect to the beginning of the PDU.
                        headerAndTrailerSize = RpceUtility.Align(headerAndTrailerSize, RpceUtility.STUB_PAD_LENGTH);
                    }

                    stub = requestPdu.stub ?? new byte[0];

                    //Fragment
                    RpceCoRequestPdu[] requestFragmentPduList = FragmentPdu <RpceCoRequestPdu>(
                        context,
                        pdu,
                        stub.Length,
                        headerAndTrailerSize);

                    for (int i = 0; i < requestFragmentPduList.Length; i++)
                    {
                        //SHOULD set the alloc_hint field in every PDU to
                        //be the combined stub data length of all remaining fragment PDUs.
                        requestFragmentPduList[i].alloc_hint = (uint)stub.Length;
                        requestFragmentPduList[i].p_cont_id  = requestPdu.p_cont_id;
                        requestFragmentPduList[i].opnum      = requestPdu.opnum;
                        requestFragmentPduList[i].@object    = requestPdu.@object;
                        requestFragmentPduList[i].stub       = ArrayUtility.SubArray(
                            stub,
                            0,
                            Math.Min(stub.Length, context.MaxTransmitFragmentSize - headerAndTrailerSize));

                        //For request and response PDUs, where the request and response PDUs are
                        //part of a fragmented request or response and authentication is requested,
                        //the sec_trailer structure MUST be present in every fragment of the request
                        //or response.
                        requestFragmentPduList[i].AppendAuthenticationVerifier();
                        requestFragmentPduList[i].SetLength();
                        stub = ArrayUtility.SubArray(stub, requestFragmentPduList[i].stub.Length);
                    }

                    return(requestFragmentPduList);

                case RpcePacketType.Response:

                    //Get stub of response PDU
                    RpceCoResponsePdu responsePdu = pdu as RpceCoResponsePdu;

                    if (responsePdu == null)
                    {
                        throw new ArgumentException("The PDU is not a valid RpceCoResponsePdu");
                    }

                    headerAndTrailerSize = responsePdu.GetSize();

                    if (responsePdu.auth_verifier != null)
                    {
                        //length of auth_verifier
                        headerAndTrailerSize += RpceUtility.AUTH_VERIFIER_SIZE;
                        headerAndTrailerSize += responsePdu.auth_verifier.Value.auth_value.Length;

                        //To keep stub always be padded to 16 bytes, and pdu doesnot exceed max transmit frag size.
                        int stubLength = context.MaxTransmitFragmentSize - headerAndTrailerSize;
                        headerAndTrailerSize +=
                            RpceUtility.Align(stubLength, RpceUtility.AUTH_PAD_LENGTH) - stubLength;

                        //The beginning of the verification_trailer header MUST be 4-byte aligned
                        //with respect to the beginning of the PDU.
                        headerAndTrailerSize = RpceUtility.Align(headerAndTrailerSize, RpceUtility.STUB_PAD_LENGTH);
                    }

                    stub = responsePdu.stub ?? new byte[0];

                    //Fragment
                    RpceCoResponsePdu[] responseFragmentPduList = FragmentPdu <RpceCoResponsePdu>(
                        context,
                        pdu,
                        stub.Length,
                        headerAndTrailerSize);

                    for (int i = 0; i < responseFragmentPduList.Length; i++)
                    {
                        //SHOULD set the alloc_hint field in every PDU to
                        //be the combined stub data length of all remaining fragment PDUs.
                        responseFragmentPduList[i].alloc_hint   = (uint)stub.Length;
                        responseFragmentPduList[i].p_cont_id    = responsePdu.p_cont_id;
                        responseFragmentPduList[i].cancel_count = responsePdu.cancel_count;
                        responseFragmentPduList[i].reserved     = responsePdu.reserved;
                        responseFragmentPduList[i].stub         = ArrayUtility.SubArray(
                            stub,
                            0,
                            Math.Min(stub.Length, context.MaxTransmitFragmentSize - headerAndTrailerSize));

                        //For request and response PDUs, where the request and response PDUs are
                        //part of a fragmented request or response and authentication is requested,
                        //the sec_trailer structure MUST be present in every fragment of the request
                        //or response.
                        responseFragmentPduList[i].AppendAuthenticationVerifier();
                        responseFragmentPduList[i].SetLength();
                        stub = ArrayUtility.SubArray(stub, responseFragmentPduList[i].stub.Length);
                    }

                    return(responseFragmentPduList);

                case RpcePacketType.Bind:
                case RpcePacketType.BindAck:
                case RpcePacketType.AlterContext:
                case RpcePacketType.AlterContextResp:
                case RpcePacketType.Auth3:
                    //Windows RPC support version 5.0 only.
                    //Bind fragment requires RPC ver 5.1.
                    //We don't support it.
                    throw new NotSupportedException("bind/bind_ack/alt_context/alt_context_resp/auth3 PDU fragment are not supported.");

                default:
                    throw new InvalidOperationException("PDU PacketType isn't supported.");
                }
            }

            //If we cannot fragment the PDU
            return(new RpceCoPdu[] { pdu });
        }
        public RpceCoRequestPdu CreateCoRequestPdu(
            RpceServerSessionContext sessionContext,
            ushort opnum,
            uint callId,
            byte[] stub)
        {
            if (sessionContext == null)
            {
                throw new ArgumentNullException("sessionContext");
            }

            if (stub == null)
            {
                stub = new byte[0];
            }

            RpceCoRequestPdu requestPdu = new RpceCoRequestPdu(sessionContext);

            requestPdu.rpc_vers = sessionContext.RpcVersionMajor;
            requestPdu.rpc_vers_minor = sessionContext.RpcVersionMinor;
            requestPdu.PTYPE = RpcePacketType.Request;
            requestPdu.pfc_flags = RpceUtility.GeneratePfcFlags(sessionContext, RpcePacketType.Request);
            requestPdu.packed_drep.dataRepFormat = sessionContext.PackedDataRepresentationFormat;
            requestPdu.packed_drep.reserved = 0;
            requestPdu.call_id = callId;

            requestPdu.alloc_hint = (uint)stub.Length;
            requestPdu.p_cont_id = sessionContext.ContextIdentifier;
            requestPdu.opnum = opnum;
            requestPdu.stub = stub;

            requestPdu.AppendAuthenticationVerifier();
            requestPdu.SetLength();

            return requestPdu;
        }
        /// <summary>
        /// Create a RpceCoRequestPdu.
        /// </summary>
        /// <param name="opnum">
        /// Opnum of a method.
        /// </param>
        /// <param name="stub">
        /// Request stub.
        /// </param>
        /// <returns>
        /// Created RpceCoRequestPdu, it's ok to be sent out if there's 
        /// no modification to any field of the PDU.
        /// </returns>
        public RpceCoRequestPdu CreateCoRequestPdu(
            ushort opnum,
            byte[] stub)
        {
            if (stub == null)
            {
                stub = new byte[0];
            }

            RpceCoRequestPdu requestPdu = new RpceCoRequestPdu(context);

            requestPdu.rpc_vers = context.RpcVersionMajor;
            requestPdu.rpc_vers_minor = context.RpcVersionMinor;
            requestPdu.PTYPE = RpcePacketType.Request;
            requestPdu.pfc_flags = RpceUtility.GeneratePfcFlags(context, RpcePacketType.Request);
            requestPdu.packed_drep.dataRepFormat = context.PackedDataRepresentationFormat;
            requestPdu.packed_drep.reserved = 0;
            requestPdu.call_id = ComputeNextCallId();

            requestPdu.alloc_hint = (uint)stub.Length;
            requestPdu.p_cont_id = context.ContextIdentifier;
            requestPdu.opnum = opnum;
            requestPdu.stub = stub;

            requestPdu.AppendAuthenticationVerifier();
            requestPdu.SetLength();

            return requestPdu;
        }