Files
linker/linker.messenger.example/Program.cs
snltty 9ef71ce4cb demo
2024-12-22 17:59:01 +08:00

515 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using linker.libs;
using linker.libs.extends;
using linker.messenger.relay.client;
using linker.messenger.relay.client.transport;
using linker.messenger.relay.messenger;
using linker.messenger.relay.server;
using linker.messenger.relay.server.caching;
using linker.messenger.relay.server.validator;
using linker.messenger.signin;
using linker.messenger.tunnel;
using linker.plugins.tunnel;
using linker.tunnel;
using linker.tunnel.connection;
using linker.tunnel.transport;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace linker.messenger.example
{
internal class Program
{
public static PublicConfigInfo publicConfigInfo = new PublicConfigInfo
{
Certificate = new X509Certificate2("./snltty.pfx", "oeq9tw1o"),
TunnelTransports = new List<TunnelTransportItemInfo>
{
new TunnelTransportItemInfo{ BufferSize=3, Disabled=false, DisableReverse=false, DisableSSL=false, Name="udp", Order=0, ProtocolType= TunnelProtocolType.Udp.ToString(), Reverse=true, SSL=true },
new TunnelTransportItemInfo{ BufferSize=3, Disabled=false, DisableReverse=false, DisableSSL=false, Name="TcpP2PNAT", Order=1, ProtocolType= TunnelProtocolType.Tcp.ToString(), Reverse=true, SSL=true },
new TunnelTransportItemInfo{ BufferSize=3, Disabled=false, DisableReverse=false, DisableSSL=false, Name="TcpNutssb", Order=2, ProtocolType= TunnelProtocolType.Tcp.ToString(), Reverse=true, SSL=true },
}
};
static async Task Main(string[] args)
{
LoggerConsole();
Console.WriteLine($"输入server 或者 client:");
string type = Console.ReadLine();
if (type == "server")
{
Server();
}
else
{
await Client();
}
Console.ReadLine();
}
public sealed class TunnelConnectionReceiveCallback : ITunnelConnectionReceiveCallback
{
public async Task Closed(ITunnelConnection connection, object state)
{
Console.WriteLine($"{(connection.Type == TunnelType.P2P ? "" : "")}关闭,收到 {connection.IPEndPoint} {connection.RemoteMachineId} 的关闭");
await Task.CompletedTask;
}
public async Task Receive(ITunnelConnection connection, ReadOnlyMemory<byte> data, object state)
{
Console.WriteLine($"{(connection.Type == TunnelType.P2P ? "" : "")}数据,收到 {connection.IPEndPoint} {connection.RemoteMachineId} 的数据:{data.Span.GetString()}");
await Task.CompletedTask;
}
}
private static async Task Client()
{
//序列化
ISerializer serializer = new Serializer();
//信标发送和接受
IMessengerSender messengerSender = new MessengerSender();
IMessengerResolver messengerResolver = new MessengerResolver(messengerSender);
//打洞相关
TunnelExcludeIPTransfer tunnelExcludeIPTransfer = new TunnelExcludeIPTransfer();
//tunnelExcludeIPTransfer.LoadTunnelExcludeIPs(new List<ITunnelExcludeIP>());
TunnelMessengerAdapter tunnelMessengerAdapter = new TunnelMessengerAdapter(messengerSender, tunnelExcludeIPTransfer, serializer, new TunnelMessengerAdapterStore());
TunnelTransfer tunnelTransfer = new TunnelTransfer(tunnelMessengerAdapter);
tunnelTransfer.SetConnectedCallback("default", (connection) =>
{
Console.WriteLine($"打洞成功,收到 {connection.IPEndPoint} {connection.RemoteMachineId} 的连接");
connection.BeginReceive(new TunnelConnectionReceiveCallback(), null);
});
TunnelClientMessenger tunnelClientMessenger = new TunnelClientMessenger(tunnelTransfer, messengerSender, serializer);
//中继相关
IRelayClientStore relayClientStore = new RelayClientStore();
RelayClientTransfer relayClientTransfer = new RelayClientTransfer(messengerSender, serializer, relayClientStore);
relayClientTransfer.SetConnectedCallback("default", (connection) =>
{
Console.WriteLine($"中继成功,收到 {connection.IPEndPoint} {connection.RemoteMachineId} 的连接");
connection.BeginReceive(new TunnelConnectionReceiveCallback(), null);
});
RelayClientMessenger relayClientMessenger = new RelayClientMessenger(relayClientTransfer, serializer);
//加载这些信标处理器
messengerResolver.LoadMessenger(new List<IMessenger>
{
tunnelClientMessenger,
relayClientMessenger
});
Console.WriteLine($"输入服务端ip端口:");
publicConfigInfo.Host = Console.ReadLine();
Console.WriteLine($"开始连接服务器");
IPEndPoint server = NetworkHelper.GetEndPoint(publicConfigInfo.Host, 1802);
Socket socket = new Socket(server.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(server).WaitAsync(TimeSpan.FromMilliseconds(5000)).ConfigureAwait(false);
publicConfigInfo.SignConnection = await messengerResolver.BeginReceiveClient(socket, true, 1).ConfigureAwait(false);
Console.WriteLine($"开始登录");
MessageResponeInfo resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = publicConfigInfo.SignConnection,
MessengerId = (ushort)SignInMessengerIds.SignIn_V_1_3_1,
Timeout = 2000,
Payload = serializer.Serialize(new SignInfo
{
MachineName = Dns.GetHostName(),
MachineId = string.Empty,
Version = VersionHelper.version,
Args = new Dictionary<string, string>(),
GroupId = "default"
})
}).ConfigureAwait(false);
if (resp.Code != MessageResponeCodes.OK)
{
Console.WriteLine($"登录失败 : {resp.Code}");
publicConfigInfo.SignConnection?.Disponse(6);
return;
}
SignInResponseInfo signResp = serializer.Deserialize<string>(resp.Data.Span).DeJson<SignInResponseInfo>();
if (signResp.Status == false)
{
Console.WriteLine($"登录失败 : {signResp.Msg}");
publicConfigInfo.SignConnection?.Disponse(6);
return;
}
publicConfigInfo.SignConnection.Id = signResp.MachineId;
Console.WriteLine($"你的id:{signResp.MachineId}");
tunnelTransfer.Refresh();
//获取在线列表,其它功能,参照 SignInServerMessenger 里的方法serializer.Deserialize 什么,就传什么
resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = publicConfigInfo.SignConnection,
MessengerId = (ushort)SignInMessengerIds.List,
Timeout = 2000,
Payload = serializer.Serialize(new SignInListRequestInfo
{
Asc = true,
Page = 1,
Size = 10
})
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK)
{
Console.WriteLine($"当前在线 : {serializer.Deserialize<SignInListResponseInfo>(resp.Data.Span).List.ToJson()}");
}
Console.WriteLine($"去连接吗?1打洞2中继:");
string connect = Console.ReadLine();
Console.WriteLine($"输入对方id:");
string id = Console.ReadLine();
ITunnelConnection tunnelConnection = null;
switch (connect)
{
case "1":
{
tunnelConnection = await tunnelTransfer.ConnectAsync(id, "default", TunnelProtocolType.None);
}
break;
case "2":
{
tunnelConnection = await relayClientTransfer.ConnectAsync(publicConfigInfo.SignConnection.Id, id, "default");
}
break;
default:
break;
}
if (tunnelConnection != null)
{
for (int i = 0; i < 10; i++)
{
string msg = $"hello {i}";
var msgBytes = msg.ToBytes();
//首部4字节存长度剩下的才是真实数据
byte[] bytes = new byte[4 + msgBytes.Length];
msgBytes.Length.ToBytes(bytes);
msgBytes.AsMemory().CopyTo(bytes.AsMemory(4));
await tunnelConnection.SendAsync(bytes);
await Task.Delay(1000);
}
}
}
private static void Server()
{
Console.WriteLine($"输入服务端端口:");
publicConfigInfo.Port = int.Parse(Console.ReadLine());
//序列化
ISerializer serializer = new Serializer();
//信标发送和接受
IMessengerSender messengerSender = new MessengerSender();
IMessengerResolver messengerResolver = new MessengerResolver(messengerSender);
messengerResolver.Initialize(publicConfigInfo.Certificate);
//登录相关
SignInArgsTransfer signInArgsTransfer = new SignInArgsTransfer();
//signInArgsTransfer.LoadArgs(new List<ISignInArgs>());
ISignInStore signInStore = new SignInStore();
SignCaching signCaching = new SignCaching(signInStore, signInArgsTransfer);
SignInServerMessenger signInServerMessenger = new SignInServerMessenger(messengerSender, signCaching, serializer);
//打洞相关
TunnelExternalResolver tunnelExternalResolver = new TunnelExternalResolver();
TunnelServerMessenger tunnelServerMessenger = new TunnelServerMessenger(messengerSender, signCaching, serializer);
//中继相关
IRelayServerMasterStore relayServerMasterStore = new RelayServerMasterStore();
IRelayServerNodeStore relayServerNodeStore = new RelayServerNodeStore();
RelayServerNodeTransfer relayServerNodeTransfer = new RelayServerNodeTransfer(serializer, relayServerNodeStore, relayServerMasterStore);
RelayServerResolver relayServerResolver = new RelayServerResolver(relayServerNodeTransfer, serializer);
IRelayServerCaching relayServerCaching = new RelayServerCachingMemory(serializer);
RelayServerMasterTransfer relayServerMasterTransfer = new RelayServerMasterTransfer(relayServerCaching, serializer, relayServerMasterStore);
RelayServerReportResolver relayServerReportResolver = new RelayServerReportResolver(relayServerMasterTransfer);
//自定义中继验证
RelayServerValidatorTransfer relayServerValidatorTransfer = new RelayServerValidatorTransfer();
//relayServerValidatorTransfer.LoadValidators(new List<IRelayServerValidator> { });
RelayServerMessenger relayServerMessenger = new RelayServerMessenger(messengerSender, signCaching, serializer, relayServerMasterTransfer, relayServerValidatorTransfer);
//加载这些信标处理器
messengerResolver.LoadMessenger(new List<IMessenger>
{
signInServerMessenger,
tunnelServerMessenger,
relayServerMessenger
});
//TCP
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, publicConfigInfo.Port));
socket.Listen(int.MaxValue);
TimerHelper.Async(async () =>
{
while (true)
{
var client = await socket.AcceptAsync();
TimerHelper.Async(async () =>
{
try
{
var bytes = new byte[1024];
int length = await client.ReceiveAsync(bytes.AsMemory(0, 1));
//外网端口
if (bytes[0] == 0)
{
await tunnelExternalResolver.Resolve(client, Helper.EmptyArray);
}
//信标
else if (bytes[0] == 1)
{
await messengerResolver.BeginReceiveServer(client, Helper.EmptyArray);
}
//中继
else if (bytes[0] == 2)
{
await relayServerResolver.Resolve(client, Helper.EmptyArray);
}
//中继节点报告
else if (bytes[0] == 3)
{
await relayServerReportResolver.Resolve(client, Helper.EmptyArray);
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
}
});
}
});
//UDP
Socket socketUdp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socketUdp.Bind(new IPEndPoint(IPAddress.Any, publicConfigInfo.Port));
socketUdp.WindowsUdpBug();
TimerHelper.Async(async () =>
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
byte[] buffer = new byte[1 * 1024 * 1024];
while (true)
{
try
{
SocketReceiveFromResult result = await socketUdp.ReceiveFromAsync(buffer, SocketFlags.None, endPoint).ConfigureAwait(false);
IPEndPoint ep = result.RemoteEndPoint as IPEndPoint;
try
{
//外网端口
if (buffer[0] == 0)
{
await tunnelExternalResolver.Resolve(socketUdp, ep, buffer.AsMemory(1, result.ReceivedBytes - 1));
}
//中继节点报告
else if (buffer[0] == 3)
{
await relayServerReportResolver.Resolve(socketUdp, ep, buffer.AsMemory(1, result.ReceivedBytes - 1));
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
}
}
catch (Exception ex)
{
LoggerHelper.Instance.Error(ex);
break;
}
}
});
}
private static void LoggerConsole()
{
LoggerHelper.Instance.OnLogger += (model) =>
{
ConsoleColor currentForeColor = Console.ForegroundColor;
switch (model.Type)
{
case LoggerTypes.DEBUG:
Console.ForegroundColor = ConsoleColor.Blue;
break;
case LoggerTypes.INFO:
Console.ForegroundColor = ConsoleColor.White;
break;
case LoggerTypes.WARNING:
Console.ForegroundColor = ConsoleColor.Yellow;
break;
case LoggerTypes.ERROR:
Console.ForegroundColor = ConsoleColor.Red;
break;
default:
break;
}
string line = $"[{model.Type,-7}][{model.Time:yyyy-MM-dd HH:mm:ss}]:{model.Content}";
Console.WriteLine(line);
Console.ForegroundColor = currentForeColor;
};
}
}
public sealed class PublicConfigInfo
{
public IConnection SignConnection { get; set; }
public X509Certificate2 Certificate { get; set; }
public List<TunnelTransportItemInfo> TunnelTransports { get; set; }
public string Host { get; set; }
public int Port { get; set; } = 12345;
}
/// <summary>
/// 中继的客户端存储库
/// </summary>
public sealed class RelayClientStore : IRelayClientStore
{
public byte Flag => 2;
public X509Certificate2 Certificate => Program.publicConfigInfo.Certificate;
public IConnection SigninConnection => Program.publicConfigInfo.SignConnection;
public string SecretKey => string.Empty;
public bool Disabled => false;
public bool SSL => true;
public RelayClientType RelayType => RelayClientType.Linker;
}
/// <summary>
/// 中继节点信息存储库
/// </summary>
public sealed class RelayServerNodeStore : IRelayServerNodeStore
{
public byte Flag => 3;
public int ServicePort => Program.publicConfigInfo.Port;
public RelayServerNodeInfo Node => new RelayServerNodeInfo { };
public void Confirm()
{
}
public void SetMaxGbTotalLastBytes(ulong value)
{
}
public void SetMaxGbTotalMonth(int month)
{
}
}
/// <summary>
/// 中继主机信息存储库
/// </summary>
public sealed class RelayServerMasterStore : IRelayServerMasterStore
{
public RelayServerMasterInfo Master => new RelayServerMasterInfo { SecretKey = "snltty" };
}
/// <summary>
/// 自定义打洞的存储库
/// </summary>
public sealed class TunnelMessengerAdapterStore : ITunnelMessengerAdapterStore
{
public IConnection SignConnection => Program.publicConfigInfo.SignConnection;
public X509Certificate2 Certificate => Program.publicConfigInfo.Certificate;
public int RouteLevelPlus => 0;
public int PortMapPrivate => 0;
public int PortMapPublic => 0;
public TunnelMessengerAdapterStore()
{
}
public async Task<List<TunnelTransportItemInfo>> GetTunnelTransports()
{
return await Task.FromResult(Program.publicConfigInfo.TunnelTransports);
}
public async Task<bool> SetTunnelTransports(List<TunnelTransportItemInfo> list)
{
return await Task.FromResult(true);
}
}
/// <summary>
/// 自定义序列化
/// </summary>
public sealed class Serializer : ISerializer
{
public T Deserialize<T>(ReadOnlySpan<byte> buffer)
{
return buffer.GetString().DeJson<T>();
}
public byte[] Serialize<T>(T value)
{
return value.ToJson().ToBytes();
}
}
/// <summary>
/// 自定义登录持久化存储
/// </summary>
public sealed class SignInStore : ISignInStore
{
public void Confirm()
{
}
public bool Delete(string id)
{
return true;
}
public SignCacheInfo Find(string id)
{
return null;
}
public IEnumerable<SignCacheInfo> Find()
{
return new List<SignCacheInfo>();
}
public string Insert(SignCacheInfo value)
{
return string.Empty;
}
public string NewId()
{
return Guid.NewGuid().ToString();
}
public bool Update(SignCacheInfo value)
{
return true;
}
}
}