diff --git a/shadowsocks-csharp/Controller/Service/UDPListener.cs b/shadowsocks-csharp/Controller/Service/UDPListener.cs index dfc8b5df..53b92723 100644 --- a/shadowsocks-csharp/Controller/Service/UDPListener.cs +++ b/shadowsocks-csharp/Controller/Service/UDPListener.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; using NLog; using Shadowsocks.Model; @@ -49,6 +51,7 @@ namespace Shadowsocks.Controller bool _shareOverLAN; Socket _udpSocket; IEnumerable _services; + CancellationTokenSource tokenSource = new CancellationTokenSource(); public UDPListener(Configuration config, IEnumerable services) { @@ -84,54 +87,35 @@ namespace Shadowsocks.Controller logger.Info($"Shadowsocks started UDP ({UpdateChecker.Version})"); logger.Debug(Encryption.EncryptorFactory.DumpRegisteredEncryptor()); UDPState udpState = new UDPState(_udpSocket); - _udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); - - } - - public void Stop() - { - _udpSocket?.Close(); - foreach (var s in _services) - { - s.Stop(); - } + // _udpSocket.BeginReceiveFrom(udpState.buffer, 0, udpState.buffer.Length, 0, ref udpState.remoteEndPoint, new AsyncCallback(RecvFromCallback), udpState); + Task.Run(() => WorkLoop(tokenSource.Token)); } - public void RecvFromCallback(IAsyncResult ar) + private async Task WorkLoop(CancellationToken token) { - UDPState state = (UDPState)ar.AsyncState; - var socket = state.socket; - try + byte[] buffer = new byte[4096]; + EndPoint remote = new IPEndPoint(_udpSocket.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, 0); + while (!token.IsCancellationRequested) { - int bytesRead = socket.EndReceiveFrom(ar, ref state.remoteEndPoint); + var result = await _udpSocket.ReceiveFromAsync(buffer, SocketFlags.None, remote); + var len = result.ReceivedBytes; foreach (IDatagramService service in _services) { - if (service.Handle(state.buffer, bytesRead, socket, state)) + if (service.Handle(buffer, len, _udpSocket, remote)) { break; } } } - catch (ObjectDisposedException) - { - } - catch (Exception ex) - { - logger.Debug(ex); - } - finally + } + + public void Stop() + { + tokenSource.Cancel(); + _udpSocket?.Close(); + foreach (var s in _services) { - try - { - socket.BeginReceiveFrom(state.buffer, 0, state.buffer.Length, 0, ref state.remoteEndPoint, new AsyncCallback(RecvFromCallback), state); - } - catch (ObjectDisposedException) - { - // do nothing - } - catch (Exception) - { - } + s.Stop(); } } } diff --git a/shadowsocks-csharp/Controller/Service/UDPRelay.cs b/shadowsocks-csharp/Controller/Service/UDPRelay.cs index fb5b5854..ecef6cb2 100644 --- a/shadowsocks-csharp/Controller/Service/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/UDPRelay.cs @@ -44,8 +44,8 @@ namespace Shadowsocks.Controller { return false; } - UDPListener.UDPState udpState = (UDPListener.UDPState)state; - IPEndPoint remoteEndPoint = (IPEndPoint)udpState.remoteEndPoint; + // UDPListener.UDPState udpState = (UDPListener.UDPState)state; + IPEndPoint remoteEndPoint = (IPEndPoint)state; UDPHandler handler = _cache.get(remoteEndPoint); if (handler == null) { @@ -70,16 +70,16 @@ namespace Shadowsocks.Controller private IPEndPoint _localEndPoint; private IPEndPoint _remoteEndPoint; - private IPAddress GetIPAddress() + private IPAddress ListenAddress { - switch (_remote.AddressFamily) + get { - case AddressFamily.InterNetwork: - return IPAddress.Any; - case AddressFamily.InterNetworkV6: - return IPAddress.IPv6Any; - default: - return IPAddress.Any; + return _remote.AddressFamily switch + { + AddressFamily.InterNetwork => IPAddress.Any, + AddressFamily.InterNetworkV6 => IPAddress.IPv6Any, + _ => throw new NotSupportedException(), + }; } } @@ -99,24 +99,23 @@ namespace Shadowsocks.Controller } _remoteEndPoint = new IPEndPoint(ipAddress, server.server_port); _remote = new Socket(_remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); - _remote.Bind(new IPEndPoint(GetIPAddress(), 0)); + _remote.Bind(new IPEndPoint(ListenAddress, 0)); } public void Send(byte[] data, int length) { IEncryptor encryptor = EncryptorFactory.GetEncryptor(_server.method, _server.password); - // byte[] dataIn = new byte[length - 3]; - // Array.Copy(data, 3, dataIn, 0, length - 3); - byte[] dataOut = new byte[65536]; // enough space for AEAD ciphers - // encryptor.EncryptUDP(dataIn, length - 3, dataOut, out outlen); - int outlen = encryptor.EncryptUDP(data.AsSpan(3), dataOut); + var slicedData = data.AsSpan(0, length); + byte[] dataOut = new byte[slicedData.Length + 1000]; + var dataToSend = slicedData[3..]; + int outlen = encryptor.EncryptUDP(slicedData[3..], dataOut); logger.Debug(_localEndPoint, _remoteEndPoint, outlen, "UDP Relay"); _remote?.SendTo(dataOut, outlen, SocketFlags.None, _remoteEndPoint); } public void Receive() { - EndPoint remoteEndPoint = new IPEndPoint(GetIPAddress(), 0); + EndPoint remoteEndPoint = new IPEndPoint(ListenAddress, 0); logger.Debug($"++++++Receive Server Port, size:" + _buffer.Length); _remote?.BeginReceiveFrom(_buffer, 0, _buffer.Length, 0, ref remoteEndPoint, new AsyncCallback(RecvFromCallback), null); } @@ -126,7 +125,7 @@ namespace Shadowsocks.Controller try { if (_remote == null) return; - EndPoint remoteEndPoint = new IPEndPoint(GetIPAddress(), 0); + EndPoint remoteEndPoint = new IPEndPoint(ListenAddress, 0); int bytesRead = _remote.EndReceiveFrom(ar, ref remoteEndPoint); byte[] dataOut = new byte[bytesRead];