/// <summary>
        /// Disconnects the specified client.
        /// </summary>
        /// <param name="ipPort">IP:port of the client.</param>
        public void DisconnectClient(string ipPort)
        {
            if (String.IsNullOrEmpty(ipPort))
            {
                throw new ArgumentNullException(nameof(ipPort));
            }

            ClientMetadata client = null;

            if (!_Clients.TryGetValue(ipPort, out client))
            {
                Logger?.Invoke(_Header + "unable to find client: " + ipPort);
            }
            else
            {
                if (!_ClientsTimedout.ContainsKey(ipPort))
                {
                    Logger?.Invoke(_Header + "kicking: " + ipPort);
                    _ClientsKicked.TryAdd(ipPort, DateTime.Now);
                }
            }

            if (client != null)
            {
                if (!client.TokenSource.IsCancellationRequested)
                {
                    client.TokenSource.Cancel();
                    Logger?.Invoke(_Header + "requesting disposal of: " + ipPort);
                }

                client.Dispose();
            }
        }
Пример #2
0
        private async Task <bool> StartTls(ClientMetadata client)
        {
            try
            {
                await client.SslStream.AuthenticateAsServerAsync(
                    _SslCertificate,
                    MutuallyAuthenticate,
                    SslProtocols.Tls12,
                    !AcceptInvalidCertificates);

                if (!client.SslStream.IsEncrypted)
                {
                    Logger?.Invoke("[SimpleTcp.Server] Client " + client.IpPort + " not encrypted, disconnecting");
                    client.Dispose();
                    return(false);
                }

                if (!client.SslStream.IsAuthenticated)
                {
                    Logger?.Invoke("[SimpleTcp.Server] Client " + client.IpPort + " not SSL/TLS authenticated, disconnecting");
                    client.Dispose();
                    return(false);
                }

                if (MutuallyAuthenticate && !client.SslStream.IsMutuallyAuthenticated)
                {
                    Logger?.Invoke("[SimpleTcp.Server] Client " + client.IpPort + " failed mutual authentication, disconnecting");
                    client.Dispose();
                    return(false);
                }
            }
            catch (Exception e)
            {
                Logger?.Invoke("[SimpleTcp.Server] Client " + client.IpPort + " SSL/TLS exception: " + Environment.NewLine + e.ToString());
                client.Dispose();
                return(false);
            }

            return(true);
        }
Пример #3
0
        private async Task <bool> StartTls(ClientMetadata client)
        {
            try
            {
                await client.SslStream.AuthenticateAsServerAsync(
                    _SslCertificate,
                    MutuallyAuthenticate,
                    SslProtocols.Tls12,
                    !AcceptInvalidCertificates);

                if (!client.SslStream.IsEncrypted)
                {
                    Log("[" + client.IpPort + "] not encrypted");
                    client.Dispose();
                    return(false);
                }

                if (!client.SslStream.IsAuthenticated)
                {
                    Log("[" + client.IpPort + "] stream not authenticated");
                    client.Dispose();
                    return(false);
                }

                if (MutuallyAuthenticate && !client.SslStream.IsMutuallyAuthenticated)
                {
                    Log("[" + client.IpPort + "] failed mutual authentication");
                    client.Dispose();
                    return(false);
                }
            }
            catch (Exception e)
            {
                Log("[" + client.IpPort + "] TLS exception" + Environment.NewLine + e.ToString());
                client.Dispose();
                return(false);
            }

            return(true);
        }
