/// <summary>
        /// Calling this method to be notified when a new RPC connection is coming.
        /// Users, who don't care about the coming of a new connection, just call ExpectCall directly.
        /// </summary>
        /// <param name="ifId">
        /// If_id to accept the bind. Null to accept all interface regardless the if_id.
        /// </param>
        /// <param name="ifMajorVer">
        /// If_major_ver to accept the bind. Null to accept all interface regardless the if_major_ver.
        /// </param>
        /// <param name="ifMinorVer">
        /// If_minor_ver to accept the bind. Null to accept all interface regardless the if_minor_ver.
        /// </param>
        /// <param name="timeout">Timeout of expecting a connection.</param>
        /// <param name="sessionContext">The sessionContext of binded connection.</param>
        /// <exception cref="InvalidOperationException">
        /// Thrown when receive error from server.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when securityProvider is null and auth_level is not NONE
        /// </exception>
        /// <exception cref="SspiException">
        /// Thrown when accept client token failed
        /// </exception>
        public virtual void ExpectBind(
            Guid?ifId,
            ushort?ifMajorVer,
            ushort?ifMinorVer,
            TimeSpan timeout,
            out RpceServerSessionContext sessionContext)
        {
            if (this.registeredInterfaceList.Count > 0)
            {
                throw new InvalidOperationException("Auto accept bind was turned on, ExpectBind is not allowed.");
            }

            DateTime t0 = DateTime.Now;

            sessionContext = rpceServer.ExpectConnect(timeout);

            RpcIfMatchFunc matchFunc = delegate(RpcIf rpcIf)
            {
                return(!((ifId != null && rpcIf.id != ifId.Value) ||
                         (ifMajorVer != null && rpcIf.majorVer != ifMajorVer.Value) ||
                         (ifMinorVer != null && rpcIf.minorVer != ifMinorVer.Value)));
            };

            while (!InternalExpectBind(matchFunc, timeout - (DateTime.Now - t0), ref sessionContext))
            {
                if ((DateTime.Now - t0) >= timeout)
                {
                    throw new TimeoutException();
                }
            }
        }
        /// <summary>
        /// Calling this method to be notified when a new RPC connection is coming.
        /// </summary>
        /// <param name="ifMatchFunc">Matching function.</param>
        /// <param name="timeout">Timeout of expecting a connection.</param>
        /// <param name="sessionContext">The sessionContext of binded connection.</param>
        /// <returns>If bind succeeded, return true; otherwise, false.</returns>
        private bool InternalExpectBind(
            RpcIfMatchFunc ifMatchFunc,
            TimeSpan timeout,
            ref RpceServerSessionContext sessionContext)
        {
            RpcePdu       receivedPdu = ReceiveAndReassemblePdu(timeout, ref sessionContext);
            RpceCoBindPdu bindPdu     = receivedPdu as RpceCoBindPdu;

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

            RpcIf rpcIf = new RpcIf(sessionContext.InterfaceId, sessionContext.InterfaceMajorVersion, sessionContext.InterfaceMinorVersion);

            if (!ifMatchFunc(rpcIf))
            {
                // Interface doesn't match, response BindNak
                RpceCoBindNakPdu bindNakPdu =
                    rpceServer.CreateCoBindNakPdu(sessionContext, p_reject_reason_t.REASON_NOT_SPECIFIED, null);
                FragmentAndSendPdu(sessionContext, bindNakPdu);
                return(false);
            }

            RpceCoBindAckPdu bindAckPdu = rpceServer.CreateCoBindAckPdu(sessionContext);

            FragmentAndSendPdu(sessionContext, bindAckPdu);

            while (sessionContext.SecurityContext != null && sessionContext.SecurityContextNeedContinueProcessing)
            {
                receivedPdu = ReceiveAndReassemblePdu(timeout, ref sessionContext);
                RpceCoAlterContextPdu alterContextPdu = receivedPdu as RpceCoAlterContextPdu;
                RpceCoAuth3Pdu        auth3Pdu        = receivedPdu as RpceCoAuth3Pdu;

                if (alterContextPdu != null)
                {
                    RpceCoAlterContextRespPdu alterContextRespPdu =
                        rpceServer.CreateCoAlterContextRespPdu(sessionContext);

                    FragmentAndSendPdu(sessionContext, alterContextRespPdu);
                }
                else if (auth3Pdu != null)
                {
                    //Do nothing
                }
            }

            return(true);
        }
        /// <summary>
        /// Receive and reassemble PDU.
        /// </summary>
        /// <param name="timeout">Timeout of receiving PDU</param>
        /// <param name="sessionContext">Context of the RPCE session</param>
        /// <returns>Received PDU</returns>
        private RpcePdu ReceiveAndReassemblePdu(
            TimeSpan timeout,
            ref RpceServerSessionContext sessionContext)
        {
            RpcePdu receivedPdu;
            bool    expectAny = sessionContext == null;

WaitForEvent:

            if (expectAny)
            {
                sessionContext = null;
            }
            EventType eventType = rpceServer.ExpectEvent(timeout, ref sessionContext, out receivedPdu);

            if (this.registeredInterfaceList.Count > 0)
            {
                // auto accept connect/bind/disconnect
                if (eventType == EventType.Connected)
                {
                    RpcIfMatchFunc matchFunc = delegate(RpcIf rpcIf)
                    {
                        for (int i = 0; i < this.registeredInterfaceList.Count; i++)
                        {
                            if (this.registeredInterfaceList[i].Equals(rpcIf))
                            {
                                return(true);
                            }
                        }
                        return(false);
                    };
                    InternalExpectBind(matchFunc, timeout, ref sessionContext);
                    goto WaitForEvent;
                }
                else if (eventType == EventType.Disconnected)
                {
                    goto WaitForEvent;
                }
                else
                {
                    // it is a PDU.
                }
            }
            else if (eventType != EventType.ReceivedPacket)
            {
                throw new InvalidOperationException(
                          string.Format("Unexpected event ({0}) received.", eventType));
            }


            RpceCoPdu receivedCoPdu = receivedPdu as RpceCoPdu;

            if (receivedCoPdu == null)
            {
                return(receivedPdu);
            }

            List <RpceCoPdu> pduList = new List <RpceCoPdu>();

            pduList.Add(receivedCoPdu);

            while ((receivedCoPdu.pfc_flags & RpceCoPfcFlags.PFC_LAST_FRAG) == 0)
            {
                receivedPdu = rpceServer.ExpectPdu(timeout, ref sessionContext);

                receivedCoPdu = receivedPdu as RpceCoPdu;
                if (receivedCoPdu == null)
                {
                    throw new InvalidOperationException("CL PDU received inside a connection.");
                }

                pduList.Add(receivedCoPdu);
            }

            return(RpceUtility.ReassemblePdu(sessionContext, pduList.ToArray()));
        }
        /// <summary>
        /// Calling this method to be notified when a new RPC connection is coming. 
        /// </summary>
        /// <param name="ifMatchFunc">Matching function.</param>
        /// <param name="timeout">Timeout of expecting a connection.</param>
        /// <param name="sessionContext">The sessionContext of binded connection.</param>
        /// <returns>If bind succeeded, return true; otherwise, false.</returns>
        private bool InternalExpectBind(
            RpcIfMatchFunc ifMatchFunc,
            TimeSpan timeout,
            ref RpceServerSessionContext sessionContext)
        {
            RpcePdu receivedPdu = ReceiveAndReassemblePdu(timeout, ref sessionContext);
            RpceCoBindPdu bindPdu = receivedPdu as RpceCoBindPdu;

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

            RpcIf rpcIf = new RpcIf(sessionContext.InterfaceId, sessionContext.InterfaceMajorVersion, sessionContext.InterfaceMinorVersion);
            if (!ifMatchFunc(rpcIf))
            {
                // Interface doesn't match, response BindNak
                RpceCoBindNakPdu bindNakPdu =
                    rpceServer.CreateCoBindNakPdu(sessionContext, p_reject_reason_t.REASON_NOT_SPECIFIED, null);
                FragmentAndSendPdu(sessionContext, bindNakPdu);
                return false;
            }

            RpceCoBindAckPdu bindAckPdu = rpceServer.CreateCoBindAckPdu(sessionContext);

            FragmentAndSendPdu(sessionContext, bindAckPdu);

            while (sessionContext.SecurityContext != null && sessionContext.SecurityContextNeedContinueProcessing)
            {
                receivedPdu = ReceiveAndReassemblePdu(timeout, ref sessionContext);
                RpceCoAlterContextPdu alterContextPdu = receivedPdu as RpceCoAlterContextPdu;
                RpceCoAuth3Pdu auth3Pdu = receivedPdu as RpceCoAuth3Pdu;

                if (alterContextPdu != null)
                {
                    RpceCoAlterContextRespPdu alterContextRespPdu =
                        rpceServer.CreateCoAlterContextRespPdu(sessionContext);

                    FragmentAndSendPdu(sessionContext, alterContextRespPdu);
                }
                else if (auth3Pdu != null)
                {
                    //Do nothing
                }
            }

            return true;
        }