Feature: Server http connect time Test

This commit is contained in:
ChsBuffer
2021-09-11 01:12:28 +08:00
parent 635212f24d
commit 3e377f2e9d
4 changed files with 127 additions and 39 deletions

View File

@@ -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<NatTypeTestResult> NatTestAsync()
public static async Task<NatTypeTestResult> 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<int?> HttpConnectAsync(CancellationToken ctx = default)
{
Debug.Assert(Socks5Server != null, nameof(Socks5Server) + " != null");
return await Socks5ServerTestUtils.HttpConnectAsync(Socks5Server, ctx);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
/// <summary>
/// 更新 NAT指示灯颜色
/// </summary>
/// <param name="natType"></param>
/// <param name="natType">NAT Type. keep default(-1) to Hide Light</param>
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();
}
/// <summary>
/// 测试 NAT
/// </summary>
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

View File

@@ -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<NatTypeTestResult> StartAsync(Socks5Server socks5, CancellationToken ctx = default)
public static async Task<NatTypeTestResult> 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<int?> 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;
}
}
}