Пример #4
0
        private async Task DataReceiver(ClientMetadata client)
        {
            Logger?.Invoke("[SimpleTcp.Server] Data receiver started for client " + client.IpPort);

            while (true)
            {
                try
                {
                    if (client.Token.IsCancellationRequested ||
                        !IsClientConnected(client.Client))
                    {
                        Logger?.Invoke("[SimpleTcp.Server] Client " + client.IpPort + " disconnected");
                        break;
                    }

                    if (client.Token.IsCancellationRequested)
                    {
                        Logger?.Invoke("[SimpleTcp.Server] Cancellation requested (data receiver for client " + client.IpPort + ")");
                        break;
                    }

                    byte[] data = await DataReadAsync(client);

                    if (data == null)
                    {
                        await Task.Delay(30);

                        continue;
                    }

                    DataReceived?.Invoke(this, new DataReceivedFromClientEventArgs(client.IpPort, data));
                    _Stats.ReceivedBytes += data.Length;
                    UpdateClientLastSeen(client.IpPort);
                }
                catch (SocketException)
                {
                    Logger?.Invoke("[SimpleTcp.Server] Data receiver socket exception (disconnection) for " + client.IpPort);
                }
                catch (Exception e)
                {
                    Logger?.Invoke("[SimpleTcp.Server] Data receiver exception for client " + client.IpPort + ":" +
                                   Environment.NewLine +
                                   e.ToString() +
                                   Environment.NewLine);

                    break;
                }
            }

            Logger?.Invoke("[SimpleTcp.Server] Data receiver terminated for client " + client.IpPort);

            if (_ClientsKicked.ContainsKey(client.IpPort))
            {
                ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Kicked));
            }
            else if (_ClientsTimedout.ContainsKey(client.IpPort))
            {
                ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Timeout));
            }
            else
            {
                ClientDisconnected?.Invoke(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Normal));
            }

            DateTime removedTs;

            _Clients.TryRemove(client.IpPort, out ClientMetadata destroyed);
            _ClientsLastSeen.TryRemove(client.IpPort, out removedTs);
            _ClientsKicked.TryRemove(client.IpPort, out removedTs);
            _ClientsTimedout.TryRemove(client.IpPort, out removedTs);
            client.Dispose();
        }
Пример #5
0
        private async void AcceptConnections()
        {
            while (!_Token.IsCancellationRequested)
            {
                ClientMetadata client = null;

                try
                {
                    System.Net.Sockets.TcpClient tcpClient = await _Listener.AcceptTcpClientAsync();

                    string clientIp = tcpClient.Client.RemoteEndPoint.ToString();

                    client = new ClientMetadata(tcpClient);

                    if (_Ssl)
                    {
                        if (AcceptInvalidCertificates)
                        {
                            client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(AcceptCertificate));
                        }
                        else
                        {
                            client.SslStream = new SslStream(client.NetworkStream, false);
                        }

                        bool success = await StartTls(client);

                        if (!success)
                        {
                            client.Dispose();
                            continue;
                        }
                    }

                    _Clients.TryAdd(clientIp, client);
                    _ClientsLastSeen.TryAdd(clientIp, DateTime.Now);
                    Logger?.Invoke("[SimpleTcp.Server] Starting data receiver for: " + clientIp);
                    ClientConnected?.Invoke(this, new ClientConnectedEventArgs(clientIp));
                    Task unawaited = Task.Run(() => DataReceiver(client), _Token);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (ObjectDisposedException)
                {
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    continue;
                }
                catch (Exception e)
                {
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    Logger?.Invoke("[SimpleTcp.Server] Exception while awaiting connections: " + e.ToString());
                    continue;
                }
            }
        }
