Example #1
0
        //internal void DeregisterConnection(ForwardingConnection con) {
        //    lock (connections) {
        //        connections.Remove(con.ConId);
        //    }
        //}

        public async Task RunAsync()
        {
            // Ensure that exceptions thrown by listener.Start() are thrown in this thread
            // TODO: make the number of backlog queue configurable
            listener.Start(1000);

            while (true)
            {
                // Wait for the concurrent connections semaphore.
                await concurrentConnectionsSemaphore.WaitAsync();

                TcpClient client;
                try {
                    client = await listener.AcceptTcpClientAsync();
                } catch (ObjectDisposedException ex) {
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
                    // Listener has been stopped.
                    // Ignore
                    return;
                }

                BigInteger conId = nextConId++;
                Func <SemaphoreSlim, Task> waitForSendingDelegate   = sem => ConnectionWaitForSending(sem, true);
                Func <SemaphoreSlim, Task> waitForReceivingDelegate = sem => ConnectionWaitForSending(sem, false);


                IPAddress[] bindAndConnectAddresses = new IPAddress[2];
                if (RemoteHost == "[localhost-random]")
                {
                    for (int i = 0; i < bindAndConnectAddresses.Length; i++)
                    {
                        // Generate two random addresses in the range 127.0.0.1-127.255.255.254.
                        // Bind to one of these addresses as local endpoint and use the other one for the remote endpoint.
                        // This ensures that if a lot of connections are opened and closed in a very short time, that we do not
                        // get errors that an address+port has been used multiple times when opening new connections (as the TCP/IP standard
                        // defines that between consecutive connections using the same combination of a specific local endpoint (adr+port) and a specific remote endpoint (adr+port)
                        // some time must pass, to minimize data corruption).
                        // If we use random addresses in the above range we are minimizing the risk of using the same adr+port again in a short time interval.

                        byte[] adr;
                        adr    = new byte[4];
                        adr[0] = 127;

                        // TODO: Currently, for the last byte only numbers in the range 1-254 are generated although a address like
                        // 127.2.3.255 would be OK (but 127.255.255-255 wouldn't).
                        for (int x = 1; x < adr.Length; x++)
                        {
                            adr[x] = (byte)(localhostAddressRNG.Next(254 + (x != 3 ? 2 : 0)) + (x == 3 ? 1 : 0));
                        }

                        bindAndConnectAddresses[i] = new IPAddress(adr);
                    }
                }

                ForwardingConnection con = new ForwardingConnection(this, client, conId, bindAndConnectAddresses[0], bindAndConnectAddresses[1], waitForSendingDelegate, waitForReceivingDelegate, concurrentConnectionsSemaphore);

                //lock (connections) {
                //    connections.Add(con.ConId, con);
                //}

                OnConnectionAccepted(con);

                // TODO maybe save the Task somewhere.
                Task t = ExceptionUtils.WrapTaskForHandlingUnhandledExceptions(async() => await con.Run());
            }
        }