Contains SSL configuration options
        private TCPConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient, SSLOptions sslOptions)
#endif
            : base(connectionInfo, defaultSendReceiveOptions)
        {
            if (connectionInfo.ConnectionType != ConnectionType.TCP)
                throw new ArgumentException("Provided connectionType must be TCP.", "connectionInfo");

            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];

            //We don't guarantee that the tcpClient has been created yet
#if WINDOWS_PHONE || NETFX_CORE
            if (socket != null) this.socket = socket;
#else
            if (tcpClient != null) this.tcpClient = tcpClient;
            this.SSLOptions = sslOptions;
#endif
        }
        /// <summary>
        /// Internal <see cref="TCPConnection"/> creation which hides the necessary internal calls
        /// </summary>
        /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>
        /// <param name="defaultSendReceiveOptions">Connection default SendReceiveOptions</param>
        /// <param name="tcpClient">If this is an incoming connection we will already have access to the tcpClient, otherwise use null</param>
        /// <param name="establishIfRequired">Establish during create if true</param>
        /// <param name="sslOptions">SSL options that will be used with this connection.</param>
        /// <returns>An existing connection or a new one</returns>
        internal static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient, bool establishIfRequired, SSLOptions sslOptions = null)
#endif
        {
            connectionInfo.ConnectionType = ConnectionType.TCP;

            //If we have a tcpClient at this stage we must be server side
#if WINDOWS_PHONE || NETFX_CORE
            if (socket != null)
            {
                connectionInfo.ServerSide = true;
            }
#else
            if (tcpClient != null)
            {
                connectionInfo.ServerSide = true;
            }
            if (sslOptions == null)
            {
                sslOptions = new SSLOptions();
            }
#endif

            //Set default connection options if none have been provided
            if (defaultSendReceiveOptions == null)
            {
                defaultSendReceiveOptions = NetworkComms.DefaultSendReceiveOptions;
            }

            bool          newConnection = false;
            TCPConnection connection;

            lock (NetworkComms.globalDictAndDelegateLocker)
            {
                List <Connection> existingConnections = NetworkComms.GetExistingConnection(connectionInfo.RemoteIPEndPoint, connectionInfo.LocalIPEndPoint, connectionInfo.ConnectionType, connectionInfo.ApplicationLayerProtocol);

                //Check to see if a connection already exists, if it does return that connection, if not return a new one
                if (existingConnections.Count > 0)
                {
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace("Attempted to create new TCPConnection to connectionInfo='" + connectionInfo + "' but there is an existing connection. Existing connection will be returned instead.");
                    }

                    establishIfRequired = false;
                    connection          = (TCPConnection)existingConnections[0];
                }
                else
                {
                    if (NetworkComms.LoggingEnabled)
                    {
                        NetworkComms.Logger.Trace("Creating new TCPConnection to connectionInfo='" + connectionInfo + "'." + (establishIfRequired ? " Connection will be established." : " Connection will not be established."));
                    }

                    if (connectionInfo.ConnectionState == ConnectionState.Establishing)
                    {
                        throw new ConnectionSetupException("Connection state for connection " + connectionInfo + " is marked as establishing. This should only be the case here due to a bug.");
                    }

                    //If an existing connection does not exist but the info we are using suggests it should we need to reset the info
                    //so that it can be reused correctly. This case generally happens when using Comms in the format
                    //TCPConnection.GetConnection(info).SendObject(packetType, objToSend);
                    if (connectionInfo.ConnectionState == ConnectionState.Established || connectionInfo.ConnectionState == ConnectionState.Shutdown)
                    {
                        connectionInfo.ResetConnectionInfo();
                    }

                    //We add a reference to networkComms for this connection within the constructor
#if WINDOWS_PHONE || NETFX_CORE
                    connection = new TCPConnection(connectionInfo, defaultSendReceiveOptions, socket);
#else
                    connection = new TCPConnection(connectionInfo, defaultSendReceiveOptions, tcpClient, sslOptions);
#endif
                    newConnection = true;
                }
            }

            if (newConnection && establishIfRequired)
            {
                connection.EstablishConnection();
            }
            else if (!newConnection)
            {
                connection.WaitForConnectionEstablish(NetworkComms.ConnectionEstablishTimeoutMS);
            }

            if (!NetworkComms.commsShutdown)
            {
                TriggerConnectionKeepAliveThread();
            }

            return(connection);
        }
 /// <summary>
 /// Create a TCP connection with the provided connectionInfo and sets the connection default SendReceiveOptions. If there is an existing connection that is returned instead.
 /// If a new connection is created it will be registered with NetworkComms and can be retrieved using <see cref="NetworkComms.GetExistingConnection(ConnectionInfo)"/> and overrides.
 /// </summary>
 /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>
 /// <param name="defaultSendReceiveOptions">The SendReceiveOptions which will be set as this connections defaults</param>
 /// <param name="sslOptions">SSLOptions to use with this connection</param>
 /// <param name="establishIfRequired">If true will establish the TCP connection with the remote end point before returning</param>
 /// <returns>Returns a <see cref="TCPConnection"/></returns>
 public static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, SSLOptions sslOptions, bool establishIfRequired = true)
 {
     return(GetConnection(connectionInfo, defaultSendReceiveOptions, null, establishIfRequired, sslOptions));
 }
        /// <summary>
        /// Internal <see cref="TCPConnection"/> creation which hides the necessary internal calls
        /// </summary>
        /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>
        /// <param name="defaultSendReceiveOptions">Connection default SendReceiveOptions</param>
        /// <param name="tcpClient">If this is an incoming connection we will already have access to the tcpClient, otherwise use null</param>
        /// <param name="establishIfRequired">Establish during create if true</param>
        /// <param name="sslOptions">SSL options that will be used with this connection.</param>
        /// <returns>An existing connection or a new one</returns>
        internal static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient, bool establishIfRequired, SSLOptions sslOptions = null)