Пример #6
0
        private async Task DataReceiver(ClientMetadata client)
        {
            Logger?.Invoke(_Header + "data receiver started for client " + client.IpPort, TCPLogType.Debug);

            while (true)
            {
                try
                {
                    if (client.Token.IsCancellationRequested ||
                        !IsClientConnected(client.Client))
                    {
                        Logger?.Invoke(_Header + "client " + client.IpPort + " disconnected", TCPLogType.Debug);
                        break;
                    }

                    if (client.Token.IsCancellationRequested)
                    {
                        Logger?.Invoke(_Header + "cancellation requested (data receiver for client " + client.IpPort + ")", TCPLogType.Debug);
                        break;
                    }

                    byte[] m_Buffer = await DataReadAsync(client);

                    if (m_Buffer == null)
                    {
                        await Task.Delay(30);

                        continue;
                    }

                    int BufferStart = 0;
                    int nBytesRec   = m_Buffer.Length;

                    // We support the PROXY protocol (currently v1)
                    // PROXY TCP4 192.168.0.37 192.168.0.121 57307 16248\r\n
                    // PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n
                    // \x0D \x0A \x0D \x0A \x00 \x0D \x0A \x51 \x55 \x49 \x54 \x0A
                    // Min 32 bytes, max 108 bytes
                    if (nBytesRec > 32 && m_Buffer[0] == 'P' && m_Buffer[1] == 'R' && m_Buffer[2] == 'O' && m_Buffer[3] == 'X' && m_Buffer[4] == 'Y' && m_Buffer[5] == ' ')
                    {
                        try
                        {
                            string   msg        = Encoding.UTF8.GetString(m_Buffer, 0, Math.Min(108, nBytesRec)); // 108 is the max we need to parse
                            string[] proxy      = msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                            string[] proxyparts = proxy[0].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);

                            client.OriginalIP       = IPAddress.Parse(proxyparts[2]);
                            client.OriginalSrcPort  = int.Parse(proxyparts[4]);
                            client.OriginalDestPort = int.Parse(proxyparts[5]);

                            client.IsProxied = true;

                            int split = msg.IndexOf("\r\n");

                            if (split > 32)
                            {
                                nBytesRec  -= split + 2;
                                BufferStart = split + 2;
                            }
                        }
                        catch (Exception)
                        {
                        }
                    }

                    byte[] package = new byte[nBytesRec];
                    Buffer.BlockCopy(m_Buffer, BufferStart, package, 0, nBytesRec);

                    var args = new DataReceivedFromClientEventArgs(client.IpPort, package, client.IncomingProtocol, client.Client.Client.RemoteEndPoint);
                    args.Data     = package;
                    args.Protocol = client.IncomingProtocol;

                    if (client.IsWebSocket)
                    {
                        args.WebSocketFrame = DecodeWebSocketMessage(package);

                        if (args.WebSocketFrame.OpCode == 0x9)
                        {
                            package[0] = (byte)((package[0] & 0xF0) + 0xA);
                            Send(client.IpPort, package);

                            return;
                        }
                    }

                    if (client.IsProxied)
                    {
                        args.OriginalIP       = client.OriginalIP;
                        args.OriginalSrcPort  = client.OriginalSrcPort;
                        args.OriginalDestPort = client.OriginalDestPort;
                    }

                    _Events.HandleDataReceived(this, args);
                    _Statistics.ReceivedBytes += package.Length;
                    UpdateClientLastSeen(client.IpPort);
                }
                catch (SocketException)
                {
                    Logger?.Invoke(_Header + "data receiver socket exception (disconnection) for " + client.IpPort, TCPLogType.Debug);
                }
                catch (Exception e)
                {
                    Logger?.Invoke(_Header + "data receiver exception for client " + client.IpPort + ":" +
                                   Environment.NewLine +
                                   e.ToString() +
                                   Environment.NewLine, TCPLogType.Warn);

                    break;
                }
            }

            Logger?.Invoke(_Header + "data receiver terminated for client " + client.IpPort, TCPLogType.Debug);

            if (_ClientsKicked.ContainsKey(client.IpPort))
            {
                _Events.HandleClientDisconnected(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Kicked));
            }
            else if (_ClientsTimedout.ContainsKey(client.IpPort))
            {
                _Events.HandleClientDisconnected(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Timeout));
            }
            else
            {
                _Events.HandleClientDisconnected(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Normal));
            }

            DateTime removedTs;

            _Clients.TryRemove(client.IpPort, out ClientMetadata destroyed);
            _ClientsLastSeen.TryRemove(client.IpPort, out removedTs);
            _ClientsKicked.TryRemove(client.IpPort, out removedTs);
            _ClientsTimedout.TryRemove(client.IpPort, out removedTs);
            client.Dispose();
        }
