@@ -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(); | |||
@@ -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) | |||
{ | |||
@@ -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]; | |||
@@ -95,7 +95,6 @@ namespace Shadowsocks.Controller | |||
StatisticsConfiguration = StatisticsStrategyConfiguration.Load(); | |||
_strategyManager = new StrategyManager(this); | |||
_pluginsByServer = new ConcurrentDictionary<Server, Sip003Plugin>(); | |||
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) | |||
@@ -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<byte> plain, Span<byte> 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<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
int clen = cipher.Length - tagLen; | |||
using AesGcm aes = new AesGcm(sessionKey); | |||
ReadOnlySpan<byte> ciphertxt = cipher.Slice(0, clen); | |||
ReadOnlySpan<byte> tag = cipher.Slice(clen); | |||
aes.Decrypt(nonce, ciphertxt, tag, plain.Slice(0, clen)); | |||
@@ -43,14 +43,14 @@ namespace Shadowsocks.Encryption.AEAD | |||
public override int CipherEncrypt(ReadOnlySpan<byte> plain, Span<byte> 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<byte> plain, ReadOnlySpan<byte> cipher) | |||
{ | |||
byte[] pt = enc!.Decrypt(cipher, null, nonce); | |||
byte[] pt = enc.Decrypt(cipher, null, nonce); | |||
pt.CopyTo(plain); | |||
return pt.Length; | |||
} | |||
@@ -41,7 +41,7 @@ namespace Shadowsocks.Encryption.Stream | |||
{ | |||
Span<byte> 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(); | |||
@@ -39,6 +39,12 @@ namespace Shadowsocks.Encryption.Stream | |||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)] | |||
private int CipherUpdate(ReadOnlySpan<byte> i, Span<byte> 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<byte>,Span<byte>)... | |||
int len = i.Length; | |||
int pad = remain; | |||
i.CopyTo(chachaBuf.AsSpan(pad)); | |||
@@ -46,7 +46,7 @@ namespace Shadowsocks.Encryption.Stream | |||
// don't know why we need third array, but it works... | |||
Span<byte> 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<byte> s, Span<byte> data, int length) | |||
private void RC4(Span<byte> s, Span<byte> 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]); | |||
} | |||
} | |||
@@ -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); | |||
@@ -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); | |||
@@ -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) | |||