internal unsafe bool ServerHandshake(ServerProperties serverProperties, Socket UdpClient, GetClientsDelegate getClientsDelegate, PrivateKeyHandler KeyHandler)
        {
            this.PeerSide = SecureSocketProtocol2.PeerSide.Server;

            //check certificate info
            if (serverProperties.ServerCertificate.PrivateKey == null || (serverProperties.ServerCertificate.PrivateKey != null && serverProperties.ServerCertificate.PrivateKey.Length <= 16))
            {
                throw new ArgumentException("The private key must be longer then 16 in length", "PrivateKey");
            }

            onAddProtection(Connection.protection); //no error handling by SSP, this must work or there is simply no connection

            //apply private key
            ApplyPrivateKey(serverProperties.ServerCertificate.PrivateKey);

            if (serverProperties.KeyFiles != null)
            {
                foreach (Stream stream in serverProperties.KeyFiles)
                {
                    while (stream.Position < stream.Length)
                    {
                        byte[] data = new byte[32768];
                        int    read = stream.Read(data, 0, data.Length);

                        if (read <= 0)
                        {
                            break;
                        }

                        Array.Resize(ref data, read);
                        ApplyPrivateKey(data);
                    }
                }
            }

            ServerSideHandshake handShake = new ServerSideHandshake(this, serverProperties, UdpClient, getClientsDelegate, KeyHandler);

            if (!handShake.DoHandshake())
            {
                Disconnect(DisconnectReason.HandShakeFailed);
                throw new Exception("An unexpected error occured in the HandShake");
            }

            this.CompletedHandshake     = true;
            this.Connection.KeepAliveSW = Stopwatch.StartNew();
            return(true);
        }
        /// <summary>
        /// Initialize a new SSPServer
        /// </summary>
        /// <param name="serverProperties">The properties for the server</param>
        public SSPServer(ServerProperties serverProperties)
        {
            if (serverProperties == null)
            {
                throw new ArgumentNullException("serverProperties");
            }

            this.Random           = new RandomDecimal(DateTime.Now.Millisecond);
            this.KeyHandler       = new PrivateKeyHandler(serverProperties.GenerateKeysInBackground);
            this.serverProperties = serverProperties;
            this.Clients          = new SortedList <decimal, SSPClient>();
            this.TcpServer        = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.TcpServer.Bind(new IPEndPoint(IPAddress.Parse(serverProperties.ListenIp), serverProperties.ListenPort));
            this.TcpServer.Listen(100);

            if (serverProperties.AllowUdp)
            {
                try
                {
                    this.UdpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    this.UdpServer.Bind(new IPEndPoint(IPAddress.Parse(serverProperties.ListenIp), serverProperties.ListenPort));
                    this.UdpServer.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
                    this.udpAsyncSocket = new SocketAsyncEventArgs();
                    this.udpAsyncSocket.SetBuffer(new byte[70000], 0, 70000);
                    this.udpAsyncSocket.RemoteEndPoint = new IPEndPoint(0, 0);
                    this.udpAsyncSocket.Completed     += UdpAsyncSocketCallback;

                    if (!UdpServer.ReceiveFromAsync(udpAsyncSocket))
                    {
                        UdpAsyncSocketCallback(null, udpAsyncSocket);
                    }
                }
                catch (Exception ex)
                {
                    this.TcpServer.Close();
                    throw ex;
                }
            }

            this.RootSocket_DNS = new RootDns();

            //ThreadPool.QueueUserWorkItem(ServerThread);
            this.Running = true;

            TcpServer.BeginAccept(AsyncAction, null);
        }