This commit is contained in:
snltty
2025-03-14 21:19:03 +08:00
parent 8e21f0734d
commit bb6ca0c03a
10 changed files with 521 additions and 84 deletions

View File

@@ -153,9 +153,9 @@ action.json
:::tip[v1.7.0+]
1. 如果你使用第三方程序启动linker`仅配置文件不存在时初始化,后续不会覆盖`,可以传入参数进行初始化,`client.json``server.json``action.json``common.json`
2. 像这样不填写的字段将以默认值生成json的双引号需要转义json里不能有空格
2. 像这样,不填写的字段将以默认值生成,json转为base64
```
linker.exe --config-client {\"a\":\"1\"} --config-server {\"a\":\"1\"} --config-action {\"a\":\"1\"} --config-common {\"a\":\"1\"}
linker.exe --config-client base641 --config-server base642 --config-action base643 --config-common base644
```
:::

View File

@@ -18,7 +18,6 @@ using linker.messenger.updater;
using linker.messenger.store.file;
using linker.messenger.serializer.memorypack;
using linker.libs;
using linker.libs.extends;
namespace linker.messenger.entry
{
@@ -30,11 +29,6 @@ namespace linker.messenger.entry
private static OperatingManager builded = new OperatingManager();
private static OperatingManager setuped = new OperatingManager();
public static void InputJsonConfig(string str)
{
Console.WriteLine(str.DeJson<ConfigClientInfo>().ToJsonFormat());
}
/// <summary>
/// 开始初始化
/// </summary>

View File

@@ -60,7 +60,7 @@ namespace linker.messenger.listen
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, port);
Socket socket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.IPv6Only(localEndPoint.AddressFamily, false);
//socket.IPv6Only(localEndPoint.AddressFamily, false);
socket.Bind(localEndPoint);
socket.Listen(int.MaxValue);

View File

