From 3e377f2e9de2eb2695f099ed465117bbc795b68d Mon Sep 17 00:00:00 2001 From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com> Date: Sat, 11 Sep 2021 01:12:28 +0800 Subject: [PATCH] Feature: Server http connect time Test --- Netch/Controllers/MainController.cs | 11 ++- Netch/Forms/MainForm.Designer.cs | 20 +++- Netch/Forms/MainForm.cs | 97 +++++++++++++------ ...TypeTester.cs => Socks5ServerTestUtils.cs} | 38 +++++++- 4 files changed, 127 insertions(+), 39 deletions(-) rename Netch/Utils/{NatTypeTester.cs => Socks5ServerTestUtils.cs} (65%) diff --git a/Netch/Controllers/MainController.cs b/Netch/Controllers/MainController.cs index da26e6dd..b717cbf2 100644 --- a/Netch/Controllers/MainController.cs +++ b/Netch/Controllers/MainController.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.Threading; using Netch.Enums; @@ -168,10 +169,16 @@ namespace Netch.Controllers PortCheck(port, portName, PortType.TCP); } - public static async Task NatTestAsync() + public static async Task DiscoveryNatTypeAsync(CancellationToken ctx = default) { Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null"); - return await NatTypeTester.StartAsync(Socks5Server); + return await Socks5ServerTestUtils.DiscoveryNatTypeAsync(Socks5Server, ctx); + } + + public static async Task HttpConnectAsync(CancellationToken ctx = default) + { + Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null"); + return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx); } } } \ No newline at end of file diff --git a/Netch/Forms/MainForm.Designer.cs b/Netch/Forms/MainForm.Designer.cs index ee66d847..6b982b7e 100644 --- a/Netch/Forms/MainForm.Designer.cs +++ b/Netch/Forms/MainForm.Designer.cs @@ -73,6 +73,7 @@ this.DownloadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.UploadSpeedLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.blankToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.TcpStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.NatTypeStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.NatTypeStatusLightLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.ControlButton = new System.Windows.Forms.Button(); @@ -521,6 +522,7 @@ this.DownloadSpeedLabel, this.UploadSpeedLabel, this.blankToolStripStatusLabel, + this.TcpStatusLabel, this.NatTypeStatusLabel, this.NatTypeStatusLightLabel}); this.StatusStrip.Location = new System.Drawing.Point(0, 272); @@ -560,9 +562,18 @@ // blankToolStripStatusLabel // this.blankToolStripStatusLabel.Name = "blankToolStripStatusLabel"; - this.blankToolStripStatusLabel.Size = new System.Drawing.Size(494, 17); + this.blankToolStripStatusLabel.Size = new System.Drawing.Size(240, 17); this.blankToolStripStatusLabel.Spring = true; // + // TcpStatusLabel + // + this.TcpStatusLabel.Name = "TcpStatusLabel"; + this.TcpStatusLabel.Size = new System.Drawing.Size(33, 17); + this.TcpStatusLabel.Text = "TCP:"; + this.TcpStatusLabel.TextAlign = System.Drawing.ContentAlignment.BottomLeft; + this.TcpStatusLabel.Visible = false; + this.TcpStatusLabel.Click += new System.EventHandler(this.TcpStatusLabel_Click); + // // NatTypeStatusLabel // this.NatTypeStatusLabel.Name = "NatTypeStatusLabel"; @@ -609,19 +620,19 @@ this.ExitToolStripButton}); this.NotifyMenu.Name = "NotifyMenu"; this.NotifyMenu.ShowItemToolTips = false; - this.NotifyMenu.Size = new System.Drawing.Size(181, 70); + this.NotifyMenu.Size = new System.Drawing.Size(108, 48); // // ShowMainFormToolStripButton // this.ShowMainFormToolStripButton.Name = "ShowMainFormToolStripButton"; - this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(180, 22); + this.ShowMainFormToolStripButton.Size = new System.Drawing.Size(107, 22); this.ShowMainFormToolStripButton.Text = "Show"; this.ShowMainFormToolStripButton.Click += new System.EventHandler(this.ShowMainFormToolStripButton_Click); // // ExitToolStripButton // this.ExitToolStripButton.Name = "ExitToolStripButton"; - this.ExitToolStripButton.Size = new System.Drawing.Size(180, 22); + this.ExitToolStripButton.Size = new System.Drawing.Size(107, 22); this.ExitToolStripButton.Text = "Exit"; this.ExitToolStripButton.Click += new System.EventHandler(this.ExitToolStripButton_Click); // @@ -792,5 +803,6 @@ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; private System.Windows.Forms.ContainerControl ButtomControlContainerControl; private System.Windows.Forms.ToolStripMenuItem ShowHideConsoleToolStripMenuItem; + private System.Windows.Forms.ToolStripStatusLabel TcpStatusLabel; } } \ No newline at end of file diff --git a/Netch/Forms/MainForm.cs b/Netch/Forms/MainForm.cs index 95504ec9..16b10da5 100644 --- a/Netch/Forms/MainForm.cs +++ b/Netch/Forms/MainForm.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Windows.Win32; @@ -90,8 +91,8 @@ namespace Netch.Forms // 加载翻译 TranslateControls(); - // 隐藏 NatTypeStatusLabel - NatTypeStatusText(); + // 隐藏 ConnectivityStatusLabel + ConnectivityStatusVisible(false); // 加载快速配置 LoadProfiles(); @@ -547,7 +548,8 @@ namespace Netch.Forms State = State.Started; Task.Run(Bandwidth.NetTraffic).Forget(); - NatTestAsync().Forget(); + DiscoveryNatTypeAsync().Forget(); + HttpConnectAsync().Forget(); if (Global.Settings.MinimizeWhenStarted) Minimize(); @@ -1028,7 +1030,7 @@ namespace Netch.Forms ProfileGroupBox.Enabled = false; BandwidthState(false); - NatTypeStatusText(); + ConnectivityStatusVisible(false); break; case State.Stopped: ControlButton.Enabled = true; @@ -1099,18 +1101,14 @@ namespace Netch.Forms UsedBandwidthLabel.Visible /*= UploadSpeedLabel.Visible*/ = DownloadSpeedLabel.Visible = state; } - private void NatTypeStatusText(string? text = null, string? country = null) + private void UpdateNatTypeStatusLabelText(string? text, string? country = null) { - if (State != State.Started) - { - NatTypeStatusLabel.Text = ""; - NatTypeStatusLabel.Visible = NatTypeStatusLightLabel.Visible = false; - return; - } - if (!string.IsNullOrEmpty(text)) { - NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} {(!country.IsNullOrEmpty() ? $"[{country}]" : "")}"; + if (country == null) + NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} "; + else + NatTypeStatusLabel.Text = $"NAT{i18N.Translate(": ")}{text} [{country}]"; UpdateNatTypeLight(int.TryParse(text, out var natType) ? natType : -1); } @@ -1122,10 +1120,18 @@ namespace Netch.Forms NatTypeStatusLabel.Visible = true; } + private void ConnectivityStatusVisible(bool visible) + { + if (!visible) + TcpStatusLabel.Text = NatTypeStatusLabel.Text = ""; + + TcpStatusLabel.Visible = NatTypeStatusLabel.Visible = NatTypeStatusLightLabel.Visible = visible; + } + /// /// 更新 NAT指示灯颜色 /// - /// + /// NAT Type. keep default(-1) to Hide Light private void UpdateNatTypeLight(int natType = -1) { if (natType > 0 && natType < 5) @@ -1148,43 +1154,76 @@ namespace Netch.Forms } } - private async void NatTypeStatusLabel_Click(object sender, EventArgs e) + private async void TcpStatusLabel_Click(object sender, EventArgs e) { - await NatTestAsync(); + await HttpConnectAsync(); } - /// - /// 测试 NAT - /// - private async Task NatTestAsync() + private async void NatTypeStatusLabel_Click(object sender, EventArgs e) + { + await DiscoveryNatTypeAsync(); + } + + private async Task DiscoveryNatTypeAsync() { NatTypeStatusLabel.Enabled = false; + NatTypeStatusLabel.Text = i18N.Translate("Testing NAT Type"); + + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(5)); + + var discoveryNatTypeAsync = MainController.DiscoveryNatTypeAsync(cts.Token); + try { - NatTypeStatusText(i18N.Translate("Testing NAT Type")); - - var res = await MainController.NatTestAsync(); + var res = await discoveryNatTypeAsync; if (!string.IsNullOrEmpty(res.PublicEnd)) { var country = await Utils.Utils.GetCityCodeAsync(res.PublicEnd); - NatTypeStatusText(res.Result, country); + + UpdateNatTypeStatusLabelText(res.Result, country); + if (int.TryParse(res.Result, out var natType)) + UpdateNatTypeLight(natType); + else + UpdateNatTypeLight(); } else { - NatTypeStatusText(res.Result ?? "Error"); + UpdateNatTypeStatusLabelText(res.Result ?? "Error"); + NatTypeStatusLightLabel.Visible = false; } } - catch (Exception e) - { - NatTypeStatusText(e.Message); - } finally { NatTypeStatusLabel.Enabled = true; } } + private async Task HttpConnectAsync() + { + TcpStatusLabel.Enabled = false; + + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(5)); + var httpConnectAsync = MainController.HttpConnectAsync(cts.Token); + + try + { + var httpRes = await httpConnectAsync; + if (httpRes != null) + TcpStatusLabel.Text = $"TCP{i18N.Translate(": ")}{httpRes}ms"; + else + TcpStatusLabel.Text = $"TCP{i18N.Translate(": ", "Timeout")}"; + + TcpStatusLabel.Visible = true; + } + finally + { + TcpStatusLabel.Enabled = true; + } + } + #endregion #endregion diff --git a/Netch/Utils/NatTypeTester.cs b/Netch/Utils/Socks5ServerTestUtils.cs similarity index 65% rename from Netch/Utils/NatTypeTester.cs rename to Netch/Utils/Socks5ServerTestUtils.cs index dfed2715..05ab4a52 100644 --- a/Netch/Utils/NatTypeTester.cs +++ b/Netch/Utils/Socks5ServerTestUtils.cs @@ -1,4 +1,6 @@ -using System.Net; +using System; +using System.Diagnostics; +using System.Net; using System.Threading; using System.Threading.Tasks; using Netch.Models; @@ -11,9 +13,9 @@ using STUN.StunResult; namespace Netch.Utils { - public static class NatTypeTester + public static class Socks5ServerTestUtils { - public static async Task StartAsync(Socks5Server socks5, CancellationToken ctx = default) + public static async Task DiscoveryNatTypeAsync(Socks5Server socks5, CancellationToken ctx = default) { var stunServer = Global.Settings.STUN_Server; var port = (ushort)Global.Settings.STUN_Server_Port; @@ -30,7 +32,11 @@ namespace Netch.Utils } }; - var ip = await DnsUtils.LookupAsync(stunServer) ?? throw new MessageException("Wrong STUN Server!"); + var ip = await DnsUtils.LookupAsync(stunServer); + if (ip == null) + { + return new NatTypeTestResult { Result = "Wrong STUN Server!" }; + } using IUdpProxy proxy = ProxyFactory.CreateProxy(ProxyType.Socks5, new IPEndPoint(IPAddress.Loopback, 0), socks5Option); using var client = new StunClient5389UDP(new IPEndPoint(ip, port), local, proxy); @@ -72,5 +78,29 @@ namespace Netch.Utils return res.FilteringBehavior.ToString(); } } + + public static async Task HttpConnectAsync(Socks5Server socks5, CancellationToken ctx) + { + var socks5Option = new Socks5CreateOption + { + Address = await DnsUtils.LookupAsync(socks5.Hostname), + Port = socks5.Port, + UsernamePassword = new UsernamePassword + { + UserName = socks5.Username, + Password = socks5.Password + } + }; + + var stopwatch = Stopwatch.StartNew(); + + var result = await Socks5.Utils.Socks5TestUtils.Socks5ConnectAsync(socks5Option, token: ctx); + + stopwatch.Stop(); + if (result) + return Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + + return null; + } } } \ No newline at end of file