Browse Source

add load balancing

tags/2.5
clowwindy 10 years ago
parent
commit
4afd5faf3f
19 changed files with 234 additions and 41 deletions
  1. +0
    -0
      shadowsocks-csharp/Controller/Service/GfwListUpdater.cs
  2. +0
    -0
      shadowsocks-csharp/Controller/Service/Listener.cs
  3. +0
    -0
      shadowsocks-csharp/Controller/Service/PACServer.cs
  4. +0
    -0
      shadowsocks-csharp/Controller/Service/PolipoRunner.cs
  5. +0
    -0
      shadowsocks-csharp/Controller/Service/PortForwarder.cs
  6. +5
    -4
      shadowsocks-csharp/Controller/Service/TCPRelay.cs
  7. +5
    -4
      shadowsocks-csharp/Controller/Service/UDPRelay.cs
  8. +0
    -0
      shadowsocks-csharp/Controller/Service/UpdateChecker.cs
  9. +37
    -3
      shadowsocks-csharp/Controller/ShadowsocksController.cs
  10. +72
    -0
      shadowsocks-csharp/Controller/Strategy/BalancingStrategy.cs
  11. +30
    -0
      shadowsocks-csharp/Controller/Strategy/IStrategy.cs
  12. +21
    -0
      shadowsocks-csharp/Controller/Strategy/StrategyManager.cs
  13. +0
    -0
      shadowsocks-csharp/Controller/System/AutoStartup.cs
  14. +0
    -0
      shadowsocks-csharp/Controller/System/SystemProxy.cs
  15. +1
    -0
      shadowsocks-csharp/Data/cn.txt
  16. +5
    -2
      shadowsocks-csharp/Model/Configuration.cs
  17. +1
    -1
      shadowsocks-csharp/View/ConfigForm.cs
  18. +44
    -17
      shadowsocks-csharp/View/MenuViewController.cs
  19. +13
    -10
      shadowsocks-csharp/shadowsocks-csharp.csproj

shadowsocks-csharp/Controller/GfwListUpdater.cs → shadowsocks-csharp/Controller/Service/GfwListUpdater.cs View File


shadowsocks-csharp/Controller/Listener.cs → shadowsocks-csharp/Controller/Service/Listener.cs View File


shadowsocks-csharp/Controller/PACServer.cs → shadowsocks-csharp/Controller/Service/PACServer.cs View File


shadowsocks-csharp/Controller/PolipoRunner.cs → shadowsocks-csharp/Controller/Service/PolipoRunner.cs View File


shadowsocks-csharp/Controller/PortForwarder.cs → shadowsocks-csharp/Controller/Service/PortForwarder.cs View File


shadowsocks-csharp/Controller/TCPRelay.cs → shadowsocks-csharp/Controller/Service/TCPRelay.cs View File

@@ -5,16 +5,17 @@ using System.Net.Sockets;
using System.Net; using System.Net;
using Shadowsocks.Encryption; using Shadowsocks.Encryption;
using Shadowsocks.Model; using Shadowsocks.Model;
using Shadowsocks.Controller.Strategy;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
class TCPRelay : Listener.Service 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) 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); socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
Handler handler = new Handler(); Handler handler = new Handler();
handler.connection = socket; 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.encryptor = EncryptorFactory.GetEncryptor(server.method, server.password);
handler.server = server; handler.server = server;

shadowsocks-csharp/Controller/UDPRelay.cs → shadowsocks-csharp/Controller/Service/UDPRelay.cs View File

@@ -6,16 +6,17 @@ using Shadowsocks.Model;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net; using System.Net;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Shadowsocks.Controller.Strategy;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
class UDPRelay : Listener.Service class UDPRelay : Listener.Service
{ {
private Configuration _config;
private ShadowsocksController _controller;
private LRUCache<IPEndPoint, UDPHandler> _cache; 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 this._cache = new LRUCache<IPEndPoint, UDPHandler>(512); // todo: choose a smart number
} }
@@ -34,7 +35,7 @@ namespace Shadowsocks.Controller
UDPHandler handler = _cache.get(remoteEndPoint); UDPHandler handler = _cache.get(remoteEndPoint);
if (handler == null) 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); _cache.add(remoteEndPoint, handler);
} }
handler.Send(firstPacket, length); handler.Send(firstPacket, length);

