Browse Source

add LRUCache for UDPRelay

tags/2.4
clowwindy 10 years ago
parent
commit
09def2fc27
2 changed files with 91 additions and 5 deletions
  1. +1
    -1
      shadowsocks-csharp/Controller/Listener.cs
  2. +90
    -4
      shadowsocks-csharp/Controller/UDPRelay.cs

+ 1
- 1
shadowsocks-csharp/Controller/Listener.cs View File

@@ -18,7 +18,7 @@ namespace Shadowsocks.Controller
public class UDPState public class UDPState
{ {
public byte[] buffer = new byte[4096]; public byte[] buffer = new byte[4096];
public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
public EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 1);
} }
Configuration _config; Configuration _config;


+ 90
- 4
shadowsocks-csharp/Controller/UDPRelay.cs View File

@@ -5,15 +5,18 @@ using Shadowsocks.Encryption;
using Shadowsocks.Model; using Shadowsocks.Model;
using System.Net.Sockets; using System.Net.Sockets;
using System.Net; using System.Net;
using System.Runtime.CompilerServices;
namespace Shadowsocks.Controller namespace Shadowsocks.Controller
{ {
class UDPRelay : Listener.Service class UDPRelay : Listener.Service
{ {
private Configuration _config; private Configuration _config;
private LRUCache<IPEndPoint, UDPHandler> _cache;
public UDPRelay(Configuration config) public UDPRelay(Configuration config)
{ {
this._config = config; this._config = config;
this._cache = new LRUCache<IPEndPoint, UDPHandler>(512); // todo: choose a smart number
} }
public bool Handle(byte[] firstPacket, int length, Socket socket, object state) public bool Handle(byte[] firstPacket, int length, Socket socket, object state)
@@ -27,14 +30,19 @@ namespace Shadowsocks.Controller
return false; return false;
} }
Listener.UDPState udpState = (Listener.UDPState)state; Listener.UDPState udpState = (Listener.UDPState)state;
// TODO add cache
UDPHandler handler = new UDPHandler(socket, _config.GetCurrentServer(), (IPEndPoint)udpState.remoteEndPoint);
IPEndPoint remoteEndPoint = (IPEndPoint)udpState.remoteEndPoint;
UDPHandler handler = _cache.get(remoteEndPoint);
if (handler == null)
{
handler = new UDPHandler(socket, _config.GetCurrentServer(), remoteEndPoint);
_cache.add(remoteEndPoint, handler);
}
handler.Send(firstPacket, length); handler.Send(firstPacket, length);
handler.Receive(); handler.Receive();
return true; return true;
} }
class UDPHandler
public class UDPHandler
{ {
private Socket _local; private Socket _local;
private Socket _remote; private Socket _remote;
@@ -47,7 +55,6 @@ namespace Shadowsocks.Controller
public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint) public UDPHandler(Socket local, Server server, IPEndPoint localEndPoint)
{ {
// TODO add timeout
_local = local; _local = local;
_server = server; _server = server;
_localEndPoint = localEndPoint; _localEndPoint = localEndPoint;
@@ -108,6 +115,85 @@ namespace Shadowsocks.Controller
{ {
} }
} }
public void Close()
{
try
{
_remote.Close();
}
catch (ObjectDisposedException)
{
}
catch (Exception e)
{
}
finally
{
}
}
}
}
// cc by-sa 3.0 http://stackoverflow.com/a/3719378/1124054
class LRUCache<K, V> where V : UDPRelay.UDPHandler
{
private int capacity;
private Dictionary<K, LinkedListNode<LRUCacheItem<K, V>>> cacheMap = new Dictionary<K, LinkedListNode<LRUCacheItem<K, V>>>();
private LinkedList<LRUCacheItem<K, V>> lruList = new LinkedList<LRUCacheItem<K, V>>();
public LRUCache(int capacity)
{
this.capacity = capacity;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public V get(K key)
{
LinkedListNode<LRUCacheItem<K, V>> node;
if (cacheMap.TryGetValue(key, out node))
{
V value = node.Value.value;
lruList.Remove(node);
lruList.AddLast(node);
return value;
}
return default(V);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void add(K key, V val)
{
if (cacheMap.Count >= capacity)
{
RemoveFirst();
}
LRUCacheItem<K, V> cacheItem = new LRUCacheItem<K, V>(key, val);
LinkedListNode<LRUCacheItem<K, V>> node = new LinkedListNode<LRUCacheItem<K, V>>(cacheItem);
lruList.AddLast(node);
cacheMap.Add(key, node);
} }
private void RemoveFirst()
{
// Remove from LRUPriority
LinkedListNode<LRUCacheItem<K, V>> node = lruList.First;
lruList.RemoveFirst();
// Remove from cache
cacheMap.Remove(node.Value.key);
node.Value.value.Close();
}
}
class LRUCacheItem<K, V>
{
public LRUCacheItem(K k, V v)
{
key = k;
value = v;
}
public K key;
public V value;
} }
} }

Loading…
Cancel
Save