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;
|
2019-12-26 15:47:36 +08:00
|
|
|
|
using System.Timers;
|
|
|
|
|
using System.Threading;
|
2020-01-02 23:59:31 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2020-04-08 18:37:37 +08:00
|
|
|
|
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
|
|
|
|
|
2019-12-26 15:47:36 +08:00
|
|
|
|
System.Timers.Timer timer_heart;
|
|
|
|
|
|
2020-04-07 23:56:46 +08:00
|
|
|
|
double heartInterval = 10 * 1000; // 10 秒心跳
|
2020-04-08 18:37:37 +08:00
|
|
|
|
public DateTime lastHeart;
|
2019-12-26 15:47:36 +08:00
|
|
|
|
|
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;
|
2020-04-08 18:37:37 +08:00
|
|
|
|
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;
|
2020-04-08 18:37:37 +08:00
|
|
|
|
_newCustomerHandler = newCustomerHandler;
|
|
|
|
|
_newSSHHandler = newSSHHandler;
|
|
|
|
|
_logHandler = logHandler;
|
|
|
|
|
_clientHeartHandler = clientHeartHandler;
|
2021-06-18 13:54:23 +08:00
|
|
|
|
_configuration = configuration;
|
2019-12-26 15:47:36 +08:00
|
|
|
|
|
|
|
|
|
timer_heart = new System.Timers.Timer();
|
2020-04-08 18:37:37 +08:00
|
|
|
|
timer_heart.AutoReset = false;
|
2020-04-07 23:56:46 +08:00
|
|
|
|
timer_heart.Interval = heartInterval;
|
2019-12-26 15:47:36 +08:00
|
|
|
|
timer_heart.Elapsed += HeartElapsed;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-01 18:32:32 +08:00
|
|
|
|
private async Task reConnAsync()
|
2019-12-26 15:47:36 +08:00
|
|
|
|
{
|
2021-06-19 14:26:57 +08:00
|
|
|
|
Close();
|
2021-07-04 22:36:12 +08:00
|
|
|
|
|
|
|
|
|
do
|
2019-12-26 15:47:36 +08:00
|
|
|
|
{
|
2021-06-19 14:26:57 +08:00
|
|
|
|
try
|
2020-04-08 18:37:37 +08:00
|
|
|
|
{
|
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);
|
2020-04-08 18:37:37 +08:00
|
|
|
|
|
2021-06-19 14:26:57 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError(ex.Message);
|
2020-04-08 18:37:37 +08:00
|
|
|
|
}
|
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();
|
2019-12-26 15:47:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HeartElapsed(object sender, ElapsedEventArgs e)
|
|
|
|
|
{
|
2020-04-08 18:37:37 +08:00
|
|
|
|
timer_heart.Enabled = false;
|
|
|
|
|
|
2019-12-26 15:47:36 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
2021-08-01 18:32:32 +08:00
|
|
|
|
socket.SendAsync(new Message<HeartMassage> { MessageType = MessageType.Heart, Content = null }, cancellationTokenSource.Token).Wait();
|
2019-12-26 15:47:36 +08:00
|
|
|
|
}
|
2021-06-19 14:26:57 +08:00
|
|
|
|
catch (Exception)
|
2019-12-26 15:47:36 +08:00
|
|
|
|
{
|
2021-06-19 14:26:57 +08:00
|
|
|
|
// 与服务端断开连接
|
2021-08-01 18:32:32 +08:00
|
|
|
|
reConnAsync();
|
2019-12-26 15:47:36 +08:00
|
|
|
|
}
|
2020-04-08 18:37:37 +08:00
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
timer_heart.Enabled = true;
|
|
|
|
|
}
|
2019-12-26 15:47:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2019-12-26 15:47:36 +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("通信已建立");
|
2019-12-26 15:47:36 +08:00
|
|
|
|
|
|
|
|
|
// 心跳开始
|
|
|
|
|
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
|
|
|
|
}
|
2020-04-08 18:37:37 +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
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|