private static async Task CrossoverBindingAsync(CancellationToken cancelToken, BindingInfo sourceBinding, BindingInfo destBinding)
        {
            while (!cancelToken.IsCancellationRequested)
            {
                switch (sourceBinding.BindingType)
                {
                case BindingType.NamedPipe:
                {
                    using (
                        var pipeServer = new NamedPipeServerStream(
                            sourceBinding.Address,
                            PipeDirection.InOut,
                            1,
                            PipeTransmissionMode.Byte,
                            PipeOptions.Asynchronous,
                            4096,
                            4096))
                    {
                        while (!cancelToken.IsCancellationRequested)
                        {
                            pipeServer.WaitForConnection();
                            Console.WriteLine("Connection from " + sourceBinding);

                            if (pipeServer.IsConnected)
                            {
                                var serverStream = new PluggableStream(pipeServer);
                                try
                                {
                                    await ClientConnectAsync(cancelToken, serverStream, destBinding);
                                }
                                catch (OperationCanceledException e)
                                {
                                    Console.WriteLine(e.Message);
                                }
                            }
                            pipeServer.Disconnect();
                        }

                        break;
                    }
                }

                case BindingType.Serial:
                {
                    SerialPort serialPortServer;
                    try
                    {
                        serialPortServer = new SerialPort(
                            String.Format("COM{0}", sourceBinding.Port), 115200, Parity.None, 8, StopBits.One);
                        serialPortServer.Open();
                        serialPortServer.DtrEnable = true;
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // could not connect COM port, disconnect the client
                        serialPortServer = null;
                        throw new OperationCanceledException();
                    }

                    if (serialPortServer != null)
                    {
                        Console.WriteLine("Connection from " + sourceBinding);
                        var serverStream = new PluggableStream(serialPortServer.BaseStream);
                        await ClientConnectAsync(cancelToken, serverStream, destBinding);

                        serialPortServer.Close();
                    }

                    break;
                }

                case BindingType.Socket:
                {
                    var ep = new IPEndPoint(IPAddress.Parse(sourceBinding.Address), sourceBinding.Port ?? 80);
                    using (var socketServer = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
                    {
                        socketServer.Bind(ep);
                        socketServer.Listen(1);
                        while (!cancelToken.IsCancellationRequested)
                        {
                            using (var dataSocket = socketServer.Accept())
                            {
                                dataSocket.NoDelay = true;
                                Console.WriteLine("Connection from " + sourceBinding);
                                var serverStream = new PluggableSocket(dataSocket);
                                try
                                {
                                    await ClientConnectAsync(cancelToken, serverStream, destBinding);
                                }
                                catch (OperationCanceledException e)
                                {
                                    Console.WriteLine(e.Message);
                                }
                            }
                        }
                    }
                    break;
                }
                }
            }
        }
        private static async Task ClientConnectAsync(CancellationToken cancelToken, IPluggableStreamAsync serverStream, BindingInfo clientBinding)
        {
            IPluggableStreamAsync clientStream;

            if (clientBinding.BindingType == BindingType.Serial)
            {
                using (var serialPortClient = new SerialPort(string.Format("COM{0}", clientBinding.Port), 115200, Parity.None, 8, StopBits.One))
                {
                    try
                    {
                        serialPortClient.DtrEnable = true;
                        serialPortClient.Open();
                    }
                    catch (UnauthorizedAccessException)
                    {
                        throw new InvalidOperationException("Could not connect COM port");
                    }

                    clientStream = new PluggableStream(serialPortClient.BaseStream);
                    Console.WriteLine("Connection made");
                    await StreamCrossover.HandleClientAsync(cancelToken, serverStream, clientStream);
                }
            }
            else if (clientBinding.BindingType == BindingType.Socket)
            {
                var ep = new IPEndPoint(IPAddress.Parse(clientBinding.Address), clientBinding.Port ?? 80);
                while (!cancelToken.IsCancellationRequested)
                {
                    using (var socketClient = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
                    {
                        try
                        {
                            socketClient.Connect(ep);
                        }
                        catch (SocketException e)
                        {
                            Console.WriteLine("Exception connecting to outgoing host: " + e + ": " + e.Message);
                            await Task.Delay(10000);

                            continue;
                        }

                        socketClient.NoDelay = true;

                        clientStream = new PluggableSocket(socketClient);
                        Console.WriteLine("Connection made");

                        try
                        {
                            await StreamCrossover.HandleClientAsync(cancelToken, serverStream, clientStream);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                        }

                        socketClient.Disconnect(false);

                        if (!serverStream.IsConnected())
                        {
                            return;
                        }
                    }
                }
            }
            else if (clientBinding.BindingType == BindingType.NamedPipe)
            {
                using (var pipeClient = new NamedPipeClientStream(".", clientBinding.Address, PipeDirection.InOut, PipeOptions.Asynchronous))
                {
                    pipeClient.Connect();
                    if (!pipeClient.IsConnected)
                    {
                        return;
                    }

                    clientStream = new PluggableStream(pipeClient);
                    Console.WriteLine("Connection made");

                    try
                    {
                        await StreamCrossover.HandleClientAsync(cancelToken, serverStream, clientStream);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
        }