@@ -329,4 +329,318 @@ namespace linker.messenger.relay.client.transport
return new List<RelayServerNodeReportInfo170>();
}
}
public class RelayClientTransportSelfHostUdp : IRelayClientTransport
{
public string Name => "LinkerUdp";
public RelayClientType Type => RelayClientType.Linker;
public TunnelProtocolType ProtocolType => TunnelProtocolType.Udp;
private readonly IMessengerSender messengerSender;
private readonly ISerializer serializer;
private readonly IRelayClientStore relayClientStore;
private readonly SignInClientState signInClientState;
private readonly IMessengerStore messengerStore;
public RelayClientTransportSelfHostUdp(IMessengerSender messengerSender, ISerializer serializer, IRelayClientStore relayClientStore, SignInClientState signInClientState, IMessengerStore messengerStore)
{
this.messengerSender = messengerSender;
this.serializer = serializer;
this.relayClientStore = relayClientStore;
this.signInClientState = signInClientState;
this.messengerStore = messengerStore;
}
public async Task<ITunnelConnection> RelayAsync(RelayInfo170 relayInfo)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
try
{
//问一下能不能中继
RelayAskResultInfo170 relayAskResultInfo = await RelayAsk(relayInfo);
relayInfo.FlowingId = relayAskResultInfo.FlowingId;
if (relayInfo.FlowingId == 0 || relayAskResultInfo.Nodes.Count == 0)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay ask fail,flowid:{relayInfo.FlowingId},nodes:{relayAskResultInfo.Nodes.Count}");
return null;
}
//测试一下延迟
if (relayAskResultInfo.Nodes.Count > 1)
{
//relayAskResultInfo.Nodes = await TestDelay(relayAskResultInfo.Nodes);
}
//连接中继节点服务器
Socket socket = await ConnectNodeServer(relayInfo, relayAskResultInfo.Nodes);
if (socket == null)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay connect server fail,flowid:{relayInfo.FlowingId},nodes:{relayAskResultInfo.Nodes.Count}");
return null;
}
//让对方确认中继
if (await RelayConfirm(relayInfo) == false)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay confirm fail,flowid:{relayInfo.FlowingId},nodes:{relayAskResultInfo.Nodes.Count}");
return null;
}
//成功建立连接,
SslStream sslStream = null;
if (relayInfo.SSL)
{
sslStream = new SslStream(new NetworkStream(socket, false), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
{
EnabledSslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
}).ConfigureAwait(false);
}
return new TunnelConnectionTcp
{
Direction = TunnelDirection.Forward,
ProtocolType = TunnelProtocolType.Tcp,
RemoteMachineId = relayInfo.RemoteMachineId,
RemoteMachineName = relayInfo.RemoteMachineName,
Stream = sslStream,
Socket = socket,
Mode = TunnelMode.Client,
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
TransactionId = relayInfo.TransactionId,
TransportName = Name,
Type = TunnelType.Relay,
NodeId = relayInfo.NodeId,
SSL = relayInfo.SSL,
BufferSize = 3
};
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
return null;
}
private async Task<RelayAskResultInfo170> RelayAsk(RelayInfo170 relayInfo)
{
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.RelayAsk170,
Payload = serializer.Serialize(relayInfo),
Timeout = 2000
}).ConfigureAwait(false);
if (resp.Code != MessageResponeCodes.OK)
{
return new RelayAskResultInfo170();
}
RelayAskResultInfo170 result = serializer.Deserialize<RelayAskResultInfo170>(resp.Data.Span);
return result;
}
private async Task<Socket> ConnectNodeServer(RelayInfo170 relayInfo, List<RelayServerNodeReportInfo170> nodes)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(1 * 1024);
try
{
foreach (var node in nodes.Where(c => c.Id == relayInfo.NodeId).Concat(nodes.Where(c => c.Id != relayInfo.NodeId)))
{
try
{
IPEndPoint ep = node.EndPoint;
if (ep == null || ep.Address.Equals(IPAddress.Any))
{
ep = signInClientState.Connection.Address;
}
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Debug($"connect relay server {ep}");
//连接中继服务器
Socket socket = new Socket(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
//建立关联
RelayMessageInfo relayMessage = new RelayMessageInfo
{
FlowId = relayInfo.FlowingId,
Type = RelayMessengerType.Ask,
FromId = relayInfo.FromMachineId,
ToId = relayInfo.RemoteMachineId,
NodeId = node.Id,
};
await socket.SendAsync(new byte[] { (byte)ResolverType.Relay });
await socket.SendAsync(serializer.Serialize(relayMessage));
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG) LoggerHelper.Instance.Debug($"relay connected {ep}");
//是否允许连接
int length = await socket.ReceiveAsync(buffer.AsMemory(0, 1));
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Debug($"relay connected {ep}->{buffer[0]}");
if (buffer[0] == 0)
{
relayInfo.Server = node.EndPoint;
relayInfo.NodeId = node.Id;
return socket;
}
socket.SafeClose();
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
}
}
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
return null;
}
private async Task<bool> RelayConfirm(RelayInfo170 relayInfo)
{
//通知对方去确认中继
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.RelayForward170,
Payload = serializer.Serialize(relayInfo),
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
public async Task<bool> OnBeginAsync(RelayInfo170 relayInfo, Action<ITunnelConnection> callback)
{
try
{
IPEndPoint ep = relayInfo.Server == null || relayInfo.Server.Address.Equals(IPAddress.Any) ? signInClientState.Connection.Address : relayInfo.Server;
Socket socket = new Socket(ep.AddressFamily, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(ep).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
RelayMessageInfo relayMessage = new RelayMessageInfo
{
FlowId = relayInfo.FlowingId,
Type = RelayMessengerType.Answer,
FromId = relayInfo.FromMachineId,
ToId = relayInfo.RemoteMachineId,
NodeId = relayInfo.NodeId,
};
await socket.SendAsync(new byte[] { (byte)ResolverType.Relay });
await socket.SendAsync(serializer.Serialize(relayMessage));
_ = WaitSSL(socket, relayInfo).ContinueWith((result) =>
{
callback(result.Result);
});
return true;
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
callback(null);
}
return false;
}
private async Task<TunnelConnectionTcp> WaitSSL(Socket socket, RelayInfo170 relayInfo)
{
try
{
SslStream sslStream = null;
if (relayInfo.SSL)
{
sslStream = new SslStream(new NetworkStream(socket, false), false);
await sslStream.AuthenticateAsServerAsync(messengerStore.Certificate, false, SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false).ConfigureAwait(false);
}
return new TunnelConnectionTcp
{
Direction = TunnelDirection.Reverse,
ProtocolType = TunnelProtocolType.Tcp,
RemoteMachineId = relayInfo.RemoteMachineId,
RemoteMachineName = relayInfo.RemoteMachineName,
Stream = sslStream,
Socket = socket,
Mode = TunnelMode.Server,
IPEndPoint = NetworkHelper.TransEndpointFamily(socket.RemoteEndPoint as IPEndPoint),
TransactionId = relayInfo.TransactionId,
TransportName = Name,
Type = TunnelType.Relay,
NodeId = relayInfo.NodeId,
SSL = relayInfo.SSL,
BufferSize = 3,
};
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
LoggerHelper.Instance.Error(ex);
}
socket.SafeClose();
}
return null;
}
public async Task<List<RelayServerNodeReportInfo170>> RelayTestAsync(RelayTestInfo170 relayTestInfo)
{
try
{
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.RelayTest170,
Payload = serializer.Serialize(relayTestInfo),
Timeout = 2000
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<List<RelayServerNodeReportInfo170>>(resp.Data.Span);
}
}
catch (Exception)
{
}
return new List<RelayServerNodeReportInfo170>();
}
}
}

