Monday, May 11, 2009

Wake On LAN (WOL) in C#

Stumble del.icio.us Reddit MyWeb! Facebook Google bookmark

I was looking for something to wake my remote machine on LAN or a different laptop connected in my network to wake up without having to press the power button again and again. There are some programs available but you have to pay for them. It's pretty easy to make a packet (so called magic packet) and broadcast it in the network. The packet contains the MAC address of the machine which has to be woken up. If that machine is in network and is connected via a LAN cable, it should wake itself up. So here is the program in C# which creates the magic packet and broadcasts it in the network. You might also like to check my post on Get MAC address from hostname or IP address to integrate this program and the other one together so you will just have to enter the hostname/IP address of the machine which you want woken up without worrying about it's MAC address. If you want just the exe, let me know via a comment here and I'll send you the executable.


    1 // No copyrights(c). Use as you wish!

    2 

    3 using System;

    4 using System.Globalization;

    5 using System.Text.RegularExpressions;

    6 using System.Net;

    7 using System.Net.Sockets;

    8 

    9 namespace Yours.Truly

   10 {

   11     // *************************************************************************

   12     /// <summary>

   13     /// A class to demonstrate Wake up on LAN. For this program to function, your

   14     /// machine must be setup to accept wake-up on LAN requests. Usually this

   15     /// option can set to "Enabled" state in boot(BIOS) options. You can see the

   16     /// set value by Rebooting your PC/Laptop and press F2 just after you power

   17     /// on your PC/Laptop. (you might have to keep pressing F2 until it comes up

   18     /// with boot options)

   19     /// </summary>

   20     /// <remarks>

   21     /// <para>

   22     /// For more information see http://support.microsoft.com/kb/257277 and

   23     /// http://en.wikipedia.org/wiki/Wake-on-LAN.

   24     /// </para>

   25     /// <para>For an in depth details please visit :

   26     /// http://en.wikipedia.org/wiki/Data_link_layer and

   27     /// http://en.wikipedia.org/wiki/Network_layer </para>

   28     /// </remarks>

   29     public sealed class WakeUpOnLan

   30     {

   31         // *********************************************************************

   32         /// <summary>

   33         /// Main entry point of the application.

   34         /// </summary>

   35         /// <param name="args">An array of command line arguments.</param>

   36         static void Main(string[] args)

   37         {

   38             bool wakeUp = true;

   39             while (wakeUp)

   40             {

   41                 Console.WriteLine("Enter the MAC address of the host to wake up " +

   42                     " on LAN (no space or hyphen(-). e.g. 0021702BA7A5." +

   43                     "Type Exit to end the program):");

   44                 string macAddress = Console.ReadLine();

   45 

   46                 StringComparer cp = StringComparer.OrdinalIgnoreCase;

   47                 if (cp.Compare(macAddress, "Exit") == 0) break;

   48 

   49                 //remove all non 0-9, A-F, a-f characters

   50                 macAddress = Regex.Replace(macAddress, @"[^0-9A-Fa-f]", "");

   51                 //check if mac adress length is valid

   52                 if (macAddress.Length != 12)

   53                 {

   54                     Console.WriteLine("Invalid MAC address. Try again!");

   55                 }

   56                 else

   57                 {

   58                     Wakeup(macAddress);

   59                 }

   60             }

   61         }

   62 

   63         // *********************************************************************

   64         /// <summary>

   65         /// Wakes up the machine with the given <paramref name="macAddress"/>.

   66         /// </summary>

   67         /// <remarks>

   68         /// <para>

   69         /// <note>

   70         /// <list type="number">

   71         /// <item> The motherboard must support Wake On LAN.</item>

   72         /// <item> The NIC must support Wake On LAN.</item>

   73         /// <item> There must be a wire connecting the motherboard's WOL port to

   74         /// the NIC's WOL port. Usually there always is a connection on most of

   75         /// the PCs.</item>

   76         /// <item> The Wake On LAN feature must be enabled in the motherboard's

   77         /// BIOS. Usually this is also enabled by default, but you might like to

   78         /// check again.</item>

   79         /// <item> The "Good Connection" light on the back of the NIC must be lit

   80         /// when the machine is off. (By default always good if you are not

   81         /// facing any network issues)</item>

   82         /// <item> Port 12287 (0x2FFF) must be open. (By default it should be

   83         /// open unless some antivirus or any other such program has changed

   84         /// settings.)</item>

   85         /// <item> Packets cannot be broadcast across the Internet.  That's why

   86         /// it's called Wake On Lan, not Wake On Internet.</item>

   87         /// <item> To find your MAC address, run the MSINFO32.EXE tool that is a

   88         /// part of Windows and navigate to Components > Network > Adapteror

   89         /// or simply type nbtstat -a &lt;your hostname &lt at command prompt.

   90         /// e.g. nbtstat -a mymachinename or nbtstat -A 10.2.100.213.

   91         /// .</item>

   92         /// </list>

   93         /// </note>

   94         /// </para>

   95         /// <para>You could also use my other blog on "Get MAC address" to simply

   96         /// integrate this program and my other program so you just have to input

   97         /// the hostname/IP address of the machine which you want woken up.</para>

   98         /// <para>See http://mycomponent.blogspot.com/2009/05/get-mac-address-in-c-from-ip.html

   99         /// </para>

  100         /// </remarks>

  101         /// <param name="macAddress">The MAC address of the host which has to be

  102         /// woken up.</param>

  103         private static void Wakeup(string macAddress)

  104         {

  105             WOLUdpClient client = new WOLUdpClient();

  106             client.Connect(

  107                     new IPAddress(0xffffffff),    //255.255.255.255  i.e broadcast

  108                     0x2fff); // port = 12287

  109             // Set the socketoptions

  110             if (client.IsClientInBrodcastMode())

  111             {

  112                 int byteCount = 0;

  113                 // buffer to be sent:

  114                 // 6 bytes each with 255 + 16 times mac each 6 bytes

  115                 byte[] bytes = new byte[102];

  116                 // The packet begins with 6 bytes trailer of FF bytes which is

  117                 // followed by 16 times repeated MAC address of the target device

  118                 // (i.e. the device that should be switched on). MAC Address is

  119                 // used as an identifier in the packet, because that is the only

  120                 // valuable identification that is available when the PC is not

  121                 // running. MAC Address is assigned by the manufacturer (it is

  122                 // a layer 2 - Data link layer identifier) and it stored in the

  123                 // flash memory of the network card itself, so the network card

  124                 // can perform the comparison very easily. It cannot use an IP

  125                 // address, because network card simply does not have one when

  126                 // PC is not running - IP address is a layer 3 - network layer

  127                 // identifier, which means it is assigned by the OS.

  128                 // You may also ask why the MAC address is repeated 16 times?

  129                 // As mentioned above the network card scans all packets that

  130                 // are coming in and it does not support any protocols of higher

  131                 // levels (TCP, HTTP, etc.) - it will literally go through all

  132                 // bytes in the packet and if it finds the "magic packet"

  133                 // sequence anywhere in the data or even a packet header, it

  134                 // will turn on the PC. Imagine that the packet did not repeat

  135                 // the MAC Address, so it would only utilise 6 bytes of FF and

  136                 // then 6 bytes of the MAC address. This 12 bytes combination

  137                 // may sooner or later appear in your network communication

  138                 // (in a file transfer, incoming email, a picture, etc.). 12

  139                 // bytes is just not enough, which is why the MAC address is

  140                 // repeated 16 times giving the packet solid 102 bytes. The

  141                 // probability that those 102 bytes will unintentionally appear

  142                 // in transferred data is exponentially lower (there are

  143                 // 256^102 different packets which should be safe enough).

  144 

  145                 // First 6 bytes should be 0xFF

  146                 for (int trailer = 0; trailer < 6; trailer++)

  147                 {

  148                     bytes[byteCount++] = 0xFF;

  149                 }

  150                 // Repeat MAC 16 times

  151                 for (int macPackets = 0; macPackets < 16; macPackets++)

  152                 {

  153                     int i = 0;

  154                     for (int macBytes = 0; macBytes < 6; macBytes++)

  155                     {

  156                         bytes[byteCount++] =

  157                             byte.Parse(macAddress.Substring(i, 2),

  158                             NumberStyles.HexNumber);

  159                         i += 2;

  160                     }

  161                 }

  162 

  163                 // Send wake up packet (the magic packet!)

  164                 int returnValue = client.Send(bytes, byteCount);

  165                 Console.WriteLine(returnValue + " bytes sent to " + macAddress +

  166                     Environment.NewLine + "Check if it's woken up. If not, try again!" +

  167                     Environment.NewLine);

  168             }

  169             else

  170             {

  171                 Console.WriteLine("Remote client could not be set in broadcast mode!");

  172             }

  173         } // end Wakeup

  174 

  175     } // end class WakeUpOnLan

  176 

  177     // *************************************************************************

  178     /// <summary>

  179     /// A <see cref="UdpClient"/> class to set the client to broadcast mode.

  180     /// </summary>

  181     /// <remarks>

  182     /// <para>

  183     /// This class just sets the SocketOption to

  184     /// <see cref="SocketOptionName.Broadcast"/> mode.

  185     /// </para>

  186     /// </remarks>

  187     public class WOLUdpClient : UdpClient

  188     {

  189         // *********************************************************************

  190         /// <summary>

  191         /// Initializes a new instance of <see cref="WOLUdpClient"/>.

  192         /// </summary>

  193         public WOLUdpClient() : base()

  194         {

  195         }

  196 

  197         // *********************************************************************

  198         /// <summary>

  199         /// Sets up the UDP client to broadcast packets.

  200         /// </summary>

  201         /// <returns><see langword="true"/> if the UDP client is set in

  202         /// broadcast mode.</returns>

  203         public bool IsClientInBrodcastMode()

  204         {

  205             bool broadcast = false;

  206             if (this.Active)

  207             {

  208                 try

  209                 {

  210                     this.Client.SetSocketOption(SocketOptionLevel.Socket,

  211                                             SocketOptionName.Broadcast, 0);

  212                     broadcast = true;

  213                 }

  214                 catch

  215                 {

  216                     broadcast = false;

  217                 }

  218             }

  219             return broadcast;

  220         }

  221 

  222     } // end class WOLUdpClient

  223 } // end namespace Yours.Truly



5 comments:

  1. Hi!
    thanks for nice example - but regarding your note about integration with "Get MAC from ip" - how could you integrate this, if you are waking up computer that is turned off? if it is turned off, you can't get MAC from it .. or am i missing something?
    Tomas

    ReplyDelete
  2. I would like the executable, please.

    lincoln116@hotmail.com

    Thanks.

    ReplyDelete
  3. do you a vb.net version of this program?

    ReplyDelete
  4. pls email me at mpegamerz@gmail.com

    ReplyDelete

Please leave your opinion...