using SharpPcap.LibPcap; namespace gatuna_client; public partial class MainForm : Form { readonly SessionManager _sessions = new(); readonly ComboBox _deviceBox = new(); readonly Button _discoverBtn = new(); readonly ListView _listView = new(); readonly Label _statusLabel = new(); TunnelLink? _link; public MainForm() { Text = "gatuna"; Width = 520; Height = 380; FormBorderStyle = FormBorderStyle.FixedSingle; MaximizeBox = false; MinimizeBox = false; StartPosition = FormStartPosition.CenterScreen; InitializeComponents(); _sessions.Log += msg => this.Invoke(() => _statusLabel.Text = msg); _sessions.ManifestReceived += entries => this.Invoke(() => PopulateList(entries)); foreach (var d in TunnelLink.ListDevices()) _deviceBox.Items.Add($"{d.Name} — {d.Interface?.FriendlyName ?? d.Interface?.Description}"); if (_deviceBox.Items.Count > 0) _deviceBox.SelectedIndex = 0; } void InitializeComponents() { Controls.Add(new Label { Text = "Adapter:", Left = 12, Top = 12, AutoSize = true }); _deviceBox.Left = 70; _deviceBox.Top = 9; _deviceBox.Width = 330; _deviceBox.DropDownStyle = ComboBoxStyle.DropDownList; Controls.Add(_deviceBox); _discoverBtn.Text = "Discover"; _discoverBtn.Left = 410; _discoverBtn.Top = 8; _discoverBtn.Width = 80; _discoverBtn.Click += OnDiscover; Controls.Add(_discoverBtn); _listView.Left = 12; _listView.Top = 40; _listView.Width = 478; _listView.Height = 250; _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 = 12; _statusLabel.Top = 304; _statusLabel.Width = 478; _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(); _statusLabel.Text = "discovering..."; } void PopulateList(UpstreamEntry[] entries) { _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 OnFormClosing(FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; Hide(); return; } base.OnFormClosing(e); } public void Shutdown() { _sessions.Dispose(); _link?.Dispose(); } }