Files
gatuna/win/gatuna-client/MainForm.cs
T

214 lines
6.7 KiB
C#
Raw Normal View History

using SharpPcap.LibPcap;
namespace gatuna_client;
public partial class MainForm : Form
{
readonly SessionManager _sessions = new();
readonly ComboBox _deviceBox = new();
readonly Button _discoverBtn = new();
readonly Button _testBtn = new();
readonly Label _serverLabel = new();
readonly Label _pingStatsLabel = new();
readonly ListView _listView = new();
readonly Label _statusLabel = new();
TunnelLink? _link;
PingTest? _pingTest;
public MainForm()
{
Text = "gatuna";
Width = 520;
Height = 420;
2026-08-13 08:34:59 +00:00
FormBorderStyle = FormBorderStyle.FixedSingle;
MaximizeBox = false;
StartPosition = FormStartPosition.CenterScreen;
Icon = SystemIcons.GetStockIcon(StockIconId.NetworkConnect, 32);
InitializeComponents();
_sessions.Log += msg => this.Invoke(() => _statusLabel.Text = msg);
_sessions.ManifestReceived += (hostname, mac, entries) =>
this.Invoke(() => PopulateList(hostname, mac, entries));
foreach (var d in TunnelLink.ListDevices())
{
var friendly = d.Interface?.FriendlyName ?? "";
var desc = d.Interface?.Description ?? "";
var mac = d.MacAddress?.GetAddressBytes();
var macStr = mac != null
? string.Join(":", mac.Select(b => b.ToString("X2")))
: "??-??-??-??-??-??";
_deviceBox.Items.Add($"{friendly} — {desc} — {macStr}");
}
if (_deviceBox.Items.Count > 0)
_deviceBox.SelectedIndex = 0;
}
void InitializeComponents()
{
const int pad = 12;
_deviceBox.Left = pad; _deviceBox.Top = 12;
_deviceBox.Width = ClientSize.Width - pad * 2;
_deviceBox.DropDownStyle = ComboBoxStyle.DropDownList;
Controls.Add(_deviceBox);
_discoverBtn.Text = "Discover";
_discoverBtn.Left = pad; _discoverBtn.Top = _deviceBox.Bottom + 8;
_discoverBtn.Width = 80;
_discoverBtn.Click += OnDiscover;
Controls.Add(_discoverBtn);
_testBtn.Text = "Test";
_testBtn.Left = _discoverBtn.Right + 8; _testBtn.Top = _discoverBtn.Top;
_testBtn.Width = 60;
_testBtn.Click += OnTest;
Controls.Add(_testBtn);
_serverLabel.Left = pad; _serverLabel.Top = _discoverBtn.Bottom + 8;
_serverLabel.Width = ClientSize.Width - pad * 2;
_serverLabel.AutoEllipsis = true;
_serverLabel.Text = "Server: not connected";
Controls.Add(_serverLabel);
_pingStatsLabel.Left = pad; _pingStatsLabel.Top = _serverLabel.Bottom + 4;
_pingStatsLabel.Width = ClientSize.Width - pad * 2;
_pingStatsLabel.AutoEllipsis = true;
_pingStatsLabel.Text = "";
Controls.Add(_pingStatsLabel);
_listView.Left = pad; _listView.Top = _pingStatsLabel.Bottom + 8;
_listView.Width = ClientSize.Width - pad * 2;
_listView.Height = 180;
_listView.View = View.Details;
_listView.FullRowSelect = true;
_listView.CheckBoxes = true;
_listView.Columns.Add("ID", 36);
_listView.Columns.Add("Proto", 50);
_listView.Columns.Add("Port", 56);
_listView.Columns.Add("Label", 160);
_listView.Columns.Add("Mirror", 70);
_listView.ItemChecked += OnItemChecked;
Controls.Add(_listView);
_statusLabel.Left = pad; _statusLabel.Top = _listView.Bottom + 8;
_statusLabel.Width = ClientSize.Width - pad * 2;
_statusLabel.AutoEllipsis = true;
Controls.Add(_statusLabel);
}
void OnDiscover(object? s, EventArgs e)
{
if (_deviceBox.SelectedIndex < 0)
{
MessageBox.Show("Select a network adapter first.");
return;
}
if (_link != null)
{
_sessions.StopAll();
_sessions.DetachLink();
_link.Dispose();
}
var devices = TunnelLink.ListDevices();
var device = devices[_deviceBox.SelectedIndex];
_link = new TunnelLink(device);
_link.Log += msg => this.Invoke(() => _statusLabel.Text = msg);
_sessions.AttachLink(_link);
_link.Open();
_sessions.Discover();
_serverLabel.Text = "Server: discovering...";
_statusLabel.Text = "discovering...";
}
void OnTest(object? s, EventArgs e)
{
if (_pingTest != null && _pingTest.Running)
{
_sessions.StopPing();
_pingTest = null;
_testBtn.Text = "Test";
return;
}
_pingTest = _sessions.StartPing();
if (_pingTest == null)
{
MessageBox.Show("Discover a server first.");
return;
}
_pingTest.StatsUpdated += stats => this.Invoke(() =>
{
_pingStatsLabel.Text =
$"sent: {stats.Sent} recv: {stats.Received} " +
$"loss: {stats.LossPct:F1}% " +
$"avg: {stats.AvgLatencyMs:F1}ms " +
$"jitter: {stats.JitterMs:F1}ms";
});
_testBtn.Text = "Stop";
_pingStatsLabel.Text = "pinging...";
}
void PopulateList(string hostname, byte[] mac, UpstreamEntry[] entries)
{
var macStr = string.Join(":", mac.Select(b => b.ToString("X2")));
_serverLabel.Text = $"Server: {hostname} — {macStr}";
_listView.BeginUpdate();
_listView.Items.Clear();
foreach (var up in entries)
{
var item = new ListViewItem(up.Id.ToString());
item.SubItems.Add(up.ProtoName);
item.SubItems.Add(up.Port.ToString());
item.SubItems.Add(up.Label ?? "");
item.SubItems.Add("");
item.Tag = up;
_listView.Items.Add(item);
}
_listView.EndUpdate();
}
void OnItemChecked(object? s, ItemCheckedEventArgs e)
{
if (e.Item.Tag is not UpstreamEntry up) return;
if (e.Item.Checked)
{
var port = _sessions.StartListener(up);
e.Item.SubItems[4].Text = port.ToString();
}
else
{
if (int.TryParse(e.Item.SubItems[4].Text, out var port) && port > 0)
{
_sessions.StopListener(port);
e.Item.SubItems[4].Text = "";
}
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
if (WindowState == FormWindowState.Minimized)
{
Hide();
WindowState = FormWindowState.Normal;
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
Shutdown();
base.OnFormClosing(e);
}
public void Shutdown()
{
_sessions.Dispose();
_link?.Dispose();
}
}