diff --git a/FastTunnel.Api/Controllers/AccountController.cs b/FastTunnel.Api/Controllers/AccountController.cs index a86cdad..e245537 100644 --- a/FastTunnel.Api/Controllers/AccountController.cs +++ b/FastTunnel.Api/Controllers/AccountController.cs @@ -6,7 +6,6 @@ using FastTunnel.Api.Models; using FastTunnel.Core.Config; -using FastTunnel.Server.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; diff --git a/FastTunnel.Api/Controllers/BaseController.cs b/FastTunnel.Api/Controllers/BaseController.cs index 7a40cff..57a0d83 100644 --- a/FastTunnel.Api/Controllers/BaseController.cs +++ b/FastTunnel.Api/Controllers/BaseController.cs @@ -4,7 +4,7 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Server.Models; +using FastTunnel.Api.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/FastTunnel.Api/Controllers/SystemController.cs b/FastTunnel.Api/Controllers/SystemController.cs index 5186156..d4e4baa 100644 --- a/FastTunnel.Api/Controllers/SystemController.cs +++ b/FastTunnel.Api/Controllers/SystemController.cs @@ -4,8 +4,8 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H +using FastTunnel.Api.Models; using FastTunnel.Core.Client; -using FastTunnel.Server.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; diff --git a/FastTunnel.Api/Filters/CustomExceptionFilterAttribute.cs b/FastTunnel.Api/Filters/CustomExceptionFilterAttribute.cs index 14262d8..90a0fd1 100644 --- a/FastTunnel.Api/Filters/CustomExceptionFilterAttribute.cs +++ b/FastTunnel.Api/Filters/CustomExceptionFilterAttribute.cs @@ -4,7 +4,7 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Server.Models; +using FastTunnel.Api.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; diff --git a/FastTunnel.Api/Models/ApiResponse.cs b/FastTunnel.Api/Models/ApiResponse.cs index 8062309..8b643a3 100644 --- a/FastTunnel.Api/Models/ApiResponse.cs +++ b/FastTunnel.Api/Models/ApiResponse.cs @@ -4,7 +4,7 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -namespace FastTunnel.Server.Models +namespace FastTunnel.Api.Models { public class ApiResponse { diff --git a/FastTunnel.Core/Client/FastTunnelClient.cs b/FastTunnel.Core/Client/FastTunnelClient.cs index b42947b..ddbbdd4 100644 --- a/FastTunnel.Core/Client/FastTunnelClient.cs +++ b/FastTunnel.Core/Client/FastTunnelClient.cs @@ -4,153 +4,152 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Config; -using FastTunnel.Core.Models; using System; -using System.Text; -using System.Threading.Tasks; -using FastTunnel.Core.Extensions; -using System.Threading; -using Microsoft.Extensions.Logging; -using FastTunnel.Core.Handlers.Client; -using Microsoft.Extensions.Options; using System.Net.WebSockets; -using FastTunnel.Core.Utilitys; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using FastTunnel.Core.Config; +using FastTunnel.Core.Extensions; +using FastTunnel.Core.Handlers.Client; +using FastTunnel.Core.Models; using FastTunnel.Core.Models.Massage; +using FastTunnel.Core.Utilitys; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; -namespace FastTunnel.Core.Client +namespace FastTunnel.Core.Client; + +public class FastTunnelClient : IFastTunnelClient { - public class FastTunnelClient : IFastTunnelClient + private ClientWebSocket socket; + + protected readonly ILogger _logger; + private readonly SwapHandler _newCustomerHandler; + private readonly LogHandler _logHandler; + + public DefaultClientConfig ClientConfig { get; private set; } + + public SuiDaoServer Server { get; protected set; } + + public FastTunnelClient( + ILogger logger, + SwapHandler newCustomerHandler, + LogHandler logHandler, + IOptionsMonitor configuration) { - private ClientWebSocket socket; + _logger = logger; + _newCustomerHandler = newCustomerHandler; + _logHandler = logHandler; + ClientConfig = configuration.CurrentValue; + Server = ClientConfig.Server; + } - protected readonly ILogger _logger; - private readonly SwapHandler _newCustomerHandler; - private readonly LogHandler _logHandler; + /// + /// 启动客户端 + /// + /// + /// 自定义登录信息,可进行扩展业务 + public async void StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("===== FastTunnel Client Start ====="); - public DefaultClientConfig ClientConfig { get; private set; } - - public SuiDaoServer Server { get; protected set; } - - public FastTunnelClient( - ILogger logger, - SwapHandler newCustomerHandler, - LogHandler logHandler, - IOptionsMonitor configuration) - { - _logger = logger; - _newCustomerHandler = newCustomerHandler; - _logHandler = logHandler; - ClientConfig = configuration.CurrentValue; - Server = ClientConfig.Server; - } - - /// - /// 启动客户端 - /// - /// - /// 自定义登录信息,可进行扩展业务 - public async void StartAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("===== FastTunnel Client Start ====="); - - while (!cancellationToken.IsCancellationRequested) - { - try - { - await loginAsync(cancellationToken); - await ReceiveServerAsync(cancellationToken); - } - catch (Exception ex) - { - _logger.LogError(ex.Message); - await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); - } - } - - _logger.LogInformation("===== FastTunnel Client End ====="); - } - - private async Task loginAsync(CancellationToken cancellationToken) + while (!cancellationToken.IsCancellationRequested) { try { - var logMsg = GetLoginMsg(cancellationToken); - - // 连接到的目标IP - socket = new ClientWebSocket(); - socket.Options.RemoteCertificateValidationCallback = delegate { return true; }; - socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_VERSION, AssemblyUtility.GetVersion().ToString()); - socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_TOKEN, ClientConfig.Token); - - _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}"); - await socket.ConnectAsync( - new Uri($"{Server.Protocol}://{Server.ServerAddr}:{Server.ServerPort}"), cancellationToken); - - _logger.LogDebug("连接服务端成功"); - - // 登录 - await socket.SendCmdAsync(MessageType.LogIn, logMsg, cancellationToken); - } - catch (Exception) - { - throw; - } - } - - public virtual string GetLoginMsg(CancellationToken cancellationToken) - { - Server = ClientConfig.Server; - return new LogInMassage - { - Webs = ClientConfig.Webs, - Forwards = ClientConfig.Forwards, - }.ToJson(); - } - - private async Task ReceiveServerAsync(CancellationToken cancellationToken) - { - byte[] buffer = new byte[FastTunnelConst.MAX_CMD_LENGTH]; - while (!cancellationToken.IsCancellationRequested) - { - var res = await socket.ReceiveAsync(buffer, cancellationToken); - var type = buffer[0]; - var content = Encoding.UTF8.GetString(buffer, 1, res.Count - 1); - HandleServerRequestAsync(type, content, cancellationToken); - } - } - - private async void HandleServerRequestAsync(byte cmd, string ctx, CancellationToken cancellationToken) - { - await Task.Yield(); - - try - { - IClientHandler handler; - switch ((MessageType)cmd) - { - case MessageType.SwapMsg: - case MessageType.Forward: - handler = _newCustomerHandler; - break; - case MessageType.Log: - handler = _logHandler; - break; - default: - throw new Exception($"未处理的消息:cmd={cmd}"); - } - - await handler.HandlerMsgAsync(this, ctx, cancellationToken); + await loginAsync(cancellationToken); + await ReceiveServerAsync(cancellationToken); } catch (Exception ex) { - _logger.LogError(ex); + _logger.LogError(ex.Message); + await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); } } - public void Stop(CancellationToken cancellationToken) + _logger.LogInformation("===== FastTunnel Client End ====="); + } + + private async Task loginAsync(CancellationToken cancellationToken) + { + try { - _logger.LogInformation("===== FastTunnel Client Stoping ====="); + var logMsg = GetLoginMsg(cancellationToken); + + // 连接到的目标IP + socket = new ClientWebSocket(); + socket.Options.RemoteCertificateValidationCallback = delegate { return true; }; + socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_VERSION, AssemblyUtility.GetVersion().ToString()); + socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_TOKEN, ClientConfig.Token); + + _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}"); + await socket.ConnectAsync( + new Uri($"{Server.Protocol}://{Server.ServerAddr}:{Server.ServerPort}"), cancellationToken); + + _logger.LogDebug("连接服务端成功"); + + // 登录 + await socket.SendCmdAsync(MessageType.LogIn, logMsg, cancellationToken); + } + catch (Exception) + { + throw; } } + + public virtual string GetLoginMsg(CancellationToken cancellationToken) + { + Server = ClientConfig.Server; + return new LogInMassage + { + Webs = ClientConfig.Webs, + Forwards = ClientConfig.Forwards, + }.ToJson(); + } + + private async Task ReceiveServerAsync(CancellationToken cancellationToken) + { + var buffer = new byte[FastTunnelConst.MAX_CMD_LENGTH]; + while (!cancellationToken.IsCancellationRequested) + { + var res = await socket.ReceiveAsync(buffer, cancellationToken); + var type = buffer[0]; + var content = Encoding.UTF8.GetString(buffer, 1, res.Count - 1); + HandleServerRequestAsync(type, content, cancellationToken); + } + } + + private async void HandleServerRequestAsync(byte cmd, string ctx, CancellationToken cancellationToken) + { + await Task.Yield(); + + try + { + IClientHandler handler; + switch ((MessageType)cmd) + { + case MessageType.SwapMsg: + case MessageType.Forward: + handler = _newCustomerHandler; + break; + case MessageType.Log: + handler = _logHandler; + break; + default: + throw new Exception($"未处理的消息:cmd={cmd}"); + } + + await handler.HandlerMsgAsync(this, ctx, cancellationToken); + } + catch (Exception ex) + { + _logger.LogError(ex); + } + } + + public void Stop(CancellationToken cancellationToken) + { + _logger.LogInformation("===== FastTunnel Client Stoping ====="); + } } diff --git a/FastTunnel.Core/Client/FastTunnelServer.cs b/FastTunnel.Core/Client/FastTunnelServer.cs index 0a94a94..8e41e6b 100644 --- a/FastTunnel.Core/Client/FastTunnelServer.cs +++ b/FastTunnel.Core/Client/FastTunnelServer.cs @@ -4,73 +4,69 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; using FastTunnel.Core.Config; using FastTunnel.Core.Models; using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; -using System; -using System.Threading.Tasks; -using System.Threading; using Microsoft.Extensions.Options; -using System.IO; -using Yarp.ReverseProxy.Configuration; -using System.Collections.Generic; -namespace FastTunnel.Core.Client +namespace FastTunnel.Core.Client; + +public class FastTunnelServer { - public class FastTunnelServer + public int ConnectedClientCount; + public readonly IOptionsMonitor ServerOption; + private readonly ILogger logger; + + public ConcurrentDictionary> ResponseTasks { get; } = new(); + + public ConcurrentDictionary WebList { get; private set; } = new(); + + public ConcurrentDictionary> ForwardList { get; private set; } + = new ConcurrentDictionary>(); + + /// + /// 在线客户端列表 + /// + public IList Clients = new List(); + + public FastTunnelServer(ILogger logger, IOptionsMonitor serverSettings) { - public int ConnectedClientCount; - public readonly IOptionsMonitor ServerOption; - public IProxyConfigProvider proxyConfig; - readonly ILogger logger; + this.logger = logger; + this.ServerOption = serverSettings; + } - public ConcurrentDictionary> ResponseTasks { get; } = new(); + /// + /// 客户端登录 + /// + /// + internal void OnClientLogin(TunnelClient client) + { + Interlocked.Increment(ref ConnectedClientCount); + logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}"); + Clients.Add(client); + } - public ConcurrentDictionary WebList { get; private set; } = new(); + /// + /// 客户端退出 + /// + /// + /// + internal void OnClientLogout(TunnelClient client) + { + Interlocked.Decrement(ref ConnectedClientCount); + logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}"); + Clients.Remove(client); + client.Logout(); + } - public ConcurrentDictionary> ForwardList { get; private set; } - = new ConcurrentDictionary>(); - - /// - /// 在线客户端列表 - /// - public IList Clients = new List(); - - public FastTunnelServer(ILogger logger, IProxyConfigProvider proxyConfig, IOptionsMonitor serverSettings) - { - this.logger = logger; - this.ServerOption = serverSettings; - this.proxyConfig = proxyConfig; - } - - /// - /// 客户端登录 - /// - /// - internal void OnClientLogin(TunnelClient client) - { - Interlocked.Increment(ref ConnectedClientCount); - logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}"); - Clients.Add(client); - } - - /// - /// 客户端退出 - /// - /// - /// - internal void OnClientLogout(TunnelClient client) - { - Interlocked.Decrement(ref ConnectedClientCount); - logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}"); - Clients.Remove(client); - client.Logout(); - } - - internal bool TryGetWebProxyByHost(string host, out WebInfo web) - { - return WebList.TryGetValue(host, out web); - } + internal bool TryGetWebProxyByHost(string host, out WebInfo web) + { + return WebList.TryGetValue(host, out web); } } diff --git a/FastTunnel.Core/Client/IFastTunnelClient.cs b/FastTunnel.Core/Client/IFastTunnelClient.cs index a3952f9..fb7af1c 100644 --- a/FastTunnel.Core/Client/IFastTunnelClient.cs +++ b/FastTunnel.Core/Client/IFastTunnelClient.cs @@ -1,4 +1,4 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE @@ -6,12 +6,11 @@ using System.Threading; -namespace FastTunnel.Core.Client -{ - public interface IFastTunnelClient - { - void StartAsync(CancellationToken cancellationToken); +namespace FastTunnel.Core.Client; - void Stop(CancellationToken cancellationToken); - } +public interface IFastTunnelClient +{ + void StartAsync(CancellationToken cancellationToken); + + void Stop(CancellationToken cancellationToken); } diff --git a/FastTunnel.Core/Config/DefaultClientConfig.cs b/FastTunnel.Core/Config/DefaultClientConfig.cs index c4b8022..f52eba9 100644 --- a/FastTunnel.Core/Config/DefaultClientConfig.cs +++ b/FastTunnel.Core/Config/DefaultClientConfig.cs @@ -1,22 +1,21 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Models; using System.Collections.Generic; +using FastTunnel.Core.Models; -namespace FastTunnel.Core.Config +namespace FastTunnel.Core.Config; + +public class DefaultClientConfig : IClientConfig { - public class DefaultClientConfig : IClientConfig - { - public SuiDaoServer Server { get; set; } + public SuiDaoServer Server { get; set; } - public string Token { get; set; } + public string Token { get; set; } - public IEnumerable Webs { get; set; } + public IEnumerable Webs { get; set; } - public IEnumerable Forwards { get; set; } - } -} \ No newline at end of file + public IEnumerable Forwards { get; set; } +} diff --git a/FastTunnel.Core/Config/DefaultServerConfig.cs b/FastTunnel.Core/Config/DefaultServerConfig.cs index 14167df..c144a6c 100644 --- a/FastTunnel.Core/Config/DefaultServerConfig.cs +++ b/FastTunnel.Core/Config/DefaultServerConfig.cs @@ -1,4 +1,4 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE @@ -7,48 +7,47 @@ using System; using System.Collections.Generic; -namespace FastTunnel.Core.Config +namespace FastTunnel.Core.Config; + +public class DefaultServerConfig : IServerConfig { - public class DefaultServerConfig : IServerConfig + public string WebDomain { get; set; } + + public string[] WebAllowAccessIps { get; set; } + + public bool EnableForward { get; set; } + + [Obsolete("由Tokens替换")] + public string Token { get; set; } + + public List Tokens { get; set; } + + public ApiOptions Api { get; set; } + + public class ApiOptions { - public string WebDomain { get; set; } + public JWTOptions JWT { get; set; } - public string[] WebAllowAccessIps { get; set; } + public Account[] Accounts { get; set; } + } - public bool EnableForward { get; set; } + public class JWTOptions + { + public int ClockSkew { get; set; } - [Obsolete("由Tokens替换")] - public string Token { get; set; } + public string ValidAudience { get; set; } - public List Tokens { get; set; } + public string ValidIssuer { get; set; } - public ApiOptions Api { get; set; } + public string IssuerSigningKey { get; set; } - public class ApiOptions - { - public JWTOptions JWT { get; set; } + public int Expires { get; set; } + } - public Account[] Accounts { get; set; } - } + public class Account + { + public string Name { get; set; } - public class JWTOptions - { - public int ClockSkew { get; set; } - - public string ValidAudience { get; set; } - - public string ValidIssuer { get; set; } - - public string IssuerSigningKey { get; set; } - - public int Expires { get; set; } - } - - public class Account - { - public string Name { get; set; } - - public string Password { get; set; } - } + public string Password { get; set; } } } diff --git a/FastTunnel.Core/Config/IClientConfig.cs b/FastTunnel.Core/Config/IClientConfig.cs index 79010ac..ee1bd05 100644 --- a/FastTunnel.Core/Config/IClientConfig.cs +++ b/FastTunnel.Core/Config/IClientConfig.cs @@ -1,29 +1,28 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Models; using System.Collections.Generic; +using FastTunnel.Core.Models; -namespace FastTunnel.Core.Config +namespace FastTunnel.Core.Config; + +public interface IClientConfig { - public interface IClientConfig - { - public SuiDaoServer Server { get; set; } + public SuiDaoServer Server { get; set; } - public IEnumerable Webs { get; set; } + public IEnumerable Webs { get; set; } - public IEnumerable Forwards { get; set; } - } - - public class SuiDaoServer - { - public string Protocol { get; set; } = "ws"; - - public string ServerAddr { get; set; } - - public int ServerPort { get; set; } - } + public IEnumerable Forwards { get; set; } +} + +public class SuiDaoServer +{ + public string Protocol { get; set; } = "ws"; + + public string ServerAddr { get; set; } + + public int ServerPort { get; set; } } diff --git a/FastTunnel.Core/Config/IServerConfig.cs b/FastTunnel.Core/Config/IServerConfig.cs index 02b9541..5d0f6b7 100644 --- a/FastTunnel.Core/Config/IServerConfig.cs +++ b/FastTunnel.Core/Config/IServerConfig.cs @@ -1,17 +1,16 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -namespace FastTunnel.Core.Config +namespace FastTunnel.Core.Config; + +public interface IServerConfig { - public interface IServerConfig - { - string WebDomain { get; set; } + string WebDomain { get; set; } - string[] WebAllowAccessIps { get; set; } + string[] WebAllowAccessIps { get; set; } - bool EnableForward { get; set; } - } + bool EnableForward { get; set; } } diff --git a/FastTunnel.Core/Exceptions/APIErrorException.cs b/FastTunnel.Core/Exceptions/APIErrorException.cs index bbc4177..52c9816 100644 --- a/FastTunnel.Core/Exceptions/APIErrorException.cs +++ b/FastTunnel.Core/Exceptions/APIErrorException.cs @@ -5,16 +5,13 @@ // Copyright (c) 2019 Gui.H using System; -using System.Collections.Generic; -using System.Text; -namespace FastTunnel.Core.Exceptions +namespace FastTunnel.Core.Exceptions; + +public class APIErrorException : Exception { - public class APIErrorException : Exception + public APIErrorException(string message) + : base(message) { - public APIErrorException(string message) - : base(message) - { - } } } diff --git a/FastTunnel.Core/Exceptions/ClienOffLineException.cs b/FastTunnel.Core/Exceptions/ClienOffLineException.cs index 708bf5a..d5df259 100644 --- a/FastTunnel.Core/Exceptions/ClienOffLineException.cs +++ b/FastTunnel.Core/Exceptions/ClienOffLineException.cs @@ -6,13 +6,12 @@ using System; -namespace FastTunnel.Core.Exceptions +namespace FastTunnel.Core.Exceptions; + +public class ClienOffLineException : Exception { - public class ClienOffLineException : Exception + public ClienOffLineException(string message) + : base(message) { - public ClienOffLineException(string message) - : base(message) - { - } } } diff --git a/FastTunnel.Core/Exceptions/SocketClosedException.cs b/FastTunnel.Core/Exceptions/SocketClosedException.cs index 7541440..a3729be 100644 --- a/FastTunnel.Core/Exceptions/SocketClosedException.cs +++ b/FastTunnel.Core/Exceptions/SocketClosedException.cs @@ -5,17 +5,12 @@ // Copyright (c) 2019 Gui.H using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace FastTunnel.Core.Exceptions +namespace FastTunnel.Core.Exceptions; + +public class SocketClosedException : Exception { - public class SocketClosedException : Exception + public SocketClosedException(string msg) : base(msg) { - public SocketClosedException(string msg) : base(msg) - { - } } } diff --git a/FastTunnel.Core/Extensions/ByteArrayExtensions.cs b/FastTunnel.Core/Extensions/ByteArrayExtensions.cs index 94a4f17..639ce7b 100644 --- a/FastTunnel.Core/Extensions/ByteArrayExtensions.cs +++ b/FastTunnel.Core/Extensions/ByteArrayExtensions.cs @@ -1,4 +1,4 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE @@ -6,13 +6,12 @@ using System.Text; -namespace FastTunnel.Core.Extensions +namespace FastTunnel.Core.Extensions; + +public static class ByteArrayExtensions { - public static class ByteArrayExtensions + public static string GetString(this byte[] buffer, int offset, int count) { - public static string GetString(this byte[] buffer, int offset, int count) - { - return Encoding.UTF8.GetString(buffer, offset, count); - } + return Encoding.UTF8.GetString(buffer, offset, count); } } diff --git a/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs b/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs index 0b35342..06bf832 100644 --- a/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs +++ b/FastTunnel.Core/Extensions/ListenOptionsSwapExtensions.cs @@ -4,11 +4,6 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using FastTunnel.Core.Client; using FastTunnel.Core.Forwarder.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Core; diff --git a/FastTunnel.Core/Extensions/LoggerExtentions.cs b/FastTunnel.Core/Extensions/LoggerExtentions.cs index c6cc4df..32578f5 100644 --- a/FastTunnel.Core/Extensions/LoggerExtentions.cs +++ b/FastTunnel.Core/Extensions/LoggerExtentions.cs @@ -4,16 +4,15 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using Microsoft.Extensions.Logging; using System; +using Microsoft.Extensions.Logging; -namespace FastTunnel.Core.Extensions +namespace FastTunnel.Core.Extensions; + +public static class LoggerExtentions { - public static class LoggerExtentions + public static void LogError(this ILogger logger, Exception ex) { - public static void LogError(this ILogger logger, Exception ex) - { - logger.LogError(ex, string.Empty); - } + logger.LogError(ex, string.Empty); } } diff --git a/FastTunnel.Core/Extensions/ObjectExtensions.cs b/FastTunnel.Core/Extensions/ObjectExtensions.cs index 5c17e0e..b23737f 100644 --- a/FastTunnel.Core/Extensions/ObjectExtensions.cs +++ b/FastTunnel.Core/Extensions/ObjectExtensions.cs @@ -6,19 +6,18 @@ using System.Text.Json; -namespace FastTunnel.Core.Extensions -{ - public static class ObjectExtensions - { - public static string ToJson(this object message) - { - if (message == null) - { - return null; - } +namespace FastTunnel.Core.Extensions; - var jsonOptions = new JsonSerializerOptions { WriteIndented = false }; - return JsonSerializer.Serialize(message, message.GetType(), jsonOptions); +public static class ObjectExtensions +{ + public static string ToJson(this object message) + { + if (message == null) + { + return null; } + + var jsonOptions = new JsonSerializerOptions { WriteIndented = false }; + return JsonSerializer.Serialize(message, message.GetType(), jsonOptions); } } diff --git a/FastTunnel.Core/Extensions/ServicesExtensions.cs b/FastTunnel.Core/Extensions/ServicesExtensions.cs index 3ba183e..03acc11 100644 --- a/FastTunnel.Core/Extensions/ServicesExtensions.cs +++ b/FastTunnel.Core/Extensions/ServicesExtensions.cs @@ -7,94 +7,59 @@ using FastTunnel.Core.Client; using FastTunnel.Core.Config; using FastTunnel.Core.Forwarder.MiddleWare; -using FastTunnel.Core.Forwarder; using FastTunnel.Core.Handlers.Client; +using FastTunnel.Core.Handlers.Server; using FastTunnel.Core.Services; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Yarp.ReverseProxy.Forwarder; -using Microsoft.AspNetCore.Builder; -using FastTunnel.Core.Filters; -using Microsoft.AspNetCore.Mvc.Filters; -using FastTunnel.Core.Models; -using FastTunnel.Core.Handlers.Server; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Options; -using System.Threading.Tasks; -using System.Threading; -using Microsoft.AspNetCore.Http; -namespace FastTunnel.Core.Extensions +namespace FastTunnel.Core.Extensions; + +public static class ServicesExtensions { - public static class ServicesExtensions + /// + /// 客户端依赖及HostedService + /// + /// + public static void AddFastTunnelClient(this IServiceCollection services, IConfigurationSection configurationSection) { - /// - /// 客户端依赖及HostedService - /// - /// - public static void AddFastTunnelClient(this IServiceCollection services, IConfigurationSection configurationSection) - { - services.Configure(configurationSection); - services.AddFastTunnelClient(); - } + services.Configure(configurationSection); + services.AddFastTunnelClient(); + } - public static void AddFastTunnelClient(this IServiceCollection services) - { - services.AddTransient() - .AddSingleton() - .AddSingleton() - .AddSingleton(); + public static void AddFastTunnelClient(this IServiceCollection services) + { + services.AddTransient() + .AddSingleton() + .AddSingleton(); - services.AddHostedService(); - } + services.AddHostedService(); + } - /// - /// 添加服务端后台进程 - /// - /// - public static void AddFastTunnelServer(this IServiceCollection services, IConfigurationSection configurationSection) - { - services.AddReverseProxy().LoadFromMemory(); - services.AddSingleton(); + /// + /// 添加服务端后台进程 + /// + /// + public static void AddFastTunnelServer(this IServiceCollection services, IConfigurationSection configurationSection) + { + services.Configure(configurationSection) + .AddTransient() + .AddSingleton() + .AddSingleton() + .AddSingleton(); + } - services.Configure(configurationSection) - .AddSingleton() - .AddTransient() - .AddSingleton() - .AddSingleton() - .AddSingleton(); - } + /// + /// 服务端中间件 + /// + /// + public static void UseFastTunnelServer(this IApplicationBuilder app) + { + app.UseWebSockets(); - /// - /// 服务端中间件 - /// - /// - public static void UseFastTunnelServer(this IApplicationBuilder app) - { - app.UseWebSockets(); - - // var swapHandler = app.ApplicationServices.GetRequiredService(); - var clientHandler = app.ApplicationServices.GetRequiredService(); - app.Use(clientHandler.Handle); - } - - //public static void MapFastTunnelServer(this IEndpointRouteBuilder endpoints) - //{ - // endpoints.MapReverseProxy(); - // endpoints.MapFallback(context => - // { - // var options = context.RequestServices.GetRequiredService>(); - // var host = context.Request.Host.Host; - // if (!host.EndsWith(options.CurrentValue.WebDomain) || host.Equals(options.CurrentValue.WebDomain)) - // { - // context.Response.StatusCode = 404; - // return Task.CompletedTask; - // } - - // context.Response.StatusCode = 200; - // context.Response.WriteAsync(TunnelResource.Page_NotFound, CancellationToken.None); - // return Task.CompletedTask; - // }); - //} + // var swapHandler = app.ApplicationServices.GetRequiredService(); + var clientHandler = app.ApplicationServices.GetRequiredService(); + app.Use(clientHandler.Handle); } } diff --git a/FastTunnel.Core/Extensions/SocketExtensions.cs b/FastTunnel.Core/Extensions/SocketExtensions.cs index 565b32f..8d2d484 100644 --- a/FastTunnel.Core/Extensions/SocketExtensions.cs +++ b/FastTunnel.Core/Extensions/SocketExtensions.cs @@ -4,21 +4,18 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Models; -using FastTunnel.Core.Models.Massage; -using System; -using System.Collections.Generic; using System.Net.Sockets; using System.Text; +using FastTunnel.Core.Models; +using FastTunnel.Core.Models.Massage; -namespace FastTunnel.Core.Extensions +namespace FastTunnel.Core.Extensions; + +public static class SocketExtensions { - public static class SocketExtensions + public static void SendCmd(this Socket socket, Message message) + where T : TunnelMassage { - public static void SendCmd(this Socket socket, Message message) - where T : TunnelMassage - { - socket.Send(Encoding.UTF8.GetBytes(message.ToJson() + "\n")); - } + socket.Send(Encoding.UTF8.GetBytes(message.ToJson() + "\n")); } } diff --git a/FastTunnel.Core/Extensions/TaskCompletionSourceExtensions.cs b/FastTunnel.Core/Extensions/TaskCompletionSourceExtensions.cs index f37009c..1f890c4 100644 --- a/FastTunnel.Core/Extensions/TaskCompletionSourceExtensions.cs +++ b/FastTunnel.Core/Extensions/TaskCompletionSourceExtensions.cs @@ -1,31 +1,27 @@ -// Licensed under the Apache License, Version 2.0 (the "License"). +// Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // You may obtain a copy of the License at // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -namespace FastTunnel.Core.Extensions -{ - public static class TaskCompletionSourceExtensions - { - public static void SetTimeOut(this TaskCompletionSource tcs, int timeoutMs, Action? action) - { - var ct = new CancellationTokenSource(timeoutMs); - ct.Token.Register(() => - { - if (tcs.Task.IsCompleted) - return; +namespace FastTunnel.Core.Extensions; - tcs.TrySetCanceled(); - action?.Invoke(); - }, useSynchronizationContext: false); - } +public static class TaskCompletionSourceExtensions +{ + public static void SetTimeOut(this TaskCompletionSource tcs, int timeoutMs, Action? action) + { + var ct = new CancellationTokenSource(timeoutMs); + ct.Token.Register(() => + { + if (tcs.Task.IsCompleted) + return; + + tcs.TrySetCanceled(); + action?.Invoke(); + }, useSynchronizationContext: false); } } diff --git a/FastTunnel.Core/Extensions/ValueTaskExtensions.cs b/FastTunnel.Core/Extensions/ValueTaskExtensions.cs index de597cb..3c30760 100644 --- a/FastTunnel.Core/Extensions/ValueTaskExtensions.cs +++ b/FastTunnel.Core/Extensions/ValueTaskExtensions.cs @@ -4,48 +4,43 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Collections.Generic; using System.IO.Pipelines; -using System.Linq; using System.Runtime.CompilerServices; -using System.Text; using System.Threading.Tasks; -namespace FastTunnel.Core.Extensions -{ - internal static class ValueTaskExtensions - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Task GetAsTask(this in ValueTask valueTask) - { - // Try to avoid the allocation from AsTask - if (valueTask.IsCompletedSuccessfully) - { - // Signal consumption to the IValueTaskSource - valueTask.GetAwaiter().GetResult(); - return Task.CompletedTask; - } - else - { - return valueTask.AsTask(); - } - } +namespace FastTunnel.Core.Extensions; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ValueTask GetAsValueTask(this in ValueTask valueTask) +internal static class ValueTaskExtensions +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Task GetAsTask(this in ValueTask valueTask) + { + // Try to avoid the allocation from AsTask + if (valueTask.IsCompletedSuccessfully) { - // Try to avoid the allocation from AsTask - if (valueTask.IsCompletedSuccessfully) - { - // Signal consumption to the IValueTaskSource - valueTask.GetAwaiter().GetResult(); - return default; - } - else - { - return new ValueTask(valueTask.AsTask()); - } + // Signal consumption to the IValueTaskSource + valueTask.GetAwaiter().GetResult(); + return Task.CompletedTask; + } + else + { + return valueTask.AsTask(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ValueTask GetAsValueTask(this in ValueTask valueTask) + { + // Try to avoid the allocation from AsTask + if (valueTask.IsCompletedSuccessfully) + { + // Signal consumption to the IValueTaskSource + valueTask.GetAwaiter().GetResult(); + return default; + } + else + { + return new ValueTask(valueTask.AsTask()); } } } diff --git a/FastTunnel.Core/Extensions/WebSocketExtensions.cs b/FastTunnel.Core/Extensions/WebSocketExtensions.cs index 62ae2a8..b51c469 100644 --- a/FastTunnel.Core/Extensions/WebSocketExtensions.cs +++ b/FastTunnel.Core/Extensions/WebSocketExtensions.cs @@ -4,33 +4,29 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Exceptions; -using FastTunnel.Core.Models; using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using FastTunnel.Core.Exceptions; +using FastTunnel.Core.Models; -namespace FastTunnel.Core.Extensions +namespace FastTunnel.Core.Extensions; + +public static class WebSocketExtensions { - public static class WebSocketExtensions + public static async Task SendCmdAsync(this WebSocket socket, MessageType type, string content, CancellationToken cancellationToken) { - public static async Task SendCmdAsync(this WebSocket socket, MessageType type, string content, CancellationToken cancellationToken) + if (socket.State == WebSocketState.Closed || socket.State == WebSocketState.Aborted) { - if (socket.State == WebSocketState.Closed || socket.State == WebSocketState.Aborted) - { - throw new SocketClosedException(socket.State.ToString()); - } - - var buffer = Encoding.UTF8.GetBytes($"{(char)type}{content}\n"); - if (type != MessageType.LogIn && buffer.Length > FastTunnelConst.MAX_CMD_LENGTH) - throw new ArgumentOutOfRangeException(nameof(content)); - - await socket.SendAsync(buffer, WebSocketMessageType.Binary, false, cancellationToken); + throw new SocketClosedException(socket.State.ToString()); } + + var buffer = Encoding.UTF8.GetBytes($"{(char)type}{content}\n"); + if (type != MessageType.LogIn && buffer.Length > FastTunnelConst.MAX_CMD_LENGTH) + throw new ArgumentOutOfRangeException(nameof(content)); + + await socket.SendAsync(buffer, WebSocketMessageType.Binary, false, cancellationToken); } } diff --git a/FastTunnel.Core/FastTunnel.Core.csproj b/FastTunnel.Core/FastTunnel.Core.csproj index c00fe9c..ec590b9 100644 --- a/FastTunnel.Core/FastTunnel.Core.csproj +++ b/FastTunnel.Core/FastTunnel.Core.csproj @@ -1,43 +1,46 @@ - - net6.0 - 2.1.0 - https://github.com/SpringHgui/FastTunnel - MIT - FastTunnel - expose a local server behind a NAT or firewall to the internet like ngrok and frp - Gui.H - FastTunnel - FastTunnel - false - true - https://github.com/SpringHgui/FastTunnel - git - FastTunnel.Core - true - FastTunnel.Core - + + net6.0 + 2.1.0 + https://github.com/SpringHgui/FastTunnel + MIT + FastTunnel + expose a local server behind a NAT or firewall to the internet like ngrok and frp + Gui.H + FastTunnel + FastTunnel + false + true + https://github.com/SpringHgui/FastTunnel + git + FastTunnel.Core + true + FastTunnel.Core + + + + + + + + + + - - - - - + + + True + True + TunnelResource.resx + + - - - True - True - TunnelResource.resx - - - - - - PublicResXFileCodeGenerator - TunnelResource.Designer.cs - - + + + PublicResXFileCodeGenerator + TunnelResource.Designer.cs + + diff --git a/FastTunnel.Core/FastTunnelConst.cs b/FastTunnel.Core/FastTunnelConst.cs index c67f839..b6163ec 100644 --- a/FastTunnel.Core/FastTunnelConst.cs +++ b/FastTunnel.Core/FastTunnelConst.cs @@ -4,20 +4,13 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace FastTunnel.Core; -namespace FastTunnel.Core +public class FastTunnelConst { - public class FastTunnelConst - { - public const string FASTTUNNEL_VERSION = "FT_VERSION"; - public const string FASTTUNNEL_MSGID = "FT_MSGID"; - public const string FASTTUNNEL_TOKEN = "FT_TOKEN"; + public const string FASTTUNNEL_VERSION = "FT_VERSION"; + public const string FASTTUNNEL_MSGID = "FT_MSGID"; + public const string FASTTUNNEL_TOKEN = "FT_TOKEN"; - public const int MAX_CMD_LENGTH = 100; - } + public const int MAX_CMD_LENGTH = 100; } diff --git a/FastTunnel.Core/Filters/FastTunnelExceptionFilter.cs b/FastTunnel.Core/Filters/FastTunnelExceptionFilter.cs index 4c5699a..07f80ca 100644 --- a/FastTunnel.Core/Filters/FastTunnelExceptionFilter.cs +++ b/FastTunnel.Core/Filters/FastTunnelExceptionFilter.cs @@ -1,34 +1,37 @@ -// Licensed under the Apache License, Version 2.0 (the "License") +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H -using Microsoft.AspNetCore.Mvc.Filters; +using FastTunnel.Core.Extensions; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using FastTunnel.Core.Extensions; -namespace FastTunnel.Core.Filters +namespace FastTunnel.Core.Filters; + +public class FastTunnelExceptionFilter : IExceptionFilter { - public class FastTunnelExceptionFilter : IExceptionFilter + private readonly IWebHostEnvironment _hostingEnvironment; + private readonly ILogger logger; + + public FastTunnelExceptionFilter( + ILogger logger, + IWebHostEnvironment hostingEnvironment) { - private readonly IWebHostEnvironment _hostingEnvironment; - private readonly ILogger logger; + this.logger = logger; + _hostingEnvironment = hostingEnvironment; + } - public FastTunnelExceptionFilter( - ILogger logger, - IWebHostEnvironment hostingEnvironment) + public void OnException(ExceptionContext context) + { + if (!_hostingEnvironment.IsDevelopment()) { - this.logger = logger; - _hostingEnvironment = hostingEnvironment; + return; } - public void OnException(ExceptionContext context) - { - if (!_hostingEnvironment.IsDevelopment()) - { - return; - } - - logger.LogError(context.Exception, "[全局异常]"); - } + logger.LogError(context.Exception, "[全局异常]"); } } diff --git a/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs b/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs deleted file mode 100644 index 6130dbd..0000000 --- a/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel -// The FastTunnel licenses this file to you under the Apache License Version 2.0. -// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/LICENSE - -using FastTunnel.Core.Client; -using FastTunnel.Core.Extensions; -using FastTunnel.Core.Models; -using FastTunnel.Core.Sockets; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; -using Yarp.ReverseProxy.Forwarder; - -namespace FastTunnel.Core.Forwarder -{ - public class FastTunnelForwarderHttpClientFactory : ForwarderHttpClientFactory - { - readonly ILogger logger; - readonly FastTunnelServer fastTunnelServer; - - public FastTunnelForwarderHttpClientFactory(ILogger logger, FastTunnelServer fastTunnelServer) - { - this.fastTunnelServer = fastTunnelServer; - this.logger = logger; - } - - protected override void ConfigureHandler(ForwarderHttpClientContext context, SocketsHttpHandler handler) - { - base.ConfigureHandler(context, handler); - handler.ConnectCallback = ConnectCallback; - } - - private async ValueTask ConnectCallback(SocketsHttpConnectionContext context, CancellationToken cancellationToken) - { - var host = context.InitialRequestMessage.RequestUri.Host; - - try - { - var res = await proxyAsync(host, context, cancellationToken); - return res; - } - catch (Exception ex) - { - logger.LogError(ex, "ConnectCallback Error"); - throw; - } - } - - public async ValueTask proxyAsync(string host, SocketsHttpConnectionContext context, CancellationToken cancellation) - { - WebInfo web; - if (!fastTunnelServer.WebList.TryGetValue(host, out web)) - { - // 客户端已离线 - return await OfflinePage(host, context); - } - - var msgId = Guid.NewGuid().ToString().Replace("-", ""); - - TaskCompletionSource tcs = new(cancellation); - logger.LogDebug($"[Http]Swap开始 {msgId}|{host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}"); - tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Proxy TimeOut]:{msgId}"); }); - - fastTunnelServer.ResponseTasks.TryAdd(msgId, tcs); - - try - { - // 发送指令给客户端,等待建立隧道 - await web.Socket.SendCmdAsync(MessageType.SwapMsg, $"{msgId}|{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}", cancellation); - var res = await tcs.Task; - - logger.LogDebug($"[Http]Swap OK {msgId}"); - return res; - } - catch (WebSocketException) - { - // 通讯异常,返回客户端离线 - return await OfflinePage(host, context); - } - catch (Exception) - { - throw; - } - finally - { - fastTunnelServer.ResponseTasks.TryRemove(msgId, out _); - } - } - - - private async ValueTask OfflinePage(string host, SocketsHttpConnectionContext context) - { - var bytes = Encoding.UTF8.GetBytes( - $"HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n{TunnelResource.Page_Offline}\r\n"); - - return await Task.FromResult(new ResponseStream(bytes)); - } - } -} diff --git a/FastTunnel.Core/Forwarder/FastTunnelProxyConfig.cs b/FastTunnel.Core/Forwarder/FastTunnelProxyConfig.cs deleted file mode 100644 index ac970fc..0000000 --- a/FastTunnel.Core/Forwarder/FastTunnelProxyConfig.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Microsoft.Extensions.Primitives; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Yarp.ReverseProxy.Configuration; - -namespace FastTunnel.Core.Forwarder -{ - public class FastTunnelProxyConfig : IProxyConfig - { - public FastTunnelProxyConfig() - : this(Array.Empty(), Array.Empty()) - { - } - - public FastTunnelProxyConfig(IReadOnlyList routes, IReadOnlyList clusters) - { - this.Routes = routes; - this.Clusters = clusters; - this.ChangeToken = new CancellationChangeToken(cancellationToken.Token); - } - - public IReadOnlyList Routes { get; } - - public IReadOnlyList Clusters { get; } - - public IChangeToken ChangeToken { get; } - - private readonly CancellationTokenSource cancellationToken = new(); - } -} diff --git a/FastTunnel.Core/Forwarder/ForwarderClientFactory.cs b/FastTunnel.Core/Forwarder/ForwarderClientFactory.cs deleted file mode 100644 index c298726..0000000 --- a/FastTunnel.Core/Forwarder/ForwarderClientFactory.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel -// The FastTunnel licenses this file to you under the Apache License Version 2.0. -// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/LICENSE - -using FastTunnel.Core.Client; -using FastTunnel.Core.Extensions; -using FastTunnel.Core.Models; -using FastTunnel.Core.Sockets; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Linq; -using Yarp.ReverseProxy.Forwarder; - -namespace FastTunnel.Core.Forwarder -{ - public class ForwarderClientFactory : ForwarderHttpClientFactory - { - readonly ILogger logger; - readonly FastTunnelServer fastTunnelServer; - - public ForwarderClientFactory(ILogger logger, FastTunnelServer fastTunnelServer) - { - this.fastTunnelServer = fastTunnelServer; - this.logger = logger; - } - - protected override void ConfigureHandler(ForwarderHttpClientContext context, SocketsHttpHandler handler) - { - base.ConfigureHandler(context, handler); - handler.ConnectCallback = ConnectCallback; - } - - private async ValueTask ConnectCallback(SocketsHttpConnectionContext context, CancellationToken cancellationToken) - { - var host = context.InitialRequestMessage.RequestUri.Host; - - try - { - var res = await proxyAsync(host, context, cancellationToken); - return res; - } - catch (Exception) - { - throw; - } - } - - public async ValueTask proxyAsync(string host, SocketsHttpConnectionContext context, CancellationToken cancellation) - { - WebInfo web; - if (!fastTunnelServer.WebList.TryGetValue(host, out web)) - { - // 客户端已离线 - return await OfflinePage(host, context); - } - - var msgId = Guid.NewGuid().ToString().Replace("-", ""); - - TaskCompletionSource tcs = new(); - logger.LogDebug($"[Http]Swap开始 {msgId}|{host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}"); - tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Proxy TimeOut]:{msgId}"); }); - - fastTunnelServer.ResponseTasks.TryAdd(msgId, tcs); - - try - { - // 发送指令给客户端,等待建立隧道 - await web.Socket.SendCmdAsync(MessageType.SwapMsg, $"{msgId}|{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}", cancellation); - var res = await tcs.Task; - - logger.LogDebug($"[Http]Swap OK {msgId}"); - return res; - } - catch (WebSocketException) - { - // 通讯异常,返回客户端离线 - return await OfflinePage(host, context); - } - catch (Exception) - { - throw; - } - finally - { - fastTunnelServer.ResponseTasks.TryRemove(msgId, out _); - } - } - - - private async ValueTask OfflinePage(string host, SocketsHttpConnectionContext context) - { - var bytes = Encoding.UTF8.GetBytes( - $"HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n{TunnelResource.Page_Offline}\r\n"); - - return await Task.FromResult(new ResponseStream(bytes)); - } - } -} diff --git a/FastTunnel.Core/Forwarder/InMemoryConfigProvider.cs b/FastTunnel.Core/Forwarder/InMemoryConfigProvider.cs deleted file mode 100644 index 8eea920..0000000 --- a/FastTunnel.Core/Forwarder/InMemoryConfigProvider.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Primitives; -using Yarp.ReverseProxy.Configuration; -using System.Linq; - -namespace FastTunnel.Core.Forwarder -{ - /// - /// Extends the IReverseProxyBuilder to support the InMemoryConfigProvider - /// - public static class InMemoryConfigProviderExtensions - { - public static IReverseProxyBuilder LoadFromMemory(this IReverseProxyBuilder builder) - { - builder.Services.AddSingleton( - new InMemoryConfigProvider(Array.Empty(), Array.Empty())); - - return builder; - } - } - - /// - /// Provides an implementation of IProxyConfigProvider to support config being generated by code. - /// - public class InMemoryConfigProvider : IProxyConfigProvider - { - // Marked as volatile so that updates are atomic - private volatile InMemoryConfig _config; - private object locker = new object(); - - public InMemoryConfigProvider(IReadOnlyList routes, IReadOnlyList clusters) - { - _config = new InMemoryConfig(routes, clusters); - } - - /// - /// Implementation of the IProxyConfigProvider.GetConfig method to supply the current snapshot of configuration - /// - /// An immutable snapshot of the current configuration state - public IProxyConfig GetConfig() => _config; - - /// - /// Swaps the config state with a new snapshot of the configuration, then signals the change - /// - public void Update(IReadOnlyList routes, IReadOnlyList clusters) - { - var oldConfig = _config; - _config = new InMemoryConfig(routes, clusters); - oldConfig.SignalChange(); - } - - public void AddWeb(string hostName) - { - lock (locker) - { - var oldConfig = _config; - if (oldConfig.Routes.Any(x => x.ClusterId == hostName)) - { - return; - } - - var newRoutes = oldConfig.Routes.ToList(); - newRoutes.Add(new RouteConfig - { - ClusterId = hostName, - RouteId = hostName, - Match = new RouteMatch { Hosts = new string[] { hostName } } - }); - - var newClusters = oldConfig.Clusters.ToList(); - newClusters.Add(new ClusterConfig - { - ClusterId = hostName, - Destinations = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "default", new DestinationConfig() {Address = $"http://{hostName}",} } - } - }); - - _config = new InMemoryConfig(newRoutes, newClusters); - oldConfig.SignalChange(); - } - } - - /// - /// Implementation of IProxyConfig which is a snapshot of the current config state. The data for this class should be immutable. - /// - private class InMemoryConfig : IProxyConfig - { - // Used to implement the change token for the state - private readonly CancellationTokenSource _cts = new CancellationTokenSource(); - - public InMemoryConfig(IReadOnlyList routes, IReadOnlyList clusters) - { - Routes = routes; - Clusters = clusters; - ChangeToken = new CancellationChangeToken(_cts.Token); - } - - /// - /// A snapshot of the list of routes for the proxy - /// - public IReadOnlyList Routes { get; } - - /// - /// A snapshot of the list of Clusters which are collections of interchangable destination endpoints - /// - public IReadOnlyList Clusters { get; } - - /// - /// Fired to indicate the the proxy state has changed, and that this snapshot is now stale - /// - public IChangeToken ChangeToken { get; } - - internal void SignalChange() - { - _cts.Cancel(); - } - } - } -} diff --git a/FastTunnel.Core/Forwarder/Kestrel/ClientConnectionMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/ClientConnectionMiddleware.cs index 21257be..be9e0af 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/ClientConnectionMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/ClientConnectionMiddleware.cs @@ -6,22 +6,18 @@ using System; using System.Buffers; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Linq; using System.Text; using System.Threading.Tasks; using FastTunnel.Core.Client; using Microsoft.AspNetCore.Connections; -using Microsoft.AspNetCore.Connections.Features; using Microsoft.Extensions.Logging; namespace FastTunnel.Core.Forwarder.Kestrel; internal class ClientConnectionMiddleware { - readonly ConnectionDelegate next; - readonly ILogger logger; - FastTunnelServer fastTunnelServer; + private readonly ConnectionDelegate next; + private readonly ILogger logger; + private readonly FastTunnelServer fastTunnelServer; public ClientConnectionMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) { @@ -43,7 +39,7 @@ internal class ClientConnectionMiddleware /// /// /// is for FastTunnel - async Task ReadPipeAsync(ConnectionContext context) + private async Task ReadPipeAsync(ConnectionContext context) { var reader = context.Transport.Input; diff --git a/FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs b/FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs index 393bc00..6beae9d 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/FastTunnelConnectionContext.cs @@ -8,7 +8,6 @@ using System; using System.Buffers; using System.Collections.Generic; using System.IO.Pipelines; -using System.Linq; using System.Text; using System.Threading.Tasks; using FastTunnel.Core.Client; @@ -20,9 +19,9 @@ using Microsoft.Extensions.Logging; namespace FastTunnel.Core.Forwarder.Kestrel; internal class FastTunnelConnectionContext : ConnectionContext { - private ConnectionContext _inner; - FastTunnelServer fastTunnelServer; - ILogger _logger; + private readonly ConnectionContext _inner; + private readonly FastTunnelServer fastTunnelServer; + private readonly ILogger _logger; public FastTunnelConnectionContext(ConnectionContext context, FastTunnelServer fastTunnelServer, ILogger logger) { @@ -48,7 +47,7 @@ internal class FastTunnelConnectionContext : ConnectionContext return _inner.DisposeAsync(); } - ReadOnlySequence readableBuffer; + private readonly ReadOnlySequence readableBuffer; /// /// 解析FastTunnel协议 @@ -106,9 +105,8 @@ internal class FastTunnelConnectionContext : ConnectionContext public string Method; public string Host = null; public string MessageId; - - bool complete = false; - bool isFirstLine = true; + private bool complete = false; + private bool isFirstLine = true; /// /// @@ -154,7 +152,7 @@ internal class FastTunnelConnectionContext : ConnectionContext if (Method != "PROXY") { // 匹配Host, - if (fastTunnelServer.TryGetWebProxyByHost(Host, out WebInfo web)) + if (fastTunnelServer.TryGetWebProxyByHost(Host, out var web)) { MatchWeb = web; } diff --git a/FastTunnel.Core/Forwarder/Kestrel/HandleHttpConnectionMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/HandleHttpConnectionMiddleware.cs index 457f5b5..93707b9 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/HandleHttpConnectionMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/HandleHttpConnectionMiddleware.cs @@ -4,11 +4,6 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; using FastTunnel.Core.Client; using Microsoft.AspNetCore.Connections; @@ -18,9 +13,9 @@ namespace FastTunnel.Core.Forwarder.Kestrel; internal class HandleHttpConnectionMiddleware { - readonly ConnectionDelegate next; - readonly ILogger logger; - FastTunnelServer fastTunnelServer; + private readonly ConnectionDelegate next; + private readonly ILogger logger; + private readonly FastTunnelServer fastTunnelServer; public HandleHttpConnectionMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) { diff --git a/FastTunnel.Core/Forwarder/Kestrel/SwapConnectionMiddleware.cs b/FastTunnel.Core/Forwarder/Kestrel/SwapConnectionMiddleware.cs index c019e8c..7d42394 100644 --- a/FastTunnel.Core/Forwarder/Kestrel/SwapConnectionMiddleware.cs +++ b/FastTunnel.Core/Forwarder/Kestrel/SwapConnectionMiddleware.cs @@ -6,10 +6,7 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.IO; -using System.IO.Pipelines; -using System.Linq; using System.Net.WebSockets; using System.Text; using System.Threading.Tasks; @@ -25,9 +22,9 @@ namespace FastTunnel.Core.Forwarder.Kestrel; internal class SwapConnectionMiddleware { - readonly ConnectionDelegate next; - readonly ILogger logger; - FastTunnelServer fastTunnelServer; + private readonly ConnectionDelegate next; + private readonly ILogger logger; + private readonly FastTunnelServer fastTunnelServer; public SwapConnectionMiddleware(ConnectionDelegate next, ILogger logger, FastTunnelServer fastTunnelServer) { diff --git a/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs b/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs index bd9aa45..3909246 100644 --- a/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs +++ b/FastTunnel.Core/Forwarder/MiddleWare/DuplexPipeStream.cs @@ -6,12 +6,9 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.IO; using System.IO.Pipelines; -using System.Linq; using System.Runtime.CompilerServices; -using System.Text; using System.Threading; using System.Threading.Tasks; using FastTunnel.Core.Extensions; @@ -76,7 +73,7 @@ internal class DuplexPipeStream : Stream public override int Read(byte[] buffer, int offset, int count) { - ValueTask vt = ReadAsyncInternal(new Memory(buffer, offset, count), default); + var vt = ReadAsyncInternal(new Memory(buffer, offset, count), default); return vt.IsCompleted ? vt.Result : vt.AsTask().GetAwaiter().GetResult(); diff --git a/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs b/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs index 3046b34..55959ac 100644 --- a/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs +++ b/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs @@ -1,113 +1,114 @@ -// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel -// The FastTunnel licenses this file to you under the Apache License Version 2.0. -// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/LICENSE +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H +using System; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; using FastTunnel.Core.Client; using FastTunnel.Core.Extensions; using FastTunnel.Core.Handlers.Server; using FastTunnel.Core.Models; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using System; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; -namespace FastTunnel.Core.Forwarder.MiddleWare +namespace FastTunnel.Core.Forwarder.MiddleWare; + +public class FastTunnelClientHandler { - public class FastTunnelClientHandler + private readonly ILogger logger; + private readonly FastTunnelServer fastTunnelServer; + private readonly Version serverVersion; + private readonly ILoginHandler loginHandler; + + public FastTunnelClientHandler( + ILogger logger, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler) { - readonly ILogger logger; - readonly FastTunnelServer fastTunnelServer; - readonly Version serverVersion; - readonly ILoginHandler loginHandler; + this.logger = logger; + this.fastTunnelServer = fastTunnelServer; + this.loginHandler = loginHandler; - public FastTunnelClientHandler( - ILogger logger, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler) + serverVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + } + + public async Task Handle(HttpContext context, Func next) + { + try { - this.logger = logger; - this.fastTunnelServer = fastTunnelServer; - this.loginHandler = loginHandler; - - serverVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - } - - public async Task Handle(HttpContext context, Func next) - { - try + if (!context.WebSockets.IsWebSocketRequest || !context.Request.Headers.TryGetValue(FastTunnelConst.FASTTUNNEL_VERSION, out var version)) { - if (!context.WebSockets.IsWebSocketRequest || !context.Request.Headers.TryGetValue(FastTunnelConst.FASTTUNNEL_VERSION, out var version)) - { - await next(); - return; - }; - - await handleClient(context, version); - } - catch (Exception ex) - { - logger.LogError(ex); - } - } - - private async Task handleClient(HttpContext context, string clientVersion) - { - using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); - - if (Version.Parse(clientVersion).Major != serverVersion.Major) - { - await Close(webSocket, $"客户端版本{clientVersion}与服务端版本{serverVersion}不兼容,请升级。"); + await next(); return; - } + }; - if (!checkToken(context)) - { - await Close(webSocket, "Token验证失败"); - return; - } - - var client = new TunnelClient(webSocket, fastTunnelServer, loginHandler, context.Connection.RemoteIpAddress); - client.ConnectionPort = context.Connection.LocalPort; - - try - { - fastTunnelServer.OnClientLogin(client); - await client.ReviceAsync(CancellationToken.None); - - fastTunnelServer.OnClientLogout(client); - } - catch (Exception) - { - fastTunnelServer.OnClientLogout(client); - } + await handleClient(context, version); } - - private static async Task Close(WebSocket webSocket, string reason) + catch (Exception ex) { - await webSocket.SendCmdAsync(MessageType.Log, reason, CancellationToken.None); - await webSocket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None); + logger.LogError(ex); + } + } + + private async Task handleClient(HttpContext context, string clientVersion) + { + using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); + + if (Version.Parse(clientVersion).Major != serverVersion.Major) + { + await Close(webSocket, $"客户端版本{clientVersion}与服务端版本{serverVersion}不兼容,请升级。"); return; } - private bool checkToken(HttpContext context) + if (!checkToken(context)) { - var checkToken = false; - if (fastTunnelServer.ServerOption.CurrentValue.Tokens != null && fastTunnelServer.ServerOption.CurrentValue.Tokens.Count != 0) - { - checkToken = true; - } + await Close(webSocket, "Token验证失败"); + return; + } - if (!checkToken) - return true; + var client = new TunnelClient(webSocket, fastTunnelServer, loginHandler, context.Connection.RemoteIpAddress); + client.ConnectionPort = context.Connection.LocalPort; - // 客户端未携带token,登录失败 - if (!context.Request.Headers.TryGetValue(FastTunnelConst.FASTTUNNEL_TOKEN, out var token)) - return false; + try + { + fastTunnelServer.OnClientLogin(client); + await client.ReviceAsync(CancellationToken.None); - if (fastTunnelServer.ServerOption.CurrentValue.Tokens?.Contains(token) ?? false) - return true; - - return false; + fastTunnelServer.OnClientLogout(client); + } + catch (Exception) + { + fastTunnelServer.OnClientLogout(client); } } + + private static async Task Close(WebSocket webSocket, string reason) + { + await webSocket.SendCmdAsync(MessageType.Log, reason, CancellationToken.None); + await webSocket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None); + return; + } + + private bool checkToken(HttpContext context) + { + var checkToken = false; + if (fastTunnelServer.ServerOption.CurrentValue.Tokens != null && fastTunnelServer.ServerOption.CurrentValue.Tokens.Count != 0) + { + checkToken = true; + } + + if (!checkToken) + return true; + + // 客户端未携带token,登录失败 + if (!context.Request.Headers.TryGetValue(FastTunnelConst.FASTTUNNEL_TOKEN, out var token)) + return false; + + if (fastTunnelServer.ServerOption.CurrentValue.Tokens?.Contains(token) ?? false) + return true; + + return false; + } } diff --git a/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelSwapHandler.cs b/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelSwapHandler.cs index cef8c90..54146ff 100644 --- a/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelSwapHandler.cs +++ b/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelSwapHandler.cs @@ -1,71 +1,73 @@ +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H + +using System; +using System.Threading.Tasks; using FastTunnel.Core.Client; using FastTunnel.Core.Extensions; using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace FastTunnel.Core.Forwarder.MiddleWare +namespace FastTunnel.Core.Forwarder.MiddleWare; + +public class FastTunnelSwapHandler { - public class FastTunnelSwapHandler + private readonly ILogger logger; + private readonly FastTunnelServer fastTunnelServer; + + public FastTunnelSwapHandler(ILogger logger, FastTunnelServer fastTunnelServer) { - ILogger logger; - FastTunnelServer fastTunnelServer; + this.logger = logger; + this.fastTunnelServer = fastTunnelServer; + } - public FastTunnelSwapHandler(ILogger logger, FastTunnelServer fastTunnelServer) + public async Task Handle(HttpContext context, Func next) + { + try { - this.logger = logger; - this.fastTunnelServer = fastTunnelServer; + if (context.Request.Method != "PROXY") + { + await next(); + return; + } + + var requestId = context.Request.Path.Value.Trim('/'); + logger.LogDebug($"[PROXY]:Start {requestId}"); + + if (!fastTunnelServer.ResponseTasks.TryRemove(requestId, out var responseAwaiter)) + { + logger.LogError($"[PROXY]:RequestId不存在 {requestId}"); + return; + }; + + var lifetime = context.Features.Get(); + var transport = context.Features.Get(); + + if (lifetime == null || transport == null) + { + return; + } + + using var reverseConnection = new WebSocketStream(lifetime, transport); + responseAwaiter.TrySetResult(reverseConnection); + + var closedAwaiter = new TaskCompletionSource(); + + lifetime.ConnectionClosed.Register((task) => + { + (task as TaskCompletionSource).SetResult(null); + }, closedAwaiter); + + await closedAwaiter.Task; + logger.LogDebug($"[PROXY]:Closed {requestId}"); } - - public async Task Handle(HttpContext context, Func next) + catch (Exception ex) { - try - { - if (context.Request.Method != "PROXY") - { - await next(); - return; - } - - var requestId = context.Request.Path.Value.Trim('/'); - logger.LogDebug($"[PROXY]:Start {requestId}"); - - if (!fastTunnelServer.ResponseTasks.TryRemove(requestId, out var responseAwaiter)) - { - logger.LogError($"[PROXY]:RequestId不存在 {requestId}"); - return; - }; - - var lifetime = context.Features.Get(); - var transport = context.Features.Get(); - - if (lifetime == null || transport == null) - { - return; - } - - using var reverseConnection = new WebSocketStream(lifetime, transport); - responseAwaiter.TrySetResult(reverseConnection); - - var closedAwaiter = new TaskCompletionSource(); - - lifetime.ConnectionClosed.Register((task) => - { - (task as TaskCompletionSource).SetResult(null); - }, closedAwaiter); - - await closedAwaiter.Task; - logger.LogDebug($"[PROXY]:Closed {requestId}"); - } - catch (Exception ex) - { - logger.LogError(ex); - } + logger.LogError(ex); } } } diff --git a/FastTunnel.Core/Forwarder/MiddleWare/LoggingStream.cs b/FastTunnel.Core/Forwarder/MiddleWare/LoggingStream.cs index 1a99ebc..c41b46a 100644 --- a/FastTunnel.Core/Forwarder/MiddleWare/LoggingStream.cs +++ b/FastTunnel.Core/Forwarder/MiddleWare/LoggingStream.cs @@ -5,232 +5,229 @@ // Copyright (c) 2019 Gui.H using System; -using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace FastTunnel.Core.Forwarder.MiddleWare +namespace FastTunnel.Core.Forwarder.MiddleWare; + +internal sealed class LoggingStream : Stream { - internal sealed class LoggingStream : Stream + private readonly Stream _inner; + private readonly ILogger _logger; + + public LoggingStream(Stream inner, ILogger logger) { - private readonly Stream _inner; - private readonly ILogger _logger; + _inner = inner; + _logger = logger; + } - public LoggingStream(Stream inner, ILogger logger) + public override bool CanRead + { + get { - _inner = inner; - _logger = logger; - } - - public override bool CanRead - { - get - { - return _inner.CanRead; - } - } - - public override bool CanSeek - { - get - { - return _inner.CanSeek; - } - } - - public override bool CanWrite - { - get - { - return _inner.CanWrite; - } - } - - public override long Length - { - get - { - return _inner.Length; - } - } - - public override long Position - { - get - { - return _inner.Position; - } - - set - { - _inner.Position = value; - } - } - - public override void Flush() - { - _inner.Flush(); - } - - public override Task FlushAsync(CancellationToken cancellationToken) - { - return _inner.FlushAsync(cancellationToken); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int read = _inner.Read(buffer, offset, count); - Log("[Read]", new ReadOnlySpan(buffer, offset, read)); - return read; - } - - public override int Read(Span destination) - { - int read = _inner.Read(destination); - Log("[Read]", destination.Slice(0, read)); - return read; - } - - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - int read = await _inner.ReadAsync(buffer.AsMemory(offset, count), cancellationToken); - Log("[ReadAsync]", new ReadOnlySpan(buffer, offset, read)); - return read; - } - - public override async ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) - { - int read = await _inner.ReadAsync(destination, cancellationToken); - Log("[ReadAsync]", destination.Span.Slice(0, read)); - return read; - } - - public override long Seek(long offset, SeekOrigin origin) - { - return _inner.Seek(offset, origin); - } - - public override void SetLength(long value) - { - _inner.SetLength(value); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Log("[Write]", new ReadOnlySpan(buffer, offset, count)); - _inner.Write(buffer, offset, count); - } - - public override void Write(ReadOnlySpan source) - { - Log("[Write]", source); - _inner.Write(source); - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - Log("WriteAsync", new ReadOnlySpan(buffer, offset, count)); - return _inner.WriteAsync(buffer, offset, count, cancellationToken); - } - - public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) - { - Log("WriteAsync", source.Span); - return _inner.WriteAsync(source, cancellationToken); - } - - private void Log(string method, ReadOnlySpan buffer) - { - var builder = new StringBuilder(); - builder.Append(method); - builder.Append('['); - builder.Append(buffer.Length); - builder.Append(']'); - - if (buffer.Length > 0) - { - builder.AppendLine(); - } - - var charBuilder = new StringBuilder(); - - // Write the hex - for (int i = 0; i < buffer.Length; i++) - { - builder.Append(buffer[i].ToString("X2", CultureInfo.InvariantCulture)); - builder.Append(' '); - - var bufferChar = (char)buffer[i]; - if (char.IsControl(bufferChar)) - { - charBuilder.Append('.'); - } - else - { - charBuilder.Append(bufferChar); - } - - if ((i + 1) % 16 == 0) - { - builder.Append(" "); - builder.Append(charBuilder); - if (i != buffer.Length - 1) - { - builder.AppendLine(); - } - charBuilder.Clear(); - } - else if ((i + 1) % 8 == 0) - { - builder.Append(' '); - charBuilder.Append(' '); - } - } - - // Different than charBuffer.Length since charBuffer contains an extra " " after the 8th byte. - var numBytesInLastLine = buffer.Length % 16; - - if (numBytesInLastLine > 0) - { - // 2 (between hex and char blocks) + num bytes left (3 per byte) - var padLength = 2 + (3 * (16 - numBytesInLastLine)); - // extra for space after 8th byte - if (numBytesInLastLine < 8) - { - padLength++; - } - - builder.Append(new string(' ', padLength)); - builder.Append(charBuilder); - } - - _logger.LogInformation(builder.ToString()); - } - - // The below APM methods call the underlying Read/WriteAsync methods which will still be logged. - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) - { - return TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state); - } - - public override int EndRead(IAsyncResult asyncResult) - { - return TaskToApm.End(asyncResult); - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) - { - return TaskToApm.Begin(WriteAsync(buffer, offset, count), callback, state); - } - - public override void EndWrite(IAsyncResult asyncResult) - { - TaskToApm.End(asyncResult); + return _inner.CanRead; } } + + public override bool CanSeek + { + get + { + return _inner.CanSeek; + } + } + + public override bool CanWrite + { + get + { + return _inner.CanWrite; + } + } + + public override long Length + { + get + { + return _inner.Length; + } + } + + public override long Position + { + get + { + return _inner.Position; + } + + set + { + _inner.Position = value; + } + } + + public override void Flush() + { + _inner.Flush(); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + return _inner.FlushAsync(cancellationToken); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var read = _inner.Read(buffer, offset, count); + Log("[Read]", new ReadOnlySpan(buffer, offset, read)); + return read; + } + + public override int Read(Span destination) + { + var read = _inner.Read(destination); + Log("[Read]", destination.Slice(0, read)); + return read; + } + + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + var read = await _inner.ReadAsync(buffer.AsMemory(offset, count), cancellationToken); + Log("[ReadAsync]", new ReadOnlySpan(buffer, offset, read)); + return read; + } + + public override async ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) + { + var read = await _inner.ReadAsync(destination, cancellationToken); + Log("[ReadAsync]", destination.Span.Slice(0, read)); + return read; + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _inner.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _inner.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Log("[Write]", new ReadOnlySpan(buffer, offset, count)); + _inner.Write(buffer, offset, count); + } + + public override void Write(ReadOnlySpan source) + { + Log("[Write]", source); + _inner.Write(source); + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + Log("WriteAsync", new ReadOnlySpan(buffer, offset, count)); + return _inner.WriteAsync(buffer, offset, count, cancellationToken); + } + + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + { + Log("WriteAsync", source.Span); + return _inner.WriteAsync(source, cancellationToken); + } + + private void Log(string method, ReadOnlySpan buffer) + { + var builder = new StringBuilder(); + builder.Append(method); + builder.Append('['); + builder.Append(buffer.Length); + builder.Append(']'); + + if (buffer.Length > 0) + { + builder.AppendLine(); + } + + var charBuilder = new StringBuilder(); + + // Write the hex + for (var i = 0; i < buffer.Length; i++) + { + builder.Append(buffer[i].ToString("X2", CultureInfo.InvariantCulture)); + builder.Append(' '); + + var bufferChar = (char)buffer[i]; + if (char.IsControl(bufferChar)) + { + charBuilder.Append('.'); + } + else + { + charBuilder.Append(bufferChar); + } + + if ((i + 1) % 16 == 0) + { + builder.Append(" "); + builder.Append(charBuilder); + if (i != buffer.Length - 1) + { + builder.AppendLine(); + } + charBuilder.Clear(); + } + else if ((i + 1) % 8 == 0) + { + builder.Append(' '); + charBuilder.Append(' '); + } + } + + // Different than charBuffer.Length since charBuffer contains an extra " " after the 8th byte. + var numBytesInLastLine = buffer.Length % 16; + + if (numBytesInLastLine > 0) + { + // 2 (between hex and char blocks) + num bytes left (3 per byte) + var padLength = 2 + (3 * (16 - numBytesInLastLine)); + // extra for space after 8th byte + if (numBytesInLastLine < 8) + { + padLength++; + } + + builder.Append(new string(' ', padLength)); + builder.Append(charBuilder); + } + + _logger.LogInformation(builder.ToString()); + } + + // The below APM methods call the underlying Read/WriteAsync methods which will still be logged. + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + { + return TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return TaskToApm.End(asyncResult); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + { + return TaskToApm.Begin(WriteAsync(buffer, offset, count), callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + TaskToApm.End(asyncResult); + } } diff --git a/FastTunnel.Core/Forwarder/MiddleWare/TaskToApm.cs b/FastTunnel.Core/Forwarder/MiddleWare/TaskToApm.cs index 5b2e09d..09dff7e 100644 --- a/FastTunnel.Core/Forwarder/MiddleWare/TaskToApm.cs +++ b/FastTunnel.Core/Forwarder/MiddleWare/TaskToApm.cs @@ -5,10 +5,7 @@ // Copyright (c) 2019 Gui.H using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/FastTunnel.Core/Forwarder/ResponseStream.cs b/FastTunnel.Core/Forwarder/ResponseStream.cs index 7ff0c6a..e05a825 100644 --- a/FastTunnel.Core/Forwarder/ResponseStream.cs +++ b/FastTunnel.Core/Forwarder/ResponseStream.cs @@ -9,75 +9,74 @@ using System.IO; using System.Text; using System.Threading.Tasks; -namespace FastTunnel.Core.Forwarder +namespace FastTunnel.Core.Forwarder; + +public class ResponseStream : Stream { - public class ResponseStream : Stream + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => throw new NotImplementedException(); + + public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + private readonly MemoryStream m_Stream; + + public ResponseStream(byte[] bytes) { - public override bool CanRead => true; + m_Stream = new MemoryStream(bytes); + } - public override bool CanSeek => false; + public override void Flush() + { + throw new NotImplementedException(); + } - public override bool CanWrite => true; + private bool complete; - public override long Length => throw new NotImplementedException(); - - public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - readonly MemoryStream m_Stream; - - public ResponseStream(byte[] bytes) + public override int Read(byte[] buffer, int offset, int count) + { + if (!complete) { - m_Stream = new MemoryStream(bytes); + return 0; + }; + + var len = m_Stream.Read(buffer, offset, count); + return len; + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Console.Write(Encoding.UTF8.GetString(buffer, offset, count)); + complete = true; + } + + protected override void Dispose(bool disposing) + { + if (!disposing) + { + return; } - public override void Flush() - { - throw new NotImplementedException(); - } + m_Stream.Dispose(); + } - bool complete; - - public override int Read(byte[] buffer, int offset, int count) - { - if (!complete) - { - return 0; - }; - - var len = m_Stream.Read(buffer, offset, count); - return len; - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - Console.Write(Encoding.UTF8.GetString(buffer, offset, count)); - complete = true; - } - - protected override void Dispose(bool disposing) - { - if (!disposing) - { - return; - } - - m_Stream.Dispose(); - } - - public override ValueTask DisposeAsync() - { - Dispose(true); - return ValueTask.CompletedTask; - } + public override ValueTask DisposeAsync() + { + Dispose(true); + return ValueTask.CompletedTask; } } diff --git a/FastTunnel.Core/Forwarder/TranStream.cs b/FastTunnel.Core/Forwarder/TranStream.cs index dfcda0e..095280a 100644 --- a/FastTunnel.Core/Forwarder/TranStream.cs +++ b/FastTunnel.Core/Forwarder/TranStream.cs @@ -1,111 +1,109 @@ -// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel -// The FastTunnel licenses this file to you under the Apache License Version 2.0. -// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/LICENSE +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H -using Microsoft.AspNetCore.Http; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; -namespace FastTunnel.Core.Forwarder +namespace FastTunnel.Core.Forwarder; + +public class TranStream : Stream { - public class TranStream : Stream + private readonly Stream readStream; + private readonly Stream wirteStream; + + public TranStream(HttpContext context) { - private readonly Stream readStream; - private readonly Stream wirteStream; + this.readStream = context.Request.BodyReader.AsStream(); + this.wirteStream = context.Response.BodyWriter.AsStream(); + } + public override bool CanRead => true; - public TranStream(HttpContext context) - { - this.readStream = context.Request.BodyReader.AsStream(); - this.wirteStream = context.Response.BodyWriter.AsStream(); - } - public override bool CanRead => true; + public override bool CanSeek => false; - public override bool CanSeek => false; + public override bool CanWrite => true; - public override bool CanWrite => true; + public override long Length => throw new NotSupportedException(); - public override long Length => throw new NotSupportedException(); + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } + public override void Flush() + { + this.wirteStream.Flush(); + } - public override void Flush() - { - this.wirteStream.Flush(); - } + public override Task FlushAsync(CancellationToken cancellationToken) + { + return this.wirteStream.FlushAsync(cancellationToken); + } - public override Task FlushAsync(CancellationToken cancellationToken) - { - return this.wirteStream.FlushAsync(cancellationToken); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override int Read(byte[] buffer, int offset, int count) + { + return this.readStream.Read(buffer, offset, count); + } + public override void Write(byte[] buffer, int offset, int count) + { + this.wirteStream.Write(buffer, offset, count); + } + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + return this.readStream.ReadAsync(buffer, cancellationToken); + } - public override int Read(byte[] buffer, int offset, int count) - { - return this.readStream.Read(buffer, offset, count); - } - public override void Write(byte[] buffer, int offset, int count) - { - this.wirteStream.Write(buffer, offset, count); - } - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - return this.readStream.ReadAsync(buffer, cancellationToken); - } + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + var len = await this.readStream.ReadAsync(buffer, offset, count, cancellationToken); + if (len == 0) { Console.WriteLine("==========ReadAsync END=========="); } + return len; + } - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - var len = await this.readStream.ReadAsync(buffer, offset, count, cancellationToken); - if (len == 0) { Console.WriteLine("==========ReadAsync END=========="); } - return len; - } + public override void Write(ReadOnlySpan buffer) + { + this.wirteStream.Write(buffer); + } - public override void Write(ReadOnlySpan buffer) - { - this.wirteStream.Write(buffer); - } + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return this.wirteStream.WriteAsync(buffer, offset, count, cancellationToken); + } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return this.wirteStream.WriteAsync(buffer, offset, count, cancellationToken); - } + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + await this.wirteStream.WriteAsync(buffer, cancellationToken); + } - public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - await this.wirteStream.WriteAsync(buffer, cancellationToken); - } + protected override void Dispose(bool disposing) + { + Console.WriteLine("========Dispose========="); + } - protected override void Dispose(bool disposing) - { - Console.WriteLine("========Dispose========="); - } + public override ValueTask DisposeAsync() + { + return ValueTask.CompletedTask; + } - public override ValueTask DisposeAsync() - { - return ValueTask.CompletedTask; - } - - public override void Close() - { - Console.WriteLine("========Close========="); - base.Close(); - } + public override void Close() + { + Console.WriteLine("========Close========="); + base.Close(); } } diff --git a/FastTunnel.Core/Forwarder/WebSocketStream.cs b/FastTunnel.Core/Forwarder/WebSocketStream.cs index d7a35ef..f568cc8 100644 --- a/FastTunnel.Core/Forwarder/WebSocketStream.cs +++ b/FastTunnel.Core/Forwarder/WebSocketStream.cs @@ -1,112 +1,112 @@ -using Microsoft; -using Microsoft.AspNetCore.Connections.Features; +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H + using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Net.WebSockets; -using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Connections.Features; -namespace FastTunnel.Core.Forwarder +namespace FastTunnel.Core.Forwarder; + +internal sealed class WebSocketStream : Stream { - sealed class WebSocketStream : Stream + private readonly Stream readStream; + private readonly Stream wirteStream; + private readonly IConnectionLifetimeFeature lifetimeFeature; + + public WebSocketStream(IConnectionLifetimeFeature lifetimeFeature, IConnectionTransportFeature transportFeature) { - private readonly Stream readStream; - private readonly Stream wirteStream; - private readonly IConnectionLifetimeFeature lifetimeFeature; + this.readStream = transportFeature.Transport.Input.AsStream(); + this.wirteStream = transportFeature.Transport.Output.AsStream(); + this.lifetimeFeature = lifetimeFeature; + } - public WebSocketStream(IConnectionLifetimeFeature lifetimeFeature, IConnectionTransportFeature transportFeature) - { - this.readStream = transportFeature.Transport.Input.AsStream(); - this.wirteStream = transportFeature.Transport.Output.AsStream(); - this.lifetimeFeature = lifetimeFeature; - } + public WebSocketStream(Stream stream) + { + this.readStream = stream; + this.wirteStream = stream; + this.lifetimeFeature = null; + } - public WebSocketStream(Stream stream) - { - this.readStream = stream; - this.wirteStream = stream; - this.lifetimeFeature = null; - } + public override bool CanRead => true; - public override bool CanRead => true; + public override bool CanSeek => false; - public override bool CanSeek => false; + public override bool CanWrite => true; - public override bool CanWrite => true; + public override long Length => throw new NotSupportedException(); - public override long Length => throw new NotSupportedException(); + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } - public override long Position - { - get => throw new NotSupportedException(); - set => throw new NotSupportedException(); - } + public override void Flush() + { + this.wirteStream.Flush(); + } - public override void Flush() - { - this.wirteStream.Flush(); - } + public override Task FlushAsync(CancellationToken cancellationToken) + { + return this.wirteStream.FlushAsync(cancellationToken); + } - public override Task FlushAsync(CancellationToken cancellationToken) - { - return this.wirteStream.FlushAsync(cancellationToken); - } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } - public override void SetLength(long value) - { - throw new NotSupportedException(); - } + public override int Read(byte[] buffer, int offset, int count) + { + return this.readStream.Read(buffer, offset, count); + } + public override void Write(byte[] buffer, int offset, int count) + { + this.wirteStream.Write(buffer, offset, count); + } + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + return this.readStream.ReadAsync(buffer, cancellationToken); + } - public override int Read(byte[] buffer, int offset, int count) - { - return this.readStream.Read(buffer, offset, count); - } - public override void Write(byte[] buffer, int offset, int count) - { - this.wirteStream.Write(buffer, offset, count); - } - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - return this.readStream.ReadAsync(buffer, cancellationToken); - } + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return this.readStream.ReadAsync(buffer, offset, count, cancellationToken); + } - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return this.readStream.ReadAsync(buffer, offset, count, cancellationToken); - } + public override void Write(ReadOnlySpan buffer) + { + this.wirteStream.Write(buffer); + } - public override void Write(ReadOnlySpan buffer) - { - this.wirteStream.Write(buffer); - } + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return this.wirteStream.WriteAsync(buffer, offset, count, cancellationToken); + } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return this.wirteStream.WriteAsync(buffer, offset, count, cancellationToken); - } + public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + await this.wirteStream.WriteAsync(buffer, cancellationToken); + } - public override async ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) - { - await this.wirteStream.WriteAsync(buffer, cancellationToken); - } + protected override void Dispose(bool disposing) + { + this.lifetimeFeature?.Abort(); + } - protected override void Dispose(bool disposing) - { - this.lifetimeFeature?.Abort(); - } - - public override ValueTask DisposeAsync() - { - this.lifetimeFeature?.Abort(); - return ValueTask.CompletedTask; - } + public override ValueTask DisposeAsync() + { + this.lifetimeFeature?.Abort(); + return ValueTask.CompletedTask; } } diff --git a/FastTunnel.Core/Handlers/Client/IClientHandler.cs b/FastTunnel.Core/Handlers/Client/IClientHandler.cs index 8520213..37f92b6 100644 --- a/FastTunnel.Core/Handlers/Client/IClientHandler.cs +++ b/FastTunnel.Core/Handlers/Client/IClientHandler.cs @@ -4,19 +4,13 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Config; -using FastTunnel.Core.Client; -using FastTunnel.Core.Models; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; using System.Threading; +using System.Threading.Tasks; +using FastTunnel.Core.Client; -namespace FastTunnel.Core.Handlers.Client +namespace FastTunnel.Core.Handlers.Client; + +public interface IClientHandler { - public interface IClientHandler - { - Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken); - } + Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken); } diff --git a/FastTunnel.Core/Handlers/Client/LogHandler.cs b/FastTunnel.Core/Handlers/Client/LogHandler.cs index 0d41b58..b238831 100644 --- a/FastTunnel.Core/Handlers/Client/LogHandler.cs +++ b/FastTunnel.Core/Handlers/Client/LogHandler.cs @@ -4,30 +4,25 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Config; -using FastTunnel.Core.Models; -using Microsoft.Extensions.Logging; -using System; -using FastTunnel.Core.Extensions; -using FastTunnel.Core.Client; -using System.Threading.Tasks; using System.Threading; +using System.Threading.Tasks; +using FastTunnel.Core.Client; +using Microsoft.Extensions.Logging; -namespace FastTunnel.Core.Handlers.Client +namespace FastTunnel.Core.Handlers.Client; + +public class LogHandler : IClientHandler { - public class LogHandler : IClientHandler + private readonly ILogger _logger; + + public LogHandler(ILogger logger) { - ILogger _logger; + _logger = logger; + } - public LogHandler(ILogger logger) - { - _logger = logger; - } - - public async Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken) - { - _logger.LogInformation(msg.Replace("\n", string.Empty)); - await Task.CompletedTask; - } + public async Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken) + { + _logger.LogInformation(msg.Replace("\n", string.Empty)); + await Task.CompletedTask; } } diff --git a/FastTunnel.Core/Handlers/Client/SwapHandler.cs b/FastTunnel.Core/Handlers/Client/SwapHandler.cs index 2f5996e..822f234 100644 --- a/FastTunnel.Core/Handlers/Client/SwapHandler.cs +++ b/FastTunnel.Core/Handlers/Client/SwapHandler.cs @@ -1,86 +1,87 @@ -// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel -// The FastTunnel licenses this file to you under the Apache License Version 2.0. -// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/LICENSE +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE +// Copyright (c) 2019 Gui.H -using FastTunnel.Core.Client; using System; using System.IO; +using System.Net.Security; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; +using FastTunnel.Core.Client; using FastTunnel.Core.Sockets; using Microsoft.Extensions.Logging; -using System.Net.Security; -namespace FastTunnel.Core.Handlers.Client +namespace FastTunnel.Core.Handlers.Client; + +public class SwapHandler : IClientHandler { - public class SwapHandler : IClientHandler + private readonly ILogger _logger; + + public SwapHandler(ILogger logger) { - readonly ILogger _logger; + _logger = logger; + } - public SwapHandler(ILogger logger) + public async Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken) + { + var msgs = msg.Split('|'); + var requestId = msgs[0]; + var address = msgs[1]; + + try { - _logger = logger; - } - - public async Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken) - { - var msgs = msg.Split('|'); - var requestId = msgs[0]; - var address = msgs[1]; - - try + using (var serverStream = await createRemote(requestId, cleint, cancellationToken)) + using (var localStream = await createLocal(requestId, address, cancellationToken)) { - using (Stream serverStream = await createRemote(requestId, cleint, cancellationToken)) - using (Stream localStream = await createLocal(requestId, address, cancellationToken)) + var taskX = serverStream.CopyToAsync(localStream, cancellationToken); + var taskY = localStream.CopyToAsync(serverStream, cancellationToken); + + try + { + await Task.WhenAll(taskX, taskY); + } + catch (Exception) { - var taskX = serverStream.CopyToAsync(localStream, cancellationToken); - var taskY = localStream.CopyToAsync(serverStream, cancellationToken); - try - { - await Task.WhenAll(taskX, taskY); - } - catch (Exception ex) - { - - } - finally - { - _logger.LogError($"=====================Swap End:{requestId}================== "); - } + } + finally + { + _logger.LogError($"=====================Swap End:{requestId}================== "); } } - catch (Exception ex) - { - _logger.LogError(ex, $"Swap error {requestId}"); - } } - - private async Task createLocal(string requestId, string localhost, CancellationToken cancellationToken) + catch (Exception ex) { - var socket = await DnsSocketFactory.ConnectAsync(localhost.Split(":")[0], int.Parse(localhost.Split(":")[1])); - return new NetworkStream(socket, true) { ReadTimeout = 1000 * 60 * 10 }; - } - - private async Task createRemote(string requestId, FastTunnelClient cleint, CancellationToken cancellationToken) - { - var socket = await DnsSocketFactory.ConnectAsync(cleint.Server.ServerAddr, cleint.Server.ServerPort); - Stream serverStream = new NetworkStream(socket, true) { ReadTimeout = 1000 * 60 * 10 }; - - if (cleint.Server.Protocol == "wss") - { - var sslStream = new SslStream(serverStream, false, delegate { return true; }); - await sslStream.AuthenticateAsClientAsync(cleint.Server.ServerAddr); - serverStream = sslStream; - } - - var reverse = $"PROXY /{requestId} HTTP/1.1\r\nHost: {cleint.Server.ServerAddr}:{cleint.Server.ServerPort}\r\n\r\n"; - - var requestMsg = Encoding.UTF8.GetBytes(reverse); - await serverStream.WriteAsync(requestMsg, cancellationToken); - return serverStream; + _logger.LogError(ex, $"Swap error {requestId}"); } } + + private async Task createLocal(string requestId, string localhost, CancellationToken cancellationToken) + { + var socket = await DnsSocketFactory.ConnectAsync(localhost.Split(":")[0], int.Parse(localhost.Split(":")[1])); + return new NetworkStream(socket, true) { ReadTimeout = 1000 * 60 * 10 }; + } + + private async Task createRemote(string requestId, FastTunnelClient cleint, CancellationToken cancellationToken) + { + var socket = await DnsSocketFactory.ConnectAsync(cleint.Server.ServerAddr, cleint.Server.ServerPort); + Stream serverStream = new NetworkStream(socket, true) { ReadTimeout = 1000 * 60 * 10 }; + + if (cleint.Server.Protocol == "wss") + { + var sslStream = new SslStream(serverStream, false, delegate { return true; }); + await sslStream.AuthenticateAsClientAsync(cleint.Server.ServerAddr); + serverStream = sslStream; + } + + var reverse = $"PROXY /{requestId} HTTP/1.1\r\nHost: {cleint.Server.ServerAddr}:{cleint.Server.ServerPort}\r\n\r\n"; + + var requestMsg = Encoding.UTF8.GetBytes(reverse); + await serverStream.WriteAsync(requestMsg, cancellationToken); + return serverStream; + } } diff --git a/FastTunnel.Core/Handlers/Server/ForwardDispatcher.cs b/FastTunnel.Core/Handlers/Server/ForwardDispatcher.cs index 4228827..cfe7634 100644 --- a/FastTunnel.Core/Handlers/Server/ForwardDispatcher.cs +++ b/FastTunnel.Core/Handlers/Server/ForwardDispatcher.cs @@ -4,109 +4,104 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H +using System; +using System.IO; +using System.Net.Sockets; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; using FastTunnel.Core.Client; using FastTunnel.Core.Exceptions; using FastTunnel.Core.Extensions; using FastTunnel.Core.Models; -using FastTunnel.Core.Sockets; -using Microsoft.AspNetCore.Hosting.Server; using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Sockets; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -namespace FastTunnel.Core.Handlers.Server +namespace FastTunnel.Core.Handlers.Server; + +public class ForwardDispatcher { - public class ForwardDispatcher + private readonly FastTunnelServer _server; + private readonly ForwardConfig _config; + private readonly ILogger logger; + + public ForwardDispatcher(ILogger logger, FastTunnelServer server, ForwardConfig config) { - private FastTunnelServer _server; - private ForwardConfig _config; - ILogger logger; + this.logger = logger; + _server = server; + _config = config; + } - public ForwardDispatcher(ILogger logger, FastTunnelServer server, ForwardConfig config) - { - this.logger = logger; - _server = server; - _config = config; - } + /// + /// + /// + /// 用户请求 + /// FastTunnel客户端 + /// + public async Task DispatchAsync(Socket _socket, WebSocket client) + { + var msgId = Guid.NewGuid().ToString().Replace("-", ""); - /// - /// - /// - /// 用户请求 - /// FastTunnel客户端 - /// - public async Task DispatchAsync(Socket _socket, WebSocket client) + try { - var msgId = Guid.NewGuid().ToString().Replace("-", ""); + await Task.Yield(); + logger.LogDebug($"[Forward]Swap开始 {msgId}|{_config.RemotePort}=>{_config.LocalIp}:{_config.LocalPort}"); + + var tcs = new TaskCompletionSource(); + tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Dispatch TimeOut]:{msgId}"); }); + + _server.ResponseTasks.TryAdd(msgId, tcs); try { - await Task.Yield(); - logger.LogDebug($"[Forward]Swap开始 {msgId}|{_config.RemotePort}=>{_config.LocalIp}:{_config.LocalPort}"); - - var tcs = new TaskCompletionSource(); - tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Dispatch TimeOut]:{msgId}"); }); - - _server.ResponseTasks.TryAdd(msgId, tcs); - - try - { - await client.SendCmdAsync(MessageType.Forward, $"{msgId}|{_config.LocalIp}:{_config.LocalPort}", CancellationToken.None); - } - catch (SocketClosedException sex) - { - // TODO:客户端已掉线,但是没有移除对端口的监听 - logger.LogError($"[Forward]Swap 客户端已离线 {sex.Message}"); - tcs.TrySetCanceled(); - Close(_socket); - return; - } - catch (Exception ex) - { - // 网络不稳定 - logger.LogError(ex, $"[Forward]Swap Exception"); - tcs.TrySetCanceled(); - Close(_socket); - return; - } - - using (var stream1 = await tcs.Task) - using (var stream2 = new NetworkStream(_socket, true) { ReadTimeout = 1000 * 60 * 10 }) - { - await Task.WhenAll(stream1.CopyToAsync(stream2), stream2.CopyToAsync(stream1)); - } - - logger.LogDebug($"[Forward]Swap OK {msgId}"); + await client.SendCmdAsync(MessageType.Forward, $"{msgId}|{_config.LocalIp}:{_config.LocalPort}", CancellationToken.None); + } + catch (SocketClosedException sex) + { + // TODO:客户端已掉线,但是没有移除对端口的监听 + logger.LogError($"[Forward]Swap 客户端已离线 {sex.Message}"); + tcs.TrySetCanceled(); + Close(_socket); + return; } catch (Exception ex) { - logger.LogDebug($"[Forward]Swap Error {msgId}:" + ex.Message); + // 网络不稳定 + logger.LogError(ex, $"[Forward]Swap Exception"); + tcs.TrySetCanceled(); + Close(_socket); + return; } - finally - { - _server.ResponseTasks.TryRemove(msgId, out _); - } - } - private void Close(Socket socket) + using (var stream1 = await tcs.Task) + using (var stream2 = new NetworkStream(_socket, true) { ReadTimeout = 1000 * 60 * 10 }) + { + await Task.WhenAll(stream1.CopyToAsync(stream2), stream2.CopyToAsync(stream1)); + } + + logger.LogDebug($"[Forward]Swap OK {msgId}"); + } + catch (Exception ex) { - try - { - socket.Shutdown(SocketShutdown.Both); - } - catch (Exception) - { - } - finally - { - socket.Close(); - } + logger.LogDebug($"[Forward]Swap Error {msgId}:" + ex.Message); + } + finally + { + _server.ResponseTasks.TryRemove(msgId, out _); + } + } + + private void Close(Socket socket) + { + try + { + socket.Shutdown(SocketShutdown.Both); + } + catch (Exception) + { + } + finally + { + socket.Close(); } } } diff --git a/FastTunnel.Core/Handlers/Server/IClientMessageHandler.cs b/FastTunnel.Core/Handlers/Server/IClientMessageHandler.cs index 221b181..1877f21 100644 --- a/FastTunnel.Core/Handlers/Server/IClientMessageHandler.cs +++ b/FastTunnel.Core/Handlers/Server/IClientMessageHandler.cs @@ -4,21 +4,15 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Client; -using FastTunnel.Core.Models; -using System; -using System.Collections.Generic; -using System.Net.Sockets; using System.Net.WebSockets; -using System.Text; using System.Threading.Tasks; +using FastTunnel.Core.Client; -namespace FastTunnel.Core.Handlers.Server +namespace FastTunnel.Core.Handlers.Server; + +public interface IClientMessageHandler { - public interface IClientMessageHandler - { - bool NeedRecive { get; } + bool NeedRecive { get; } - Task HandlerMsg(FastTunnelServer server, WebSocket client, string msg); - } + Task HandlerMsg(FastTunnelServer server, WebSocket client, string msg); } diff --git a/FastTunnel.Core/Handlers/Server/ILoginHandler.cs b/FastTunnel.Core/Handlers/Server/ILoginHandler.cs index fabe52e..ac31200 100644 --- a/FastTunnel.Core/Handlers/Server/ILoginHandler.cs +++ b/FastTunnel.Core/Handlers/Server/ILoginHandler.cs @@ -4,14 +4,13 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H +using System.Threading.Tasks; using FastTunnel.Core.Client; using FastTunnel.Core.Models; -using System.Threading.Tasks; -namespace FastTunnel.Core.Handlers.Server +namespace FastTunnel.Core.Handlers.Server; + +public interface ILoginHandler { - public interface ILoginHandler - { - Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd); - } + Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd); } diff --git a/FastTunnel.Core/Handlers/Server/LoginHandler.cs b/FastTunnel.Core/Handlers/Server/LoginHandler.cs index 6f01492..ccc4fc1 100644 --- a/FastTunnel.Core/Handlers/Server/LoginHandler.cs +++ b/FastTunnel.Core/Handlers/Server/LoginHandler.cs @@ -4,127 +4,119 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Client; -using FastTunnel.Core.Extensions; -using FastTunnel.Core.Forwarder; -using FastTunnel.Core.Listener; -using FastTunnel.Core.Models; -using FastTunnel.Core.Models.Massage; -using Microsoft.Extensions.Logging; using System; using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Yarp.ReverseProxy.Configuration; +using FastTunnel.Core.Client; +using FastTunnel.Core.Extensions; +using FastTunnel.Core.Listener; +using FastTunnel.Core.Models; +using FastTunnel.Core.Models.Massage; +using Microsoft.Extensions.Logging; -namespace FastTunnel.Core.Handlers.Server +namespace FastTunnel.Core.Handlers.Server; + +public class LoginHandler : ILoginHandler { - public class LoginHandler : ILoginHandler - { - readonly ILogger logger; - readonly IProxyConfigProvider proxyConfig; - public const bool NeedRecive = true; + private readonly ILogger logger; + public const bool NeedRecive = true; - public LoginHandler(ILogger logger, IProxyConfigProvider proxyConfig) + public LoginHandler(ILogger logger) + { + this.logger = logger; + } + + protected async Task HandleLoginAsync(FastTunnelServer server, TunnelClient client, LogInMassage requet) + { + var hasTunnel = false; + + await client.webSocket.SendCmdAsync(MessageType.Log, $"穿透协议 | 映射关系(公网=>内网)", CancellationToken.None); + Thread.Sleep(300); + + if (requet.Webs != null && requet.Webs.Any()) { - this.proxyConfig = proxyConfig; - this.logger = logger; + hasTunnel = true; + foreach (var item in requet.Webs) + { + var hostName = $"{item.SubDomain}.{server.ServerOption.CurrentValue.WebDomain}".Trim().ToLower(); + var info = new WebInfo { Socket = client.webSocket, WebConfig = item }; + + logger.LogDebug($"new domain '{hostName}'"); + server.WebList.AddOrUpdate(hostName, info, (key, oldInfo) => { return info; }); + + await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{hostName}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None); + client.AddWeb(info); + + if (item.WWW != null) + { + foreach (var www in item.WWW) + { + // TODO:validateDomain + hostName = www.Trim().ToLower(); + server.WebList.AddOrUpdate(www, info, (key, oldInfo) => { return info; }); + + await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{www}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None); + client.AddWeb(info); + } + } + } } - protected async Task HandleLoginAsync(FastTunnelServer server, TunnelClient client, LogInMassage requet) + if (requet.Forwards != null && requet.Forwards.Any()) { - bool hasTunnel = false; - - await client.webSocket.SendCmdAsync(MessageType.Log, $"穿透协议 | 映射关系(公网=>内网)", CancellationToken.None); - Thread.Sleep(300); - - if (requet.Webs != null && requet.Webs.Any()) + if (server.ServerOption.CurrentValue.EnableForward) { hasTunnel = true; - foreach (var item in requet.Webs) + + foreach (var item in requet.Forwards) { - var hostName = $"{item.SubDomain}.{server.ServerOption.CurrentValue.WebDomain}".Trim().ToLower(); - var info = new WebInfo { Socket = client.webSocket, WebConfig = item }; - - logger.LogDebug($"new domain '{hostName}'"); - server.WebList.AddOrUpdate(hostName, info, (key, oldInfo) => { return info; }); - (proxyConfig as InMemoryConfigProvider).AddWeb(hostName); - - await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{hostName}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None); - client.AddWeb(info); - - if (item.WWW != null) + try { - foreach (var www in item.WWW) + if (server.ForwardList.TryGetValue(item.RemotePort, out var old)) { - // TODO:validateDomain - hostName = www.Trim().ToLower(); - server.WebList.AddOrUpdate(www, info, (key, oldInfo) => { return info; }); - (proxyConfig as InMemoryConfigProvider).AddWeb(www); - - await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{www}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None); - client.AddWeb(info); + logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}"); + old.Listener.Stop(); + server.ForwardList.TryRemove(item.RemotePort, out var _); } + + // TODO: 客户端离线时销毁 + var ls = new PortProxyListener("0.0.0.0", item.RemotePort, logger, client.webSocket); + ls.Start(new ForwardDispatcher(logger, server, item)); + + var forwardInfo = new ForwardInfo { Listener = ls, Socket = client.webSocket, SSHConfig = item }; + + // TODO: 客户端离线时销毁 + server.ForwardList.TryAdd(item.RemotePort, forwardInfo); + logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); + + client.AddForward(forwardInfo); + await client.webSocket.SendCmdAsync(MessageType.Log, $" TCP | {server.ServerOption.CurrentValue.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None); + } + catch (Exception ex) + { + logger.LogError($"SSH proxy error: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); + logger.LogError(ex.Message); + await client.webSocket.SendCmdAsync(MessageType.Log, ex.Message, CancellationToken.None); + continue; } } } - - if (requet.Forwards != null && requet.Forwards.Any()) + else { - if (server.ServerOption.CurrentValue.EnableForward) - { - hasTunnel = true; - - foreach (var item in requet.Forwards) - { - try - { - ForwardInfo old; - if (server.ForwardList.TryGetValue(item.RemotePort, out old)) - { - logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}"); - old.Listener.Stop(); - server.ForwardList.TryRemove(item.RemotePort, out ForwardInfo _); - } - - // TODO: 客户端离线时销毁 - var ls = new PortProxyListener("0.0.0.0", item.RemotePort, logger, client.webSocket); - ls.Start(new ForwardDispatcher(logger, server, item)); - - var forwardInfo = new ForwardInfo { Listener = ls, Socket = client.webSocket, SSHConfig = item }; - - // TODO: 客户端离线时销毁 - server.ForwardList.TryAdd(item.RemotePort, forwardInfo); - logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); - - client.AddForward(forwardInfo); - await client.webSocket.SendCmdAsync(MessageType.Log, $" TCP | {server.ServerOption.CurrentValue.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None); - } - catch (Exception ex) - { - logger.LogError($"SSH proxy error: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}"); - logger.LogError(ex.Message); - await client.webSocket.SendCmdAsync(MessageType.Log, ex.Message, CancellationToken.None); - continue; - } - } - } - else - { - await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.ForwardDisabled, CancellationToken.None); - } + await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.ForwardDisabled, CancellationToken.None); } - - if (!hasTunnel) - await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.NoTunnel, CancellationToken.None); } - public virtual async Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd) - { - var msg = JsonSerializer.Deserialize(lineCmd); - await HandleLoginAsync(fastTunnelServer, tunnelClient, msg); - return NeedRecive; - } + if (!hasTunnel) + await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.NoTunnel, CancellationToken.None); + } + + public virtual async Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd) + { + var msg = JsonSerializer.Deserialize(lineCmd); + await HandleLoginAsync(fastTunnelServer, tunnelClient, msg); + return NeedRecive; } } diff --git a/FastTunnel.Core/Listener/PortProxyListener.cs b/FastTunnel.Core/Listener/PortProxyListener.cs index 1cf33c5..40e2509 100644 --- a/FastTunnel.Core/Listener/PortProxyListener.cs +++ b/FastTunnel.Core/Listener/PortProxyListener.cs @@ -4,124 +4,122 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Handlers.Server; -using Microsoft.Extensions.Logging; using System; using System.Net; using System.Net.Sockets; using System.Net.WebSockets; using System.Threading; +using FastTunnel.Core.Handlers.Server; +using Microsoft.Extensions.Logging; -namespace FastTunnel.Core.Listener +namespace FastTunnel.Core.Listener; + +public class PortProxyListener { - public class PortProxyListener + private readonly ILogger _logerr; + + public string ListenIp { get; set; } + + public int ListenPort { get; set; } + + private int m_numConnectedSockets; + private bool shutdown; + private ForwardDispatcher _requestDispatcher; + private readonly Socket listenSocket; + private readonly WebSocket client; + + public PortProxyListener(string ip, int port, ILogger logerr, WebSocket client) { - readonly ILogger _logerr; + this.client = client; + _logerr = logerr; + this.ListenIp = ip; + this.ListenPort = port; - public string ListenIp { get; set; } + var ipa = IPAddress.Parse(ListenIp); + var localEndPoint = new IPEndPoint(ipa, ListenPort); - public int ListenPort { get; set; } + listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + listenSocket.Bind(localEndPoint); + } - int m_numConnectedSockets; + public void Start(ForwardDispatcher requestDispatcher) + { + shutdown = false; + _requestDispatcher = requestDispatcher; - bool shutdown; - ForwardDispatcher _requestDispatcher; - readonly Socket listenSocket; - readonly WebSocket client; + listenSocket.Listen(); - public PortProxyListener(string ip, int port, ILogger logerr, WebSocket client) + StartAccept(null); + } + + private void StartAccept(SocketAsyncEventArgs acceptEventArg) + { + _logerr.LogDebug($"【{ListenIp}:{ListenPort}】: StartAccept"); + if (acceptEventArg == null) { - this.client = client; - _logerr = logerr; - this.ListenIp = ip; - this.ListenPort = port; - - IPAddress ipa = IPAddress.Parse(ListenIp); - IPEndPoint localEndPoint = new IPEndPoint(ipa, ListenPort); - - listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - listenSocket.Bind(localEndPoint); + acceptEventArg = new SocketAsyncEventArgs(); + acceptEventArg.Completed += new EventHandler(AcceptEventArg_Completed); + } + else + { + // socket must be cleared since the context object is being reused + acceptEventArg.AcceptSocket = null; } - public void Start(ForwardDispatcher requestDispatcher) + var willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg); + if (!willRaiseEvent) { - shutdown = false; - _requestDispatcher = requestDispatcher; - - listenSocket.Listen(); - - StartAccept(null); + ProcessAcceptAsync(acceptEventArg); } + } - private void StartAccept(SocketAsyncEventArgs acceptEventArg) + private void ProcessAcceptAsync(SocketAsyncEventArgs e) + { + if (e.SocketError == SocketError.Success) { - _logerr.LogDebug($"【{ListenIp}:{ListenPort}】: StartAccept"); - if (acceptEventArg == null) - { - acceptEventArg = new SocketAsyncEventArgs(); - acceptEventArg.Completed += new EventHandler(AcceptEventArg_Completed); - } - else - { - // socket must be cleared since the context object is being reused - acceptEventArg.AcceptSocket = null; - } + var accept = e.AcceptSocket; - bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg); - if (!willRaiseEvent) + Interlocked.Increment(ref m_numConnectedSockets); + + _logerr.LogInformation($"【{ListenIp}:{ListenPort}】Accepted. There are {{0}} clients connected to the port", + m_numConnectedSockets); + + // 将此客户端交由Dispatcher进行管理 + _requestDispatcher.DispatchAsync(accept, client); + + // Accept the next connection request + StartAccept(e); + } + else + { + Stop(); + } + } + + private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) + { + ProcessAcceptAsync(e); + } + + public void Stop() + { + if (shutdown) + return; + + try + { + if (listenSocket.Connected) { - ProcessAcceptAsync(acceptEventArg); + listenSocket.Shutdown(SocketShutdown.Both); } } - - private void ProcessAcceptAsync(SocketAsyncEventArgs e) + catch (Exception) { - if (e.SocketError == SocketError.Success) - { - var accept = e.AcceptSocket; - - Interlocked.Increment(ref m_numConnectedSockets); - - _logerr.LogInformation($"【{ListenIp}:{ListenPort}】Accepted. There are {{0}} clients connected to the port", - m_numConnectedSockets); - - // 将此客户端交由Dispatcher进行管理 - _requestDispatcher.DispatchAsync(accept, client); - - // Accept the next connection request - StartAccept(e); - } - else - { - Stop(); - } } - - private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) + finally { - ProcessAcceptAsync(e); - } - - public void Stop() - { - if (shutdown) - return; - - try - { - if (listenSocket.Connected) - { - listenSocket.Shutdown(SocketShutdown.Both); - } - } - catch (Exception) - { - } - finally - { - shutdown = true; - listenSocket.Close(); - } + shutdown = true; + listenSocket.Close(); } } } diff --git a/FastTunnel.Core/Models/ForwardConfig.cs b/FastTunnel.Core/Models/ForwardConfig.cs index e4af5bd..8539dcf 100644 --- a/FastTunnel.Core/Models/ForwardConfig.cs +++ b/FastTunnel.Core/Models/ForwardConfig.cs @@ -4,35 +4,34 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -namespace FastTunnel.Core.Models +namespace FastTunnel.Core.Models; + +public class ForwardConfig { - public class ForwardConfig - { - /// - /// 局域网IP地址 - /// - public string LocalIp { get; set; } + /// + /// 局域网IP地址 + /// + public string LocalIp { get; set; } - /// - /// 局域网ssh端口号 - /// - public int LocalPort { get; set; } = 22; + /// + /// 局域网ssh端口号 + /// + public int LocalPort { get; set; } = 22; - /// - /// 服务端监听的端口号 1~65535 - /// - public int RemotePort { get; set; } + /// + /// 服务端监听的端口号 1~65535 + /// + public int RemotePort { get; set; } - /// - /// 协议,内网服务监听的协议 - /// - public ProtocolEnum Protocol { get; set; } - } - - public enum ProtocolEnum - { - TCP = 0, - - UDP = 1, - } + /// + /// 协议,内网服务监听的协议 + /// + public ProtocolEnum Protocol { get; set; } +} + +public enum ProtocolEnum +{ + TCP = 0, + + UDP = 1, } diff --git a/FastTunnel.Core/Models/ForwardHandlerArg.cs b/FastTunnel.Core/Models/ForwardHandlerArg.cs index 84da0af..6d305ca 100644 --- a/FastTunnel.Core/Models/ForwardHandlerArg.cs +++ b/FastTunnel.Core/Models/ForwardHandlerArg.cs @@ -4,17 +4,13 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Collections.Generic; using System.Net.Sockets; -using System.Text; -namespace FastTunnel.Core.Models +namespace FastTunnel.Core.Models; + +public class ForwardHandlerArg { - public class ForwardHandlerArg - { - public ForwardConfig SSHConfig { get; set; } + public ForwardConfig SSHConfig { get; set; } - public Socket LocalClient { get; set; } - } + public Socket LocalClient { get; set; } } diff --git a/FastTunnel.Core/Models/ForwardInfo.cs b/FastTunnel.Core/Models/ForwardInfo.cs index 7f2d7f7..7ebe8c9 100644 --- a/FastTunnel.Core/Models/ForwardInfo.cs +++ b/FastTunnel.Core/Models/ForwardInfo.cs @@ -4,21 +4,16 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Listener; -using System; -using System.Collections.Generic; -using System.Net.Sockets; using System.Net.WebSockets; -using System.Text; +using FastTunnel.Core.Listener; -namespace FastTunnel.Core.Models +namespace FastTunnel.Core.Models; + +public class ForwardInfo { - public class ForwardInfo - { - public WebSocket Socket { get; set; } + public WebSocket Socket { get; set; } - public ForwardConfig SSHConfig { get; set; } + public ForwardConfig SSHConfig { get; set; } - public PortProxyListener Listener { get; set; } - } + public PortProxyListener Listener { get; set; } } diff --git a/FastTunnel.Core/Models/Massage/LogInMassage.cs b/FastTunnel.Core/Models/Massage/LogInMassage.cs index fcb236d..c41ae30 100644 --- a/FastTunnel.Core/Models/Massage/LogInMassage.cs +++ b/FastTunnel.Core/Models/Massage/LogInMassage.cs @@ -6,18 +6,17 @@ using System.Collections.Generic; -namespace FastTunnel.Core.Models.Massage -{ - public class LogInMassage : TunnelMassage - { - /// - /// web穿透隧道列表 - /// - public IEnumerable Webs { get; set; } +namespace FastTunnel.Core.Models.Massage; - /// - /// 端口转发隧道列表 - /// - public IEnumerable Forwards { get; set; } - } +public class LogInMassage : TunnelMassage +{ + /// + /// web穿透隧道列表 + /// + public IEnumerable Webs { get; set; } + + /// + /// 端口转发隧道列表 + /// + public IEnumerable Forwards { get; set; } } diff --git a/FastTunnel.Core/Models/Massage/TunnelMassage.cs b/FastTunnel.Core/Models/Massage/TunnelMassage.cs index 84dd4f0..98ef126 100644 --- a/FastTunnel.Core/Models/Massage/TunnelMassage.cs +++ b/FastTunnel.Core/Models/Massage/TunnelMassage.cs @@ -4,9 +4,8 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -namespace FastTunnel.Core.Models.Massage +namespace FastTunnel.Core.Models.Massage; + +public class TunnelMassage { - public class TunnelMassage - { - } } diff --git a/FastTunnel.Core/Models/Message.cs b/FastTunnel.Core/Models/Message.cs index 4d991d1..ac577f0 100644 --- a/FastTunnel.Core/Models/Message.cs +++ b/FastTunnel.Core/Models/Message.cs @@ -4,24 +4,19 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Collections.Generic; -using System.Text; +namespace FastTunnel.Core.Models; -namespace FastTunnel.Core.Models +public struct Message { - public struct Message - { - public MessageType MessageType { get; set; } + public MessageType MessageType { get; set; } - public T Content { get; set; } - } - - public enum MessageType : byte - { - LogIn = 1, // client - SwapMsg = 2, - Forward = 3, - Log = 4, - } + public T Content { get; set; } +} + +public enum MessageType : byte +{ + LogIn = 1, // client + SwapMsg = 2, + Forward = 3, + Log = 4, } diff --git a/FastTunnel.Core/Models/TunnelClient.cs b/FastTunnel.Core/Models/TunnelClient.cs index 05dd119..62507ce 100644 --- a/FastTunnel.Core/Models/TunnelClient.cs +++ b/FastTunnel.Core/Models/TunnelClient.cs @@ -4,104 +4,101 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; using FastTunnel.Core.Client; using FastTunnel.Core.Handlers.Server; using FastTunnel.Core.Protocol; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -namespace FastTunnel.Core.Models +namespace FastTunnel.Core.Models; + +public class TunnelClient { - public class TunnelClient + public WebSocket webSocket { get; private set; } + + /// + /// 服务端端口号 + /// + public int ConnectionPort { get; set; } + + private readonly FastTunnelServer fastTunnelServer; + private readonly ILoginHandler loginHandler; + + public IPAddress RemoteIpAddress { get; private set; } + + private readonly IList webInfos = new List(); + private readonly IList> forwardInfos = new List>(); + + public TunnelClient(WebSocket webSocket, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler, IPAddress remoteIpAddress) { - public WebSocket webSocket { get; private set; } + this.webSocket = webSocket; + this.fastTunnelServer = fastTunnelServer; + this.loginHandler = loginHandler; + this.RemoteIpAddress = remoteIpAddress; + } - /// - /// 服务端端口号 - /// - public int ConnectionPort { get; set; } + internal void AddWeb(WebInfo info) + { + webInfos.Add(info); + } - readonly FastTunnelServer fastTunnelServer; - readonly ILoginHandler loginHandler; + internal void AddForward(ForwardInfo forwardInfo) + { + forwardInfos.Add(forwardInfo); + } - public IPAddress RemoteIpAddress { get; private set; } + public async Task ReviceAsync(CancellationToken cancellationToken) + { + var buffer = new byte[FastTunnelConst.MAX_CMD_LENGTH]; + var tunnelProtocol = new TunnelProtocol(); - readonly IList webInfos = new List(); - readonly IList> forwardInfos = new List>(); - - public TunnelClient(WebSocket webSocket, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler, IPAddress remoteIpAddress) + while (true) { - this.webSocket = webSocket; - this.fastTunnelServer = fastTunnelServer; - this.loginHandler = loginHandler; - this.RemoteIpAddress = remoteIpAddress; - } + var res = await webSocket.ReceiveAsync(buffer, cancellationToken); + var cmds = tunnelProtocol.HandleBuffer(buffer, 0, res.Count); + if (cmds == null) continue; - internal void AddWeb(WebInfo info) - { - webInfos.Add(info); - } - - internal void AddForward(ForwardInfo forwardInfo) - { - forwardInfos.Add(forwardInfo); - } - - public async Task ReviceAsync(CancellationToken cancellationToken) - { - var buffer = new byte[FastTunnelConst.MAX_CMD_LENGTH]; - var tunnelProtocol = new TunnelProtocol(); - - while (true) + foreach (var item in cmds) { - var res = await webSocket.ReceiveAsync(buffer, cancellationToken); - var cmds = tunnelProtocol.HandleBuffer(buffer, 0, res.Count); - if (cmds == null) continue; - - foreach (var item in cmds) + if (!await HandleCmdAsync(this, item)) { - if (!await HandleCmdAsync(this, item)) - { - return; - }; - } + return; + }; } } - private async Task HandleCmdAsync(TunnelClient tunnelClient, string lineCmd) - { - try - { - return await loginHandler.HandlerMsg(fastTunnelServer, tunnelClient, lineCmd.Substring(1)); - } - catch (Exception ex) - { - Console.WriteLine($"处理客户端消息失败:cmd={lineCmd} {ex}"); - return false; - } - } - - internal void Logout() - { - // forward监听终止 - if (forwardInfos != null) - { - foreach (var item in forwardInfos) - { - try - { - item.Listener.Stop(); - } - catch { } - } - } - - webSocket.CloseAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None); - } + } + private async Task HandleCmdAsync(TunnelClient tunnelClient, string lineCmd) + { + try + { + return await loginHandler.HandlerMsg(fastTunnelServer, tunnelClient, lineCmd.Substring(1)); + } + catch (Exception ex) + { + Console.WriteLine($"处理客户端消息失败:cmd={lineCmd} {ex}"); + return false; + } + } + + internal void Logout() + { + // forward监听终止 + if (forwardInfos != null) + { + foreach (var item in forwardInfos) + { + try + { + item.Listener.Stop(); + } + catch { } + } + } + + webSocket.CloseAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None); } } diff --git a/FastTunnel.Core/Models/WebConfig.cs b/FastTunnel.Core/Models/WebConfig.cs index f453a62..b0ebca2 100644 --- a/FastTunnel.Core/Models/WebConfig.cs +++ b/FastTunnel.Core/Models/WebConfig.cs @@ -4,32 +4,27 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using System; -using System.Collections.Generic; -using System.Text; +namespace FastTunnel.Core.Models; -namespace FastTunnel.Core.Models +public class WebConfig { - public class WebConfig - { - /// - /// 子域名 - /// - public string SubDomain { get; set; } + /// + /// 子域名 + /// + public string SubDomain { get; set; } - /// - /// 本地IP - /// - public string LocalIp { get; set; } + /// + /// 本地IP + /// + public string LocalIp { get; set; } - /// - /// - /// - public int LocalPort { get; set; } + /// + /// + /// + public int LocalPort { get; set; } - /// - /// 个人域名 - /// - public string[] WWW { get; set; } - } + /// + /// 个人域名 + /// + public string[] WWW { get; set; } } diff --git a/FastTunnel.Core/Models/WebInfo.cs b/FastTunnel.Core/Models/WebInfo.cs index cc7fe0f..3783f89 100644 --- a/FastTunnel.Core/Models/WebInfo.cs +++ b/FastTunnel.Core/Models/WebInfo.cs @@ -5,23 +5,19 @@ // Copyright (c) 2019 Gui.H using System; -using System.Collections.Generic; -using System.Net.Sockets; using System.Net.WebSockets; -using System.Text; -namespace FastTunnel.Core.Models +namespace FastTunnel.Core.Models; + +public class WebInfo { - public class WebInfo + public WebSocket Socket { get; set; } + + public WebConfig WebConfig { get; set; } + + internal void LogOut() { - public WebSocket Socket { get; set; } - - public WebConfig WebConfig { get; set; } - - internal void LogOut() - { - // TODO:退出登录 - throw new NotImplementedException(); - } + // TODO:退出登录 + throw new NotImplementedException(); } } diff --git a/FastTunnel.Core/Protocol/TunnelProtocol.cs b/FastTunnel.Core/Protocol/TunnelProtocol.cs index e1df723..ea59212 100644 --- a/FastTunnel.Core/Protocol/TunnelProtocol.cs +++ b/FastTunnel.Core/Protocol/TunnelProtocol.cs @@ -4,41 +4,40 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Extensions; using System.Collections.Generic; using System.Linq; using System.Text; +using FastTunnel.Core.Extensions; -namespace FastTunnel.Core.Protocol +namespace FastTunnel.Core.Protocol; + +public class TunnelProtocol { - public class TunnelProtocol + private string massgeTemp; + private readonly string m_sectionFlag = "\n"; + + public IEnumerable HandleBuffer(byte[] buffer, int offset, int count) { - string massgeTemp; - string m_sectionFlag = "\n"; + var words = buffer.GetString(offset, count); + var sum = massgeTemp + words; - public IEnumerable HandleBuffer(byte[] buffer, int offset, int count) + if (sum.Contains(m_sectionFlag)) { - var words = buffer.GetString(offset, count); - var sum = massgeTemp + words; + var array = (sum).Split(m_sectionFlag); + massgeTemp = null; + var fullMsg = words.EndsWith(m_sectionFlag); - if (sum.Contains(m_sectionFlag)) + if (!fullMsg) { - var array = (sum).Split(m_sectionFlag); - massgeTemp = null; - var fullMsg = words.EndsWith(m_sectionFlag); - - if (!fullMsg) - { - massgeTemp = array[array.Length - 1]; - } - - return array.Take(array.Length - 1); - } - else - { - massgeTemp = sum; - return null; + massgeTemp = array[array.Length - 1]; } + + return array.Take(array.Length - 1); + } + else + { + massgeTemp = sum; + return null; } } } diff --git a/FastTunnel.Core/Services/ServiceFastTunnelClient.cs b/FastTunnel.Core/Services/ServiceFastTunnelClient.cs index d49ec09..e782358 100644 --- a/FastTunnel.Core/Services/ServiceFastTunnelClient.cs +++ b/FastTunnel.Core/Services/ServiceFastTunnelClient.cs @@ -4,56 +4,50 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Config; -using FastTunnel.Core.Client; -using FastTunnel.Core.Models; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; -using System.Runtime.ExceptionServices; -using System.IO; +using FastTunnel.Core.Client; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; -namespace FastTunnel.Core.Services +namespace FastTunnel.Core.Services; + +public class ServiceFastTunnelClient : IHostedService { - public class ServiceFastTunnelClient : IHostedService + private readonly ILogger _logger; + private readonly IFastTunnelClient _fastTunnelClient; + + public ServiceFastTunnelClient(ILogger logger, IFastTunnelClient fastTunnelClient) { - readonly ILogger _logger; - readonly IFastTunnelClient _fastTunnelClient; + _logger = logger; + _fastTunnelClient = fastTunnelClient; - public ServiceFastTunnelClient(ILogger logger, IFastTunnelClient fastTunnelClient) + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + _fastTunnelClient.StartAsync(cancellationToken); + await Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _fastTunnelClient.Stop(cancellationToken); + return Task.CompletedTask; + } + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + try { - _logger = logger; - _fastTunnelClient = fastTunnelClient; - - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + _logger.LogError("【UnhandledException】" + e.ExceptionObject); + var type = e.ExceptionObject.GetType(); + _logger.LogError("ExceptionObject GetType " + type); } - - public async Task StartAsync(CancellationToken cancellationToken) + catch { - _fastTunnelClient.StartAsync(cancellationToken); - await Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - _fastTunnelClient.Stop(cancellationToken); - return Task.CompletedTask; - } - - private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { - try - { - _logger.LogError("【UnhandledException】" + e.ExceptionObject); - var type = e.ExceptionObject.GetType(); - _logger.LogError("ExceptionObject GetType " + type); - } - catch - { - } } } } diff --git a/FastTunnel.Core/Sockets/DnsSocketFactory.cs b/FastTunnel.Core/Sockets/DnsSocketFactory.cs index c64cce0..8e4cc70 100644 --- a/FastTunnel.Core/Sockets/DnsSocketFactory.cs +++ b/FastTunnel.Core/Sockets/DnsSocketFactory.cs @@ -4,25 +4,19 @@ // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // Copyright (c) 2019 Gui.H -using FastTunnel.Core.Extensions; -using FastTunnel.Core.Models; -using System; -using System.Collections.Generic; using System.Net; using System.Net.Sockets; -using System.Text; using System.Threading.Tasks; -namespace FastTunnel.Core.Sockets +namespace FastTunnel.Core.Sockets; + +public class DnsSocketFactory { - public class DnsSocketFactory + public static async Task ConnectAsync(string host, int port) { - public static async Task ConnectAsync(string host, int port) - { - var Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - DnsEndPoint dnsEndPoint = new DnsEndPoint(host, port); - await Socket.ConnectAsync(dnsEndPoint); - return Socket; - } + var Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + var dnsEndPoint = new DnsEndPoint(host, port); + await Socket.ConnectAsync(dnsEndPoint); + return Socket; } } diff --git a/FastTunnel.Core/Utilitys/AssemblyUtility.cs b/FastTunnel.Core/Utilitys/AssemblyUtility.cs index 85edfd2..344f5c4 100644 --- a/FastTunnel.Core/Utilitys/AssemblyUtility.cs +++ b/FastTunnel.Core/Utilitys/AssemblyUtility.cs @@ -6,13 +6,12 @@ using System; -namespace FastTunnel.Core.Utilitys +namespace FastTunnel.Core.Utilitys; + +public static class AssemblyUtility { - public static class AssemblyUtility + public static Version GetVersion() { - public static Version GetVersion() - { - return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - } + return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; } } diff --git a/FastTunnel.sln b/FastTunnel.sln index fbe5c0c..3033bc0 100644 --- a/FastTunnel.sln +++ b/FastTunnel.sln @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastTunnel.Hosting", "FastTunnel.Hosting\FastTunnel.Hosting.csproj", "{D7F07110-E85C-4F0E-B479-AEC9760CD2A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -40,6 +42,10 @@ Global {7D560A9A-E480-40F4-AAF7-398447438255}.Debug|Any CPU.Build.0 = Debug|Any CPU {7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.Build.0 = Release|Any CPU + {D7F07110-E85C-4F0E-B479-AEC9760CD2A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D7F07110-E85C-4F0E-B479-AEC9760CD2A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D7F07110-E85C-4F0E-B479-AEC9760CD2A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D7F07110-E85C-4F0E-B479-AEC9760CD2A7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -47,6 +53,7 @@ Global GlobalSection(NestedProjects) = preSolution {C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C} {7D560A9A-E480-40F4-AAF7-398447438255} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C} + {D7F07110-E85C-4F0E-B479-AEC9760CD2A7} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3D9C6B44-6706-4EE8-9043-802BBE474A2E}