From 69dff0cce5557858eb30e5f8802af0a00ac4af59 Mon Sep 17 00:00:00 2001 From: Student Main Date: Mon, 30 Mar 2020 04:50:00 +0800 Subject: [PATCH] per encryptor optimization --- .../Controller/Service/Listener.cs | 1 + .../Controller/Service/PACServer.cs | 1 - .../Controller/Service/UDPRelay.cs | 1 + .../Controller/ShadowsocksController.cs | 24 -------- .../AEAD/AEADAesGcmNativeEncryptor.cs | 9 ++- .../Encryption/AEAD/AEADNaClEncryptor.cs | 4 +- .../Stream/StreamAesBouncyCastleEncryptor.cs | 2 +- .../Stream/StreamChachaNaClEncryptor.cs | 6 ++ .../Stream/StreamRc4NativeEncryptor.cs | 20 +++---- shadowsocks-csharp/Program.cs | 17 +----- shadowsocks-csharp/Util/Util.cs | 55 ------------------- shadowsocks-csharp/View/MenuViewController.cs | 4 -- 12 files changed, 27 insertions(+), 117 deletions(-) diff --git a/shadowsocks-csharp/Controller/Service/Listener.cs b/shadowsocks-csharp/Controller/Service/Listener.cs index 5dbb0bec..16920ea8 100644 --- a/shadowsocks-csharp/Controller/Service/Listener.cs +++ b/shadowsocks-csharp/Controller/Service/Listener.cs @@ -9,6 +9,7 @@ using Shadowsocks.Model; namespace Shadowsocks.Controller { + // TODO: Stream/Dgram Listener, so we needn't put TCP/UDP service together public class Listener { private static Logger logger = LogManager.GetCurrentClassLogger(); diff --git a/shadowsocks-csharp/Controller/Service/PACServer.cs b/shadowsocks-csharp/Controller/Service/PACServer.cs index 430aaef1..102064cf 100644 --- a/shadowsocks-csharp/Controller/Service/PACServer.cs +++ b/shadowsocks-csharp/Controller/Service/PACServer.cs @@ -181,7 +181,6 @@ Connection: Close "; byte[] response = Encoding.UTF8.GetBytes(responseHead + pacContent); socket.BeginSend(response, 0, response.Length, 0, new AsyncCallback(SendCallback), socket); - Utils.ReleaseMemory(true); } catch (Exception e) { diff --git a/shadowsocks-csharp/Controller/Service/UDPRelay.cs b/shadowsocks-csharp/Controller/Service/UDPRelay.cs index 34891267..807398c0 100644 --- a/shadowsocks-csharp/Controller/Service/UDPRelay.cs +++ b/shadowsocks-csharp/Controller/Service/UDPRelay.cs @@ -25,6 +25,7 @@ namespace Shadowsocks.Controller this._controller = controller; } + // TODO: UDP is datagram protocol not stream protocol public override bool Handle(CachedNetworkStream stream, object state) { byte[] fp = new byte[256]; diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 548d9f17..b7a53cc9 100644 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -95,7 +95,6 @@ namespace Shadowsocks.Controller StatisticsConfiguration = StatisticsStrategyConfiguration.Load(); _strategyManager = new StrategyManager(this); _pluginsByServer = new ConcurrentDictionary(); - StartReleasingMemory(); StartTrafficStatistics(61); ProgramUpdated += (o, e) => @@ -568,7 +567,6 @@ namespace Shadowsocks.Controller ConfigChanged?.Invoke(this, new EventArgs()); UpdateSystemProxy(); - Utils.ReleaseMemory(true); } private void StartPlugin() @@ -622,28 +620,6 @@ namespace Shadowsocks.Controller Clipboard.SetDataObject(_pacServer.PacUrl); } - #region Memory Management - - private void StartReleasingMemory() - { - _ramThread = new Thread(new ThreadStart(ReleaseMemory)) - { - IsBackground = true - }; - _ramThread.Start(); - } - - private void ReleaseMemory() - { - while (true) - { - Utils.ReleaseMemory(false); - Thread.Sleep(30 * 1000); - } - } - - #endregion - #region Traffic Statistics private void StartTrafficStatistics(int queueMaxSize) diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs index 882519d9..81cb3c34 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADAesGcmNativeEncryptor.cs @@ -29,9 +29,15 @@ namespace Shadowsocks.Encryption.AEAD } #endregion + AesGcm aes; + public override void InitCipher(byte[] salt, bool isEncrypt) + { + base.InitCipher(salt, isEncrypt); + aes = new AesGcm(sessionKey); + } + public override int CipherEncrypt(ReadOnlySpan plain, Span cipher) { - using AesGcm aes = new AesGcm(sessionKey); aes.Encrypt(nonce, plain, cipher.Slice(0, plain.Length), cipher.Slice(plain.Length, tagLen)); return plain.Length + tagLen; } @@ -39,7 +45,6 @@ namespace Shadowsocks.Encryption.AEAD public override int CipherDecrypt(Span plain, ReadOnlySpan cipher) { int clen = cipher.Length - tagLen; - using AesGcm aes = new AesGcm(sessionKey); ReadOnlySpan ciphertxt = cipher.Slice(0, clen); ReadOnlySpan tag = cipher.Slice(clen); aes.Decrypt(nonce, ciphertxt, tag, plain.Slice(0, clen)); diff --git a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs index 3fc18649..07a5a87f 100644 --- a/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs +++ b/shadowsocks-csharp/Encryption/AEAD/AEADNaClEncryptor.cs @@ -43,14 +43,14 @@ namespace Shadowsocks.Encryption.AEAD public override int CipherEncrypt(ReadOnlySpan plain, Span cipher) { - byte[] ct = enc!.Encrypt(plain, null, nonce); + byte[] ct = enc.Encrypt(plain, null, nonce); ct.CopyTo(cipher); return ct.Length; } public override int CipherDecrypt(Span plain, ReadOnlySpan cipher) { - byte[] pt = enc!.Decrypt(cipher, null, nonce); + byte[] pt = enc.Decrypt(cipher, null, nonce); pt.CopyTo(plain); return pt.Length; } diff --git a/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs index b22341f3..9e0cb8db 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamAesBouncyCastleEncryptor.cs @@ -41,7 +41,7 @@ namespace Shadowsocks.Encryption.Stream { Span ob = new byte[o.Length + 128]; i.CopyTo(cfbBuf.AsSpan(ptr)); - // TODO: standard CFB + // TODO: standard CFB, maybe with native aes int total = i.Length + ptr; int blkSize = b.GetBlockSize(); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs index aad65b10..8346f171 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamChachaNaClEncryptor.cs @@ -39,6 +39,12 @@ namespace Shadowsocks.Encryption.Stream [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] private int CipherUpdate(ReadOnlySpan i, Span o, bool enc) { + // about performance problem: + // as a part of hacking for streaming, we need manually increase IC + // so we need new Chacha20 + // and to get correct position, copy paste array everytime is required + // NaCl.Core has no int Encrypt(ReadOnlySpan,Span)... + int len = i.Length; int pad = remain; i.CopyTo(chachaBuf.AsSpan(pad)); diff --git a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs index 0e2d1935..41f55186 100644 --- a/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs +++ b/shadowsocks-csharp/Encryption/Stream/StreamRc4NativeEncryptor.cs @@ -46,7 +46,7 @@ namespace Shadowsocks.Encryption.Stream // don't know why we need third array, but it works... Span t = new byte[i.Length]; i.CopyTo(t); - RC4(ctx, sbox, t, t.Length); + RC4(sbox, t, t.Length); t.CopyTo(o); return t.Length; } @@ -71,13 +71,9 @@ namespace Shadowsocks.Encryption.Stream #endregion #region RC4 - class Context - { - public int index1 = 0; - public int index2 = 0; - } - private readonly Context ctx = new Context(); + int index1 = 0; + int index2 = 0; private byte[] SBox(byte[] key) { @@ -99,17 +95,17 @@ namespace Shadowsocks.Encryption.Stream } [MethodImpl(MethodImplOptions.AggressiveOptimization)] - private void RC4(Context ctx, Span s, Span data, int length) + private void RC4(Span s, Span data, int length) { for (int n = 0; n < length; n++) { byte b = data[n]; - ctx.index1 = (ctx.index1 + 1) & 255; - ctx.index2 = (ctx.index2 + s[ctx.index1]) & 255; + index1 = (index1 + 1) & 255; + index2 = (index2 + s[index1]) & 255; - Swap(s, ctx.index1, ctx.index2); - data[n] = (byte)(b ^ s[(s[ctx.index1] + s[ctx.index2]) & 255]); + Swap(s, index1, index2); + data[n] = (byte)(b ^ s[(s[index1] + s[index2]) & 255]); } } diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index d500bb2e..1f656887 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -46,23 +46,8 @@ namespace Shadowsocks "Shadowsocks Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } -#if NET472 - // Check .NET Framework version - if (!Utils.IsSupportedRuntimeVersion()) - { - if (DialogResult.OK == MessageBox.Show(I18N.GetString("Unsupported .NET Framework, please update to {0} or later.", "4.7.2"), - "Shadowsocks Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error)) - { - //Process.Start("https://www.microsoft.com/download/details.aspx?id=53344"); // 4.6.2 - Process.Start("https://dotnet.microsoft.com/download/dotnet-framework/net472"); - } - return; - } - if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware(); -#else + Application.SetHighDpiMode(HighDpiMode.SystemAware); -#endif - Utils.ReleaseMemory(true); using (Mutex mutex = new Mutex(false, $"Global\\Shadowsocks_{Application.StartupPath.GetHashCode()}")) { Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index 81ea61e5..d96458cc 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -95,61 +95,6 @@ namespace Shadowsocks.Util return Path.Combine(GetTempPath(), filename); } - public static void ReleaseMemory(bool removePages) - { - // release any unused pages - // making the numbers look good in task manager - // this is totally nonsense in programming - // but good for those users who care - // making them happier with their everyday life - // which is part of user experience - GC.Collect(GC.MaxGeneration); - GC.WaitForPendingFinalizers(); - if (removePages) - { - // as some users have pointed out - // removing pages from working set will cause some IO - // which lowered user experience for another group of users - // - // so we do 2 more things here to satisfy them: - // 1. only remove pages once when configuration is changed - // 2. add more comments here to tell users that calling - // this function will not be more frequent than - // IM apps writing chat logs, or web browsers writing cache files - // if they're so concerned about their disk, they should - // uninstall all IM apps and web browsers - // - // please open an issue if you're worried about anything else in your computer - // no matter it's GPU performance, monitor contrast, audio fidelity - // or anything else in the task manager - // we'll do as much as we can to help you - // - // just kidding - SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, - (UIntPtr)0xFFFFFFFF, - (UIntPtr)0xFFFFFFFF); - } - } - - public static string UnGzip(byte[] buf) - { - byte[] buffer = new byte[1024]; - int n; - using (MemoryStream sb = new MemoryStream()) - { - using (GZipStream input = new GZipStream(new MemoryStream(buf), - CompressionMode.Decompress, - false)) - { - while ((n = input.Read(buffer, 0, buffer.Length)) > 0) - { - sb.Write(buffer, 0, n); - } - } - return System.Text.Encoding.UTF8.GetString(sb.ToArray()); - } - } - public static string FormatBandwidth(long n) { var result = GetBandwidthScale(n); diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index b04c28ab..5d119167 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -575,14 +575,12 @@ namespace Shadowsocks.View { logForm.Dispose(); logForm = null; - Utils.ReleaseMemory(true); } void configForm_FormClosed(object sender, FormClosedEventArgs e) { configForm.Dispose(); configForm = null; - Utils.ReleaseMemory(true); if (_isFirstRun) { CheckUpdateForFirstRun(); @@ -600,14 +598,12 @@ namespace Shadowsocks.View { proxyForm.Dispose(); proxyForm = null; - Utils.ReleaseMemory(true); } void hotkeySettingsForm_FormClosed(object sender, FormClosedEventArgs e) { hotkeySettingsForm.Dispose(); hotkeySettingsForm = null; - Utils.ReleaseMemory(true); } private void Config_Click(object sender, EventArgs e)