Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/SuperSimpleTcp/PermitType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

namespace SuperSimpleTcp
{
/// <summary>
/// PermitType's used to clarify the way to validate permitted IPs
/// </summary>
public enum PermitType : byte
{
/// <summary>
/// Only PermittedList is used when only the PermittedIPs list decides
/// </summary>
OnlyPermittedList = 0,

/// <summary>
/// FlagAndPermittedList is used to check the flag AllowAnonymousIPs first
/// and if the flag was false then checks the PermittedIPs list
/// </summary>
FlagAndPermittedList = 1
}
}
84 changes: 46 additions & 38 deletions src/SuperSimpleTcp/SimpleTcpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public SimpleTcpServer(string ipPort)
{
_ipAddress = Dns.GetHostEntry(_listenerIp).AddressList[0];
_listenerIp = _ipAddress.ToString();
}
}
}

_isListening = false;
Expand Down Expand Up @@ -236,16 +236,16 @@ public SimpleTcpServer(string listenerIp, int port)
_listenerIp = listenerIp;
}
else
{
{
if (!IPAddress.TryParse(_listenerIp, out _ipAddress))
{
_ipAddress = Dns.GetHostEntry(listenerIp).AddressList[0];
_listenerIp = _ipAddress.ToString();
}
}
}

_isListening = false;
_token = _tokenSource.Token;
_token = _tokenSource.Token;
}

/// <summary>
Expand Down Expand Up @@ -299,7 +299,7 @@ public SimpleTcpServer(string ipPort, bool ssl, string pfxCertFilename, string p
{
_sslCertificate
};
}
}
}

/// <summary>
Expand All @@ -311,7 +311,7 @@ public SimpleTcpServer(string ipPort, bool ssl, string pfxCertFilename, string p
/// <param name="pfxCertFilename">The filename of the PFX certificate file.</param>
/// <param name="pfxPassword">The password to the PFX certificate file.</param>
public SimpleTcpServer(string listenerIp, int port, bool ssl, string pfxCertFilename, string pfxPassword)
{
{
if (port < 0) throw new ArgumentException("Port must be zero or greater.");

_listenerIp = listenerIp;
Expand All @@ -324,7 +324,7 @@ public SimpleTcpServer(string listenerIp, int port, bool ssl, string pfxCertFile
}
else if (_listenerIp == "*" || _listenerIp == "+")
{
_ipAddress = IPAddress.Any;
_ipAddress = IPAddress.Any;
}
else
{
Expand All @@ -334,7 +334,7 @@ public SimpleTcpServer(string listenerIp, int port, bool ssl, string pfxCertFile
_listenerIp = _ipAddress.ToString();
}
}

_ssl = ssl;
_isListening = false;
_token = _tokenSource.Token;
Expand All @@ -354,7 +354,7 @@ public SimpleTcpServer(string listenerIp, int port, bool ssl, string pfxCertFile
{
_sslCertificate
};
}
}
}

/// <summary>
Expand Down Expand Up @@ -431,7 +431,7 @@ public void Start()
_listenerToken = _listenerTokenSource.Token;

_statistics = new SimpleTcpStatistics();

if (_idleClientMonitor == null)
{
_idleClientMonitor = Task.Run(() => IdleClientMonitor(), _token);
Expand Down Expand Up @@ -673,7 +673,7 @@ protected virtual void Dispose(bool disposing)
{
curr.Value.Dispose();
Logger?.Invoke($"{_header}disconnected client: {curr.Key}");
}
}
}

if (_tokenSource != null)
Expand Down Expand Up @@ -707,7 +707,7 @@ protected virtual void Dispose(bool disposing)
Logger?.Invoke($"{_header}disposed");
}
}

private bool IsClientConnected(TcpClient client)
{
if (client == null) return false;
Expand Down Expand Up @@ -775,7 +775,15 @@ private async Task AcceptConnections()
int clientPort = 0;
Common.ParseIpPort(clientIpPort, out clientIp, out clientPort);

if (_settings.PermittedIPs.Count > 0 && !_settings.PermittedIPs.Contains(clientIp))
if (Settings.PermitType == PermitType.OnlyPermittedList
&& (_settings.PermittedIPs.Count > 0 && !_settings.PermittedIPs.Contains(clientIp)))
{
Logger?.Invoke($"{_header}rejecting connection from {clientIp} (not permitted)");
tcpClient.Close();
continue;

}
else if (!_settings.AllowAnonymousIPs && !_settings.PermittedIPs.Contains(clientIp))
{
Logger?.Invoke($"{_header}rejecting connection from {clientIp} (not permitted)");
tcpClient.Close();
Expand All @@ -797,7 +805,7 @@ private async Task AcceptConnections()
{
client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(AcceptCertificate));
}
else if(_settings.CertificateValidationCallback != null)
else if (_settings.CertificateValidationCallback != null)
{
client.SslStream = new SslStream(client.NetworkStream, false, new RemoteCertificateValidationCallback(_settings.CertificateValidationCallback));
}
Expand Down Expand Up @@ -927,7 +935,7 @@ private async Task DataReceiver(ClientMetadata client)
while (true)
{
try
{
{
if (!IsClientConnected(client.Client))
{
Logger?.Invoke($"{_header}client {ipPort} disconnected");
Expand All @@ -938,7 +946,7 @@ private async Task DataReceiver(ClientMetadata client)
{
Logger?.Invoke($"{_header}cancellation requested (data receiver for client {ipPort})");
break;
}
}

var data = await DataReadAsync(client, linkedCts.Token).ConfigureAwait(false);
if (data == null)
Expand Down Expand Up @@ -982,7 +990,7 @@ private async Task DataReceiver(ClientMetadata client)
}
catch (Exception e)
{
Logger?.Invoke($"{_header}data receiver exception [{ipPort}]:{ Environment.NewLine}{e}{Environment.NewLine}");
Logger?.Invoke($"{_header}data receiver exception [{ipPort}]:{Environment.NewLine}{e}{Environment.NewLine}");
break;
}
}
Expand All @@ -1005,13 +1013,13 @@ private async Task DataReceiver(ClientMetadata client)
_clients.TryRemove(ipPort, out _);
_clientsLastSeen.TryRemove(ipPort, out _);
_clientsKicked.TryRemove(ipPort, out _);
_clientsTimedout.TryRemove(ipPort, out _);
_clientsTimedout.TryRemove(ipPort, out _);

if (client != null) client.Dispose();
}

private async Task<ArraySegment<byte>> DataReadAsync(ClientMetadata client, CancellationToken token)
{
{
byte[] buffer = new byte[_settings.StreamBufferSize];
int read = 0;

Expand Down Expand Up @@ -1054,23 +1062,23 @@ private async Task<ArraySegment<byte>> DataReadAsync(ClientMetadata client, Canc
}
}
}
}
}
}

