/// <summary>
        /// start at the specified endpoint<para/>
        /// the underlayer transport must be TcpServer, UdpServer or NetbiosServer.
        /// </summary>
        /// <param name="localEndPoint">
        /// an object that specifies the listener.
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when localEndPoint is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when localEndPoint is not an IPEndPoint/port.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the specified endpoint has been started.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when localEndPoint is an int port, but the LocalIpAddress is not configured.
        /// </exception>
        public void Start(object localEndPoint)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("UdpServerTransport");
            }

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

            IPEndPoint requiredLocalEP = localEndPoint as IPEndPoint;

            if (requiredLocalEP == null)
            {
                requiredLocalEP = Utility.GetEndPointByPort(this.socketConfig, localEndPoint);
            }

            if (this.listeners.ContainsKey(requiredLocalEP))
            {
                throw new InvalidOperationException("the specified endpoint has been started.");
            }

            bool isLspHooked;
            bool isBlocking;
            StackTransportType type = this.socketConfig.Type;

            // get the replaced endpoint from LSP.
            IPEndPoint actualListenedLocalEP =
                LspConsole.Instance.GetReplacedEndPoint(type, requiredLocalEP, out isLspHooked, out isBlocking);

            UdpClient         udpClient = new UdpClient(actualListenedLocalEP);
            UdpServerListener listener  = new UdpServerListener(udpClient, this, isLspHooked);

            // if LSP is enabled, intercept the traffic
            if (isLspHooked)
            {
                LspConsole.Instance.InterceptTraffic(
                    type, isBlocking, requiredLocalEP, udpClient.Client.LocalEndPoint as IPEndPoint);
            }

            listener.Start(requiredLocalEP);
            this.listeners[requiredLocalEP] = listener;

            this.started = true;
        }
        /// <summary>
        /// stop the specified listener.<para/>
        /// the underlayer transport must be TcpServer, UdpServer or NetbiosServer.
        /// </summary>
        /// <param name="localEndPoint">
        /// an object that specifies the listener.
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the server is not started, must invoke Start() first.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when remoteEndPoint is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when the specified endpoint is not an IPEndPoint/port.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the udp client is not connected to server, must invoke Start() first.
        /// </exception>
        public void Stop(object localEndPoint)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("UdpServerTransport");
            }

            if (!this.started)
            {
                throw new InvalidOperationException("server is not started, must invoke Start() first.");
            }

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

            IPEndPoint endpoint = localEndPoint as IPEndPoint;

            if (endpoint == null)
            {
                Utility.StopTransportByPort(this, this.listeners.Keys, null, localEndPoint);
                return;
            }

            if (!this.listeners.ContainsKey(endpoint))
            {
                throw new InvalidOperationException("the listener specified by endpoint cannot be found!");
            }

            UdpServerListener listener = this.listeners[endpoint];

            if (listener == null)
            {
                throw new InvalidOperationException("the listener specified by endpoint is null!");
            }

            if (listener.IsLspHooked)
            {
                LspConsole.Instance.UnblockTraffic(listener.LspHookedLocalEP, this.socketConfig.Type);
            }

            listener.Stop();

            this.listeners.Remove(endpoint);
        }
        /// <summary>
        /// start at the specified endpoint<para/>
        /// the underlayer transport must be TcpServer, UdpServer or NetbiosServer.
        /// </summary>
        /// <param name="localEndPoint">
        /// an object that specifies the listener.
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when localEndPoint is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when localEndPoint is not an IPEndPoint/port.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the specified endpoint has been started.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when localEndPoint is an int port, but the LocalIpAddress is not configured.
        /// </exception>
        public void Start(object localEndPoint)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("UdpServerTransport");
            }

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

            IPEndPoint requiredLocalEP = localEndPoint as IPEndPoint;
            if (requiredLocalEP == null)
            {
                requiredLocalEP = Utility.GetEndPointByPort(this.socketConfig, localEndPoint);
            }

            if (this.listeners.ContainsKey(requiredLocalEP))
            {
                throw new InvalidOperationException("the specified endpoint has been started.");
            }

            bool isLspHooked;
            bool isBlocking;
            StackTransportType type = this.socketConfig.Type;

            // get the replaced endpoint from LSP.
            IPEndPoint actualListenedLocalEP =
                LspConsole.Instance.GetReplacedEndPoint(type, requiredLocalEP, out isLspHooked, out isBlocking);

            UdpClient udpClient = new UdpClient(actualListenedLocalEP);
            UdpServerListener listener = new UdpServerListener(udpClient, this, isLspHooked);

            // if LSP is enabled, intercept the traffic
            if (isLspHooked)
            {
                LspConsole.Instance.InterceptTraffic(
                    type, isBlocking, requiredLocalEP, udpClient.Client.LocalEndPoint as IPEndPoint);
            }

            listener.Start(requiredLocalEP);
            this.listeners[requiredLocalEP] = listener;

            this.started = true;
        }
        /// <summary>
        /// Send arbitrary message to a special remote host.<para/>
        /// the transport must be UdpServer
        /// </summary>
        /// <param name="localEndPoint">
        /// an object that specifies the local endpoint to send bytes.
        /// </param>
        /// <param name="remoteEndPoint">
        /// an object that specifies the target endpoint to which send bytes.
        /// </param>
        /// <param name="message">
        /// a bytes array that contains the bytes to send to target.
        /// </param>
        /// <exception cref="ObjectDisposedException">
        /// thrown when this object is disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the server is not started, must invoke Start() first.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when remoteEndPoint is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when udp server is not start, must invoke Start() first.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when the specified endpoint is not an IPEndPoint.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the underlayer udp transport specified by endpoint is invalid
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// thrown when the listener on the specified localEndPoint does not exists,
        /// please invoke Start(localEndPoint) to start it first.
        /// </exception>
        public void SendBytes(object localEndPoint, object remoteEndPoint, byte[] message)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("UdpServerTransport");
            }

            if (!this.started)
            {
                throw new InvalidOperationException("server is not started, must invoke Start() first.");
            }

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

            if (this.listeners.Count == 0)
            {
                throw new InvalidOperationException("udp server is not start, must invoke Start() first.");
            }

            IPEndPoint remoteEP = remoteEndPoint as IPEndPoint;

            if (remoteEP == null)
            {
                throw new ArgumentException("the specified endpoint is not an IPEndPoint.", "remoteEndPoint");
            }

            IPEndPoint localEP = localEndPoint as IPEndPoint;

            if (localEP == null)
            {
                throw new ArgumentException("the specified endpoint is not an IPEndPoint.", "localEndPoint");
            }

            if (!this.listeners.ContainsKey(localEP))
            {
                throw new InvalidOperationException(
                          "the listener on the specified localEndPoint does not exists,"
                          + " please invoke Start(localEndPoint) to start it first.");
            }

            UdpServerListener listener = this.listeners[localEP];

            if (listener == null || listener.Listener == null)
            {
                throw new InvalidOperationException("the underlayer udp transport specified by endpoint is invalid");
            }

            IPEndPoint mappedEndPoint = null;

            if (listener.IsLspHooked)
            {
                //replace the real client endpoint with lsp dll endpoint
                mappedEndPoint =
                    LspConsole.Instance.GetMappedIPEndPoint(
                        (IPEndPoint)listener.Listener.Client.LocalEndPoint, remoteEP, StackTransportType.Udp);

                if (mappedEndPoint != null)
                {
                    //add udp header
                    message = ArrayUtility.ConcatenateArrays <byte>(Utility.CreateUdpHeader(remoteEP), message);
                }
            }

            listener.Listener.Send(message, message.Length, mappedEndPoint == null ? remoteEP : mappedEndPoint);
        }