diff --git a/EonaCat.Network/EonaCat.Network.csproj b/EonaCat.Network/EonaCat.Network.csproj
index 443f940..d0f4ebe 100644
--- a/EonaCat.Network/EonaCat.Network.csproj
+++ b/EonaCat.Network/EonaCat.Network.csproj
@@ -13,16 +13,27 @@
EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server
EonaCat Networking library with Quic, TCP, UDP, WebSockets and a Webserver
- 1.1.6
- 1.1.6
- 1.1.6
+ 1.1.7
+ 1.1.7
+ 1.1.7
icon.png
README.md
LICENSE
+
+ 1.1.7+{chash:10}.{c:ymd}
+ true
+ true
+ v[0-9]*
+ true
+ git
+ true
+ true
+
+
- false
+ True
True
README.md
False
@@ -49,10 +60,14 @@
-
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/EonaCat.Network/System/Sockets/RemoteInfo.cs b/EonaCat.Network/System/Sockets/RemoteInfo.cs
index 8ab1fd6..440cf30 100644
--- a/EonaCat.Network/System/Sockets/RemoteInfo.cs
+++ b/EonaCat.Network/System/Sockets/RemoteInfo.cs
@@ -14,6 +14,7 @@ public class RemoteInfo
public IPAddress Address => HasEndpoint ? ((IPEndPoint)EndPoint).Address : null;
public int Port => HasEndpoint ? ((IPEndPoint)EndPoint).Port : 0;
public Socket Socket { get; set; }
+ public string NickName { get; set; }
public bool IsIPv6 { get; set; }
public bool IsWebSocket { get; internal set; }
public string ClientId { get; internal set; }
diff --git a/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs b/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs
index c6244eb..8d24a29 100644
--- a/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs
+++ b/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Net.Security;
@@ -20,6 +21,8 @@ namespace EonaCat.Network
private Task _acceptTask;
private CancellationTokenSource _cancellationTokenSource;
+ private readonly ConcurrentDictionary _clientNicknames = new ConcurrentDictionary();
+
public SocketTcpServer(IPAddress ipAddress, int port, X509Certificate2 certificate = null, SslOptions sslOptions = null)
{
_listener = new TcpListener(ipAddress, port);
@@ -36,7 +39,7 @@ namespace EonaCat.Network
}
public event Action OnConnect;
- public event Action OnReceive;
+ public event Action OnReceive;
public event Action OnSend;
public event Action OnDisconnect;
public event Action OnError;
@@ -45,8 +48,8 @@ namespace EonaCat.Network
{
_listener.Start();
_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
- _acceptTask = AcceptConnectionsAsync(_cancellationTokenSource.Token);
- return _acceptTask;
+ _acceptTask = Task.Run(() => AcceptConnectionsAsync(_cancellationTokenSource.Token));
+ return Task.CompletedTask;
}
private async Task AcceptConnectionsAsync(CancellationToken cancellationToken)
@@ -56,7 +59,7 @@ namespace EonaCat.Network
try
{
var tcpClient = await _listener.AcceptTcpClientAsync().ConfigureAwait(false);
- _ = HandleConnectionAsync(tcpClient, cancellationToken);
+ _ = Task.Run(() => HandleConnectionAsync(tcpClient, cancellationToken));
}
catch (SocketException ex)
{
@@ -70,12 +73,16 @@ namespace EonaCat.Network
var remoteEndpoint = tcpClient.Client.RemoteEndPoint;
using (tcpClient)
{
+ var nickName = await GetNicknameAsync(tcpClient).ConfigureAwait(false);
+ _clientNicknames.TryAdd(tcpClient, nickName);
+
OnConnect?.Invoke(new RemoteInfo
{
Socket = tcpClient.Client,
IsTcp = true,
IsIPv6 = remoteEndpoint.AddressFamily == AddressFamily.InterNetworkV6,
- EndPoint = remoteEndpoint
+ EndPoint = remoteEndpoint,
+ NickName = nickName
});
Stream stream = tcpClient.GetStream();
@@ -84,7 +91,7 @@ namespace EonaCat.Network
var sslStream = new SslStream(stream, false, ValidateRemoteCertificate, null);
try
{
- await sslStream.AuthenticateAsServerAsync(_certificate, _sslOptions.ClientCertificateRequired, _sslOptions.SslProtocol, _sslOptions.CheckCertificateRevocation);
+ await sslStream.AuthenticateAsServerAsync(_certificate, _sslOptions.ClientCertificateRequired, _sslOptions.SslProtocol, _sslOptions.CheckCertificateRevocation).ConfigureAwait(false);
stream = sslStream;
}
catch (AuthenticationException ex)
@@ -110,8 +117,9 @@ namespace EonaCat.Network
IsTcp = true,
IsIPv6 = remoteEndpoint.AddressFamily == AddressFamily.InterNetworkV6,
EndPoint = remoteEndpoint,
+ NickName = nickName,
Data = data
- });
+ }, nickName);
}
else
{
@@ -124,20 +132,47 @@ namespace EonaCat.Network
break;
}
}
+
+ _clientNicknames.TryRemove(tcpClient, out _);
+ OnDisconnect?.Invoke(new RemoteInfo
+ {
+ Socket = tcpClient.Client,
+ IsTcp = true,
+ EndPoint = remoteEndpoint,
+ IsIPv6 = remoteEndpoint != null && remoteEndpoint.AddressFamily == AddressFamily.InterNetworkV6,
+ NickName = nickName
+ });
+ }
+ }
+
+ private async Task GetNicknameAsync(TcpClient tcpClient)
+ {
+ if (_clientNicknames.TryGetValue(tcpClient, out string nickname))
+ {
+ return await Task.FromResult(nickname).ConfigureAwait(false);
+ }
+ else
+ {
+ // Return a default nickname if one is not set
+ return await Task.FromResult("Anonymous").ConfigureAwait(false);
+ }
+ }
+
+ public bool SetNickname(TcpClient tcpClient, string nickname)
+ {
+ if (tcpClient != null && !_clientNicknames.ContainsKey(tcpClient))
+ {
+ return false;
}
- OnDisconnect?.Invoke(new RemoteInfo
- {
- Socket = tcpClient.Client,
- IsTcp = true,
- EndPoint = remoteEndpoint,
- IsIPv6 = remoteEndpoint.AddressFamily == AddressFamily.InterNetworkV6
- });
+ _clientNicknames[tcpClient] = nickname;
+ return true;
+
}
public async Task SendToAsync(Socket socket, byte[] data)
{
- await socket.SendAsync(new ArraySegment(data), SocketFlags.None).ConfigureAwait(false);
+ await Task.Run(() => socket.SendAsync(new ArraySegment(data), SocketFlags.None)).ConfigureAwait(false);
OnSend?.Invoke(new RemoteInfo
{
Socket = socket,
diff --git a/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs b/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs
index bd9d403..92f8ebc 100644
--- a/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs
+++ b/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs
@@ -2,148 +2,95 @@
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
-using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-namespace EonaCat.Network;
-
-public class SocketUdpServer
+namespace EonaCat.Network
{
- private UdpClient udpClient;
-
- ///
- /// Create UDP server
- ///
- ///
- ///
- public SocketUdpServer(IPAddress ipAddress, int port)
+ public class SocketUdpServer
{
- CreateUdpServer(ipAddress, port);
- }
+ private readonly UdpClient _udpClient;
- ///
- /// Create UDP server
- ///
- ///
- ///
- ///
- public SocketUdpServer(string ipAddress, int port)
- {
- if (!IPAddress.TryParse(ipAddress, out var ip))
+ public bool IsIPv6 { get; private set; }
+
+ public event Action OnReceive;
+ public event Action OnSend;
+ public event Action OnError;
+
+ public SocketUdpServer(IPAddress ipAddress, int port)
{
- throw new Exception("EonaCat Network: Invalid ipAddress given");
+ _udpClient = new UdpClient(ipAddress.AddressFamily);
+ IsIPv6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6;
+ _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ _udpClient.Client.Bind(new IPEndPoint(ipAddress, port));
}
- CreateUdpServer(ip, port);
- }
-
- ///
- /// Determines if the UDP server is IpV6
- ///
- public bool IsIp6 { get; private set; }
-
- ///
- /// OnReceive event
- ///
- public event Action OnReceive;
-
- ///
- /// OnSend event
- ///
- public event Action OnSend;
-
- ///
- /// OnError event
- ///
- public event Action OnError;
-
- ///
- /// OnDisconnect event
- ///
- public event Action OnDisconnect;
-
- private static void SetConnectionReset(Socket socket)
- {
- if (socket.ProtocolType != ProtocolType.Udp && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ public async Task StartAsync(CancellationToken cancellationToken = default)
{
- return;
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ try
+ {
+ var result = await _udpClient.ReceiveAsync().ConfigureAwait(false);
+ var remoteInfo = new RemoteInfo
+ {
+ EndPoint = result.RemoteEndPoint,
+ IsIPv6 = result.RemoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6,
+ Data = result.Buffer
+ };
+
+ OnReceive?.Invoke(remoteInfo);
+ }
+ catch (SocketException ex)
+ {
+ OnError?.Invoke(ex, $"SocketException: {ex.Message}");
+ }
+ catch (ObjectDisposedException ex)
+ {
+ OnError?.Invoke(ex, $"ObjectDisposedException: {ex.Message}");
+ break;
+ }
+ catch (Exception ex)
+ {
+ OnError?.Invoke(ex, $"Exception: {ex.Message}");
+ }
+ }
}
- // Disable ICMP packet shutdown (forcibly closed)
- const int SioUdpConnReset = -1744830452;
-
- byte[] inValue = { 0, 0, 0, 0 };
- socket.IOControl(SioUdpConnReset, inValue, null);
- }
-
- private void CreateUdpServer(IPAddress ipAddress, int port)
- {
- IsIp6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6;
- udpClient = new UdpClient(ipAddress.AddressFamily);
- SetConnectionReset(udpClient.Client);
-
- if (IsIp6)
+ public async Task SendToAsync(IPEndPoint endPoint, byte[] data)
{
- udpClient.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
- }
-
- udpClient.Client.Bind(new IPEndPoint(ipAddress, port));
- }
-
- ///
- /// Start UDP server
- ///
- ///
- ///
- public async Task StartAsync(CancellationToken cancellationToken = default)
- {
- while (!cancellationToken.IsCancellationRequested)
try
{
- var result = await udpClient.ReceiveAsync().ConfigureAwait(false);
- OnReceive?.Invoke(new RemoteInfo
+ await _udpClient.SendAsync(data, data.Length, endPoint).ConfigureAwait(false);
+ OnSend?.Invoke(new RemoteInfo
{
- EndPoint = result.RemoteEndPoint,
- IsIPv6 = result.RemoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6,
- Data = result.Buffer
+ EndPoint = endPoint,
+ Data = data,
+ IsIPv6 = endPoint.AddressFamily == AddressFamily.InterNetworkV6
});
}
catch (SocketException ex)
{
OnError?.Invoke(ex, $"SocketException: {ex.Message}");
}
- }
+ catch (ObjectDisposedException ex)
+ {
+ OnError?.Invoke(ex, $"ObjectDisposedException: {ex.Message}");
+ }
+ catch (Exception ex)
+ {
+ OnError?.Invoke(ex, $"Exception: {ex.Message}");
+ }
+ }
- ///
- /// Send data to endPoint
- ///
- ///
- ///
- ///
- public async Task SendToAsync(EndPoint endPoint, byte[] data)
- {
- if (endPoint is IPEndPoint ipEndPoint)
+ public async Task SendToAllAsync(byte[] data)
{
- await udpClient.SendAsync(data, data.Length, ipEndPoint).ConfigureAwait(false);
- OnSend?.Invoke(new RemoteInfo
- { EndPoint = endPoint, Data = data, IsIPv6 = endPoint.AddressFamily == AddressFamily.InterNetworkV6 });
+ var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
+ var endPoints = ipProperties.GetActiveUdpListeners();
+ foreach (var endPoint in endPoints)
+ {
+ await SendToAsync(endPoint, data).ConfigureAwait(false);
+ }
}
}
-
- ///
- /// Send data to all clients
- ///
- ///
- ///
- public async Task SendToAllAsync(byte[] data)
- {
- // get all connected clients
- var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
- var endPoints = ipProperties.GetActiveUdpListeners();
- foreach (var endPoint in endPoints)
- {
- await udpClient.SendAsync(data, data.Length, endPoint).ConfigureAwait(false);
- }
- }
-}
\ No newline at end of file
+}