private async Task IdleClientMonitor()
{
while (!_token.IsCancellationRequested)
{
{
await Task.Delay(_settings.IdleClientEvaluationIntervalMs, _token).ConfigureAwait(false);

if (_settings.IdleClientTimeoutMs == 0) continue;

try
{
{
DateTime idleTimestamp = DateTime.Now.AddMilliseconds(-1 * _settings.IdleClientTimeoutMs);

foreach (KeyValuePair<string, DateTime> curr in _clientsLastSeen)
{
{
if (curr.Value < idleTimestamp)
{
_clientsTimedout.TryAdd(curr.Key, DateTime.Now);
Expand All @@ -1085,14 +1093,14 @@ private async Task IdleClientMonitor()
}
}
}

private void UpdateClientLastSeen(string ipPort)
{
if (_clientsLastSeen.ContainsKey(ipPort))
{
_clientsLastSeen.TryRemove(ipPort, out _);
}

_clientsLastSeen.TryAdd(ipPort, DateTime.Now);
}

Expand All @@ -1114,8 +1122,8 @@ private void SendInternal(string ipPort, long contentLength, Stream stream)
bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
if (!_ssl) client.NetworkStream.Write(buffer, 0, bytesRead);
else client.SslStream.Write(buffer, 0, bytesRead);
if (!_ssl) client.NetworkStream.Write(buffer, 0, bytesRead);
else client.SslStream.Write(buffer, 0, bytesRead);

bytesRemaining -= bytesRead;
_statistics.SentBytes += bytesRead;
Expand Down Expand Up @@ -1195,19 +1203,19 @@ private void EnableKeepalives()

#elif NETFRAMEWORK

byte[] keepAlive = new byte[12];
byte[] keepAlive = new byte[12];

// Turn keepalive on
Buffer.BlockCopy(BitConverter.GetBytes((uint)1), 0, keepAlive, 0, 4);
// Turn keepalive on
Buffer.BlockCopy(BitConverter.GetBytes((uint)1), 0, keepAlive, 0, 4);

// Set TCP keepalive time
Buffer.BlockCopy(BitConverter.GetBytes((uint)_keepalive.TcpKeepAliveTimeMilliseconds), 0, keepAlive, 4, 4);
// Set TCP keepalive time
Buffer.BlockCopy(BitConverter.GetBytes((uint)_keepalive.TcpKeepAliveTimeMilliseconds), 0, keepAlive, 4, 4);

// Set TCP keepalive interval
Buffer.BlockCopy(BitConverter.GetBytes((uint)_keepalive.TcpKeepAliveIntervalMilliseconds), 0, keepAlive, 8, 4);
// Set TCP keepalive interval
Buffer.BlockCopy(BitConverter.GetBytes((uint)_keepalive.TcpKeepAliveIntervalMilliseconds), 0, keepAlive, 8, 4);

// Set keepalive settings on the underlying Socket
_listener.Server.IOControl(IOControlCode.KeepAliveValues, keepAlive, null);
// Set keepalive settings on the underlying Socket
_listener.Server.IOControl(IOControlCode.KeepAliveValues, keepAlive, null);

#elif NETSTANDARD

Expand Down
32 changes: 32 additions & 0 deletions src/SuperSimpleTcp/SimpleTcpServerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,36 @@ public List<string> BlockedIPs
}
}

/// <summary>
/// This property indicates which way to validate IPs
/// </summary>
public PermitType PermitType
{
get
{
return this._permitType;
}
set
{
this._permitType = value;
}
}

/// <summary>
/// The AllowAnonymousIPs flag to know if permitted IPs list should be checked or not.
/// </summary>
public bool AllowAnonymousIPs
{
get
{
return _allowAnonymousIPs;
}
set
{
_allowAnonymousIPs = value;
}
}

#endregion

#region Private-Members
Expand All @@ -166,6 +196,8 @@ public List<string> BlockedIPs
private int _idleClientEvaluationIntervalMs = 5000;
private List<string> _permittedIPs = new List<string>();
private List<string> _blockedIPs = new List<string>();
private PermitType _permitType = PermitType.OnlyPermittedList;
private bool _allowAnonymousIPs = true;

#endregion

Expand Down
26 changes: 26 additions & 0 deletions src/SuperSimpleTcp/SuperSimpleTcp.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.