shadowsocks-csharp/Controller/UpdateChecker.cs → shadowsocks-csharp/Controller/Service/UpdateChecker.cs View File


+ 37
- 3
shadowsocks-csharp/Controller/ShadowsocksController.cs View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Net.Sockets; using System.Net.Sockets;
using Shadowsocks.Controller.Strategy;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
@@ -20,6 +21,7 @@ namespace Shadowsocks.Controller
private Listener _listener; private Listener _listener;
private PACServer _pacServer; private PACServer _pacServer;
private Configuration _config; private Configuration _config;
private StrategyManager _strategyManager;
private PolipoRunner polipoRunner; private PolipoRunner polipoRunner;
private GFWListUpdater gfwListUpdater; private GFWListUpdater gfwListUpdater;
private bool stopped = false; private bool stopped = false;
@@ -49,6 +51,7 @@ namespace Shadowsocks.Controller
public ShadowsocksController() public ShadowsocksController()
{ {
_config = Configuration.Load(); _config = Configuration.Load();
_strategyManager = new StrategyManager(this);
} }
public void Start() public void Start()
@@ -70,11 +73,34 @@ namespace Shadowsocks.Controller
} }
// always return copy // always return copy
public Configuration GetConfiguration()
public Configuration GetConfigurationCopy()
{ {
return Configuration.Load(); 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) public void SaveServers(List<Server> servers, int localPort)
{ {
_config.configs = servers; _config.configs = servers;
@@ -134,6 +160,14 @@ namespace Shadowsocks.Controller
public void SelectServerIndex(int index) public void SelectServerIndex(int index)
{ {
_config.index = index; _config.index = index;
_config.strategy = null;
SaveConfig(_config);
}
public void SelectStrategy(string strategyID)
{
_config.index = -1;
_config.strategy = strategyID;
SaveConfig(_config); SaveConfig(_config);
} }
@@ -250,8 +284,8 @@ namespace Shadowsocks.Controller
{ {
polipoRunner.Start(_config); 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>(); List<Listener.Service> services = new List<Listener.Service>();
services.Add(tcpRelay); services.Add(tcpRelay);
services.Add(udpRelay); services.Add(udpRelay);


+ 72
- 0
shadowsocks-csharp/Controller/Strategy/BalancingStrategy.cs View File

@@ -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
}
}
}

+ 30
- 0
shadowsocks-csharp/Controller/Strategy/IStrategy.cs View File

@@ -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);
}
}

+ 21
- 0
shadowsocks-csharp/Controller/Strategy/StrategyManager.cs View File

@@ -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;
}
}
}

shadowsocks-csharp/Controller/AutoStartup.cs → shadowsocks-csharp/Controller/System/AutoStartup.cs View File


shadowsocks-csharp/Controller/SystemProxy.cs → shadowsocks-csharp/Controller/System/SystemProxy.cs View File


+ 1
- 0
shadowsocks-csharp/Data/cn.txt View File

@@ -23,6 +23,7 @@ Show Logs...=显示日志...
About...=关于... About...=关于...
Quit=退出 Quit=退出
Edit Servers=编辑服务器 Edit Servers=编辑服务器
Load Balance=负载均衡


# Config Form # Config Form




+ 5
- 2
shadowsocks-csharp/Model/Configuration.cs View File

