Task SendAndReceive(RelayConnection connection)
        {
            // implements a simple protocol that uploads and downloads 1MB of data
            // since the connection is duplex, this happens in parallel.

            Console.WriteLine("Processing connection");
            // download
            var download = Task.Run(async () =>
            {
                Console.WriteLine("Downloading 1MByte");
                var buf = new byte[1024*1024];
                int bytesRead;
                do
                {
                    bytesRead = await connection.ReadAsync(buf, 0, buf.Length);
                } while (bytesRead > 0);
                Console.WriteLine("Download done");
            });

            // upload
            var upload = Task.Run(async () =>
            {
                Console.WriteLine("Uploading 1MByte");
                var buf = new byte[16*1024];
                for (var i = 0; i < 1024/16; i++)
                {
                    rnd.NextBytes(buf);
                    await connection.WriteAsync(buf, 0, buf.Length);
                }
                await connection.ShutdownAsync();
                Console.WriteLine("Upload done");
            });
            return Task.WhenAll(upload, download);
        }
        async Task ProcessConnection(RelayConnection connection)
        {
            // implements a simple protocol that uploads and downloads 1MB of data
            // since the connection is duplex, this happens in parallel.

            Console.WriteLine("Processing connection");
            // download
            var download = Task.Run(async () =>
            {
                Console.WriteLine("downloading data");
                var buf = new byte[1024*1024];
                int totalBytes = 0, bytesRead;
                do
                {
                    totalBytes += bytesRead = await connection.ReadAsync(buf, 0, buf.Length);
                }
                while (bytesRead > 0);
                Console.WriteLine("downloaded complete, {0} bytes", totalBytes);
            });

            // upload
            var upload = Task.Run(async () =>
            {
                var buf = new byte[1024];
                for (var i = 0; i < 1024; i++)
                {
                    Rnd.NextBytes(buf);
                    await connection.WriteAsync(buf, 0, buf.Length);
                }
                await connection.ShutdownAsync();
            });
            Task.WaitAll(upload, download);
            connection.Close();
            Console.WriteLine("Connection done");
        }