#endif
        {
            connectionInfo.ConnectionType = ConnectionType.TCP;

            //If we have a tcpClient at this stage we must be server side
#if WINDOWS_PHONE || NETFX_CORE
             if (socket != null) connectionInfo.ServerSide = true;
#else
            if (tcpClient != null) connectionInfo.ServerSide = true;
            if (sslOptions == null) sslOptions = new SSLOptions();
#endif

            //Set default connection options if none have been provided
            if (defaultSendReceiveOptions == null) defaultSendReceiveOptions = NetworkComms.DefaultSendReceiveOptions;

            bool newConnection = false;
            TCPConnection connection;

            lock (NetworkComms.globalDictAndDelegateLocker)
            {
                List<Connection> existingConnections = NetworkComms.GetExistingConnection(connectionInfo.RemoteIPEndPoint, connectionInfo.LocalIPEndPoint, connectionInfo.ConnectionType, connectionInfo.ApplicationLayerProtocol);

                //Check to see if a connection already exists, if it does return that connection, if not return a new one
                if (existingConnections.Count > 0)
                {
                    if (NetworkComms.LoggingEnabled)
                        NetworkComms.Logger.Trace("Attempted to create new TCPConnection to connectionInfo='" + connectionInfo + "' but there is an existing connection. Existing connection will be returned instead.");

                    establishIfRequired = false;
                    connection = (TCPConnection)existingConnections[0];
                }
                else
                {
                    if (NetworkComms.LoggingEnabled)
                        NetworkComms.Logger.Trace("Creating new TCPConnection to connectionInfo='" + connectionInfo + "'." + (establishIfRequired ? " Connection will be established." : " Connection will not be established."));

                    if (connectionInfo.ConnectionState == ConnectionState.Establishing)
                        throw new ConnectionSetupException("Connection state for connection " + connectionInfo + " is marked as establishing. This should only be the case here due to a bug.");

                    //If an existing connection does not exist but the info we are using suggests it should we need to reset the info
                    //so that it can be reused correctly. This case generally happens when using Comms in the format 
                    //TCPConnection.GetConnection(info).SendObject(packetType, objToSend);
                    if (connectionInfo.ConnectionState == ConnectionState.Established || connectionInfo.ConnectionState == ConnectionState.Shutdown)
                        connectionInfo.ResetConnectionInfo();

                    //We add a reference to networkComms for this connection within the constructor
#if WINDOWS_PHONE || NETFX_CORE
                    connection = new TCPConnection(connectionInfo, defaultSendReceiveOptions, socket);
#else
                    connection = new TCPConnection(connectionInfo, defaultSendReceiveOptions, tcpClient, sslOptions);
#endif
                    newConnection = true;
                }
            }

            if (newConnection && establishIfRequired) connection.EstablishConnection(); 
            else if (!newConnection) connection.WaitForConnectionEstablish(NetworkComms.ConnectionEstablishTimeoutMS);

            if (!NetworkComms.commsShutdown) TriggerConnectionKeepAliveThread();

            return connection;
        }
 /// <summary>
 /// Create a TCP connection with the provided connectionInfo and sets the connection default SendReceiveOptions. If there is an existing connection that is returned instead.
 /// If a new connection is created it will be registered with NetworkComms and can be retrieved using <see cref="NetworkComms.GetExistingConnection(ConnectionInfo)"/> and overrides.
 /// </summary>
 /// <param name="connectionInfo">ConnectionInfo to be used to create connection</param>
 /// <param name="defaultSendReceiveOptions">The SendReceiveOptions which will be set as this connections defaults</param>
 /// <param name="sslOptions">SSLOptions to use with this connection</param>
 /// <param name="establishIfRequired">If true will establish the TCP connection with the remote end point before returning</param>
 /// <returns>Returns a <see cref="TCPConnection"/></returns>
 public static TCPConnection GetConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, SSLOptions sslOptions, bool establishIfRequired = true)
 {
     return GetConnection(connectionInfo, defaultSendReceiveOptions, null, establishIfRequired, sslOptions);
 }
 /// <summary>
 /// Create a new instance of a TCP listener
 /// </summary>
 /// <param name="sendReceiveOptions">The SendReceiveOptions to use with incoming data on this listener</param>
 /// <param name="applicationLayerProtocol">If enabled NetworkComms.Net uses a custom
 /// application layer protocol to provide useful features such as inline serialisation,
 /// transparent packet transmission, remote peer handshake and information etc. We strongly
 /// recommend you enable the NetworkComms.Net application layer protocol.</param>
 /// <param name="sslOptions">The SSLOptions to use with this listener</param>
 /// <param name="allowDiscoverable">Determines if the newly created <see cref="ConnectionListenerBase"/> will be discoverable if <see cref="Tools.PeerDiscovery"/> is enabled.</param>
 public TCPConnectionListener(SendReceiveOptions sendReceiveOptions,
                              ApplicationLayerProtocolStatus applicationLayerProtocol, SSLOptions sslOptions, bool allowDiscoverable = false)
     : base(ConnectionType.TCP, sendReceiveOptions, applicationLayerProtocol, allowDiscoverable)
 {
     this.SSLOptions = sslOptions;
 }
        private TCPConnection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions, TcpClient tcpClient, SSLOptions sslOptions)
