Skip to content

Commit

Permalink
Merge pull request #392 from BergHeisen/improve-wol
Browse files Browse the repository at this point in the history
Improve Wake on Lan Code
  • Loading branch information
Maassoft authored Aug 11, 2024
2 parents 9e8e77d + 42f6b33 commit 4d2ca8a
Showing 1 changed file with 36 additions and 63 deletions.
99 changes: 36 additions & 63 deletions Shared/Services/WolService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ColorControl.Shared.Common;
using NLog;
using NStandard;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
Expand All @@ -14,7 +15,7 @@ public class WolService

private const string ArgumentExceptionInvalidMacAddressLength = "Invalid MAC address length.";
private const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
private const int DefaultWolPort = 9;
private const int DefaultWolPort = 0;

private readonly WinApiService _winApiService;
private readonly RpcClientService _rpcService;
Expand All @@ -35,12 +36,19 @@ public bool SendWol(string macAddress, string ipAddress = null)
return true;
}

// If RPC faield, execute local WOL anyway
// If RPC failed, execute local WOL anyway
}

return WakeFunctionToAllNics(macAddress, ipAddress);
}

private bool IsViableWOLInterface(NetworkInterface ni) {
return ni.NetworkInterfaceType != NetworkInterfaceType.Loopback
&& !ni.Description.Contains("Hyper-V")
&& ni.SupportsMulticast
&& ni.GetIPProperties().GetIPv4Properties != null;
}

private bool WakeFunctionToAllNics(string macAddress, string ipAddressString)
{
var result = false;
Expand All @@ -55,51 +63,34 @@ private bool WakeFunctionToAllNics(string macAddress, string ipAddressString)

var interfaces = NetworkInterface.GetAllNetworkInterfaces();

foreach (var ni in interfaces)
{
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback/* || ni.Name.Contains("VirtualBox") || ni.Name.Contains("vEthernet") || ni.Description.Contains("Virtual")*/)
{
continue;
}
Logger.Debug($"Found network: {ni.Name} ({ni.Description}), type: {ni.NetworkInterfaceType}");
try
interfaces
.Where(IsViableWOLInterface)
.Each(ni =>
{
if (ni.SupportsMulticast && ni.GetIPProperties().GetIPv4Properties() == null)
{
continue;
}

foreach (var uip in ni.GetIPProperties().UnicastAddresses)
{
if (uip.Address.ToString().StartsWith("169.254") || uip.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
try
{
Logger.Debug($"Broadcast WOL in network: {ni.Name} ({ni.Description}), local address: {uip.Address}, destination IP-address: {ipAddressString ?? "broadcast"}");
BroadcastWol(uip.Address, IPAddress.Broadcast, data);

Logger.Debug($"Broadcast WOL in network: {ni.Name} ({ni.Description}), local address: {uip.Address}, destination IP-address: {ipAddressString ?? "broadcast"}");
var parts = uip.Address.ToString().Split(".").ToList();
parts[3] = "0";
var broadcastAddress = IPAddress.Parse(string.Join(".", parts));
BroadcastWol(uip.Address, broadcastAddress, data);

if (ipAddress != null && _winApiService.IsAdministrator())
result = true;
}
catch (Exception ex)
{
var localEP = new IPEndPoint(uip.Address, 0);

SendWolToIpAddress(uip.Address, ipAddress, data, physicalAddress);
Logger.Error($"WakeFunctionToAllNics: while sending to specific network: {ni.Name} ({ni.Description}): {ex.ToLogString()}");
}

BroadcastWol(uip.Address, IPAddress.Broadcast, data);

var parts = uip.Address.ToString().Split(".").ToList();
parts[3] = "0";
var broadcastAddress = IPAddress.Parse(string.Join(".", parts));
BroadcastWol(uip.Address, broadcastAddress, data);

result = true;
}
}
catch (Exception ex)
{
Logger.Error($"WakeFunctionToAllNics: while sending to specific network: {ni.Name} ({ni.Description}): {ex.ToLogString()}");
}
}
});
}
catch (Exception ex)
{
Expand All @@ -112,61 +103,43 @@ private bool WakeFunctionToAllNics(string macAddress, string ipAddressString)
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="password"/> is not 0 or 6.</exception>
private static byte[] GetWolPacket(byte[] macAddress, byte[] password = null)
private static byte[] GetWolPacket(byte[] macAddress)
{
if (macAddress == null)
throw new ArgumentNullException(nameof(macAddress));
if (macAddress.Length != 6)
throw new ArgumentException(ArgumentExceptionInvalidMacAddressLength);

password = password ?? new byte[0];
if (password.Length != 0 && password.Length != 6)
throw new ArgumentException(ArgumentExceptionInvalidPasswordLength);

var packet = new byte[17 * 6 + password.Length];
byte[] packet = new byte[102];

int offset, i;
for (offset = 0; offset < 6; ++offset)
packet[offset] = 0xFF;

for (offset = 6; offset < 17 * 6; offset += 6)
for (i = 0; i < 6; ++i)
packet[i + offset] = macAddress[i];
foreach (var i in Enumerable.Range(0, 6)) {
packet[i] = 0xFF;
}

if (password.Length > 0)
{
for (offset = 16 * 6 + 6; offset < 17 * 6 + password.Length; offset += 6)
for (i = 0; i < 6; ++i)
packet[i + offset] = password[i];
foreach (var i in Enumerable.Range(0, 16)) {
macAddress.CopyTo(packet, 6 + i * 6);
}

return packet;
}

private static void BroadcastWol(IPAddress localAddress, IPAddress broadCastAddress, byte[] data)
{
//var localEP = new IPEndPoint(localAddress, 0);
var udpc = new UdpClient();

using var udpc = new UdpClient(new IPEndPoint(localAddress, 0));
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
//udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);

var target = new IPEndPoint(broadCastAddress, DefaultWolPort);

udpc.Send(data, data.Length, target);
}

private static void SendWolToIpAddress(IPAddress localAddress, IPAddress remoteAddress, byte[] data, PhysicalAddress physicalAddress)
{
//var localEP = new IPEndPoint(localAddress, 0);

var netLuid = CreateTransientLocalNetEntry(remoteAddress, physicalAddress);
try
{
var udpc = new UdpClient();
using var udpc = new UdpClient(new IPEndPoint(localAddress, 0));
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);

var target = new IPEndPoint(remoteAddress, DefaultWolPort);

udpc.Send(data, data.Length, target);
}
finally
Expand Down

0 comments on commit 4d2ca8a

Please sign in to comment.