add load balancing
This commit is contained in:
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
+5
-4
@@ -5,16 +5,17 @@ using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using Shadowsocks.Encryption;
|
||||
using Shadowsocks.Model;
|
||||
using Shadowsocks.Controller.Strategy;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
|
||||
class TCPRelay : Listener.Service
|
||||
{
|
||||
private Configuration _config;
|
||||
public TCPRelay(Configuration config)
|
||||
private ShadowsocksController _controller;
|
||||
public TCPRelay(ShadowsocksController controller)
|
||||
{
|
||||
this._config = config;
|
||||
this._controller = controller;
|
||||
}
|
||||
|
||||
public bool Handle(byte[] firstPacket, int length, Socket socket, object state)
|
||||
@@ -30,7 +31,7 @@ namespace Shadowsocks.Controller
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||||
Handler handler = new Handler();
|
||||
handler.connection = socket;
|
||||
Server server = _config.GetCurrentServer();
|
||||
Server server = _controller.GetCurrentStrategy().GetAServer(IStrategyCallerType.TCP, (IPEndPoint)socket.RemoteEndPoint);
|
||||
handler.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
|
||||
handler.server = server;
|
||||
|
||||
+5
-4
@@ -6,16 +6,17 @@ using Shadowsocks.Model;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Shadowsocks.Controller.Strategy;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
class UDPRelay : Listener.Service
|
||||
{
|
||||
private Configuration _config;
|
||||
private ShadowsocksController _controller;
|
||||
private LRUCache<IPEndPoint, UDPHandler> _cache;
|
||||
public UDPRelay(Configuration config)
|
||||
public UDPRelay(ShadowsocksController controller)
|
||||
{
|
||||
this._config = config;
|
||||
this._controller = controller;
|
||||
this._cache = new LRUCache<IPEndPoint, UDPHandler>(512); // todo: choose a smart number
|
||||
}
|
||||
|
||||
@@ -34,7 +35,7 @@ namespace Shadowsocks.Controller
|
||||
UDPHandler handler = _cache.get(remoteEndPoint);
|
||||
if (handler == null)
|
||||
{
|
||||
handler = new UDPHandler(socket, _config.GetCurrentServer(), remoteEndPoint);
|
||||
handler = new UDPHandler(socket, _controller.GetCurrentStrategy().GetAServer(IStrategyCallerType.UDP, remoteEndPoint), remoteEndPoint);
|
||||
_cache.add(remoteEndPoint, handler);
|
||||
}
|
||||
handler.Send(firstPacket, length);
|
||||
Executable → Regular
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Net.Sockets;
|
||||
using Shadowsocks.Controller.Strategy;
|
||||
|
||||
namespace Shadowsocks.Controller
|
||||
{
|
||||
@@ -20,6 +21,7 @@ namespace Shadowsocks.Controller
|
||||
private Listener _listener;
|
||||
private PACServer _pacServer;
|
||||
private Configuration _config;
|
||||
private StrategyManager _strategyManager;
|
||||
private PolipoRunner polipoRunner;
|
||||
private GFWListUpdater gfwListUpdater;
|
||||
private bool stopped = false;
|
||||
@@ -49,6 +51,7 @@ namespace Shadowsocks.Controller
|
||||
public ShadowsocksController()
|
||||
{
|
||||
_config = Configuration.Load();
|
||||
_strategyManager = new StrategyManager(this);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@@ -70,11 +73,34 @@ namespace Shadowsocks.Controller
|
||||
}
|
||||
|
||||
// always return copy
|
||||
public Configuration GetConfiguration()
|
||||
public Configuration GetConfigurationCopy()
|
||||
{
|
||||
return Configuration.Load();
|
||||
}
|
||||
|
||||
// always return current instance
|
||||
public Configuration GetCurrentConfiguration()
|
||||
{
|
||||
return _config;
|
||||
}
|
||||
|
||||
public IList<IStrategy> GetStrategies()
|
||||
{
|
||||
return _strategyManager.GetStrategies();
|
||||
}
|
||||
|
||||
public IStrategy GetCurrentStrategy()
|
||||
{
|
||||
foreach (var strategy in _strategyManager.GetStrategies())
|
||||
{
|
||||
if (strategy.ID == this._config.strategy)
|
||||
{
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SaveServers(List<Server> servers, int localPort)
|
||||
{
|
||||
_config.configs = servers;
|
||||
@@ -134,6 +160,14 @@ namespace Shadowsocks.Controller
|
||||
public void SelectServerIndex(int index)
|
||||
{
|
||||
_config.index = index;
|
||||
_config.strategy = null;
|
||||
SaveConfig(_config);
|
||||
}
|
||||
|
||||
public void SelectStrategy(string strategyID)
|
||||
{
|
||||
_config.index = -1;
|
||||
_config.strategy = strategyID;
|
||||
SaveConfig(_config);
|
||||
}
|
||||
|
||||
@@ -250,8 +284,8 @@ namespace Shadowsocks.Controller
|
||||
{
|
||||
polipoRunner.Start(_config);
|
||||
|
||||
TCPRelay tcpRelay = new TCPRelay(_config);
|
||||
UDPRelay udpRelay = new UDPRelay(_config);
|
||||
TCPRelay tcpRelay = new TCPRelay(this);
|
||||
UDPRelay udpRelay = new UDPRelay(this);
|
||||
List<Listener.Service> services = new List<Listener.Service>();
|
||||
services.Add(tcpRelay);
|
||||
services.Add(udpRelay);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Shadowsocks.Controller;
|
||||
using Shadowsocks.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Shadowsocks.Controller.Strategy
|
||||
{
|
||||
class BalancingStrategy : IStrategy
|
||||
{
|
||||
ShadowsocksController _controller;
|
||||
Random _random;
|
||||
|
||||
public BalancingStrategy(ShadowsocksController controller)
|
||||
{
|
||||
_controller = controller;
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Load Balance";
|
||||
}
|
||||
}
|
||||
|
||||
public string ID
|
||||
{
|
||||
get
|
||||
{
|
||||
return "com.shadowsocks.strategy.balancing";
|
||||
}
|
||||
}
|
||||
|
||||
public Server GetAServer(IStrategyCallerType type, IPEndPoint localIPEndPoint)
|
||||
{
|
||||
var configs = _controller.GetCurrentConfiguration().configs;
|
||||
int index;
|
||||
if (type == IStrategyCallerType.TCP)
|
||||
{
|
||||
index = _random.Next();
|
||||
}
|
||||
else
|
||||
{
|
||||
index = localIPEndPoint.GetHashCode();
|
||||
}
|
||||
return configs[index % configs.Count];
|
||||
}
|
||||
|
||||
public void UpdateLatency(Model.Server server)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void UpdateLastRead(Model.Server server)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void UpdateLastWrite(Model.Server server)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void SetFailure(Model.Server server)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Shadowsocks.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Shadowsocks.Controller.Strategy
|
||||
{
|
||||
public enum IStrategyCallerType
|
||||
{
|
||||
TCP,
|
||||
UDP
|
||||
}
|
||||
|
||||
public interface IStrategy
|
||||
{
|
||||
string Name { get; }
|
||||
string ID { get; }
|
||||
|
||||
Server GetAServer(IStrategyCallerType type, IPEndPoint localIPEndPoint);
|
||||
|
||||
void UpdateLatency(Server server);
|
||||
|
||||
void UpdateLastRead(Server server);
|
||||
|
||||
void UpdateLastWrite(Server server);
|
||||
|
||||
void SetFailure(Server server);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Shadowsocks.Controller;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Shadowsocks.Controller.Strategy
|
||||
{
|
||||
class StrategyManager
|
||||
{
|
||||
List<IStrategy> _strategies;
|
||||
public StrategyManager(ShadowsocksController controller)
|
||||
{
|
||||
_strategies = new List<IStrategy>();
|
||||
_strategies.Add(new BalancingStrategy(controller));
|
||||
}
|
||||
public IList<IStrategy> GetStrategies()
|
||||
{
|
||||
return _strategies;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable → Regular
@@ -23,6 +23,7 @@ Show Logs...=显示日志...
|
||||
About...=关于...
|
||||
Quit=退出
|
||||
Edit Servers=编辑服务器
|
||||
Load Balance=负载均衡
|
||||
|
||||
# Config Form
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ namespace Shadowsocks.Model
|
||||
public class Configuration
|
||||
{
|
||||
public List<Server> configs;
|
||||
|
||||
// when strategy is set, index is ignored
|
||||
public string strategy;
|
||||
public int index;
|
||||
public bool global;
|
||||
public bool enabled;
|
||||
@@ -79,9 +82,9 @@ namespace Shadowsocks.Model
|
||||
{
|
||||
config.index = config.configs.Count - 1;
|
||||
}
|
||||
if (config.index < 0)
|
||||
if (config.index < -1)
|
||||
{
|
||||
config.index = 0;
|
||||
config.index = -1;
|
||||
}
|
||||
config.isDefault = false;
|
||||
try
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Shadowsocks.View
|
||||
|
||||
private void LoadCurrentConfiguration()
|
||||
{
|
||||
_modifiedConfiguration = controller.GetConfiguration();
|
||||
_modifiedConfiguration = controller.GetConfigurationCopy();
|
||||
LoadConfiguration(_modifiedConfiguration);
|
||||
_oldSelectedIndex = _modifiedConfiguration.index;
|
||||
ServersListBox.SelectedIndex = _modifiedConfiguration.index;
|
||||
|
||||
@@ -71,9 +71,9 @@ namespace Shadowsocks.View
|
||||
|
||||
LoadCurrentConfiguration();
|
||||
|
||||
updateChecker.CheckUpdate(controller.GetConfiguration());
|
||||
updateChecker.CheckUpdate(controller.GetConfigurationCopy());
|
||||
|
||||
if (controller.GetConfiguration().isDefault)
|
||||
if (controller.GetConfigurationCopy().isDefault)
|
||||
{
|
||||
_isFirstRun = true;
|
||||
ShowConfigForm();
|
||||
@@ -106,7 +106,7 @@ namespace Shadowsocks.View
|
||||
{
|
||||
icon = Resources.ss24;
|
||||
}
|
||||
Configuration config = controller.GetConfiguration();
|
||||
Configuration config = controller.GetConfigurationCopy();
|
||||
bool enabled = config.enabled;
|
||||
bool global = config.global;
|
||||
if (!enabled)
|
||||
@@ -124,12 +124,21 @@ namespace Shadowsocks.View
|
||||
}
|
||||
_notifyIcon.Icon = Icon.FromHandle(icon.GetHicon());
|
||||
|
||||
string serverInfo = null;
|
||||
if (config.strategy != null)
|
||||
{
|
||||
serverInfo = I18N.GetString(controller.GetCurrentStrategy().Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
serverInfo = config.GetCurrentServer().FriendlyName();
|
||||
}
|
||||
// we want to show more details but notify icon title is limited to 63 characters
|
||||
string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" +
|
||||
(enabled ?
|
||||
I18N.GetString("System Proxy On: ") + (global ? I18N.GetString("Global") : I18N.GetString("PAC")) :
|
||||
String.Format(I18N.GetString("Running: Port {0}"), config.localPort)) // this feedback is very important because they need to know Shadowsocks is running
|
||||
+ "\n" + config.GetCurrentServer().FriendlyName();
|
||||
+ "\n" + serverInfo;
|
||||
_notifyIcon.Text = text.Substring(0, Math.Min(63, text.Length));
|
||||
}
|
||||
|
||||
@@ -185,18 +194,18 @@ namespace Shadowsocks.View
|
||||
|
||||
private void controller_EnableStatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
enableItem.Checked = controller.GetConfiguration().enabled;
|
||||
enableItem.Checked = controller.GetConfigurationCopy().enabled;
|
||||
modeItem.Enabled = enableItem.Checked;
|
||||
}
|
||||
|
||||
void controller_ShareOverLANStatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
ShareOverLANItem.Checked = controller.GetConfiguration().shareOverLan;
|
||||
ShareOverLANItem.Checked = controller.GetConfigurationCopy().shareOverLan;
|
||||
}
|
||||
|
||||
void controller_EnableGlobalChanged(object sender, EventArgs e)
|
||||
{
|
||||
globalModeItem.Checked = controller.GetConfiguration().global;
|
||||
globalModeItem.Checked = controller.GetConfigurationCopy().global;
|
||||
PACModeItem.Checked = !globalModeItem.Checked;
|
||||
}
|
||||
|
||||
@@ -243,7 +252,7 @@ namespace Shadowsocks.View
|
||||
|
||||
private void LoadCurrentConfiguration()
|
||||
{
|
||||
Configuration config = controller.GetConfiguration();
|
||||
Configuration config = controller.GetConfigurationCopy();
|
||||
UpdateServersMenu();
|
||||
enableItem.Checked = config.enabled;
|
||||
modeItem.Enabled = config.enabled;
|
||||
@@ -263,20 +272,32 @@ namespace Shadowsocks.View
|
||||
{
|
||||
items.RemoveAt(0);
|
||||
}
|
||||
|
||||
Configuration configuration = controller.GetConfiguration();
|
||||
for (int i = 0; i < configuration.configs.Count; i++)
|
||||
int i = 0;
|
||||
foreach (var strategy in controller.GetStrategies())
|
||||
{
|
||||
MenuItem item = new MenuItem(I18N.GetString(strategy.Name));
|
||||
item.Tag = strategy.ID;
|
||||
item.Click += AStrategyItem_Click;
|
||||
items.Add(i, item);
|
||||
i++;
|
||||
}
|
||||
Configuration configuration = controller.GetConfigurationCopy();
|
||||
foreach (var server in configuration.configs)
|
||||
{
|
||||
Server server = configuration.configs[i];
|
||||
MenuItem item = new MenuItem(server.FriendlyName());
|
||||
item.Tag = i;
|
||||
item.Click += AServerItem_Click;
|
||||
items.Add(i, item);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (configuration.index >= 0 && configuration.index < configuration.configs.Count)
|
||||
foreach (MenuItem item in items)
|
||||
{
|
||||
items[configuration.index].Checked = true;
|
||||
if (item.Tag != null && (item.Tag.ToString() == configuration.index.ToString() || item.Tag.ToString() == configuration.strategy))
|
||||
{
|
||||
item.Checked = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,6 +401,12 @@ namespace Shadowsocks.View
|
||||
controller.SelectServerIndex((int)item.Tag);
|
||||
}
|
||||
|
||||
private void AStrategyItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
MenuItem item = (MenuItem)sender;
|
||||
controller.SelectStrategy((string)item.Tag);
|
||||
}
|
||||
|
||||
private void ShowLogItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
string argument = Logging.LogFile;
|
||||
@@ -511,11 +538,11 @@ namespace Shadowsocks.View
|
||||
{
|
||||
if (!onlinePACItem.Checked)
|
||||
{
|
||||
if (String.IsNullOrEmpty(controller.GetConfiguration().pacUrl))
|
||||
if (String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl))
|
||||
{
|
||||
UpdateOnlinePACURLItem_Click(sender, e);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(controller.GetConfiguration().pacUrl))
|
||||
if (!String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl))
|
||||
{
|
||||
localPACItem.Checked = false;
|
||||
onlinePACItem.Checked = true;
|
||||
@@ -527,7 +554,7 @@ namespace Shadowsocks.View
|
||||
|
||||
private void UpdateOnlinePACURLItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
string origPacUrl = controller.GetConfiguration().pacUrl;
|
||||
string origPacUrl = controller.GetConfigurationCopy().pacUrl;
|
||||
string pacUrl = Microsoft.VisualBasic.Interaction.InputBox(
|
||||
I18N.GetString("Please input PAC Url"),
|
||||
I18N.GetString("Edit Online PAC URL"),
|
||||
|
||||
@@ -124,15 +124,15 @@
|
||||
<Compile Include="3rd\zxing\ResultPoint.cs" />
|
||||
<Compile Include="3rd\zxing\ResultPointCallback.cs" />
|
||||
<Compile Include="3rd\zxing\WriterException.cs" />
|
||||
<Compile Include="Controller\AutoStartup.cs" />
|
||||
<Compile Include="Controller\System\AutoStartup.cs" />
|
||||
<Compile Include="Controller\FileManager.cs" />
|
||||
<Compile Include="Controller\GFWListUpdater.cs" />
|
||||
<Compile Include="Controller\Service\GFWListUpdater.cs" />
|
||||
<Compile Include="Controller\I18N.cs" />
|
||||
<Compile Include="Controller\Listener.cs" />
|
||||
<Compile Include="Controller\Service\Listener.cs" />
|
||||
<Compile Include="Controller\Logging.cs" />
|
||||
<Compile Include="Controller\PortForwarder.cs" />
|
||||
<Compile Include="Controller\UDPRelay.cs" />
|
||||
<Compile Include="Controller\UpdateChecker.cs" />
|
||||
<Compile Include="Controller\Service\PortForwarder.cs" />
|
||||
<Compile Include="Controller\Service\UDPRelay.cs" />
|
||||
<Compile Include="Controller\Service\UpdateChecker.cs" />
|
||||
<Compile Include="Encryption\EncryptorBase.cs" />
|
||||
<Compile Include="Encryption\EncryptorFactory.cs" />
|
||||
<Compile Include="Encryption\IVEncryptor.cs" />
|
||||
@@ -142,7 +142,7 @@
|
||||
<Compile Include="Encryption\SodiumEncryptor.cs" />
|
||||
<Compile Include="Encryption\TableEncryptor.cs" />
|
||||
<Compile Include="Encryption\IEncryptor.cs" />
|
||||
<Compile Include="Controller\PACServer.cs" />
|
||||
<Compile Include="Controller\Service\PACServer.cs" />
|
||||
<Compile Include="Model\Server.cs" />
|
||||
<Compile Include="Model\Configuration.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
@@ -150,6 +150,9 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controller\Strategy\BalancingStrategy.cs" />
|
||||
<Compile Include="Controller\Strategy\StrategyManager.cs" />
|
||||
<Compile Include="Controller\Strategy\IStrategy.cs" />
|
||||
<Compile Include="Util\Util.cs" />
|
||||
<Compile Include="View\ConfigForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -157,12 +160,12 @@
|
||||
<Compile Include="View\ConfigForm.Designer.cs">
|
||||
<DependentUpon>ConfigForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controller\TCPRelay.cs" />
|
||||
<Compile Include="Controller\PolipoRunner.cs" />
|
||||
<Compile Include="Controller\Service\TCPRelay.cs" />
|
||||
<Compile Include="Controller\Service\PolipoRunner.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Controller\ShadowsocksController.cs" />
|
||||
<Compile Include="Controller\SystemProxy.cs" />
|
||||
<Compile Include="Controller\System\SystemProxy.cs" />
|
||||
<Compile Include="View\MenuViewController.cs" />
|
||||
<Compile Include="View\QRCodeForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
||||
Reference in New Issue
Block a user