/// <summary>
        /// consturctor.
        /// </summary>
        /// <param name="transportConfig">
        /// a TransportConfig object that contains the config.
        /// </param>
        /// <param name="decodePacketCallback">
        /// a DecodePacketCallback delegate that is used to decode the packet from bytes.
        /// </param>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not SocketTransportConfig
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportConfig is null.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when decodePacketCallback is null.
        /// </exception>
        public TcpServerTransport(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback)
        {
            if (transportConfig == null)
            {
                throw new ArgumentNullException("transportConfig");
            }

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

            this.UpdateConfig(transportConfig);

            this.decoder = decodePacketCallback;
            this.listeners = new Dictionary<IPEndPoint, TcpServerListener>();
            this.connections = new Dictionary<IPEndPoint, TcpServerConnection>();
            this.eventQueue = new SyncFilterQueue<TransportEvent>();
            this.sequence = new DataSequence();
            this.packetCache = new SyncFilterQueue<IPEndPointStackPacket>();
        }
        /// <summary>
        /// to update the config of transport at runtime.
        /// </summary>
        /// <param name="config">
        /// a TransportConfig object that contains the config to update
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not SocketTransportConfig.
        /// </exception>
        public void UpdateConfig(TransportConfig config)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("TcpServerTransport");
            }

            SocketTransportConfig socketTransportConfig = config as SocketTransportConfig;

            if (socketTransportConfig == null)
            {
                throw new ArgumentException("transportConfig must be SocketTransportConfig", "config");
            }

            this.socketConfig = socketTransportConfig;
        }
        /// <summary>
        /// to update the config of transport at runtime.
        /// </summary>
        /// <param name="config">
        /// a TransportConfig object that contains the config to update
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the underlayer transport is null! the config for TransportStack is invalid.
        /// </exception>
        public virtual void UpdateConfig(TransportConfig config)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("TransportStack");
            }

            if (this.transport == null)
            {
                throw new InvalidOperationException(
                    "the underlayer transport is null! the config for TransportStack is invalid.");
            }

            this.transport.UpdateConfig(config);
        }
        /// <summary>
        /// Constructor. To create the instance of transport specified in the transportConfig.
        /// </summary>
        /// <param name="transportConfig">
        /// a TransportConfig object that specifies the transport type and parameters.
        /// </param>
        /// <param name="decodePacketCallback">
        /// a DecodePacketCallback delegate that is used to decode the packet from bytes.
        /// </param>
        /// <exception cref="InvalidOperationException">
        /// thrown when StackTransportType is invalid.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when Role is invalid, for transport type is Tcp, it must be Server or Client.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when Role is invalid, for transport type is Netbios, it must be Server or Client.
        /// </exception>
        public TransportStack(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback)
        {
            switch (transportConfig.Type)
            {
                case StackTransportType.Tcp:

                    if (transportConfig.Role == Role.Client)
                    {
                        this.transport = new TcpClientTransport(transportConfig, decodePacketCallback);
                    }
                    else if (transportConfig.Role == Role.Server)
                    {
                        this.transport = new TcpServerTransport(transportConfig, decodePacketCallback);
                    }
                    else
                    {
                        throw new InvalidOperationException(
                            "Role is invalid, for transport type is Tcp, it must be Server or Client.");
                    }

                    break;

                case StackTransportType.Netbios:

                    if (transportConfig.Role == Role.Client)
                    {
                        this.transport = new NetbiosClientTransport(transportConfig, decodePacketCallback);
                    }
                    else if (transportConfig.Role == Role.Server)
                    {
                        this.transport = new NetbiosServerTransport(transportConfig, decodePacketCallback);
                    }
                    else
                    {
                        throw new InvalidOperationException(
                            "Role is invalid, for transport type is Netbios, it must be Server or Client.");
                    }

                    break;

                case StackTransportType.Stream:

                    this.transport = new StreamTransport(transportConfig, decodePacketCallback);

                    break;

                case StackTransportType.Udp:

                    if (transportConfig.Role == Role.Server)
                    {
                        this.transport = new UdpServerTransport(transportConfig, decodePacketCallback);
                    }
                    // all other role are equals to Client.
                    else
                    {
                        this.transport = new UdpClientTransport(transportConfig, decodePacketCallback);
                    }

                    break;

                default:
                    throw new InvalidOperationException("StackTransportType is invalid.");
            }
        }
        /// <summary>
        /// consturctor.
        /// </summary>
        /// <param name="transportConfig">
        /// a TransportConfig object that contains the config.
        /// </param>
        /// <param name="decodePacketCallback">
        /// a DecodePacketCallback delegate that is used to decode the packet from bytes.
        /// </param>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not StreamConfig
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportConfig is null.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when decodePacketCallback is null.
        /// </exception>
        public RdpbcgrClientTransportStack(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback)
        {
            if (transportConfig == null)
            {
                throw new ArgumentNullException("transportConfig");
            }

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

            this.UpdateConfig(transportConfig);
            buffer = new List<byte>();
            this.eventQueue = new SyncFilterQueue<TransportEvent>();
            this.packetCache = new SyncFilterQueue<StackPacket>();

            this.decoder = decodePacketCallback;
        }
        /// <summary>
        /// to update the config of transport at runtime.
        /// </summary>
        /// <param name="config">
        /// a TransportConfig object that contains the config to update
        /// </param>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not StreamTransport
        /// </exception>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when config is null.
        /// </exception>
        public void UpdateConfig(TransportConfig config)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("StreamTransport");
            }

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

            buffer = new List<byte>();
            StreamConfig theStreamConfig = config as StreamConfig;

            if (theStreamConfig == null)
            {
                throw new ArgumentException("transportConfig must be StreamConfig", "config");
            }

            this.streamConfig = theStreamConfig;

            // if the decoder is null, the instance has not initialized
            // do not terminate the thread and return directly.
            if (this.decoder == null || this.packetCache == null)
            {
                return;
            }

            #region update the underlayer stream.

            // abort the blocked receive thread.
            if (this.thread != null)
            {
                this.stopThread = true;
                this.thread = null;
            }

            // reconnect to received data from new stream.
            // if the stream is null, just stop the receiver of stream.
            if (this.streamConfig.Stream != null)
            {
                this.Connect();
            }

            #endregion
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="ldapVersion">The LDAP version that client uses.</param>
        /// <param name="config">
        /// The transport stack configuration. Note that for ADTS-LDAP, only socket transport is supported.
        /// </param>
        /// <exception cref="StackException">Thrown when the TransportConfig is not SocketTransportConfig</exception>
        /// <exception cref="ArgumentException">
        /// Thrown when the stack transport type is neither TCP nor UDP.
        /// </exception>
        public AdtsLdapClient(AdtsLdapVersion ldapVersion, TransportConfig config)
        {
            this.ldapVersion = ldapVersion;
            this.config = config;

            if (ldapVersion == AdtsLdapVersion.V2)
            {
                this.encoder = new AdtsLdapV2Encoder();
            }
            else
            {
                this.encoder = new AdtsLdapV3Encoder();
            }
        }
        /// <summary>
        /// Release resources. 
        /// </summary>
        /// <param name = "disposing">
        /// If disposing equals true, Managed and unmanaged resources are disposed. if false, Only unmanaged resources 
        /// can be disposed. 
        /// </param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed and unmanaged resources.
                if (disposing)
                {
                    // Free managed resources & other reference types:
                    if (this.transportStack != null)
                    {
                        this.transportStack.Dispose();
                        this.transportStack = null;
                    }
                    if (this.security != null)
                    {
                        this.security.Dispose();
                        this.security = null;
                    }
                    this.config = null;
                    this.encoder = null;
                    this.decoder = null;
                }

                // Call the appropriate methods to clean up unmanaged resources.
                // If disposing is false, only the following code is executed:

                this.disposed = true;
            }
        }
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="transportConfig">
        /// a TransportConfig object that contains the config.
        /// </param>
        /// <param name="decodePacketCallback">
        /// a DecodePacketCallback delegate that is used to decode the packet from bytes.
        /// </param>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not SocketTransportConfig
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportConfig is null.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when decodePacketCallback is null.
        /// </exception>
        public UdpServerTransport(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback)
        {
            if (transportConfig == null)
            {
                throw new ArgumentNullException("transportConfig");
            }

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

            this.UpdateConfig(transportConfig);

            this.listeners = new Dictionary<IPEndPoint, UdpServerListener>();
            this.eventQueue = new SyncFilterQueue<TransportEvent>();
            this.packetCache = new SyncFilterQueue<IPEndPointStackPacket>();
            this.buffer = new SyncFilterQueue<UdpReceivedBytes>();

            this.decoder = decodePacketCallback;
        }
        /// <summary>
        /// to update the config of transport at runtime.
        /// </summary>
        /// <param name="config">
        /// a TransportConfig object that contains the config to update
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not NetbiosTransportConfig.
        /// </exception>
        public void UpdateConfig(TransportConfig config)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("NetbiosServerTransport");
            }

            NetbiosTransportConfig netbiosTransportConfig = config as NetbiosTransportConfig;

            if (netbiosTransportConfig == null)
            {
                throw new ArgumentException("transportConfig must be NetbiosTransportConfig", "config");
            }

            this.netbiosConfig = netbiosTransportConfig;
        }
        /// <summary>
        /// consturctor.
        /// </summary>
        /// <param name="transportConfig">
        /// a TransportConfig object that contains the config.
        /// </param>
        /// <param name="decodePacketCallback">
        /// a DecodePacketCallback delegate that is used to decode the packet from bytes.
        /// </param>
        /// <exception cref="ArgumentException">
        /// thrown when transportConfig is not StreamConfig
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when transportConfig is null.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when decodePacketCallback is null.
        /// </exception>
        public StreamTransport(TransportConfig transportConfig, DecodePacketCallback decodePacketCallback)
        {
            if (transportConfig == null)
            {
                throw new ArgumentNullException("transportConfig");
            }

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

            this.UpdateConfig(transportConfig);

            this.buffer = new BytesBuffer();
            this.eventQueue = new SyncFilterQueue<TransportEvent>();
            this.packetCache = new SyncFilterQueue<StackPacket>();

            this.decoder = decodePacketCallback;
        }