diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj
index 9f482d1..5264086 100644
--- a/ColorControl/ColorControl.csproj
+++ b/ColorControl/ColorControl.csproj
@@ -27,7 +27,7 @@
ColorControl
Maassoft
0
- 1.5.3.0
+ 1.5.4.0
false
true
true
diff --git a/ColorControl/Properties/AssemblyInfo.cs b/ColorControl/Properties/AssemblyInfo.cs
index fe2ca0f..2a69284 100644
--- a/ColorControl/Properties/AssemblyInfo.cs
+++ b/ColorControl/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.5.3.0")]
-[assembly: AssemblyFileVersion("1.5.3.0")]
+[assembly: AssemblyVersion("1.5.4.0")]
+[assembly: AssemblyFileVersion("1.5.4.0")]
diff --git a/ColorControl/WOL.cs b/ColorControl/WOL.cs
index 97ae727..97234be 100644
--- a/ColorControl/WOL.cs
+++ b/ColorControl/WOL.cs
@@ -1,12 +1,10 @@
using NLog;
using System;
-using System.Globalization;
using PacketDotNet;
using System.Net.NetworkInformation;
using SharpPcap;
-using System.Diagnostics;
using SharpPcap.Npcap;
-using System.Linq;
+using System.Net;
namespace ColorControl
{
@@ -14,8 +12,12 @@ class WOL
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
- //You need SharpPcap for this to work
+ public static void WakeFunction2(string macAddress)
+ {
+ //PhysicalAddress.Parse(macAddress).SendWol();
+ }
+ //You need SharpPcap for this to work
public static void WakeFunction(string macAddress)
{
/* Retrieve the device list */
@@ -40,7 +42,14 @@ public static void WakeFunction(string macAddress)
// }
//}
- Logger.Debug("Opening network device: " + device.Name);
+ if (device is NpcapDevice npcapDevice)
+ {
+ Logger.Debug($"Opening network device (NpcapDevice): FriendlyName: {npcapDevice.Interface.FriendlyName}, Description: {npcapDevice.Interface.Description}");
+ }
+ else
+ {
+ Logger.Debug($"Opening network device (NOT A NpcapDevice!): {device.Name}, Description: {device.Description}");
+ }
//Open the device
device.Open();
diff --git a/WakeOnLan/ArpRequest.cs b/WakeOnLan/ArpRequest.cs
new file mode 100644
index 0000000..7a1aa59
--- /dev/null
+++ b/WakeOnLan/ArpRequest.cs
@@ -0,0 +1,39 @@
+using System.ComponentModel;
+using System.Net.NetworkInformation;
+using System.Threading.Tasks;
+
+namespace System.Net
+{
+ /// Stellt Methoden für das Senden von Anfragen über das ARP-Protokoll bereit.
+ public static class ArpRequest
+ {
+ ///
+ /// Sendet eine Anfrage über das ARP-Protokoll, um eine IP-Adresse in die Physikalische Adresse aufzulösen. Falls sich die physikalische Adresse bereits im Cache des Hosts befindet, wird diese zurückgegeben.
+ ///
+ /// Destination .
+ /// Eine ArpRequestResult-Instanz, welche die Ergebnisse der Anfrage enthält.
+ public static ArpRequestResult Send(IPAddress destination)
+ {
+ if (destination == null)
+ throw new ArgumentNullException(nameof(destination));
+
+ int destIp = BitConverter.ToInt32(destination.GetAddressBytes(), 0);
+
+ var addr = new byte[6];
+ var len = addr.Length;
+
+ var res = NativeMethods.SendARP(destIp, 0, addr, ref len);
+
+ if (res == 0)
+ return new ArpRequestResult(new PhysicalAddress(addr));
+ return new ArpRequestResult(new Win32Exception(res));
+ }
+
+ ///
+ /// Sendet eine Anfrage über das ARP-Protokoll, um eine IP-Adresse in die Physikalische Adresse aufzulösen. Falls sich die physikalische Adresse bereits im Cache des Hosts befindet, wird diese zurückgegeben.
+ ///
+ /// Destination .
+ /// Ein asynchroner Task, welcher einen ARP-Request sendet.
+ public static Task SendAsync(IPAddress destination) => Task.Run(() => Send(destination));
+ }
+}
diff --git a/WakeOnLan/ArpRequestResult.cs b/WakeOnLan/ArpRequestResult.cs
new file mode 100644
index 0000000..ae5ffd1
--- /dev/null
+++ b/WakeOnLan/ArpRequestResult.cs
@@ -0,0 +1,57 @@
+using System.Net.NetworkInformation;
+using System.Text;
+
+namespace System.Net
+{
+ // TODO: rethink the whole exception thing
+
+ ///
+ /// Enthält die Rückgabewerte der ArpRequest.Send-Funktion.
+ ///
+ public class ArpRequestResult
+ {
+ /// Falls Fehler bei der Protokollanfrage auftreten, werden diese in dieser Eigenschaft abgelegt. Andernfalls null.
+ public Exception Exception { get; }
+
+ /// Die aufgelöste physikalische Adresse.
+ public PhysicalAddress Address { get; }
+
+ /// Erstellt eine neue ArpRequestResult-Instanz
+ /// Die physikalische Adresse
+ public ArpRequestResult(PhysicalAddress address)
+ {
+ this.Exception = null;
+ Address = address;
+ }
+
+ /// Erstellt eine neue ArpRequestResult-Instanz
+ /// Der aufgetretene Fehler
+ public ArpRequestResult(Exception exception)
+ {
+ this.Exception = exception;
+ Address = null;
+ }
+
+ /// Konvertiert ARP-Rückgabewerte in eine Zeichenfolge.
+ public override string ToString()
+ {
+ var sb = new StringBuilder();
+ if (Address == null)
+ sb.Append("no address");
+ else
+ {
+ sb.Append("address: ");
+ sb.Append(Address);
+ }
+ sb.Append(", ");
+ if (Exception == null)
+ sb.Append("no exception");
+ else
+ {
+ sb.Append("exception: ");
+ sb.Append(Exception.Message);
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/WakeOnLan/GlobalSuppressions.cs b/WakeOnLan/GlobalSuppressions.cs
new file mode 100644
index 0000000..5652ddc
--- /dev/null
+++ b/WakeOnLan/GlobalSuppressions.cs
@@ -0,0 +1,62 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+//
+// To add a suppression to this file, right-click the message in the
+// Code Analysis results, point to "Suppress Message", and click
+// "In Suppression File".
+// You do not need to add suppressions to this file manually.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Int32)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[],System.Int32)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[],System.Int32,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[])")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[],System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Int32)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[],System.Int32)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[],System.Int32,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[])")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[],System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Byte[])")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Byte[],System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Byte[])")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Byte[],System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Lan")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Scope = "member", Target = "System.Net.Topology.INetMask.#GetMaskBytes()")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_Equality(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_Inequality(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_BitwiseAnd(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Scope = "type", Target = "System.Net.Topology.SiblingOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "type", Target = "System.Net.SendWol")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_BitwiseOr(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#BitwiseOr(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint,System.Net.SecureOnPassword)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cidr", Scope = "member", Target = "System.Net.Topology.INetMask.#Cidr")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "m", Scope = "member", Target = "System.Net.Topology.NetMask.#.ctor(System.Byte,System.Byte,System.Byte,System.Byte)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#BitwiseAnd(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "cidr", Scope = "member", Target = "System.Net.Topology.NetMask.#.ctor(System.Int32)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "cidr", Scope = "member", Target = "System.Net.Topology.NetMask.#.ctor(System.Byte)")]
diff --git a/WakeOnLan/IPAddressExtensions.cs b/WakeOnLan/IPAddressExtensions.cs
new file mode 100644
index 0000000..72b049b
--- /dev/null
+++ b/WakeOnLan/IPAddressExtensions.cs
@@ -0,0 +1,166 @@
+using System.Threading.Tasks;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+
+namespace System.Net
+{
+ /// Provides extension methods for sending Wake On LAN signals (magic packets) to a specific .
+ public static class IPAddressExtensions
+ {
+ private const int DefaultWolPort = 7;
+ #region Wol
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The port to send the packet to.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void SendWol(this IPAddress target, byte[] macAddress, int port) => target.SendWol(macAddress, port, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The port to send the packet to.
+ /// The SecureOn password of the client.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void SendWol(this IPAddress target, byte[] macAddress, int port, SecureOnPassword password)
+ {
+ Net.MagicPacket.Send(new IPEndPoint(target, port), macAddress, password);
+ }
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void SendWol(this IPAddress target, byte[] macAddress) => target.SendWol(macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void SendWol(this IPAddress target, byte[] macAddress, SecureOnPassword password)
+ {
+ Net.MagicPacket.Send(new IPEndPoint(target, DefaultWolPort), macAddress, password);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The length of the is not 6.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void SendWol(this IPAddress target, PhysicalAddress macAddress) => target.SendWol(macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// The length of the is not 6.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void SendWol(this IPAddress target, PhysicalAddress macAddress, SecureOnPassword password)
+ {
+ Net.MagicPacket.Send(new IPEndPoint(target, DefaultWolPort), macAddress, password);
+ }
+
+ #endregion
+ #region ARP
+
+ ///
+ /// Sendet eine Anfrage über das ARP-Protokoll, um eine IP-Adresse in die Physikalische Adresse aufzulösen. Falls sich die physikalische Adresse bereits im Cache des Hosts befindet, wird diese zurückgegeben.
+ ///
+ /// Destination .
+ /// Eine ArpRequestResult-Instanz, welche die Ergebnisse der Anfrage enthält.
+ public static ArpRequestResult SendArpRequest(this IPAddress destination) => ArpRequest.Send(destination);
+
+ #endregion
+ #region TAP
+
+ #region Wol
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The port to send the packet to.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPAddress target, byte[] macAddress, int port) => target.SendWolAsync(macAddress, port, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The port to send the packet to.
+ /// The SecureOn password of the client.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPAddress target, byte[] macAddress, int port, SecureOnPassword password)
+ {
+ return Net.MagicPacket.SendAsync(new IPEndPoint(target, port), macAddress, password);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The length of the array is not 6.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPAddress target, byte[] macAddress) => target.SendWolAsync(macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// The length of the array is not 6.
+ /// is null.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPAddress target, byte[] macAddress, SecureOnPassword password)
+ {
+ return Net.MagicPacket.SendAsync(new IPEndPoint(target, DefaultWolPort), macAddress, password);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The length of the is not 6.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPAddress target, PhysicalAddress macAddress) => target.SendWolAsync(macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// The length of the is not 6.
+ /// is null.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPAddress target, PhysicalAddress macAddress, SecureOnPassword password)
+ {
+ return Net.MagicPacket.SendAsync(new IPEndPoint(target, DefaultWolPort), macAddress, password);
+ }
+
+ #endregion
+
+ #region ARP
+
+ /// Sends a request via ARP to resolve an IP address to aphysical address. If the physical address is already cached, it's cached value is returned.
+ /// Destination .
+ /// An asynchronous which sends an ARP request.
+ public static Task SendArpRequestAsync(this IPAddress destination) => ArpRequest.SendAsync(destination);
+
+ #endregion
+
+ #endregion
+ }
+}
diff --git a/WakeOnLan/IPEndPointExtensions.cs b/WakeOnLan/IPEndPointExtensions.cs
new file mode 100644
index 0000000..5c5ad52
--- /dev/null
+++ b/WakeOnLan/IPEndPointExtensions.cs
@@ -0,0 +1,101 @@
+using System.Threading.Tasks;
+using System.Net.NetworkInformation;
+
+namespace System.Net
+{
+ /// Provides extension methods for sending Wake On LAN signals (magic packets) to a specific .
+ public static class IPEndPointExtensions
+ {
+ #region Wol
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The length of the array macAddress is not 6.
+ /// is null.
+ public static void SendWol(this IPEndPoint target, byte[] macAddress)
+ {
+ Net.MagicPacket.Send(target, macAddress);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// is null.
+ public static void SendWol(this IPEndPoint target, PhysicalAddress macAddress)
+ {
+ Net.MagicPacket.Send(target, macAddress);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// The length of the array macAddress is not 6.
+ /// is null.
+ public static void SendWol(this IPEndPoint target, byte[] macAddress, SecureOnPassword password)
+ {
+ Net.MagicPacket.Send(target, macAddress, password);
+ }
+
+ ///
+ /// Sendet ein Wake-On-LAN-Signal an einen Client.
+ ///
+ /// Der Ziel-IPEndPoint.
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// is null.
+ public static void SendWol(this IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
+ {
+ Net.MagicPacket.Send(target, macAddress, password);
+ }
+
+ #endregion
+ #region TAP
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The length of the array macAddress is not 6.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPEndPoint target, byte[] macAddress)
+ {
+ return Net.MagicPacket.SendAsync(target, macAddress);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPEndPoint target, PhysicalAddress macAddress)
+ {
+ return Net.MagicPacket.SendAsync(target, macAddress);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// The length of the array macAddress is not 6.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPEndPoint target, byte[] macAddress, SecureOnPassword password)
+ {
+ return Net.MagicPacket.SendAsync(target, macAddress, password);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the client.
+ /// The SecureOn password of the client.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
+ {
+ return Net.MagicPacket.SendAsync(target, macAddress, password);
+ }
+ #endregion
+ }
+}
diff --git a/WakeOnLan/Localization.cs b/WakeOnLan/Localization.cs
new file mode 100644
index 0000000..405c9d3
--- /dev/null
+++ b/WakeOnLan/Localization.cs
@@ -0,0 +1,12 @@
+#define GERMAN
+
+namespace System.Net
+{
+ internal static class Localization
+ {
+ public const string ArgumentExceptionInvalidMacAddressLength = "Invalid MAC address length.";
+ public const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
+
+ public const string ArgumentExceptionIsNotAValidMadAddress = " is not a valid MAC address.";
+ }
+}
diff --git a/WakeOnLan/MagicPacket.cs b/WakeOnLan/MagicPacket.cs
new file mode 100644
index 0000000..15aa6b7
--- /dev/null
+++ b/WakeOnLan/MagicPacket.cs
@@ -0,0 +1,171 @@
+using System.Threading.Tasks;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+
+namespace System.Net
+{
+ /// Provides methods for sending Wake On LAN signals (magic packets).
+ public static class MagicPacket
+ {
+ #region Wol
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// target is null.
+ /// is null.
+ /// The length of the array macAddress is not 6.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void Send(IPEndPoint target, byte[] macAddress) => Send(target, macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// The SecureOn password of the client.
+ /// is null.
+ /// is null.
+ /// The length of the array is not 6.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void Send(IPEndPoint target, byte[] macAddress, SecureOnPassword password)
+ {
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+
+ byte[] passwordBuffer = password?.GetPasswordBytes();
+ byte[] packet = GetWolPacket(macAddress, passwordBuffer);
+ SendPacket(target, packet);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void Send(IPEndPoint target, PhysicalAddress macAddress) => Send(target, macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// The SecureOn password of the client.
+ /// is null.
+ /// An error occurred when accessing the socket. See Remarks section of for more information.
+ public static void Send(IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
+ {
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+
+ byte[] passwordBuffer = password?.GetPasswordBytes();
+ byte[] packet = GetWolPacket(macAddress.GetAddressBytes(), passwordBuffer);
+ SendPacket(target, packet);
+ }
+
+ private static void SendPacket(IPEndPoint target, byte[] packet)
+ {
+ using (var cl = new UdpClient())
+ cl.Send(packet, packet.Length, target);
+ }
+
+ #endregion
+ #region TAP
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// is null.
+ /// is null.
+ /// The length of the array is not 6.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendAsync(IPEndPoint target, byte[] macAddress) => SendAsync(target, macAddress);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// The SecureOn password of the client.
+ /// is null.
+ /// is null.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendAsync(IPEndPoint target, byte[] macAddress, SecureOnPassword password)
+ {
+ if (target == null)
+ throw new ArgumentNullException(nameof(target));
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+
+ var passwordBuffer = password?.GetPasswordBytes();
+ var packet = GetWolPacket(macAddress, passwordBuffer);
+ return SendPacketAsync(target, packet);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// is null.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendAsync(IPEndPoint target, PhysicalAddress macAddress) => SendAsync(target, macAddress, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a client.
+ /// Destination .
+ /// The MAC address of the designated client.
+ /// The SecureOn password of the client.
+ /// is null.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendAsync(IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
+ {
+ if (target == null)
+ throw new ArgumentNullException(nameof(target));
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+
+ var passwordBuffer = password?.GetPasswordBytes();
+ var p = GetWolPacket(macAddress.GetAddressBytes(), passwordBuffer);
+ return SendPacketAsync(target, p);
+ }
+
+ private static Task SendPacketAsync(IPEndPoint target, byte[] packet)
+ {
+ var cl = new UdpClient();
+ return cl.SendAsync(packet, packet.Length, target).ContinueWith((Task t) => cl.Close());
+ }
+
+ #endregion
+ #region internal
+
+ /// is null.
+ /// The length of the array is not 6.
+ /// The length of the array is not 0 or 6.
+ private static byte[] GetWolPacket(byte[] macAddress, byte[] password)
+ {
+ if (macAddress == null)
+ throw new ArgumentNullException(nameof(macAddress));
+ if (macAddress.Length != 6)
+ throw new ArgumentException(Localization.ArgumentExceptionInvalidMacAddressLength);
+
+ password = password ?? new byte[0];
+ if (password.Length != 0 && password.Length != 6)
+ throw new ArgumentException(Localization.ArgumentExceptionInvalidPasswordLength);
+
+ var packet = new byte[17 * 6 + password.Length];
+
+ 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];
+
+ 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];
+ }
+ return packet;
+ }
+
+ #endregion
+ }
+}
diff --git a/WakeOnLan/NativeMethods.cs b/WakeOnLan/NativeMethods.cs
new file mode 100644
index 0000000..73c4f88
--- /dev/null
+++ b/WakeOnLan/NativeMethods.cs
@@ -0,0 +1,14 @@
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace System.Net
+{
+ internal static class NativeMethods
+ {
+ private const string IphlpApi = "iphlpapi.dll";
+
+ [DllImport(IphlpApi, ExactSpelling = true)]
+ [SecurityCritical]
+ internal static extern int SendARP(int destinationIp, int sourceIp, byte[] macAddress, ref int physicalAddrLength);
+ }
+}
diff --git a/WakeOnLan/PhysicalAddressExtensions.cs b/WakeOnLan/PhysicalAddressExtensions.cs
new file mode 100644
index 0000000..4a8ac93
--- /dev/null
+++ b/WakeOnLan/PhysicalAddressExtensions.cs
@@ -0,0 +1,148 @@
+using System.Threading.Tasks;
+using System.Net.NetworkInformation;
+
+namespace System.Net
+{
+ /// Provides extension methods for sending Wake On LAN signals (magic packets) using a specific .
+ public static class PhysicalAddressExtensions
+ {
+ #region Wol
+
+ /// Sends a Wake On LAN signal (magic packet) to the broadcast IP address with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// is null.
+ public static void SendWol(this PhysicalAddress address) => address.SendWol(IPAddress.Broadcast, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// is null.
+ public static void SendWol(this PhysicalAddress address, IPAddress target) => address.SendWol(target, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// The SecureOn password of the client.
+ /// is null.
+ public static void SendWol(this PhysicalAddress address, IPAddress target, SecureOnPassword password)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ target.SendWol(address.GetAddressBytes(), password);
+ }
+
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// is null.
+ public static void SendWol(this PhysicalAddress address, IPEndPoint target) => address.SendWol(target, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// The SecureOn password of the client.
+ /// is null.
+ public static void SendWol(this PhysicalAddress address, IPEndPoint target, SecureOnPassword password)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ target.SendWol(address.GetAddressBytes(), password);
+ }
+
+ #endregion
+ #region TAP
+
+ /// Sends a Wake On LAN signal (magic packet) to the broadcast IP address with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ /// is null.
+ public static Task SendWolAsync(this PhysicalAddress address)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ return IPAddress.Broadcast.SendWolAsync(address.GetAddressBytes());
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this PhysicalAddress address, IPAddress target) => address.SendWolAsync(target, null);
+
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// The SecureOn password of the client.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this PhysicalAddress address, IPAddress target, SecureOnPassword password)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ return target.SendWolAsync(address.GetAddressBytes(), password);
+ }
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this PhysicalAddress address, IPEndPoint target) => address.SendWolAsync(target, null);
+
+ /// Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.
+ /// The instance of the physical address that should be used in the magic packet.
+ /// Destination .
+ /// The SecureOn password of the client.
+ /// is null.
+ /// An asynchronous which sends a Wake On LAN signal (magic packet) to a client.
+ public static Task SendWolAsync(this PhysicalAddress address, IPEndPoint target, SecureOnPassword password)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ return target.SendWolAsync(address.GetAddressBytes(), password);
+ }
+
+ #endregion
+ #region common
+
+ /// Gets the type () of the .
+ /// The address.
+ /// is null.
+ /// The of the physical addess (MAC address).
+ public static PhysicalAddressType GetAddressType(this PhysicalAddress address)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ var bytes = address.GetAddressBytes();
+ if (bytes == null || bytes.Length < 1)
+ throw new ArgumentException($"Invalid {nameof(address)}.");
+ return (bytes[0] & 0x1) == 0 ? PhysicalAddressType.Unicast : PhysicalAddressType.Multicast;
+ }
+
+ /// Gets the administrator () of the .
+ /// The address.
+ /// is null.
+ /// The of the physical addess (MAC address).
+ public static PhysicalAddressAdministrator GetAddressAdministrator(this PhysicalAddress address)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+
+ var bytes = address.GetAddressBytes();
+ if (bytes == null || bytes.Length < 1)
+ throw new ArgumentException($"Invalid {nameof(address)}.");
+ return (bytes[0] & 0x2) == 0 ? PhysicalAddressAdministrator.Global : PhysicalAddressAdministrator.Local;
+ }
+
+ #endregion
+ }
+}
diff --git a/WakeOnLan/PhysicalAddressProperties.cs b/WakeOnLan/PhysicalAddressProperties.cs
new file mode 100644
index 0000000..837f5f7
--- /dev/null
+++ b/WakeOnLan/PhysicalAddressProperties.cs
@@ -0,0 +1,34 @@
+namespace System.Net
+{
+ ///
+ /// Der Administrator der physikalischen Adresse gibt an, ob die Adresse globally unique oder local administrated ist.
+ ///
+ public enum PhysicalAddressAdministrator
+ {
+ ///
+ /// Die Adresse ist global einzigartig (nach der OUI).
+ ///
+ Global,
+
+ ///
+ /// Die Adresse ist lokal administriert.
+ ///
+ Local
+ }
+
+ ///
+ /// Der Typ der physikalischen Adresse gibt an, ob es um eine UNicast oder Multicast-Adresse handelt.
+ ///
+ public enum PhysicalAddressType
+ {
+ ///
+ /// Bezeichnet eine Unicast-Adresse.
+ ///
+ Unicast,
+
+ ///
+ /// Bezeichnet eine Multicast-Adresse
+ ///
+ Multicast
+ }
+}
diff --git a/WakeOnLan/Properties/AssemblyInfo.cs b/WakeOnLan/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..97813fb
--- /dev/null
+++ b/WakeOnLan/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.CompilerServices;
+using System;
+
+[assembly: InternalsVisibleTo("WakeOnLan.Tests")]
diff --git a/WakeOnLan/SecureOnPassword.cs b/WakeOnLan/SecureOnPassword.cs
new file mode 100644
index 0000000..d159dab
--- /dev/null
+++ b/WakeOnLan/SecureOnPassword.cs
@@ -0,0 +1,95 @@
+namespace System.Net
+{
+ /// Provides a SecureOn password.
+ [Serializable]
+ public sealed class SecureOnPassword
+ {
+ private readonly byte[] _password;
+
+ /// Initializes a new instance of with the given password.
+ /// The password as array.
+ /// is null.
+ /// The length of the array password is not 6.
+ public SecureOnPassword(byte[] password)
+ {
+ if (password == null)
+ throw new ArgumentNullException(nameof(password));
+ if (password.Length != 6)
+ throw new ArgumentException(Localization.ArgumentExceptionInvalidPasswordLength);
+ _password = password;
+ }
+
+ /// Gets the buffer of the password.
+ public byte[] GetPasswordBytes()
+ {
+ if (_password == null)
+ return null;
+ var buffer = new byte[_password.Length];
+ Array.Copy(_password, buffer, 0);
+ return buffer;
+ }
+
+ /// Initializes a new instance of with the given password.
+ /// The password as .
+ /// is null.
+ /// Uses as encoding.
+ public SecureOnPassword(string password)
+ : this(password, Text.Encoding.Default)
+ { }
+
+
+ /// Initializes a new instance of with the given password.
+ /// The password as .
+ /// The instance to use for the password.
+ /// is null.
+ /// is null.
+ /// The array wich is created using the password has more elements than 6.
+ public SecureOnPassword(string password, Text.Encoding encoding)
+ {
+ if (password == null)
+ throw new ArgumentNullException(nameof(password));
+ if (encoding == null)
+ throw new ArgumentNullException(nameof(encoding));
+
+ if (string.IsNullOrEmpty(password))
+ _password = new byte[6];
+
+ var bytes = encoding.GetBytes(password);
+ if (bytes.Length > 6)
+ throw new ArgumentException(Localization.ArgumentExceptionInvalidPasswordLength);
+
+ _password = new byte[6];
+ for (int i = 0; i < bytes.Length; i++)
+ _password[i] = bytes[i];
+ if (bytes.Length < 6)
+ {
+ for (int i = bytes.Length - 1; i < 6; i++)
+ _password[i] = 0x00;
+ }
+ }
+
+ /// Converts the to dash notation.
+ /// A representing the as dash notation.
+ public override string ToString() => ToString("X2");
+
+ /// Converts the to dash notation.
+ /// A representing the as dash notation.
+ private string ToString(string format)
+ {
+ var f = new string[6];
+ for (int i = 0; i < f.Length; i++)
+ f[i] = _password[i].ToString(format);
+ return string.Join("-", f);
+ }
+
+ /// Converts the to dash notation.
+ /// A representing the as dash notation.
+ public string ToString(IFormatProvider format)
+ {
+ var f = new string[6];
+ for (int i = 0; i < f.Length; i++)
+ f[i] = _password[i].ToString(format);
+ return string.Join("-", f);
+ }
+ }
+}
diff --git a/WakeOnLan/Topology/ByteArrayExtensions.cs b/WakeOnLan/Topology/ByteArrayExtensions.cs
new file mode 100644
index 0000000..5f33979
--- /dev/null
+++ b/WakeOnLan/Topology/ByteArrayExtensions.cs
@@ -0,0 +1,287 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace System.Net.Topology
+{
+ internal static class ByteArrayExtensions
+ {
+ internal static IEnumerable ToBitStream(this byte[] bytes, bool fromLeft)
+ {
+ if (bytes == null)
+ throw new ArgumentNullException(nameof(bytes));
+
+ if (fromLeft)
+ {
+ for (int i = 0; i < bytes.Length; ++i)
+ {
+ byte tmp = bytes[i].ReverseBits();
+ for (int j = 0; j < 8; ++j)
+ {
+ yield return (tmp & 1) == 1;
+ tmp >>= 1;
+ }
+ }
+ }
+ else
+ {
+ for (int i = bytes.Length - 1; i >= 0; --i)
+ {
+ byte tmp = bytes[i];
+ for (int j = 0; j < 8; ++j)
+ {
+ yield return (tmp & 1) == 1;
+ tmp >>= 1;
+ }
+ }
+ }
+ }
+
+ private static int CountFromSide(byte[] bits, bool value, bool fromleft)
+ {
+ int counter = 0;
+ var str = bits.ToBitStream(fromleft);
+ foreach (var bit in str)
+ {
+ if (bit == value)
+ ++counter;
+ else return counter;
+ }
+ return counter;
+ }
+
+ internal static int CountFromLeft(this byte[] bits, bool value)
+ {
+ if (bits == null)
+ throw new ArgumentNullException(nameof(bits));
+ return CountFromSide(bits, value, true);
+ }
+
+ internal static int CountFromRight(this byte[] bits, bool value)
+ {
+ if (bits == null)
+ throw new ArgumentNullException(nameof(bits));
+ return CountFromSide(bits, value, false);
+ }
+
+ internal static string ToBinaryString(this byte[] bits, char separator)
+ {
+ if (bits == null)
+ throw new ArgumentNullException(nameof(bits));
+
+ const int radix = 2;
+ const int padding = 8;
+ const char paddingChar = '0';
+
+ var sb = new StringBuilder();
+ sb.Append(Convert.ToString(bits[0], radix).PadLeft(padding, paddingChar)).Append(separator);
+ sb.Append(Convert.ToString(bits[1], radix).PadLeft(padding, paddingChar)).Append(separator);
+ sb.Append(Convert.ToString(bits[2], radix).PadLeft(padding, paddingChar)).Append(separator);
+ sb.Append(Convert.ToString(bits[3], radix).PadLeft(padding, paddingChar));
+ return sb.ToString();
+ }
+
+ internal static string ToBinaryString(this byte[] bits)
+ {
+ if (bits == null)
+ throw new ArgumentNullException(nameof(bits));
+
+ const int radix = 2;
+ const int padding = 8;
+ const char paddingChar = '0';
+
+ var sb = new StringBuilder();
+ sb.Append(Convert.ToString(bits[0], radix).PadLeft(padding, paddingChar));
+ sb.Append(Convert.ToString(bits[1], radix).PadLeft(padding, paddingChar));
+ sb.Append(Convert.ToString(bits[2], radix).PadLeft(padding, paddingChar));
+ sb.Append(Convert.ToString(bits[3], radix).PadLeft(padding, paddingChar));
+ return sb.ToString();
+ }
+
+ internal static bool RepresentsValidNetMask(this byte[] bits)
+ {
+ if (bits == null)
+ throw new ArgumentNullException(nameof(bits));
+
+ int fromLeft = bits.CountFromLeft(true);
+ int fromRight = bits.CountFromRight(false);
+
+ // Sum of all counted indexes schloud be equal the whole length
+ return (fromLeft + fromRight) == (8 * NetMask.MaskLength);
+ }
+
+ internal static byte[] And(this byte[] b1, byte[] b2)
+ {
+ if (b1 == null)
+ throw new ArgumentNullException(nameof(b1));
+ if (b2 == null)
+ throw new ArgumentNullException(nameof(b2));
+
+ if (b1.Length == 1 && b2.Length == 1)
+ {
+ int ib1 = b1[0];
+ int ib2 = b2[0];
+ return new[] { (byte)(ib1 & ib2) };
+ }
+ if (b1.Length == 2 && b2.Length == 2)
+ {
+ var sb1 = BitConverter.ToInt16(b1, 0);
+ var sb2 = BitConverter.ToInt16(b2, 0);
+ return BitConverter.GetBytes((short)(sb1 & sb2));
+ }
+ if (b1.Length == 4 && b2.Length == 4)
+ {
+ var ib1 = BitConverter.ToInt32(b1, 0);
+ var ib2 = BitConverter.ToInt32(b2, 0);
+ return BitConverter.GetBytes(ib1 & ib2);
+ }
+ if (b1.Length != b2.Length)
+ {
+ // Or maybe throw exception?
+
+ int maxIndex = Math.Max(b1.Length, b2.Length);
+ byte[] biggerArray = b1.Length > b2.Length ? b1 : b2;
+ byte[] smallerArray = b1.Length <= b2.Length ? b1 : b2;
+
+ var paddedArray = new byte[maxIndex];
+
+ Buffer.BlockCopy(smallerArray, 0, paddedArray, 0, smallerArray.Length);
+
+ Debug.Assert(biggerArray.Length == paddedArray.Length);
+
+ return And(biggerArray, paddedArray);
+ }
+
+ var targetIndex = b1.Length;
+ var andedArray = new byte[targetIndex];
+ Buffer.BlockCopy(b1, 0, andedArray, 0, andedArray.Length);
+
+ for (int i = 0; i < targetIndex; ++i)
+ andedArray[i] &= b2[i];
+
+ return andedArray;
+ }
+
+ internal static byte[] Or(this byte[] b1, byte[] b2)
+ {
+ if (b1 == null)
+ throw new ArgumentNullException(nameof(b1));
+ if (b2 == null)
+ throw new ArgumentNullException(nameof(b2));
+
+ if (b1.Length == 1 && b2.Length == 1)
+ {
+ int ib1 = b1[0];
+ int ib2 = b2[0];
+ return new[] { (byte)(ib1 | ib2) };
+ }
+ if (b1.Length == 2 && b2.Length == 2)
+ {
+ var sb1 = BitConverter.ToInt16(b1, 0);
+ var sb2 = BitConverter.ToInt16(b2, 0);
+ return BitConverter.GetBytes((short)(sb1 | sb2));
+ }
+ if (b1.Length == 4 && b2.Length == 4)
+ {
+ var ib1 = BitConverter.ToInt32(b1, 0);
+ var ib2 = BitConverter.ToInt32(b2, 0);
+ return BitConverter.GetBytes(ib1 | ib2);
+ }
+ if (b1.Length != b2.Length)
+ {
+ // Or maybe throw exception?
+
+ int maxIndex = Math.Max(b1.Length, b2.Length);
+ byte[] biggerArray = b1.Length > b2.Length ? b1 : b2;
+ byte[] smallerArray = b1.Length <= b2.Length ? b1 : b2;
+
+ var paddedArray = new byte[maxIndex];
+
+ Buffer.BlockCopy(smallerArray, 0, paddedArray, 0, smallerArray.Length);
+
+ Debug.Assert(biggerArray.Length == paddedArray.Length);
+
+ return Or(biggerArray, paddedArray);
+ }
+
+ var targetIndex = b1.Length;
+ var oredArray = new byte[targetIndex];
+ Buffer.BlockCopy(b1, 0, oredArray, 0, oredArray.Length);
+
+ for (int i = 0; i < targetIndex; ++i)
+ oredArray[i] |= b2[i];
+
+ return oredArray;
+ }
+
+ internal static byte[] Xor(this byte[] b1, byte[] b2)
+ {
+ if (b1 == null)
+ throw new ArgumentNullException(nameof(b1));
+ if (b2 == null)
+ throw new ArgumentNullException(nameof(b2));
+
+ // TODO: Testing
+
+ if (b1.Length == 1 && b2.Length == 1)
+ {
+ int ib1 = b1[0];
+ int ib2 = b2[0];
+ return new[] { (byte)(ib1 ^ ib2) };
+ }
+ if (b1.Length == 2 && b2.Length == 2)
+ {
+ var sb1 = BitConverter.ToInt16(b1, 0);
+ var sb2 = BitConverter.ToInt16(b2, 0);
+ return BitConverter.GetBytes((short)(sb1 ^ sb2));
+ }
+ if (b1.Length == 4 && b2.Length == 4)
+ {
+ var ib1 = BitConverter.ToInt32(b1, 0);
+ var ib2 = BitConverter.ToInt32(b2, 0);
+ return BitConverter.GetBytes(ib1 ^ ib2);
+ }
+ if (b1.Length != b2.Length)
+ {
+ // Or maybe throw exception?
+
+ int maxIndex = Math.Max(b1.Length, b2.Length);
+ byte[] biggerArray = b1.Length > b2.Length ? b1 : b2;
+ byte[] smallerArray = b1.Length <= b2.Length ? b1 : b2;
+
+ var paddedArray = new byte[maxIndex];
+
+ Buffer.BlockCopy(smallerArray, 0, paddedArray, 0, smallerArray.Length);
+
+ Debug.Assert(biggerArray.Length == paddedArray.Length);
+
+ return Xor(biggerArray, paddedArray);
+ }
+
+ var targetIndex = b1.Length;
+ var xoredArray = new byte[targetIndex];
+ Buffer.BlockCopy(b1, 0, xoredArray, 0, xoredArray.Length);
+
+ for (int i = 0; i < targetIndex; ++i)
+ xoredArray[i] ^= b2[i];
+
+ return xoredArray;
+ }
+
+ internal static byte[] Not(this byte[] bits)
+ {
+ if (bits == null)
+ throw new ArgumentNullException(nameof(bits));
+
+ if (bits.Length == 4)
+ {
+ var i = BitConverter.ToInt32(bits, 0);
+ return BitConverter.GetBytes(~i);
+ }
+ var newBytes = new byte[bits.Length];
+ for (int i = 0; i < newBytes.Length; ++i)
+ newBytes[i] = unchecked((byte)(~bits[i]));
+ return newBytes;
+ }
+ }
+}
diff --git a/WakeOnLan/Topology/ByteExtensions.cs b/WakeOnLan/Topology/ByteExtensions.cs
new file mode 100644
index 0000000..403e94a
--- /dev/null
+++ b/WakeOnLan/Topology/ByteExtensions.cs
@@ -0,0 +1,43 @@
+
+namespace System.Net.Topology
+{
+ internal static class ByteExtensions
+ {
+ public static byte[] BitReverseTable = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+ };
+
+ public static byte ReverseBits(this byte toReverse) => BitReverseTable[toReverse];
+ }
+}
diff --git a/WakeOnLan/Topology/INetMask.cs b/WakeOnLan/Topology/INetMask.cs
new file mode 100644
index 0000000..6413a37
--- /dev/null
+++ b/WakeOnLan/Topology/INetMask.cs
@@ -0,0 +1,17 @@
+
+namespace System.Net.Topology
+{
+ /// Provides an interface for IP net masks.
+ public interface INetMask
+ {
+ /// Gets the length of the net mask in bits.
+ int AddressLength { get; }
+
+ /// Gets the amount of set bits from the left side (used in CIDR-Notation of net masks).
+ int Cidr { get; }
+
+ /// Gets the bits of the net mask instance as an BitArray object instance.
+ /// The bits of the net mask instance as an BitArray object instance
+ byte[] GetMaskBytes();
+ }
+}
diff --git a/WakeOnLan/Topology/IPAddressExtensions.cs b/WakeOnLan/Topology/IPAddressExtensions.cs
new file mode 100644
index 0000000..4919f45
--- /dev/null
+++ b/WakeOnLan/Topology/IPAddressExtensions.cs
@@ -0,0 +1,167 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace System.Net.Topology
+{
+ /// Provides extension methods for the .
+ public static class IPAddressExtensions
+ {
+ private const string OnlyIPv4Supported = "Only IPv4 is currently supported";
+
+ /// Enumerates through the siblings of an in a network. Compliant to RFC 950 (2^n-2).
+ /// The address
+ /// The net mask of the network
+ public static IEnumerable GetSiblings(this IPAddress address, NetMask mask)
+ {
+ return GetSiblings(address, mask, SiblingOptions.ExcludeUnusable);
+ }
+
+ /// Enumerates through the siblings of an in a network.
+ /// The address
+ /// The net mask of the network
+ /// Options which addresses to include an which not
+ public static IEnumerable GetSiblings(this IPAddress address, NetMask mask, SiblingOptions options)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+ if (mask == null)
+ throw new ArgumentNullException(nameof(mask));
+ if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
+ throw new NotSupportedException(OnlyIPv4Supported);
+
+ bool includeSelf = BitHelper.IsOptionSet(options, SiblingOptions.IncludeSelf);
+ bool includeBroadcast = BitHelper.IsOptionSet(options, SiblingOptions.IncludeBroadcast);
+ bool includeNetworkIdentifier = BitHelper.IsOptionSet(options, SiblingOptions.IncludeNetworkIdentifier);
+
+ bool alreadyReturnedSelf = false;
+
+ var netPrefix = address.GetNetworkPrefix(mask);
+
+ if (includeNetworkIdentifier)
+ {
+ netPrefix = address.GetNetworkPrefix(mask);
+ if (netPrefix.Equals(address))
+ alreadyReturnedSelf = true;
+ yield return netPrefix;
+ }
+
+ var selfAddressBytes = address.GetAddressBytes();
+
+ var netPrefixBytes = netPrefix.GetAddressBytes();
+
+ int cidr = mask.Cidr;
+ uint maxHosts = 0xFFFFFFFF;
+
+ if (cidr > 0)
+ maxHosts = (uint)(1 << (8 * NetMask.MaskLength - cidr)) - 1;
+
+ var hostBytes = new byte[NetMask.MaskLength];
+ for (int hostPart = 1; hostPart < maxHosts; ++hostPart)
+ {
+ unchecked
+ {
+ hostBytes[0] = (byte)(hostPart >> 24);
+ hostBytes[1] = (byte)(hostPart >> 16);
+ hostBytes[2] = (byte)(hostPart >> 8);
+ hostBytes[3] = (byte)(hostPart >> 0);
+ }
+
+ Debug.WriteLine("HostPart: " + hostPart.ToString("X2").PadLeft(8, '0') + " (" + BitConverter.ToString(hostBytes) + ")");
+
+ var nextIpBytes = netPrefixBytes.Or(hostBytes);
+ var nextIp = new IPAddress(nextIpBytes);
+
+ if (!alreadyReturnedSelf)
+ {
+ if (includeSelf)
+ {
+ if (nextIpBytes[0] == selfAddressBytes[0]
+ && nextIpBytes[1] == selfAddressBytes[1]
+ && nextIpBytes[2] == selfAddressBytes[2]
+ && nextIpBytes[3] == selfAddressBytes[3])
+ alreadyReturnedSelf = true;
+ yield return nextIp;
+ }
+ else if (nextIpBytes[0] != selfAddressBytes[0]
+ || nextIpBytes[1] != selfAddressBytes[1]
+ || nextIpBytes[2] != selfAddressBytes[2]
+ || nextIpBytes[3] != selfAddressBytes[3])
+ yield return nextIp;
+ }
+ else
+ yield return nextIp;
+ }
+
+ if (includeBroadcast)
+ {
+ var broadcastAddress = address.GetBroadcastAddress(mask);
+ if (!address.Equals(broadcastAddress) || (address.Equals(broadcastAddress) && !alreadyReturnedSelf))
+ yield return broadcastAddress;
+ }
+ }
+
+ /// Gets the network prefix of an .
+ /// The address
+ /// The net mask of the network
+ /// The network prefix of an
+ public static IPAddress GetNetworkPrefix(this IPAddress address, NetMask mask)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+ if (mask == null)
+ throw new ArgumentNullException(nameof(mask));
+
+ if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
+ throw new NotSupportedException(OnlyIPv4Supported);
+
+ return mask & address;
+ }
+
+ /// Gets the broadcast address of an .
+ /// The address
+ /// The net mask of the network
+ /// The broadcast address of an
+ public static IPAddress GetBroadcastAddress(this IPAddress address, NetMask mask)
+ {
+ if (address == null)
+ throw new ArgumentNullException("address");
+ if (mask == null)
+ throw new ArgumentNullException("mask");
+
+ if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
+ throw new NotSupportedException(OnlyIPv4Supported);
+
+ // TODO: Test
+
+ var ipBytes = address.GetAddressBytes();
+ var notMaskBytes = mask.GetMaskBytes().Not();
+
+ var broadcastAddressBytes = notMaskBytes.Or(ipBytes);
+ return new IPAddress(broadcastAddressBytes);
+ }
+
+ /// Gets the host identifier (rest) an .
+ /// The address
+ /// The net mask of the network
+ /// The host identifier (rest) an
+ public static IPAddress GetHostIdentifier(this IPAddress address, NetMask mask)
+ {
+ if (address == null)
+ throw new ArgumentNullException(nameof(address));
+ if (mask == null)
+ throw new ArgumentNullException(nameof(mask));
+ if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
+ throw new NotSupportedException(OnlyIPv4Supported);
+
+ var maskBits = mask.GetMaskBytes();
+ var ipBits = address.GetAddressBytes();
+
+ // ~Mask & IP
+ var retVal = maskBits.Not().And(ipBits);
+ var bytes = new byte[NetMask.MaskLength];
+ Buffer.BlockCopy(retVal, 0, bytes, 0, bytes.Length);
+
+ return new IPAddress(bytes);
+ }
+ }
+}
diff --git a/WakeOnLan/Topology/NetMask.cs b/WakeOnLan/Topology/NetMask.cs
new file mode 100644
index 0000000..7706aac
--- /dev/null
+++ b/WakeOnLan/Topology/NetMask.cs
@@ -0,0 +1,312 @@
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace System.Net.Topology
+{
+ // TODO: Use Span when available (instead of byte arrays)
+ /// Represents an IPv4 net mask.
+ [StructLayout(LayoutKind.Explicit)]
+ public struct NetMask : INetMask, IEquatable
+ {
+ [FieldOffset(0)]
+ private readonly uint _mask;
+
+ #region byte-wise fields
+
+ // We are assuming here, that the byte-ordering is like on a normal x86 system
+
+ [FieldOffset(3)]
+ private readonly byte _maskB0;
+ [FieldOffset(2)]
+ private readonly byte _maskB1;
+ [FieldOffset(1)]
+ private readonly byte _maskB2;
+ [FieldOffset(0)]
+ private readonly byte _maskB3;
+
+ #endregion
+
+ internal const int MaskLength = 4;
+
+ /// Represents an empty IPv4 NetMask (all bits set to 0).
+ public static NetMask Empty { get; } = new NetMask();
+
+ /// Gets the length of the net mask in bits.
+ public int AddressLength => MaskLength * 8;
+
+ /// Gets the amount of set bits from the left side (used in CIDR-Notation of net masks).
+ public int Cidr => GetCidr(_mask);
+
+ #region Ctors
+
+ /// Creates a new instance of cloning an existing instance of .
+ public NetMask(NetMask mask)
+ {
+ if (mask == null)
+ throw new ArgumentNullException(nameof(mask));
+ _maskB0 = _maskB1 = _maskB2 = _maskB3 = 0;
+ _mask = mask._mask;
+ }
+
+ /// Creates a new instance of from an array of .
+ public NetMask(byte[] value)
+ {
+ _maskB0 = _maskB1 = _maskB2 = _maskB3 = 0;
+ _mask = 0;
+ if (value == null || value.Length == 0) // maybe throw ArgumentNullException?
+ return;
+
+ if (value.Length != MaskLength)
+ throw new ArgumentException("Invalid mask length.");
+
+ CheckMaskBytes(value); // check if passed mask are a valid mask. if not, throw Exception
+ _maskB0 = value[0];
+ _maskB1 = value[1];
+ _maskB2 = value[2];
+ _maskB3 = value[3];
+ }
+
+ /// Creates a new instance of from a given .
+ /// The IPv4 address.
+ public NetMask(IPAddress address)
+ : this(address == null ? null : address.GetAddressBytes())
+ { }
+
+ /// Creates a new instance of .
+ /// The first byte.
+ /// The second byte.
+ /// The third byte.
+ /// The fourth byte.
+ public NetMask(byte m0, byte m1, byte m2, byte m3)
+ : this(new[] { m0, m1, m2, m3 })
+ { }
+
+ /// Creates a new instance of .
+ /// The mask represented by the CIDR notation integer.
+ public NetMask(byte cidr)
+ {
+ // maybe change parameter type interpretation to CIDR?
+ if (cidr > MaskLength * 8)
+ throw new ArgumentException("Invalid CIDR length");
+ _maskB0 = _maskB1 = _maskB2 = _maskB3 = 0; // to keep init checks happy
+ _mask = GetUIntFromCidrValue(cidr);
+ }
+
+ private NetMask(uint ipv4Mask)
+ {
+ _maskB0 = _maskB1 = _maskB2 = _maskB3 = 0; // to keep init checks happy
+ _mask = ipv4Mask;
+ }
+
+ #endregion
+
+ private static void CheckMaskBytes(byte[] bytes)
+ {
+ if (!bytes.RepresentsValidNetMask())
+ throw new ArgumentException("The passed mask do not represent a valid net mask.");
+ }
+
+ /// Gets the bits of the net mask instance as an BitArray object instance.
+ /// The bits of the net mask instance as an BitArray object instance.
+ public byte[] GetMaskBytes() => new[] { _maskB0, _maskB1, _maskB2, _maskB3 };
+
+ private static int GetCidr(uint mask)
+ {
+ Debug.Assert(sizeof(uint) == MaskLength);
+ return mask.CountOnesFromLeft();
+ }
+
+ /// Extends the current instance by a given value (CIDR-wise).
+ /// The mask to use as a reference.
+ /// The value.
+ /// Because is a reference type, this method is static. If it were not like this, you could change the value of .Empty, for example.
+ public static NetMask Extend(NetMask mask, int value)
+ {
+ int currentCidr = mask.Cidr;
+ if (currentCidr >= MaskLength * 8)
+ return new NetMask(mask);
+ if (currentCidr <= 0)
+ currentCidr = 0;
+
+ int newLength = Math.Max(Math.Min(currentCidr + value, 32), 0);
+
+ var m = BytesFromCidrValue(newLength);
+
+ return new NetMask(m);
+ }
+
+ /// Abbreviates the current instance by a given value (CIDR-wise).
+ /// The mask to use as a reference.
+ /// The value.
+ /// Because is a reference type, this method is static. If it were not like this, you could change the value of .Empty, for example.
+ public static NetMask Abbreviate(NetMask mask, int value)
+ {
+ int currentCidr = mask.Cidr;
+ if (currentCidr < 1)
+ return new NetMask(mask);
+ if (currentCidr >= MaskLength * 8)
+ currentCidr = MaskLength * 8;
+
+ int newLength = Math.Max(Math.Min(currentCidr - value, 32), 0);
+
+ var m = BytesFromCidrValue(newLength);
+ return new NetMask(m);
+ }
+
+ /// Returns a value indicating whether the given array of represents a valid net mask.
+ /// True if the given array of represents a valid net mask, otherwise false.
+ public static bool GetIsValidNetMask(byte[] mask) => mask.RepresentsValidNetMask();
+
+ // TODO: Testing(!)
+ [Obsolete]
+ private static byte[] BytesFromCidrValue(int cidr)
+ {
+ int target = MaskLength * 8 - cidr;
+ int mask = 0;
+ for (int i = 0; i < target; ++i)
+ {
+ mask >>= 1;
+ mask |= unchecked((int)0x80000000);
+ }
+ var bytes = BitConverter.GetBytes(~mask);
+ return new[] {
+ bytes[0].ReverseBits(),
+ bytes[1].ReverseBits(),
+ bytes[2].ReverseBits(),
+ bytes[3].ReverseBits()
+ };
+ }
+
+ // TODO: Testing(!)
+ private static uint GetUIntFromCidrValue(int cidr) => UIntExtensions.CreateWithOnesFromLeft(cidr);
+
+ #region Operators
+
+ #region Equality
+
+ /// Returns a other indicating whether two instances of are equal.
+ /// The first other to compare.
+ /// The second other to compare.
+ /// true if and are equal; otherwise, false.
+ public static bool operator ==(NetMask n1, NetMask n2)
+ {
+ if (ReferenceEquals(n1, n2))
+ return true;
+ if (((object)n1 == null) || ((object)n2 == null))
+ return false;
+ return n1.Equals(n2);
+ }
+
+ /// Returns a other indicating whether two instances of are not equal.
+ /// The first other to compare.
+ /// The second other to compare.
+ /// true if and are not equal; otherwise, false.
+ public static bool operator !=(NetMask n1, NetMask n2) => !(n1 == n2); // Problem solved
+
+ #endregion
+ #region And
+
+ /// Bitwise combines a instance and an the AND operation.
+ /// The net mask.
+ /// The IPAddress.
+ /// The bitwised combination using the AND operation.
+ public static IPAddress operator &(IPAddress address, NetMask mask) => mask & address;
+
+ /// Bitwise combines a instance and an the AND operation.
+ /// The net mask.
+ /// The IPAddress.
+ /// The bitwised combination using the AND operation.
+ public static IPAddress BitwiseAnd(IPAddress address, NetMask mask) => mask & address;
+
+ /// Bitwise combines a instance and an the AND operation.
+ /// The net mask.
+ /// The IPAddress.
+ /// The bitwised combination using the AND operation.
+ public static IPAddress operator &(NetMask mask, IPAddress address)
+ {
+ var ipBytes = address == null
+ ? new byte[MaskLength]
+ : address.GetAddressBytes();
+ var maskBytes = mask == null
+ ? new byte[MaskLength]
+ : new byte[] { mask._maskB0, mask._maskB1, mask._maskB2, mask._maskB3 };
+
+ byte[] combinedBytes = maskBytes.And(ipBytes);
+ return new IPAddress(combinedBytes);
+ }
+
+ /// Bitwise combines a instance and an the AND operation.
+ /// The net mask.
+ /// The IPAddress.
+ /// The bitwised combination using the AND operation.
+ public static IPAddress BitwiseAnd(NetMask mask, IPAddress address) => mask & address;
+
+ /// Bitwise combines the two instances of using the AND operation.
+ /// The first other.
+ /// The second other.
+ /// The bitwised combination using the AND operation.
+ public static NetMask operator &(NetMask n1, NetMask n2) => new NetMask(n1._mask & n2._mask);
+
+ /// Bitwise combines the two instances of using the AND operation.
+ /// The first other.
+ /// The second other.
+ /// The bitwised combination using the AND operation.
+ public static NetMask BitwiseAnd(NetMask n1, NetMask n2) => n1 & n2;
+
+ #endregion
+ #region Or
+
+ /// Bitwise combines the two instances of using the OR operation.
+ /// The first other.
+ /// The second other.
+ /// The bitwised combination using the OR operation.
+ public static NetMask operator |(NetMask n1, NetMask n2) => new NetMask(n1._mask | n2._mask);
+
+ /// Bitwise combines the two instances of using the OR operation.
+ /// The first other.
+ /// The second other.
+ /// The bitwised combination using the OR operation.
+ public static NetMask BitwiseOr(NetMask n1, NetMask n2) => n1 | n2;
+
+ #endregion
+
+ #endregion
+ #region Common overrides
+
+ /// Converts the other of this instance to its equivalent string representation.
+ /// A string that represents the other of this instance.
+ /// 1
+ public override string ToString()
+ {
+ var sb = new StringBuilder(4 * 3 + 3 * 3 + 32 + 3 + 3); // 255.255.255.255 (11111111111111111111111111111111)
+
+ var arr = new byte[] { _maskB0, _maskB1, _maskB2, _maskB3 };
+ var asString = arr.ToBinaryString('.');
+
+ sb.Append(arr[0]).Append('.').Append(arr[1]).Append('.').Append(arr[2]).Append('.').Append(arr[3]).Append(" (");
+ sb.Append(asString).Append(')');
+
+ return sb.ToString();
+ }
+
+ /// Returns a value indicating whether this instance and a specified represent the same type and other.
+ /// true if is a and equal to this instance; otherwise, false.
+ /// The object to compare with this instance.
+ /// 2
+ public override bool Equals(object obj) => obj != null && obj is NetMask && Equals((NetMask)obj);
+
+ /// Returns a value indicating whether this instance and a specified object represent the same other.
+ /// true if is equal to this instance; otherwise, false.
+ /// An object to compare to this instance.
+ /// 2
+ public bool Equals(NetMask other) => other._mask == _mask;
+
+ /// Returns the hash code for this instance.
+ /// A 32-bit signed integer hash code.
+ /// 2
+ public override int GetHashCode() => unchecked((int)_mask);
+
+ #endregion
+ }
+}
diff --git a/WakeOnLan/Topology/NetMaskExtensions.cs b/WakeOnLan/Topology/NetMaskExtensions.cs
new file mode 100644
index 0000000..6b12ae7
--- /dev/null
+++ b/WakeOnLan/Topology/NetMaskExtensions.cs
@@ -0,0 +1,36 @@
+
+namespace System.Net.Topology
+{
+ /// Provides extension methods for the .
+ public static class NetMaskExtensions
+ {
+ /// Gets the number of siblings an can have in a given network. Compliant to RFC 950 (2^n-2).
+ /// The net mask of the network
+ /// The number of siblings an can have in the given network.
+ public static int GetSiblingCount(this NetMask mask) => GetSiblingCount(mask, SiblingOptions.ExcludeUnusable);
+
+ /// Gets the number of siblings an can have in a given network.
+ /// The net mask of the network
+ /// Options which addresses to include an which not
+ /// The number of siblings an can have in the given network.
+ public static int GetSiblingCount(this NetMask mask, SiblingOptions options)
+ {
+ if (mask == null)
+ throw new ArgumentNullException(nameof(mask));
+
+ bool includeSelf = BitHelper.IsOptionSet(options, SiblingOptions.IncludeSelf);
+ bool includeBroadcast = BitHelper.IsOptionSet(options, SiblingOptions.IncludeBroadcast);
+ bool includeNetworkIdentifier = BitHelper.IsOptionSet(options, SiblingOptions.IncludeNetworkIdentifier);
+
+ var hostPartBits = mask.GetMaskBytes().CountFromRight(false);
+ var total = 1 << hostPartBits;
+ total -= includeSelf ? 0 : 1;
+ total -= includeBroadcast ? 0 : 1;
+ total -= includeNetworkIdentifier ? 0 : 1;
+
+ // TODO: Testing
+
+ return total;
+ }
+ }
+}
diff --git a/WakeOnLan/Topology/SiblingOptions.cs b/WakeOnLan/Topology/SiblingOptions.cs
new file mode 100644
index 0000000..5a84476
--- /dev/null
+++ b/WakeOnLan/Topology/SiblingOptions.cs
@@ -0,0 +1,27 @@
+namespace System.Net.Topology
+{
+ /// Provides options for doing network sibling calculations using a net mask.
+ [Flags]
+ public enum SiblingOptions
+ {
+ /// Do not include the broadcast or net address neither the addess passed to the method.
+ ExcludeAll = 0,
+ /// Include the addess passed to the method.
+ IncludeSelf = 1,
+ /// Include the addess passed to the method. Compliant to RFC 950 (2^n-2).
+ ExcludeUnusable = IncludeSelf,
+ /// Include the broadcast address.
+ IncludeBroadcast = 2,
+ /// Include the net address.
+ IncludeNetworkIdentifier = 4,
+ /// Include all addresses possible. RFC 1878 (2^n).
+ IncludeAll = IncludeSelf | IncludeBroadcast | IncludeNetworkIdentifier
+ }
+
+ internal static class BitHelper
+ {
+ [Runtime.TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] // as if NGen will ever compile this assembly ;)
+ [Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
+ internal static bool IsOptionSet(SiblingOptions value, SiblingOptions testValue) => (value & testValue) == testValue;
+ }
+}
diff --git a/WakeOnLan/Topology/StringExtensions.cs b/WakeOnLan/Topology/StringExtensions.cs
new file mode 100644
index 0000000..e506670
--- /dev/null
+++ b/WakeOnLan/Topology/StringExtensions.cs
@@ -0,0 +1,39 @@
+
+namespace System.Net.Topology
+{
+ internal static class StringExtensions
+ {
+ // TODO: The following method uses unsafe stuff. We don't want to pass the /unsafe flag to the compiler, so we use a simple, safe method instead.
+ // As soon as .NET Standard with Span and the new String.Create is available, we can make this faster and safe.
+ /*
+ internal static unsafe string Reverse(this string input)
+ {
+ int len = input.Length;
+
+ // Why allocate a char[] array on the heap when you won't use it
+ // outside of this method? Use the stack.
+ char* reversed = stackalloc char[len];
+
+ // Avoid bounds-checking performance penalties.
+ fixed (char* str = input)
+ {
+ int i = 0;
+ int j = i + len - 1;
+ while (i < len)
+ reversed[i++] = str[j--];
+ }
+
+ // Need to use this overload for the System.String constructor
+ // as providing just the char* pointer could result in garbage
+ // at the end of the string (no guarantee of null terminator).
+ return new string(reversed, 0, len);
+ }
+ */
+ internal static string Reverse(this string input)
+ {
+ char[] chars = input.ToCharArray();
+ Array.Reverse(chars);
+ return new string(chars);
+ }
+ }
+}
diff --git a/WakeOnLan/Topology/UIntExtensions.cs b/WakeOnLan/Topology/UIntExtensions.cs
new file mode 100644
index 0000000..ccad88d
--- /dev/null
+++ b/WakeOnLan/Topology/UIntExtensions.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace System.Net.Topology
+{
+ internal static class UIntExtensions
+ {
+ // TODO: Tests
+ public static int CountOnesFromLeft(this uint value)
+ {
+ var occurences = 0;
+ for (uint i = 1u << 31; i >= 0; i >>= 1)
+ {
+ if ((i & value) != 0)
+ ++occurences;
+ else
+ break;
+ }
+ return occurences;
+ }
+
+ // TODO: Tests
+ public static uint CreateWithOnesFromLeft(int count)
+ {
+ if (count > 32)
+ throw new ArgumentException("Cannot set more than 32 bits to one!");
+
+ var value = 0u;
+
+ var mask = 1u << 31;
+ for (int i = 0; i < count; ++i)
+ {
+ value |= mask;
+ mask >>= 1;
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/WakeOnLan/WakeOnLan.csproj b/WakeOnLan/WakeOnLan.csproj
new file mode 100644
index 0000000..b9ef27c
--- /dev/null
+++ b/WakeOnLan/WakeOnLan.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netstandard2.0
+ Niklas Mollenhauer
+ 2.0.2
+ Library for Sending magic packets and performing IP address operations.
+ LGPL-3.0-only
+ https://github.com/nikeee/wake-on-lan
+ https://github.com/nikeee/wake-on-lan.git
+ WakeOnLan, magic packets
+ True
+ System.Net
+
+
+
+ latest
+
+
+
+
+
+
+
+
+