Пример #7
0
        private async Task DataReceiver(ClientMetadata client)
        {
            Logger?.Invoke(_Header + "data receiver started for client " + client.IpPort);

            CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_Token, client.Token);

            while (true)
            {
                try
                {
                    if (!IsClientConnected(client.Client))
                    {
                        Logger?.Invoke(_Header + "client " + client.IpPort + " disconnected");
                        break;
                    }

                    if (client.Token.IsCancellationRequested)
                    {
                        Logger?.Invoke(_Header + "cancellation requested (data receiver for client " + client.IpPort + ")");
                        break;
                    }

                    byte[] data = await DataReadAsync(client, linkedCts.Token).ConfigureAwait(false);

                    if (data == null)
                    {
                        await Task.Delay(10).ConfigureAwait(false);

                        continue;
                    }

                    Task unawaited = Task.Run(() => _Events.HandleDataReceived(this, new DataReceivedFromClientEventArgs(client.IpPort, data)), linkedCts.Token);
                    _Statistics.ReceivedBytes += data.Length;
                    UpdateClientLastSeen(client.IpPort);
                }
                catch (IOException)
                {
                    Logger?.Invoke(_Header + "data receiver canceled, peer disconnected [" + client.IpPort + "]");
                }
                catch (SocketException)
                {
                    Logger?.Invoke(_Header + "data receiver canceled, peer disconnected [" + client.IpPort + "]");
                }
                catch (TaskCanceledException)
                {
                    Logger?.Invoke(_Header + "data receiver task canceled [" + client.IpPort + "]");
                }
                catch (ObjectDisposedException)
                {
                    Logger?.Invoke(_Header + "data receiver canceled due to disposal [" + client.IpPort + "]");
                }
                catch (Exception e)
                {
                    Logger?.Invoke(_Header + "data receiver exception [" + client.IpPort + "]:" +
                                   Environment.NewLine +
                                   e.ToString() +
                                   Environment.NewLine);

                    break;
                }
            }

            Logger?.Invoke(_Header + "data receiver terminated for client " + client.IpPort);

            if (_ClientsKicked.ContainsKey(client.IpPort))
            {
                _Events.HandleClientDisconnected(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Kicked));
            }
            else if (_ClientsTimedout.ContainsKey(client.IpPort))
            {
                _Events.HandleClientDisconnected(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Timeout));
            }
            else
            {
                _Events.HandleClientDisconnected(this, new ClientDisconnectedEventArgs(client.IpPort, DisconnectReason.Normal));
            }

            DateTime removedTs;

            _Clients.TryRemove(client.IpPort, out ClientMetadata destroyed);
            _ClientsLastSeen.TryRemove(client.IpPort, out removedTs);
            _ClientsKicked.TryRemove(client.IpPort, out removedTs);
            _ClientsTimedout.TryRemove(client.IpPort, out removedTs);
            client.Dispose();
        }
Пример #8
0
        private async Task AcceptConnections()
        {
            _IsListening = true;
            _Listener.Start();

            while (!_Token.IsCancellationRequested)
            {
                ClientMetadata client = null;

                try
                {
                    System.Net.Sockets.TcpClient tcpClient = await _Listener.AcceptTcpClientAsync().ConfigureAwait(false);

                    string clientIp = tcpClient.Client.RemoteEndPoint.ToString();

                    client = new ClientMetadata(tcpClient);

                    if (_Ssl)
                    {
                        if (_Settings.AcceptInvalidCertificates)
                        {
                            client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(AcceptCertificate));
                        }
                        else
                        {
                            client.SslStream = new SslStream(client.NetworkStream, false);
                        }

                        bool success = await StartTls(client).ConfigureAwait(false);

                        if (!success)
                        {
                            client.Dispose();
                            continue;
                        }
                    }

                    _Clients.TryAdd(clientIp, client);
                    _ClientsLastSeen.TryAdd(clientIp, DateTime.Now);
                    Logger?.Invoke(_Header + "starting data receiver for: " + clientIp);
                    _Events.HandleClientConnected(this, new ClientConnectedEventArgs(clientIp));

                    CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(client.Token, _Token);
                    Task unawaited = Task.Run(() => DataReceiver(client), linkedCts.Token);
                }
                catch (TaskCanceledException)
                {
                    _IsListening = false;
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    return;
                }
                catch (OperationCanceledException)
                {
                    _IsListening = false;
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    return;
                }
                catch (ObjectDisposedException)
                {
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    continue;
                }
                catch (Exception e)
                {
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    Logger?.Invoke(_Header + "exception while awaiting connections: " + e.ToString());
                    continue;
                }
            }

            _IsListening = false;
        }