#endif
            : base(connectionInfo, defaultSendReceiveOptions)
        {
            if (connectionInfo.ConnectionType != ConnectionType.TCP)
            {
                throw new ArgumentException("Provided connectionType must be TCP.", "connectionInfo");
            }

            dataBuffer = new byte[NetworkComms.InitialReceiveBufferSizeBytes];

            //We don't guarantee that the tcpClient has been created yet
#if WINDOWS_PHONE || NETFX_CORE
            if (socket != null)
            {
                this.socket = socket;
            }
#else
            if (tcpClient != null)
            {
                this.tcpClient = tcpClient;
            }
            this.SSLOptions = sslOptions;
#endif
        }
        public static void RunExample()
        {
            NetworkComms.ConnectionEstablishTimeoutMS = 600000;

            //Create a suitable certificate if it does not exist
            if (!File.Exists("testCertificate.pfx"))
            {
                CertificateDetails details = new CertificateDetails("CN=networkcomms.net", DateTime.Now, DateTime.Now.AddYears(1));
                SSLTools.CreateSelfSignedCertificatePFX(details, "testCertificate.pfx");
            }

            //Load the certificate
            X509Certificate cert = new X509Certificate2("testCertificate.pfx");

            IPAddress localIPAddress = IPAddress.Parse("::1");

            Console.WriteLine("Please select mode:");
            Console.WriteLine("1 - Server (Listens for connections)");
            Console.WriteLine("2 - Client (Creates connections to server)");

            //Read in user choice
            if (Console.ReadKey(true).Key == ConsoleKey.D1) serverMode = true;
            else serverMode = false;

            if (serverMode)
            {
                NetworkComms.AppendGlobalIncomingPacketHandler<byte[]>("Data", (header, connection, data) =>
                {
                    Console.WriteLine("Received data (" + data.Length + ") from " + connection.ToString());
                });

                //Establish handler
                NetworkComms.AppendGlobalConnectionEstablishHandler((connection) =>
                {
                    Console.WriteLine("Connection established - " + connection);
                });

                //Close handler
                NetworkComms.AppendGlobalConnectionCloseHandler((connection) =>
                {
                    Console.WriteLine("Connection closed - " + connection);
                });

                SSLOptions sslOptions = new SSLOptions(cert, true, true);
                TCPConnectionListener listener = new TCPConnectionListener(NetworkComms.DefaultSendReceiveOptions, 
                    ApplicationLayerProtocolStatus.Enabled, sslOptions);
                Connection.StartListening(listener, new IPEndPoint(localIPAddress, 10000), true);

                Console.WriteLine("\nListening for TCP (SSL) messages on:");
                foreach (IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP)) 
                   Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port);

                Console.WriteLine("\nPress any key to quit.");
                ConsoleKeyInfo key = Console.ReadKey(true);
            }
            else
            {
                ConnectionInfo serverInfo = new ConnectionInfo(new IPEndPoint(localIPAddress, 10000));

                SSLOptions sslOptions = new SSLOptions("networkcomms.net", true);
                //SSLOptions sslOptions = new SSLOptions(cert, true);

                TCPConnection conn = TCPConnection.GetConnection(serverInfo, NetworkComms.DefaultSendReceiveOptions, sslOptions);
                conn.SendObject("Data", sendArray);
                Console.WriteLine("Sent data to server.");

                Console.WriteLine("\nClient complete. Press any key to quit.");
                Console.ReadKey(true);
            }

            NetworkComms.Shutdown();
        }
        public static void RunExample()
        {
            Console.WriteLine("Please select mode:");
            Console.WriteLine("1 - Server (Listens for connections)");
            Console.WriteLine("2 - Client (Creates connections to server)");

            sendReceiveOptions = new SendReceiveOptions<NullSerializer>();
            //RijndaelPSKEncrypter.AddPasswordToOptions(sendReceiveOptions.Options, "test");
            //sendReceiveOptions.DataProcessors.Add(DPSManager.GetDataProcessor<RijndaelPSKEncrypter>());

            //NetworkComms.ConnectionEstablishTimeoutMS = 600000;
            NetworkComms.ConnectionListenModeUseSync = true;

            X509Certificate cert = new X509Certificate2("testCertificate.pfx");
            sslOptions = new SSLOptions(cert, true);

            //Read in user choice
            if (Console.ReadKey(true).Key == ConsoleKey.D1) serverMode = true;
            else serverMode = false;

            UDPConnection.DefaultUDPOptions = UDPOptions.None;

            IPAddress localIPAddress = IPAddress.Parse("::1");
            packetTypeStr = "Unmanaged";

            if (serverMode)
            {
                //NetworkComms.DOSProtection.Enabled = true;

                //NetworkComms.DisableLogging();

                //Listen for connections
                int totalNumberOfListenPorts = 500;

                int portDivisor = 0;
                if ((mode & TestMode.TCP_Managed) == TestMode.TCP_Managed) portDivisor++;
                if ((mode & TestMode.TCP_Unmanaged) == TestMode.TCP_Unmanaged) portDivisor++;
                if ((mode & TestMode.UDP_Managed) == TestMode.UDP_Managed) portDivisor++;
                if ((mode & TestMode.UDP_Unmanaged) == TestMode.UDP_Unmanaged) portDivisor++;
                if ((mode & TestMode.TCPSSL_Managed) == TestMode.TCPSSL_Managed) portDivisor++;

                List<EndPoint> localIPEndPoints = new List<EndPoint>();
                List<ConnectionListenerBase> listeners = new List<ConnectionListenerBase>();
                for (int i = 0; i < totalNumberOfListenPorts/portDivisor; i++)
                {
                    if ((mode & TestMode.TCP_Managed) == TestMode.TCP_Managed)
                    {
                        localIPEndPoints.Add(new IPEndPoint(localIPAddress, 10000 + i));
                        listeners.Add(new TCPConnectionListener(sendReceiveOptions, ApplicationLayerProtocolStatus.Enabled));
                    }

                    if ((mode & TestMode.TCP_Unmanaged) == TestMode.TCP_Unmanaged)
                    {
                        localIPEndPoints.Add(new IPEndPoint(localIPAddress, 20000 + i));
                        listeners.Add(new TCPConnectionListener(sendReceiveOptions, ApplicationLayerProtocolStatus.Disabled));
                    }

                    if ((mode & TestMode.UDP_Managed) == TestMode.UDP_Managed)
                    {
                        localIPEndPoints.Add(new IPEndPoint(localIPAddress, 30000 + i));
                        listeners.Add(new UDPConnectionListener(sendReceiveOptions, ApplicationLayerProtocolStatus.Enabled, UDPConnection.DefaultUDPOptions));
                    }

                    if ((mode & TestMode.UDP_Unmanaged) == TestMode.UDP_Unmanaged)
                    {
                        localIPEndPoints.Add(new IPEndPoint(localIPAddress, 40000 + i));
                        listeners.Add(new UDPConnectionListener(sendReceiveOptions, ApplicationLayerProtocolStatus.Disabled, UDPConnection.DefaultUDPOptions));
                    }

                    if ((mode & TestMode.TCPSSL_Managed) == TestMode.TCPSSL_Managed)
                    {
                        localIPEndPoints.Add(new IPEndPoint(localIPAddress, 50000 + i));
                        listeners.Add(new TCPConnectionListener(sendReceiveOptions, ApplicationLayerProtocolStatus.Enabled, sslOptions));
                    }
                }

                Connection.StartListening(listeners, localIPEndPoints, true);

                object locker = new object();
                int messageCount = 0;
                long totalBytesReceived = 0;
                int tcpFragmentationConcatCount = 0;
                int connectionEstablishCount = 0;
                int connectionCloseCount = 0;

                //List<string> packetSequenceNumbers = new List<string>();

                NetworkComms.AppendGlobalIncomingPacketHandler<byte[]>(packetTypeStr, (header, connection, data) =>
                    {
                        lock (locker)
                        {
                            //long seqNumber = header.GetOption(PacketHeaderLongItems.PacketSequenceNumber);
                            //packetSequenceNumbers.Add(connection.ToString() + "," + seqNumber);

                            //Increment a global counter
                            messageCount++;

                            if (data.Length != testDataSize)
                                tcpFragmentationConcatCount++;

                            totalBytesReceived += data.Length;
                        }
                    }, sendReceiveOptions);

                //Establish handler
                NetworkComms.AppendGlobalConnectionEstablishHandler((connection) =>
                    { lock (locker)
                        connectionEstablishCount++;
                    });

                //Close handler
                NetworkComms.AppendGlobalConnectionCloseHandler((connection) =>
                {
                    lock (locker)
                        connectionCloseCount++;
                });

                //Save the ports list out to disk
                using (StreamWriter sw = new StreamWriter("TCPServerPorts.txt", false))
                {
                    List<EndPoint> localListenEndPoints = Connection.ExistingLocalListenEndPoints(ConnectionType.TCP);
                    foreach (IPEndPoint endPoint in localListenEndPoints)
                    {
                        if (Connection.ExistingLocalListeners<TCPConnectionListener>(endPoint)[0].ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
                            sw.WriteLine("T-"+endPoint.Address.ToString() + "-" + endPoint.Port);
                        else
                            sw.WriteLine("F-" + endPoint.Address.ToString() + "-" + endPoint.Port);
                    }
                }

                //Save the ports list out to disk
                using (StreamWriter sw = new StreamWriter("UDPServerPorts.txt", false))
                {
                    List<EndPoint> localListenEndPoints = Connection.ExistingLocalListenEndPoints(ConnectionType.UDP);
                    foreach (IPEndPoint endPoint in localListenEndPoints)
                    {
                        if (Connection.ExistingLocalListeners<UDPConnectionListener>(endPoint)[0].ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
                            sw.WriteLine("T-" + endPoint.Address.ToString() + "-" + endPoint.Port);
                        else
                            sw.WriteLine("F-" + endPoint.Address.ToString() + "-" + endPoint.Port);
                    }
                }

                Console.WriteLine("\nSelected mode = {0}, UDPOptions = {1}", mode, UDPConnection.DefaultUDPOptions);
                Console.WriteLine("Connection close after send = {0}", (closeConnectionAfterSend? "TRUE" : "FALSE"));
                Console.WriteLine("\nListening for incoming connections on {0} ports. Press 'c' key to see message count.", totalNumberOfListenPorts);

                while (true)
                {
                    ConsoleKeyInfo key = Console.ReadKey(true);
                    if (key.KeyChar == 'c')
                    {
                        Console.WriteLine("#Handlers={0}, #Data={2}, #TCPFragConcat={1}, #Establish={3}, #Close={4}. Press 'c' to refresh message count, any other key to quit.", messageCount, tcpFragmentationConcatCount, totalBytesReceived / (double)testDataSize, connectionEstablishCount, connectionCloseCount);
                        //using (StreamWriter sw = new StreamWriter("seqNumbers.txt", false))
                        //{
                        //    List<string> copy = packetSequenceNumbers.ToList();
                        //    foreach (string line in copy)
                        //        sw.WriteLine(line);
                        //}
                    }
                    else
                        break;
                }
            }
            else
            {
                //NetworkComms.DisableLogging();

                //Load server port list
                string[] tcpServerPortList = File.ReadAllLines("TCPServerPorts.txt");
                TCPServerEndPoints = new Dictionary<IPEndPoint, ApplicationLayerProtocolStatus>();
                foreach (string current in tcpServerPortList)
                    TCPServerEndPoints.Add(new IPEndPoint(IPAddress.Parse(current.Split('-')[1]), int.Parse(current.Split('-')[2])), (current.Substring(0, 1) == "T" ? ApplicationLayerProtocolStatus.Enabled : ApplicationLayerProtocolStatus.Disabled));

                TCPServerEndPointsKeys = TCPServerEndPoints.Keys.ToList();

                string[] udpServerPortList = File.ReadAllLines("UDPServerPorts.txt");
                UDPServerEndPoints = new Dictionary<IPEndPoint, ApplicationLayerProtocolStatus>();
                foreach (string current in udpServerPortList)
                    UDPServerEndPoints.Add(new IPEndPoint(IPAddress.Parse(current.Split('-')[1]), int.Parse(current.Split('-')[2])), (current.Substring(0, 1) == "T" ? ApplicationLayerProtocolStatus.Enabled : ApplicationLayerProtocolStatus.Disabled));

                //UDPConnectionListener udpListener = new UDPConnectionListener(sendReceiveOptions,
                //    ((UDPConnection.DefaultUDPOptions & UDPOptions.Handshake) != UDPOptions.Handshake ? ApplicationLayerProtocolStatus.Disabled : ApplicationLayerProtocolStatus.Enabled), 
                //    UDPConnection.DefaultUDPOptions);
                //Connection.StartListening(udpListener, new IPEndPoint(localIPAddress, 10010), true);

                Console.WriteLine("Listening for connections on:");
                foreach (System.Net.IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.UDP)) 
                    Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port);

                UDPServerEndPointsKeys = UDPServerEndPoints.Keys.ToList();

                Console.WriteLine("\nLoaded {0} TCP & {1} UDP server ports. Press any key to start the hammer!", TCPServerEndPoints.Count, UDPServerEndPointsKeys.Count);
                Console.ReadKey(true);
                Console.WriteLine("It's hammer time ...");

                clientHammerData = new byte[testDataSize];

                //Lets start by making as many connections as possible, go to absolute maximum performance
                ParallelOptions options = new ParallelOptions();
                options.MaxDegreeOfParallelism = 8;

                Stopwatch timer = new Stopwatch();
                timer.Start();
                Parallel.For(0, connectionHammerExecCount, options, ConnectionHammer);
                timer.Stop();

                Console.WriteLine("\nCompleted {0} connections in {1} secs. {2}ms per connection. {3} exceptions. Press any key to quit.", connectionHammerExecCount * connectionsPerHammer, (timer.ElapsedMilliseconds / 1000.0).ToString("0.00"), ((double)timer.ElapsedMilliseconds / (connectionHammerExecCount * connectionsPerHammer)).ToString("0.00"), exceptionCount);
                Console.ReadKey(true);
            }

            NetworkComms.Shutdown();
        }
        /// <summary>
        /// Select the SSL options
        /// </summary>
        private static void SelectSSLOptions()
        {
            int selectedOption;

            //Configure the server options
            //These will be applied for incoming connections
            Console.WriteLine("\nRequire connecting clients to provide certificate?\n1 - Yes (Connection will only be successful if client provides certificate.) \n2 - No (Client only requires certificate name to connect.)");
            while (true)
            {
                bool parseSucces = int.TryParse(Console.ReadKey(true).KeyChar.ToString(), out selectedOption);
                if (parseSucces && selectedOption <= 2) break;
                Console.WriteLine("Invalid connection type choice. Please try again.");
            }

            if (selectedOption == 1)
            {
                Console.WriteLine(" ... selected yes.");
                listenerSSLOptions = new SSLOptions(certificate, true, true);
            }
            else if (selectedOption == 2)
            {
                Console.WriteLine(" ... selected no.");
                listenerSSLOptions = new SSLOptions(certificate, true, false);
            }
            else
                throw new Exception("Unable to determine selected option.");

            //Configure the connection options
            //These will be used when establishing outgoing connections
            Console.WriteLine("\nProvide certificate for outgoing connections?\n1 - Yes (Connection will only be successful if client and server certificate match.)\n2 - No (Client will accept any certificate from server.)");
            while (true)
            {
                bool parseSucces = int.TryParse(Console.ReadKey(true).KeyChar.ToString(), out selectedOption);
                if (parseSucces && selectedOption <= 2) break;
                Console.WriteLine("Invalid connection type choice. Please try again.");
            }

            if (selectedOption == 1)
            {
                Console.WriteLine(" ... selected yes.");
                connectionSSLOptions = new SSLOptions(certificate, true);
            }
            else if (selectedOption == 2)
            {
                Console.WriteLine(" ... selected no.");
                connectionSSLOptions = new SSLOptions("networkcomms.net", true);
            }
            else
                throw new Exception("Unable to determine selected option.");

            //Select if the dataPadder will be enabled
            Console.WriteLine("\nWhen sending encrypted data"+
            " the quantity of traffic can give away a significant amount of information. To prevent this"+
            " traffic analysis attack we have included a data processor which if enabled ensures every packet sent"+
            " is of a fixed size. Do you want to enable this padding data processor? " + "\n1 - Yes\n2 - No");
            while (true)
            {
                bool parseSucces = int.TryParse(Console.ReadKey(true).KeyChar.ToString(), out selectedOption);
                if (parseSucces && selectedOption <= 2) break;
                Console.WriteLine("Invalid choice. Please try again.");
            }

            if (selectedOption == 1)
            {
                Console.WriteLine(" ... selected yes.");
                sendingSendReceiveOptions = new SendReceiveOptions<ProtobufSerializer, DataPadder>();
                DataPadder.AddPaddingOptions(sendingSendReceiveOptions.Options, 1024, DataPadder.DataPaddingType.Random, true);
            }
            else if (selectedOption == 2)
            {
                Console.WriteLine(" ... selected no.");
                sendingSendReceiveOptions = NetworkComms.DefaultSendReceiveOptions;
            }
            else
                throw new Exception("Unable to determine selected option.");
        }