@@ -11,6 +11,9 @@ namespace Shadowsocks.Model
public class Configuration public class Configuration
{ {
public List<Server> configs; public List<Server> configs;
// when strategy is set, index is ignored
public string strategy;
public int index; public int index;
public bool global; public bool global;
public bool enabled; public bool enabled;
@@ -79,9 +82,9 @@ namespace Shadowsocks.Model
{ {
config.index = config.configs.Count - 1; config.index = config.configs.Count - 1;
} }
if (config.index < 0)
if (config.index < -1)
{ {
config.index = 0;
config.index = -1;
} }
config.isDefault = false; config.isDefault = false;
try try


+ 1
- 1
shadowsocks-csharp/View/ConfigForm.cs View File

@@ -133,7 +133,7 @@ namespace Shadowsocks.View
private void LoadCurrentConfiguration() private void LoadCurrentConfiguration()
{ {
_modifiedConfiguration = controller.GetConfiguration();
_modifiedConfiguration = controller.GetConfigurationCopy();
LoadConfiguration(_modifiedConfiguration); LoadConfiguration(_modifiedConfiguration);
_oldSelectedIndex = _modifiedConfiguration.index; _oldSelectedIndex = _modifiedConfiguration.index;
ServersListBox.SelectedIndex = _modifiedConfiguration.index; ServersListBox.SelectedIndex = _modifiedConfiguration.index;


+ 44
- 17
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -71,9 +71,9 @@ namespace Shadowsocks.View
LoadCurrentConfiguration(); LoadCurrentConfiguration();
updateChecker.CheckUpdate(controller.GetConfiguration());
updateChecker.CheckUpdate(controller.GetConfigurationCopy());
if (controller.GetConfiguration().isDefault)
if (controller.GetConfigurationCopy().isDefault)
{ {
_isFirstRun = true; _isFirstRun = true;
ShowConfigForm(); ShowConfigForm();
@@ -106,7 +106,7 @@ namespace Shadowsocks.View
{ {
icon = Resources.ss24; icon = Resources.ss24;
} }
Configuration config = controller.GetConfiguration();
Configuration config = controller.GetConfigurationCopy();
bool enabled = config.enabled; bool enabled = config.enabled;
bool global = config.global; bool global = config.global;
if (!enabled) if (!enabled)
@@ -124,12 +124,21 @@ namespace Shadowsocks.View
} }
_notifyIcon.Icon = Icon.FromHandle(icon.GetHicon()); _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 // we want to show more details but notify icon title is limited to 63 characters
string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" + string text = I18N.GetString("Shadowsocks") + " " + UpdateChecker.Version + "\n" +
(enabled ? (enabled ?
I18N.GetString("System Proxy On: ") + (global ? I18N.GetString("Global") : I18N.GetString("PAC")) : 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 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)); _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) private void controller_EnableStatusChanged(object sender, EventArgs e)
{ {
enableItem.Checked = controller.GetConfiguration().enabled;
enableItem.Checked = controller.GetConfigurationCopy().enabled;
modeItem.Enabled = enableItem.Checked; modeItem.Enabled = enableItem.Checked;
} }
void controller_ShareOverLANStatusChanged(object sender, EventArgs e) void controller_ShareOverLANStatusChanged(object sender, EventArgs e)
{ {
ShareOverLANItem.Checked = controller.GetConfiguration().shareOverLan;
ShareOverLANItem.Checked = controller.GetConfigurationCopy().shareOverLan;
} }
void controller_EnableGlobalChanged(object sender, EventArgs e) void controller_EnableGlobalChanged(object sender, EventArgs e)
{ {
globalModeItem.Checked = controller.GetConfiguration().global;
globalModeItem.Checked = controller.GetConfigurationCopy().global;
PACModeItem.Checked = !globalModeItem.Checked; PACModeItem.Checked = !globalModeItem.Checked;
} }
@@ -243,7 +252,7 @@ namespace Shadowsocks.View
private void LoadCurrentConfiguration() private void LoadCurrentConfiguration()
{ {
Configuration config = controller.GetConfiguration();
Configuration config = controller.GetConfigurationCopy();
UpdateServersMenu(); UpdateServersMenu();
enableItem.Checked = config.enabled; enableItem.Checked = config.enabled;
modeItem.Enabled = config.enabled; modeItem.Enabled = config.enabled;
@@ -263,20 +272,32 @@ namespace Shadowsocks.View
{ {
items.RemoveAt(0); 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()); MenuItem item = new MenuItem(server.FriendlyName());
item.Tag = i; item.Tag = i;
item.Click += AServerItem_Click; item.Click += AServerItem_Click;
items.Add(i, item); 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); 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) private void ShowLogItem_Click(object sender, EventArgs e)
{ {
string argument = Logging.LogFile; string argument = Logging.LogFile;
@@ -511,11 +538,11 @@ namespace Shadowsocks.View
{ {
if (!onlinePACItem.Checked) if (!onlinePACItem.Checked)
{ {
if (String.IsNullOrEmpty(controller.GetConfiguration().pacUrl))
if (String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl))
{ {
UpdateOnlinePACURLItem_Click(sender, e); UpdateOnlinePACURLItem_Click(sender, e);
} }
if (!String.IsNullOrEmpty(controller.GetConfiguration().pacUrl))
if (!String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl))
{ {
localPACItem.Checked = false; localPACItem.Checked = false;
onlinePACItem.Checked = true; onlinePACItem.Checked = true;
@@ -527,7 +554,7 @@ namespace Shadowsocks.View
private void UpdateOnlinePACURLItem_Click(object sender, EventArgs e) private void UpdateOnlinePACURLItem_Click(object sender, EventArgs e)
{ {
string origPacUrl = controller.GetConfiguration().pacUrl;
string origPacUrl = controller.GetConfigurationCopy().pacUrl;
string pacUrl = Microsoft.VisualBasic.Interaction.InputBox( string pacUrl = Microsoft.VisualBasic.Interaction.InputBox(
I18N.GetString("Please input PAC Url"), I18N.GetString("Please input PAC Url"),
I18N.GetString("Edit Online PAC URL"), I18N.GetString("Edit Online PAC URL"),


+ 13
- 10
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -124,15 +124,15 @@
<Compile Include="3rd\zxing\ResultPoint.cs" /> <Compile Include="3rd\zxing\ResultPoint.cs" />
<Compile Include="3rd\zxing\ResultPointCallback.cs" /> <Compile Include="3rd\zxing\ResultPointCallback.cs" />
<Compile Include="3rd\zxing\WriterException.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\FileManager.cs" />
<Compile Include="Controller\GFWListUpdater.cs" />
<Compile Include="Controller\Service\GFWListUpdater.cs" />
<Compile Include="Controller\I18N.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\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\EncryptorBase.cs" />
<Compile Include="Encryption\EncryptorFactory.cs" /> <Compile Include="Encryption\EncryptorFactory.cs" />
<Compile Include="Encryption\IVEncryptor.cs" /> <Compile Include="Encryption\IVEncryptor.cs" />
@@ -142,7 +142,7 @@
<Compile Include="Encryption\SodiumEncryptor.cs" /> <Compile Include="Encryption\SodiumEncryptor.cs" />
<Compile Include="Encryption\TableEncryptor.cs" /> <Compile Include="Encryption\TableEncryptor.cs" />
<Compile Include="Encryption\IEncryptor.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\Server.cs" />
<Compile Include="Model\Configuration.cs" /> <Compile Include="Model\Configuration.cs" />
<Compile Include="Properties\Resources.Designer.cs"> <Compile Include="Properties\Resources.Designer.cs">
@@ -150,6 +150,9 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </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="Util\Util.cs" />
<Compile Include="View\ConfigForm.cs"> <Compile Include="View\ConfigForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
@@ -157,12 +160,12 @@
<Compile Include="View\ConfigForm.Designer.cs"> <Compile Include="View\ConfigForm.Designer.cs">
<DependentUpon>ConfigForm.cs</DependentUpon> <DependentUpon>ConfigForm.cs</DependentUpon>
</Compile> </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="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Controller\ShadowsocksController.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\MenuViewController.cs" />
<Compile Include="View\QRCodeForm.cs"> <Compile Include="View\QRCodeForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>


Loading…
Cancel
Save