Start the station link on launch and beacon on every interface

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 03:22:34 +00:00
co-authored by Claude Sonnet 5.5
parent c8bc141829
commit ec12fb1d0f
2 changed files with 43 additions and 3 deletions
@@ -198,6 +198,10 @@ public sealed partial class EntryWindow : Window
{ {
yield return ("station network", session.ApplyNetworkSettings); yield return ("station network", session.ApplyNetworkSettings);
} }
if (session.Settings.StationLinkEnabled)
{
yield return ("station link", session.ApplyStationLinkSettings);
}
// always, whatever the CW keyer is: this is also what builds the voice // always, whatever the CW keyer is: this is also what builds the voice
// keyer, which plays out of the sound card rather than a keying port // keyer, which plays out of the sound card rather than a keying port
yield return ("keyer", session.ApplyKeyerSettings); yield return ("keyer", session.ApplyKeyerSettings);
+39 -3
View File
@@ -1,5 +1,6 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Net; using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using Nonemm.Core; using Nonemm.Core;
@@ -525,9 +526,12 @@ public sealed class StationLink : IDisposable
StationBeacon beacon = new(computerName, Address(), port, version, mine.Operator); StationBeacon beacon = new(computerName, Address(), port, version, mine.Operator);
myAddress = beacon.Address; myAddress = beacon.Address;
byte[] message = Encoding.UTF8.GetBytes(beacon.ToWire()); byte[] message = Encoding.UTF8.GetBytes(beacon.ToWire());
await beacons! foreach (IPAddress target in BroadcastAddresses())
.SendAsync(message, new IPEndPoint(IPAddress.Broadcast, port), cancellation) {
.ConfigureAwait(false); await beacons!
.SendAsync(message, new IPEndPoint(target, port), cancellation)
.ConfigureAwait(false);
}
mine.Address = beacon.Address; mine.Address = beacon.Address;
mine.LastHeardUtc = DateTime.UtcNow; mine.LastHeardUtc = DateTime.UtcNow;
Forget(); Forget();
@@ -1138,6 +1142,38 @@ public sealed class StationLink : IDisposable
} }
} }
/// The broadcast address of each network this computer is on. The limited
/// broadcast (255.255.255.255) leaves by one interface only, so a computer
/// with a second adapter or a VPN would miss the stations on the others.
private static List<IPAddress> BroadcastAddresses()
{
List<IPAddress> found = [IPAddress.Broadcast];
foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
{
if (adapter.OperationalStatus != OperationalStatus.Up
|| adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback
|| !adapter.SupportsMulticast)
{
continue;
}
foreach (UnicastIPAddressInformation info in adapter.GetIPProperties().UnicastAddresses)
{
if (info.Address.AddressFamily != AddressFamily.InterNetwork || info.IPv4Mask is null)
{
continue;
}
byte[] address = info.Address.GetAddressBytes();
byte[] mask = info.IPv4Mask.GetAddressBytes();
IPAddress directed = new(address.Select((b, i) => (byte)(b | ~mask[i])).ToArray());
if (!found.Contains(directed))
{
found.Add(directed);
}
}
}
return found;
}
/// This computer's address on the network it can reach the others on. It is /// This computer's address on the network it can reach the others on. It is
/// only for the beacon: the other end uses the address the packet came /// only for the beacon: the other end uses the address the packet came
/// from, so a wrong answer here costs nothing. /// from, so a wrong answer here costs nothing.