Пример #9
0
        private async Task DataReceiver(ClientMetadata client)
        {
            string header = "[" + client.IpPort + "]";

            Log(header + " data receiver started");

            while (true)
            {
                try
                {
                    if (!IsClientConnected(client.Client))
                    {
                        Log(header + " client no longer connected");
                        break;
                    }

                    if (client.Token.IsCancellationRequested)
                    {
                        Log(header + " cancellation requested");
                        break;
                    }

                    byte[] data = await DataReadAsync(client);

                    if (data == null)
                    {
                        await Task.Delay(30);

                        continue;
                    }

                    if (DataReceived != null)
                    {
                        Task unawaited = Task.Run(() => DataReceived(client.IpPort, data));
                    }

                    UpdateClientLastSeen(client.IpPort);
                }
                catch (Exception e)
                {
                    Log(
                        Environment.NewLine +
                        header + " data receiver exception:" +
                        Environment.NewLine +
                        e.ToString() +
                        Environment.NewLine);

                    break;
                }
            }

            Log(header + " data receiver terminated");

            if (ClientDisconnected != null)
            {
                Task unawaited = null;

                if (_ClientsKicked.ContainsKey(client.IpPort))
                {
                    unawaited = Task.Run(() => ClientDisconnected(client.IpPort, DisconnectReason.Kicked));
                }
                else if (_ClientsTimedout.ContainsKey(client.IpPort))
                {
                    unawaited = Task.Run(() => ClientDisconnected(client.IpPort, DisconnectReason.Timeout));
                }
                else
                {
                    unawaited = Task.Run(() => ClientDisconnected(client.IpPort, DisconnectReason.Normal));
                }
            }

            DateTime removedTs;

            _Clients.TryRemove(client.IpPort, out ClientMetadata destroyed);
            _ClientsLastSeen.TryRemove(client.IpPort, out removedTs);
            _ClientsKicked.TryRemove(client.IpPort, out removedTs);
            _ClientsTimedout.TryRemove(client.IpPort, out removedTs);

            client.Dispose();
        }
Пример #10
0
        private async void AcceptConnections()
        {
            while (!_Token.IsCancellationRequested)
            {
                ClientMetadata client = null;

                try
                {
                    System.Net.Sockets.TcpClient tcpClient = await _Listener.AcceptTcpClientAsync();

                    string clientIp = tcpClient.Client.RemoteEndPoint.ToString();

                    client = new ClientMetadata(tcpClient);

                    if (_Ssl)
                    {
                        if (AcceptInvalidCertificates)
                        {
                            client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(AcceptCertificate));
                        }
                        else
                        {
                            client.SslStream = new SslStream(client.NetworkStream, false);
                        }

                        bool success = await StartTls(client);

                        if (!success)
                        {
                            client.Dispose();
                            continue;
                        }
                    }

                    _Clients.TryAdd(clientIp, client);
                    _ClientsLastSeen.TryAdd(clientIp, DateTime.Now);

                    Log("[" + clientIp + "] starting data receiver");

                    if (ClientConnected != null)
                    {
                        await Task.Run(() => ClientConnected(clientIp));
                    }

                    Task dataRecv = Task.Run(() => DataReceiver(client), _Token);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (ObjectDisposedException)
                {
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    continue;
                }
                catch (Exception e)
                {
                    if (client != null)
                    {
                        client.Dispose();
                    }
                    Log("*** AcceptConnections exception: " + e.ToString());
                    continue;
                }
                finally
                {
                }
            }
        }