View File

@@ -168,6 +168,15 @@ namespace linker.messenger.relay.server
{
return limitTotal.TryLimit(ref length);
}
/// <summary>
/// 总限速
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public bool TryLimitPacket(int length)
{
return limitTotal.TryLimitPacket(length);
}
/// <summary>
@@ -342,7 +351,7 @@ namespace linker.messenger.relay.server
MaxGbTotal = node.MaxGbTotal,
MaxGbTotalLastBytes = node.MaxGbTotalLastBytes,
MaxConnection = node.MaxConnection,
ConnectionRatio = Math.Round(connectionNum / 2.0),
ConnectionRatio = connectionNum,
EndPoint = endPoint,
Url = node.Url
};

View File

@@ -4,6 +4,7 @@ using linker.libs.extends;
using System.Collections.Concurrent;
using System.Net;
using linker.libs;
using System;
namespace linker.messenger.relay.server
{
@@ -20,9 +21,12 @@ namespace linker.messenger.relay.server
{
this.relayServerNodeTransfer = relayServerNodeTransfer;
this.serializer = serializer;
ClearTask();
}
private readonly ConcurrentDictionary<ulong, RelayWrapInfo> relayDic = new ConcurrentDictionary<ulong, RelayWrapInfo>();
private readonly ConcurrentDictionary<ulong, TaskCompletionSource<Socket>> relayDic = new ConcurrentDictionary<ulong, TaskCompletionSource<Socket>>();
private readonly ConcurrentDictionary<IPEndPoint, RelayUdpNatInfo> udpNat = new ConcurrentDictionary<IPEndPoint, RelayUdpNatInfo>();
private readonly ConcurrentDictionary<ulong, RelayUdpNatInfo> relayUdpDic = new ConcurrentDictionary<ulong, RelayUdpNatInfo>();
public virtual void AddReceive(string key, string from, string to, string groupid, long bytes)
{
@@ -40,15 +44,100 @@ namespace linker.messenger.relay.server
public async Task Resolve(Socket socket, IPEndPoint ep, Memory<byte> memory)
{
await Task.CompletedTask;
RelayUdpStep step = (RelayUdpStep)memory.Span[0];
memory = memory.Slice(1);
if (step == RelayUdpStep.Forward)
{
if (udpNat.TryGetValue(ep, out RelayUdpNatInfo natTarget) && natTarget.Target != null)
{
natTarget.LastTicks = Environment.TickCount64;
await CopyToAsync(natTarget, socket,ep,memory);
}
return;
}
RelayMessageInfo relayMessage = serializer.Deserialize<RelayMessageInfo>(memory.Span);
//ask 是发起端来的那key就是 发起端->目标端, answer的目标和来源会交换所以转换一下
string key = relayMessage.Type == RelayMessengerType.Ask ? $"{relayMessage.FromId}->{relayMessage.ToId}->{relayMessage.FlowId}" : $"{relayMessage.ToId}->{relayMessage.FromId}->{relayMessage.FlowId}";
//获取缓存
RelayCacheInfo relayCache = await relayServerNodeTransfer.TryGetRelayCache(key);
if (relayCache == null)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
await socket.SendToAsync(new byte[] { 1 }, ep);
return;
}
if (relayMessage.Type == RelayMessengerType.Ask && relayServerNodeTransfer.Validate(relayCache) == false)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} Validate false,flowid:{relayMessage.FlowId}");
await socket.SendToAsync(new byte[] { 1 }, ep);
return;
}
//流量统计
AddReceive(relayCache.FromId, relayCache.FromName, relayCache.ToName, relayCache.GroupId, memory.Length);
//回应
if (relayMessage.Type == RelayMessengerType.Answer)
{
if (relayUdpDic.TryRemove(relayCache.FlowId, out RelayUdpNatInfo natAsk))
{
natAsk.Target = ep;
RelayUdpNatInfo natAnswer = new RelayUdpNatInfo { Target = natAsk.Source, Traffic = natAsk.Traffic, Source = ep };
udpNat.AddOrUpdate(ep, natAnswer, (a, b) => natAnswer);
}
return;
}
//请求
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
RelayUdpNatInfo nat = new RelayUdpNatInfo { IsAsk = true, Source = ep, Traffic = trafficCacheInfo };
udpNat.AddOrUpdate(ep, nat, (a, b) => nat);
relayUdpDic.TryAdd(relayCache.FlowId, nat);
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
relayServerNodeTransfer.IncrementConnectionNum();
}
private async Task CopyToAsync(RelayUdpNatInfo nat, Socket socket, IPEndPoint ep, Memory<byte> memory)
{
RelayTrafficCacheInfo trafficCacheInfo = nat.Traffic;
int bytesRead = memory.Length;
//流量限制
if (relayServerNodeTransfer.AddBytes(trafficCacheInfo, bytesRead) == false)
{
return;
}
//总速度
if (relayServerNodeTransfer.NeedLimit(trafficCacheInfo) && relayServerNodeTransfer.TryLimitPacket(bytesRead) == false)
{
return;
}
//单个速度
if (trafficCacheInfo.Limit.NeedLimit() && trafficCacheInfo.Limit.TryLimitPacket(bytesRead) == false)
{
return;
}
AddReceive(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
AddSendt(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
await socket.SendToAsync(memory, nat.Target).ConfigureAwait(false);
}
public async Task Resolve(Socket socket, Memory<byte> memory)
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
byte[] buffer1 = new byte[8 * 1024];
try
{
int length = await socket.ReceiveAsync(buffer.AsMemory(), SocketFlags.None).ConfigureAwait(false);
RelayMessageInfo relayMessage = serializer.Deserialize<RelayMessageInfo>(buffer.AsMemory(0, length).Span);
int length = await socket.ReceiveAsync(buffer1.AsMemory(), SocketFlags.None).ConfigureAwait(false);
RelayMessageInfo relayMessage = serializer.Deserialize<RelayMessageInfo>(buffer1.AsMemory(0, length).Span);
//ask 是发起端来的那key就是 发起端->目标端, answer的目标和来源会交换所以转换一下
string key = relayMessage.Type == RelayMessengerType.Ask ? $"{relayMessage.FromId}->{relayMessage.ToId}->{relayMessage.FlowId}" : $"{relayMessage.ToId}->{relayMessage.FromId}->{relayMessage.FlowId}";
@@ -66,7 +155,7 @@ namespace linker.messenger.relay.server
if (relayMessage.Type == RelayMessengerType.Ask && relayServerNodeTransfer.Validate(relayCache) == false)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} Validate false,flowid:{relayMessage.FlowId}");
LoggerHelper.Instance.Error($"relay {relayMessage.Type} validate false,flowid:{relayMessage.FlowId}");
await socket.SendAsync(new byte[] { 1 });
socket.SafeClose();
return;
@@ -74,61 +163,42 @@ namespace linker.messenger.relay.server
//流量统计
AddReceive(relayCache.FromId, relayCache.FromName, relayCache.ToName, relayCache.GroupId, length);
if (relayMessage.Type == RelayMessengerType.Answer)
{
if (relayDic.TryRemove(relayCache.FlowId, out TaskCompletionSource<Socket> tcsAsk))
{
tcsAsk.SetResult(socket);
}
else
{
socket.SafeClose();
}
return;
}
try
{
switch (relayMessage.Type)
{
case RelayMessengerType.Ask:
{
//添加本地缓存
RelayWrapInfo relayWrap = new RelayWrapInfo { Socket = socket, Tcs = new TaskCompletionSource() };
await socket.SendAsync(new byte[] { 0 });
relayDic.TryAdd(relayCache.FlowId, relayWrap);
TaskCompletionSource<Socket> tcs = new TaskCompletionSource<Socket>();
relayDic.TryAdd(relayCache.FlowId, tcs);
Socket answerSocket = await tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000));
await socket.SendAsync(new byte[] { 0 });
//等待对方连接
await relayWrap.Tcs.Task.WaitAsync(TimeSpan.FromMilliseconds(15000));
}
break;
case RelayMessengerType.Answer:
{
//看发起端缓存
if (relayDic.TryRemove(relayCache.FlowId, out RelayWrapInfo relayWrap) == false || relayWrap.Socket == null)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} get cache fail,flowid:{relayMessage.FlowId}");
socket.SafeClose();
return;
}
relayWrap.Tcs.SetResult();
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
relayServerNodeTransfer.IncrementConnectionNum();
_ = Task.WhenAll(CopyToAsync(trafficCacheInfo, socket, relayWrap.Socket), CopyToAsync(trafficCacheInfo, relayWrap.Socket, socket)).ContinueWith((result) =>
{
relayServerNodeTransfer.DecrementConnectionNum();
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
});
}
break;
default:
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"relay {relayMessage.Type} unknow type,flowid:{relayMessage.FlowId}");
socket.SafeClose();
}
break;
}
byte[] buffer2 = new byte[8 * 1024];
RelayTrafficCacheInfo trafficCacheInfo = new RelayTrafficCacheInfo { Cache = relayCache, Sendt = 0, Limit = new RelaySpeedLimit() };
relayServerNodeTransfer.AddTrafficCache(trafficCacheInfo);
relayServerNodeTransfer.IncrementConnectionNum();
await Task.WhenAll(CopyToAsync(trafficCacheInfo, socket, answerSocket, buffer1), CopyToAsync(trafficCacheInfo, answerSocket, socket, buffer2)).ConfigureAwait(false);
relayServerNodeTransfer.DecrementConnectionNum();
relayServerNodeTransfer.RemoveTrafficCache(trafficCacheInfo);
}
catch (Exception ex)
{
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
LoggerHelper.Instance.Error($"{ex},flowid:{relayMessage.FlowId}");
if (relayDic.TryRemove(relayCache.FlowId, out RelayWrapInfo remove))
{
remove.Socket?.SafeClose();
}
relayDic.TryRemove(relayCache.FlowId, out _);
socket.SafeClose();
}
}
catch (Exception ex)
@@ -137,18 +207,13 @@ namespace linker.messenger.relay.server
LoggerHelper.Instance.Error(ex);
socket.SafeClose();
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
}
private async Task CopyToAsync(RelayTrafficCacheInfo trafficCacheInfo, Socket source, Socket destination)
private async Task CopyToAsync(RelayTrafficCacheInfo trafficCacheInfo, Socket source, Socket destination, Memory<byte> memory)
{
byte[] buffer = new byte[8 * 1024];
try
{
int bytesRead;
while ((bytesRead = await source.ReceiveAsync(buffer.AsMemory(), SocketFlags.None).ConfigureAwait(false)) != 0)
while ((bytesRead = await source.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false)) != 0)
{
//流量限制
if (relayServerNodeTransfer.AddBytes(trafficCacheInfo, bytesRead) == false)
@@ -182,7 +247,7 @@ namespace linker.messenger.relay.server
AddReceive(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
AddSendt(trafficCacheInfo.Cache.FromId, trafficCacheInfo.Cache.FromName, trafficCacheInfo.Cache.ToName, trafficCacheInfo.Cache.GroupId, bytesRead);
await destination.SendAsync(buffer.AsMemory(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
await destination.SendAsync(memory.Slice(0, bytesRead), SocketFlags.None).ConfigureAwait(false);
}
}
catch (Exception)
@@ -194,6 +259,47 @@ namespace linker.messenger.relay.server
destination.SafeClose();
}
}
private void ClearTask()
{
TimerHelper.SetIntervalLong(() =>
{
try
{
long ticks = Environment.TickCount64;
foreach (var item in udpNat.Values.Where(c => c.IsAsk && ticks - c.LastTicks > 30000).ToList())
{
relayServerNodeTransfer.DecrementConnectionNum();
relayServerNodeTransfer.RemoveTrafficCache(item.Traffic);
relayUdpDic.TryRemove(item.Traffic.Cache.FlowId, out _);
if (item.Target != null)
{
udpNat.TryRemove(item.Target, out _);
}
}
}
catch (Exception)
{
}
return true;
}, 5000);
}
}
public enum RelayUdpStep : byte
{
Connect = 0,
Forward = 1,
}
public sealed class RelayUdpNatInfo
{
public bool IsAsk { get; set; }
public IPEndPoint Source { get; set; }
public IPEndPoint Target { get; set; }
public long LastTicks { get; set; } = Environment.TickCount64;
public RelayTrafficCacheInfo Traffic { get; set; }
}
@@ -221,7 +327,7 @@ namespace linker.messenger.relay.server
}
public bool TryLimit(ref int length)
{
if (relayLimit == 0) return false;
if (relayLimit == 0) return true;
lock (this)
{
@@ -244,6 +350,26 @@ namespace linker.messenger.relay.server
}
return true;
}
public bool TryLimitPacket(int length)
{
if (relayLimit == 0) return true;
lock (this)
{
long _relayLimitTicks = Environment.TickCount64;
long relayLimitTicksTemp = _relayLimitTicks - relayLimitTicks;
relayLimitTicks = _relayLimitTicks;
relayLimitBucket += relayLimitTicksTemp * relayLimitToken;
if (relayLimitBucket > relayLimit) relayLimitBucket = relayLimit;
if (relayLimitBucket >= length)
{
relayLimitBucket -= length;
return true;
}
}
return false;
}
}
public sealed partial class RelayCacheInfo
@@ -279,13 +405,6 @@ namespace linker.messenger.relay.server
public long LastBytes { get; set; }
}
public sealed class RelayWrapInfo
{
public TaskCompletionSource Tcs { get; set; }
public Socket Socket { get; set; }
}
public sealed partial class RelayMessageInfo
{
public RelayMessengerType Type { get; set; }

View File

@@ -69,9 +69,9 @@ namespace linker.messenger.store.file
{
text = File.ReadAllText(item.Value.Path, encoding: System.Text.Encoding.UTF8);
}
else if (dic != null && dic.ContainsKey(item.Value.Property.Name))
else if (dic != null && dic.TryGetValue(item.Value.Property.Name, out string base64))
{
text = dic[item.Value.Property.Name];
text = Encoding.UTF8.GetString(Convert.FromBase64String(base64));
}
if (string.IsNullOrWhiteSpace(text))
{

View File

@@ -162,13 +162,14 @@ namespace linker.tun
{
return;
}
/*
CommandHelper.Windows(string.Empty, [$"net start SharedAccess"]);
string result = CommandHelper.Windows(string.Empty, [$"linker.ics.exe {defaultInterfaceName} {Name} enable"]);
if (result.Contains($"enable success"))
{
return;
}
*/
error = "NetNat and ICS not supported";
}
catch (Exception ex)
@@ -185,7 +186,7 @@ namespace linker.tun
{
CommandHelper.PowerShell($"start-service WinNat", [], out error);
CommandHelper.PowerShell($"Remove-NetNat -Name {Name} -Confirm:$false", [], out error);
CommandHelper.Windows(string.Empty, [$"linker.ics.exe {Name} disable"]);
//CommandHelper.Windows(string.Empty, [$"linker.ics.exe {Name} disable"]);
}
catch (Exception ex)
{

View File

@@ -74,7 +74,7 @@ namespace linker
Dictionary<string, string> configDic = new Dictionary<string, string>();
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "--config-cient")
if (args[i] == "--config-client")
{
configDic.Add("Client", args[i+1]);
i++;

View File

@@ -1,5 +1,5 @@
v1.7.0
2025-03-13 09:36:12
2025-03-14 21:19:03
1. 优化linux下路由跟踪问题提高启动速度
2. 优化linux下获取本机IP问题提升虚拟网卡稳定性
3. 增加ICS让win7+、win server2008+支持NAT