/// <summary>
        /// Encode a PDU to a binary stream. Then send the stream.
        /// The PDU can be got by calling method Create***Pdu.
        /// </summary>
        /// <param name="pdu">
        /// A specified type of a PDU. This argument can not be null.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when pdu parameter passed to the method is null.
        /// </exception>
        public void SendPdu(RpcePdu pdu)
        {
            if (pdu == null)
            {
                throw new ArgumentNullException("pdu");
            }

            UpdateContextOnSendingPdu(pdu);

            if (context.tcpTransport != null)
            {
                context.tcpTransport.SendPacket(pdu);
            }
            else if (context.fileServiceTransport != null)
            {
                RpceCoPdu coPdu = pdu as RpceCoPdu;
                if (coPdu != null)
                {
                    switch (coPdu.PTYPE)
                    {
                        case RpcePacketType.Request:
                        case RpcePacketType.Response:
                            if (context.fileServiceTransport is SmbClientTransport)
                            {
                                // SMB doesn't support FSCTL_PIPE_TRANSCEIVE.
                                // This is the last fragment of a request for synchronous RPCs.
                                if (context.UseTransactionForNamedPipe && !context.IsAsynchronous && ((coPdu.pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) != 0))
                                {
                                    TransactionOverWriteAndRead(pdu);
                                }
                                else
                                {
                                    context.fileServiceTransport.Write(timeoutForFsTransport, 0, pdu.ToBytes());
                                }
                            }
                            else if ((coPdu.pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) == 0)
                            {
                                // This is one of fragment PDU, but not the last.
                                context.fileServiceTransport.Write(timeoutForFsTransport, 0, pdu.ToBytes());
                            }
                            else
                            {
                                // This is the only PDU of a request,
                                // or this is the last fragment of a request.
                                byte[] inputResponse;
                                byte[] outputResponse;
                                context.fileServiceTransport.IoControl(
                                    timeoutForFsTransport,
                                    FsCtlCode.FSCTL_PIPE_TRANSCEIVE,
                                    pdu.ToBytes(),
                                    out inputResponse,
                                    out outputResponse,
                                    0,
                                    context.MaxOutputResponse);
                                if (outputResponse == null)
                                {
                                    throw new InvalidOperationException(
                                        "Got an error in SMB/SMB2 transport. SMB/SMB2 should throw exception.");
                                }
                                pipeTransceiveResponseQueue.Enqueue(outputResponse);
                            }
                            break;
                        case RpcePacketType.Bind:
                        case RpcePacketType.AlterContext:
                            if (context.UseTransactionForNamedPipe && (context.fileServiceTransport is SmbClientTransport) && !context.IsAsynchronous)
                            {
                                TransactionOverWriteAndRead(pdu);
                            }
                            else
                            {
                                context.fileServiceTransport.Write(timeoutForFsTransport, 0, pdu.ToBytes());
                            }
                            break;
                        case RpcePacketType.Auth3:
                        case RpcePacketType.CoCancel:
                        case RpcePacketType.Orphaned:
                        default:
                            context.fileServiceTransport.Write(timeoutForFsTransport, 0, pdu.ToBytes());
                            break;
                    }
                }
            }
            else
            {
                throw new InvalidOperationException("No connection was established.");
            }
        }
        /// <summary>
        /// Send a PDU to a specific connected client.
        /// </summary>
        /// <param name="pdu">Rpce PDU to send.</param>
        /// <param name="sessionContext">Context of the RPCE session.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when sessionContext or pdu is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when underlayer transport was not established.
        /// Thrown when protocol sequence is unknown.
        /// </exception>
        public virtual void SendPdu(
            RpceServerSessionContext sessionContext,
            RpcePdu pdu)
        {
            if (sessionContext == null)
            {
                throw new ArgumentNullException("sessionContext");
            }

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

            EnsureTransportIsValid();

            sessionContext.UpdateContextOnSendingPdu(pdu);

            if (sessionContext.ProtocolSequence.Equals(
                RpceUtility.RPC_OVER_TCPIP_PROTOCOL_SEQUENCE,
                StringComparison.OrdinalIgnoreCase))
            {
                this.tcpTransport.SendPacket(sessionContext.RemoteEndpoint, pdu);
            }
            else if (sessionContext.ProtocolSequence.Equals(
                RpceUtility.RPC_OVER_NAMED_PIPE_PROTOCOL_SEQUENCE,
                StringComparison.OrdinalIgnoreCase))
            {
                lock (sessionContext.smbSendingLocker)
                {
                    sessionContext.smbBufferSending = ArrayUtility.ConcatenateArrays(
                        sessionContext.smbBufferSending,
                        pdu.ToBytes());

                    if (sessionContext.smbSendingFunc != null)
                    {
                        sessionContext.smbSendingFunc();
                    }
                }
            }
            else
            {
                throw new InvalidOperationException("Unknown protocol sequence.");
            }
        }
 /// <summary>
 /// MS-RPCE Section 2.1.1.2: In the case of synchronous RPCs, an implementation of these extensions MAY require the Server Message Block (SMB) Protocol implementation 
 /// to execute a transaction encompassing the write of the last request PDU and the read of the first response PDU on the client.     
 /// The last request PDU MUST be a bind, an alter_context, or the last fragment of a request. 
 /// The first response PDU MUST be a bind_ack or bind_nak, an alter_context_response, or the first fragment of a response.
 /// The transaction over a write and read is as specified in [MS-CIFS].
 /// Windows always asks the Server Message Block implementation to execute a transaction on the client for synchronous RPCs.
 /// </summary>
 /// <param name="pdu">A specified type of a PDU. This argument can not be null.</param>
 private void TransactionOverWriteAndRead(RpcePdu pdu)
 {
     byte[] readData;
     SmbClientTransport smbClientTransport = context.fileServiceTransport as SmbClientTransport;
     smbClientTransport.Transaction(timeoutForFsTransport, pdu.ToBytes(), out readData);
     if (readData == null)
     {
         throw new InvalidOperationException(
             "Got an error in SMB/SMB2 transport. SMB/SMB2 should throw exception.");
     }
     pipeTransceiveResponseQueue.Enqueue(readData);
 }