using Common.Messaging; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; using MultiTerm.Protocols.Types; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; namespace MultiTerm.Protocols.Udp; public partial class UdpProtocolSettingsViewModel : ProtocolSettingsViewModel, IUdpProtocolSettings, IRecipient { public override Types.ProtocolType ProtocolType => Types.ProtocolType.Udp; #region IUdpProtocolSettings Implementation [ObservableProperty] private string hostname = string.Empty; [ObservableProperty] private int port = 10000; #endregion /// /// A property to display the resolved IP address that the protocol connected to. /// [ObservableProperty] private string resolvedAddress = string.Empty; public UdpProtocolSettingsViewModel(IMessenger messenger) : base(messenger) { // register for messages messenger.Register(this); // initialize IP address with first ethernet adapter local IP this.Hostname = GetFirstEthernetAdaptersSubnet(); } public bool AreValid() { if (String.IsNullOrEmpty(this.Hostname)) { this.messenger.Send(new ProtocolSettingsInvalidMessage(nameof(this.Hostname), "Null or empty")); return false; } if (this.Port < IPEndPoint.MinPort && this.Port > IPEndPoint.MaxPort) { this.messenger.Send(new ProtocolSettingsInvalidMessage(nameof(this.Port), "Out of range")); return false; } // try parse to IP address if (IPAddress.TryParse(this.Hostname, out _)) { return true; } // else try to resolve hostname else { IPHostEntry host; try { host = Dns.GetHostEntry(this.Hostname); } catch (ArgumentOutOfRangeException) { this.messenger.Send(new ProtocolSettingsInvalidMessage(nameof(this.Hostname), "Length is greater than 255 characters")); return false; } catch (SocketException) { this.messenger.Send(new ProtocolSettingsInvalidMessage(nameof(this.Hostname), "Error encountered when resolving hostname")); return false; } catch (ArgumentException) { this.messenger.Send(new ProtocolSettingsInvalidMessage(nameof(this.Hostname), "Invalid IP address")); return false; } // host not null and found at least one address => success return host != null && host.AddressList.Length > 0; } } /// /// Sets the proprty to the resolved address from the message. /// /// void IRecipient.Receive(UdpConnectedMessage message) { this.ResolvedAddress = message.ResolvedAddress.ToString(); } /// /// Tries to retrieve the first ethernet adapters subnet address. /// /// string of of the first ethernet adapters subnet address, or if not found private static string GetFirstEthernetAdaptersSubnet() { // iterate through all network interfaces NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); foreach (var adapter in interfaces) { // return first found ipv4 adapter subnet address if (adapter.OperationalStatus == OperationalStatus.Up) { try { var unicastAddresses = adapter.GetIPProperties().UnicastAddresses; foreach (var unicastAddress in unicastAddresses) { // only interested in IPv4 if (unicastAddress.Address.AddressFamily != AddressFamily.InterNetwork) continue; // Ignore loopback addresses (e.g., 127.0.0.1) if (IPAddress.IsLoopback(unicastAddress.Address)) continue; // split and only return first three parts of the IPv4 address var splitIpv4 = unicastAddress.Address.ToString().Split('.'); return $"{splitIpv4[0]}.{splitIpv4[1]}.{splitIpv4[2]}."; } } catch { } } } return string.Empty; } }