public static CancellationTokenSource ConsumeReceived(this UdpClient client, Action <UdpReceiveResult> consume)
        {
            var tokenSource = new CancellationTokenSource();

            client.ConsumeReceived(consume, tokenSource.Token);
            return(tokenSource);
        }
        public MessageTransport(string addressOrHostname, CryptoContext crypto)
        {
            _addressOrHostname = addressOrHostname;
            _crypto            = crypto;

            _client = _addressOrHostname != null ?
                      new UdpClient(_addressOrHostname, 5050) :
                      new UdpClient(AddressFamily.InterNetwork);

            if (_addressOrHostname == null)
            {
                _client.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
            }

            _cancellationTokenSource = _client.ConsumeReceived(receiveResult =>
            {
                var reader = new BEReader(receiveResult.Buffer);

                var messageType = (MessageType)reader.ReadUInt16();
                reader.Position = 0;

                var message = CreateFromMessageType(messageType);
                if (message == null)
                {
                    // TODO: Tracing for this.
                    return;
                }

                var cryptoMessage = message as ICryptoMessage;
                if (cryptoMessage != null)
                {
                    cryptoMessage.Crypto = _crypto;
                }

                message.Origin = receiveResult.RemoteEndPoint;
                message.ClientReceivedTimestamp = DateTime.Now;
                message.Deserialize(reader);

                _receiveQueue.TryAdd(message);
            });

            Task.Run(() =>
            {
                while (!_receiveQueue.IsCompleted)
                {
                    try
                    {
                        var message = _receiveQueue.Take();
                        MessageReceived?.Invoke(this, new MessageReceivedEventArgs <IMessage>(message));
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.ToString());
                        Console.WriteLine("Calling MessageReceived failed!");
                    }
                }
            });
        }
        public NanoRdpTransport(string address, int tcpPort, int udpPort)
        {
            _address = address;
            _tcpPort = tcpPort;
            _udpPort = udpPort;

            IPAddress hostAddr = IPAddress.Parse(address);

            _controlProtoEp   = new IPEndPoint(hostAddr, _tcpPort);
            _streamingProtoEp = new IPEndPoint(hostAddr, _udpPort);

            _controlProtoClient   = new TcpClient(AddressFamily.InterNetwork);
            _streamingProtoClient = new UdpClient(AddressFamily.InterNetwork);

            _controlProtoClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
            _streamingProtoClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0));

            _controlProtoClient.Connect(_controlProtoEp);
            _streamingProtoClient.Connect(_streamingProtoEp);

            _cancellationTokenSourceControl = _controlProtoClient.ConsumeReceived(receiveResult =>
            {
                BEReader reader  = new BEReader(receiveResult);
                RtpPacket packet = RtpPacket.CreateFromBuffer(reader);
                _receiveQueue.TryAdd(packet);
            });

            _cancellationTokenSourceStreaming = _streamingProtoClient.ConsumeReceived(receiveResult =>
            {
                // Lets NanoClient know when to end sending UDP handshake packets
                if (!udpDataActive)
                {
                    udpDataActive = true;
                }

                BEReader reader  = new BEReader(receiveResult.Buffer);
                RtpPacket packet = RtpPacket.CreateFromBuffer(reader);
                _receiveQueue.TryAdd(packet);
            });

            Task.Run(() =>
            {
                while (!_receiveQueue.IsCompleted)
                {
                    try
                    {
                        var message = _receiveQueue.Take();
                        MessageReceived?.Invoke(this, new MessageReceivedEventArgs <RtpPacket>(message));
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.ToString());
                        Console.WriteLine("Calling Nano MessageReceived failed!");
                    }
                }
            });
        }
        public NanoRdpTransport(string address, int tcpPort, int udpPort)
        {
            _address = address;
            _tcpPort = tcpPort;
            _udpPort = udpPort;

            _cancellationTokenSource = new CancellationTokenSource();
            IPAddress hostAddr = IPAddress.Parse(address);

            _controlProtoEp   = new IPEndPoint(hostAddr, _tcpPort);
            _streamingProtoEp = new IPEndPoint(hostAddr, _udpPort);

            _controlProtoClient   = new TcpClient(AddressFamily.InterNetwork);
            _streamingProtoClient = new UdpClient(AddressFamily.InterNetwork);

            _controlProtoClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
            _streamingProtoClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0));

            _controlProtoClient.Connect(_controlProtoEp);
            _streamingProtoClient.Connect(_streamingProtoEp);

            ChannelContext = new NanoChannelContext();

            void ProcessPacket(byte[] packetData)
            {
                try
                {
                    EndianReader reader = new EndianReader(packetData);
                    INanoPacket  packet = NanoPacketFactory.ParsePacket(packetData, ChannelContext);

                    if (packet.Header.PayloadType == NanoPayloadType.ChannelControl &&
                        packet as ChannelCreate != null)
                    {
                        ChannelContext.RegisterChannel((ChannelCreate)packet);
                    }
                    else if (packet.Header.PayloadType == NanoPayloadType.ChannelControl &&
                             packet as ChannelClose != null)
                    {
                        ChannelContext.UnregisterChannel((ChannelClose)packet);
                    }
                    else if (RemoteConnectionId == 0 && packet as ControlHandshake != null)
                    {
                        RemoteConnectionId = ((ControlHandshake)packet).ConnectionId;
                    }

                    bool success = _receiveQueue.TryAdd(packet);
                    if (!success)
                    {
                        LogTool.Log($"Failed to add message to receive queue");
                    }
                }
                catch (NanoPackingException e)
                {
                    LogTool.LogError($"Failed to parse nano packet: {e.Message}", e);
                }
            }

            _controlProtoClient.ConsumeReceivedPrefixed(
                receiveResult => ProcessPacket(receiveResult),
                _cancellationTokenSource.Token
                );

            _streamingProtoClient.ConsumeReceived(
                receiveResult => ProcessPacket(receiveResult.Buffer),
                _cancellationTokenSource.Token
                );

            Task.Run(() =>
            {
                while (!_receiveQueue.IsCompleted)
                {
                    try
                    {
                        var message = _receiveQueue.Take();
                        MessageReceived?.Invoke(this, new MessageReceivedEventArgs <INanoPacket>(message));
                    }
                    catch (Exception e)
                    {
                        LogTool.LogError(
                            e, "Calling Nano MessageReceived failed!");
                    }
                }
            }, _cancellationTokenSource.Token);
        }