FastTunnel/FastTunnel.Core/Client/FastTunnelClient.cs

354 lines
11 KiB
C#
Raw Normal View History

2021-08-01 18:32:32 +08:00
using FastTunnel.Core.Config;
2019-12-16 10:29:06 +08:00
using FastTunnel.Core.Models;
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
2019-12-25 10:11:58 +08:00
using FastTunnel.Core.Extensions;
using System.Timers;
using System.Threading;
2020-01-02 23:59:31 +08:00
using Microsoft.Extensions.Logging;
using FastTunnel.Core.Handlers.Client;
2021-06-13 00:18:34 +08:00
using Microsoft.Extensions.Configuration;
2021-06-17 20:10:45 +08:00
using FastTunnel.Core.Server;
2021-07-04 22:36:12 +08:00
using FastTunnel.Core.Sockets;
2021-07-21 23:52:26 +08:00
using Microsoft.Extensions.Options;
2021-08-01 18:32:32 +08:00
using System.Net.WebSockets;
using System.Text.Json;
2019-12-16 10:29:06 +08:00
2020-11-04 19:05:04 +08:00
namespace FastTunnel.Core.Client
2019-12-16 10:29:06 +08:00
{
2021-07-30 00:54:53 +08:00
public class FastTunnelClient : IFastTunnelClient
2019-12-16 10:29:06 +08:00
{
2021-08-01 18:32:32 +08:00
//Socket _client;
private IFastTunnelClientSocket socket;
2019-12-16 10:29:06 +08:00
2021-06-18 13:54:23 +08:00
protected ILogger<FastTunnelClient> _logger;
2019-12-16 10:29:06 +08:00
System.Timers.Timer timer_heart;
2020-04-07 23:56:46 +08:00
double heartInterval = 10 * 1000; // 10 秒心跳
public DateTime lastHeart;
2021-06-13 00:18:34 +08:00
int reTrySpan = 10 * 1000; // 登陆失败后重试间隔
2020-10-27 09:18:18 +08:00
HttpRequestHandler _newCustomerHandler;
2021-08-01 18:32:32 +08:00
NewForwardHandler _newSSHHandler;
LogHandler _logHandler;
ClientHeartHandler _clientHeartHandler;
2021-06-13 00:18:34 +08:00
Message<LogInMassage> loginMsg;
2021-07-21 23:52:26 +08:00
protected readonly IOptionsMonitor<DefaultClientConfig> _configuration;
2021-08-01 18:32:32 +08:00
private readonly CancellationTokenSource cancellationTokenSource = new();
2021-06-13 00:18:34 +08:00
2021-06-18 13:54:23 +08:00
public SuiDaoServer Server { get; protected set; }
2020-04-07 23:56:46 +08:00
2020-10-27 09:18:18 +08:00
public FastTunnelClient(
2021-06-13 00:18:34 +08:00
ILogger<FastTunnelClient> logger,
HttpRequestHandler newCustomerHandler,
2021-08-01 18:32:32 +08:00
NewForwardHandler newSSHHandler, LogHandler logHandler,
2021-07-21 23:52:26 +08:00
IOptionsMonitor<DefaultClientConfig> configuration,
2020-10-27 09:18:18 +08:00
ClientHeartHandler clientHeartHandler)
2019-12-16 10:29:06 +08:00
{
_logger = logger;
_newCustomerHandler = newCustomerHandler;
_newSSHHandler = newSSHHandler;
_logHandler = logHandler;
_clientHeartHandler = clientHeartHandler;
2021-06-18 13:54:23 +08:00
_configuration = configuration;
timer_heart = new System.Timers.Timer();
timer_heart.AutoReset = false;
2020-04-07 23:56:46 +08:00
timer_heart.Interval = heartInterval;
timer_heart.Elapsed += HeartElapsed;
}
2021-08-01 18:32:32 +08:00
private async Task reConnAsync()
{
2021-06-19 14:26:57 +08:00
Close();
2021-07-04 22:36:12 +08:00
do
{
2021-06-19 14:26:57 +08:00
try
{
2021-07-04 22:36:12 +08:00
Thread.Sleep(reTrySpan);
2021-06-19 14:26:57 +08:00
_logger.LogInformation("登录重试...");
2021-08-01 18:32:32 +08:00
socket = await loginAsync(CancellationToken.None);
2021-06-19 14:26:57 +08:00
break;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
}
2021-07-04 22:36:12 +08:00
} while (true);
2020-04-07 23:56:46 +08:00
2021-06-19 14:26:57 +08:00
connSuccessAsync();
}
private void HeartElapsed(object sender, ElapsedEventArgs e)
{
timer_heart.Enabled = false;
try
{
2021-08-01 18:32:32 +08:00
socket.SendAsync(new Message<HeartMassage> { MessageType = MessageType.Heart, Content = null }, cancellationTokenSource.Token).Wait();
}
2021-06-19 14:26:57 +08:00
catch (Exception)
{
2021-06-19 14:26:57 +08:00
// 与服务端断开连接
2021-08-01 18:32:32 +08:00
reConnAsync();
}
finally
{
timer_heart.Enabled = true;
}
}
2021-06-13 00:18:34 +08:00
/// <summary>
/// 启动客户端
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="customLoginMsg">自定义登录信息,可进行扩展业务</param>
2021-08-01 18:32:32 +08:00
public async Task StartAsync(CancellationToken cancellationToken)
2020-04-01 23:20:35 +08:00
{
2021-08-01 18:32:32 +08:00
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.cancellationTokenSource.Token);
2021-06-12 15:29:22 +08:00
2021-08-01 18:32:32 +08:00
_logger.LogInformation("===== FastTunnel Client Start =====");
2020-04-02 00:30:04 +08:00
2020-04-07 23:56:46 +08:00
try
{
2021-08-01 18:32:32 +08:00
socket = await loginAsync(cancellationToken);
2020-04-07 23:56:46 +08:00
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
2021-08-01 18:32:32 +08:00
reConnAsync();
2020-04-07 23:56:46 +08:00
return;
}
2021-06-19 14:26:57 +08:00
_ = connSuccessAsync();
2020-04-01 23:20:35 +08:00
}
2021-08-01 18:32:32 +08:00
//protected virtual Socket login()
//{
// Server = _configuration.CurrentValue.Server;
// DnsSocket _client = null;
// _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
// try
// {
// // 连接到的目标IP
// if (_client == null)
// {
// _client = new DnsSocket(Server.ServerAddr, Server.ServerPort);
// }
// _client.Connect();
// _logger.LogInformation("连接成功");
// }
// catch (Exception)
// {
// throw;
// }
// loginMsg = new Message<LogInMassage>
// {
// MessageType = MessageType.C_LogIn,
// Content = new LogInMassage
// {
// Webs = _configuration.CurrentValue.Webs,
// SSH = _configuration.CurrentValue.SSH,
// },
// };
// // 登录
// _client.Send(loginMsg);
// return _client.Socket;
//}
protected virtual async Task<IFastTunnelClientSocket> loginAsync(CancellationToken cancellationToken)
2021-06-13 00:18:34 +08:00
{
2021-07-21 23:52:26 +08:00
Server = _configuration.CurrentValue.Server;
2021-06-18 13:54:23 +08:00
_logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
2021-06-13 00:18:34 +08:00
try
{
// 连接到的目标IP
2021-08-01 18:32:32 +08:00
socket = new DefultClientSocket();
2021-07-04 22:36:12 +08:00
2021-08-01 18:32:32 +08:00
await socket.ConnectAsync(
new Uri($"ws://{_configuration.CurrentValue.Server.ServerAddr}:{_configuration.CurrentValue.Server.ServerPort}"), cancellationToken);
2021-06-13 00:18:34 +08:00
_logger.LogInformation("连接成功");
}
catch (Exception)
{
throw;
}
2021-06-18 13:54:23 +08:00
loginMsg = new Message<LogInMassage>
{
MessageType = MessageType.C_LogIn,
Content = new LogInMassage
{
2021-07-21 23:52:26 +08:00
Webs = _configuration.CurrentValue.Webs,
2021-08-01 18:32:32 +08:00
SSH = _configuration.CurrentValue.Forwards,
2021-06-18 13:54:23 +08:00
},
};
2021-06-13 00:18:34 +08:00
// 登录
2021-08-01 18:32:32 +08:00
await socket.SendAsync(loginMsg, cancellationToken);
return socket;
2021-06-13 00:18:34 +08:00
}
void Close()
{
timer_heart.Stop();
2021-08-01 18:32:32 +08:00
socket.CloseAsync();
2019-12-16 10:29:06 +08:00
}
2021-06-19 14:26:57 +08:00
private async Task connSuccessAsync()
2019-12-16 10:29:06 +08:00
{
2020-04-01 23:20:35 +08:00
_logger.LogDebug("通信已建立");
// 心跳开始
timer_heart.Start();
2021-07-09 00:32:51 +08:00
var th = new Thread(ReceiveServer);
2021-08-01 18:32:32 +08:00
th.Start(socket);
2021-07-30 23:57:39 +08:00
// await new PipeHepler(_client, ProceccLine).ProcessLinesAsync();
}
private bool ProceccLine(Socket socket, byte[] line)
{
var cmd = Encoding.UTF8.GetString(line);
HandleServerRequest(cmd);
return true;
2021-06-17 20:10:45 +08:00
}
2021-07-09 00:32:51 +08:00
private void ReceiveServer(object obj)
2021-06-17 20:10:45 +08:00
{
2021-08-01 18:32:32 +08:00
var client = obj as IFastTunnelClientSocket;
2021-07-09 00:32:51 +08:00
byte[] buffer = new byte[1024];
string lastBuffer = string.Empty;
int n = 0;
while (true)
2021-06-19 14:26:57 +08:00
{
2021-07-09 00:32:51 +08:00
try
{
2021-08-01 18:32:32 +08:00
n = client.ReceiveAsync(buffer, cancellationTokenSource.Token).GetAwaiter().GetResult();
2021-07-09 00:32:51 +08:00
if (n == 0)
{
2021-08-01 18:32:32 +08:00
client.CloseAsync();
2021-07-09 00:32:51 +08:00
break;
}
}
/// <see cref="https://docs.microsoft.com/zh-cn/windows/win32/winsock/windows-sockets-error-codes-2"/>
catch (SocketException socketEx)
{
// Connection timed out.
if (socketEx.ErrorCode == 10060)
{
_logger.LogInformation("Connection timed out");
}
else
{
_logger.LogError(socketEx);
}
break;
}
catch (Exception ex)
{
_logger.LogError(ex);
break;
}
string words = Encoding.UTF8.GetString(buffer, 0, n);
if (!string.IsNullOrEmpty(lastBuffer))
{
words = lastBuffer + words;
lastBuffer = null;
}
var msgs = words.Split("\n");
_logger.LogDebug("recive from server:" + words);
try
{
2021-07-30 23:57:39 +08:00
for (int i = 0; i < msgs.Length - 1; i++)
2021-07-09 00:32:51 +08:00
{
2021-07-30 23:57:39 +08:00
var item = msgs[i];
2021-07-09 00:32:51 +08:00
if (string.IsNullOrEmpty(item))
continue;
if (item.EndsWith("}"))
{
HandleServerRequest(item);
}
else
{
lastBuffer = item;
}
}
2021-07-30 23:57:39 +08:00
if (string.IsNullOrEmpty(msgs[msgs.Length - 1]))
{
continue;
}
lastBuffer = msgs[msgs.Length - 1];
_logger.LogDebug($"lastBuffer={lastBuffer}");
2021-07-09 00:32:51 +08:00
}
catch (Exception ex)
{
2021-07-30 23:57:39 +08:00
_logger.LogError(ex, $"HandleMsg Error {msgs.ToJson()}");
2021-07-09 00:32:51 +08:00
continue;
}
2021-06-19 14:26:57 +08:00
}
2021-07-09 00:32:51 +08:00
_logger.LogInformation("stop receive from server");
}
2021-08-01 18:32:32 +08:00
private void HandleServerRequest(string lineCmd)
2019-12-16 10:29:06 +08:00
{
2021-07-30 23:57:39 +08:00
Task.Run(() =>
2021-07-09 00:32:51 +08:00
{
2021-08-01 18:32:32 +08:00
var cmds = lineCmd.Split("||");
var type = cmds[0];
2021-07-11 12:39:05 +08:00
2021-08-01 18:32:32 +08:00
TunnelMassage msg = null;
2021-07-30 23:57:39 +08:00
IClientHandler handler;
2021-08-01 18:32:32 +08:00
switch (type)
2021-07-30 23:57:39 +08:00
{
2021-08-01 18:32:32 +08:00
case "Heart":
2021-07-30 23:57:39 +08:00
handler = _clientHeartHandler;
2021-08-01 18:32:32 +08:00
msg = JsonSerializer.Deserialize<HeartMassage>(cmds[1]);
2021-07-30 23:57:39 +08:00
break;
2021-08-01 18:32:32 +08:00
case "S_NewCustomer":
2021-07-30 23:57:39 +08:00
handler = _newCustomerHandler;
2021-08-01 18:32:32 +08:00
msg = JsonSerializer.Deserialize<NewCustomerMassage>(cmds[1]);
2021-07-30 23:57:39 +08:00
break;
2021-08-01 18:32:32 +08:00
case "S_NewSSH":
2021-07-30 23:57:39 +08:00
handler = _newSSHHandler;
2021-08-01 18:32:32 +08:00
msg = JsonSerializer.Deserialize<NewForwardMessage>(cmds[1]);
2021-07-30 23:57:39 +08:00
break;
2021-08-01 18:32:32 +08:00
case "Log":
2021-07-30 23:57:39 +08:00
handler = _logHandler;
2021-08-01 18:32:32 +08:00
msg = JsonSerializer.Deserialize<LogMassage>(cmds[1]);
2021-07-30 23:57:39 +08:00
break;
default:
2021-08-01 18:32:32 +08:00
throw new Exception($"未处理的消息:{lineCmd}");
2021-07-30 23:57:39 +08:00
}
2021-08-01 18:32:32 +08:00
handler.HandlerMsgAsync(this, msg);
2021-07-30 23:57:39 +08:00
});
2019-12-16 10:29:06 +08:00
}
}
}