Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 128

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 134

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 141

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 169

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 199

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 205

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 233

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 248

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 254

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 267

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php on line 595

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/files/model/_file.funcs.php on line 559

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_connect_db.inc.php on line 29

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_core/_param.funcs.php on line 1692

Warning: Cannot modify header information - headers already sent by (output started at /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php:128) in /mnt/data/accounts/m/memos/data/www/blog/inc/sessions/model/_session.class.php on line 219

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/generic/model/_genericelement.class.php on line 109

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_core/model/dataobjects/_dataobject.class.php on line 428

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_core/model/dataobjects/_dataobject.class.php on line 437

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/_blog_main.inc.php on line 414

Warning: Cannot modify header information - headers already sent by (output started at /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php:128) in /mnt/data/accounts/m/memos/data/www/blog/inc/_blog_main.inc.php on line 2

Warning: Cannot modify header information - headers already sent by (output started at /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php:128) in /mnt/data/accounts/m/memos/data/www/blog/inc/_blog_main.inc.php on line 3

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/items/model/_itemlist.class.php on line 483

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/items/model/_itemlistlight.class.php on line 119

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/items/model/_itemlistlight.class.php on line 838

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/items/model/_item.class.php on line 1426

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/items/model/_item.class.php on line 1429

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/inc/items/model/_item.class.php on line 3020

Warning: Cannot modify header information - headers already sent by (output started at /mnt/data/accounts/m/memos/data/www/blog/inc/_main.inc.php:128) in /mnt/data/accounts/m/memos/data/www/blog/inc/skins/_skin.funcs.php on line 383
Wake On LAN in C#
Lukas Neumann
12/06/08

Wake On LAN in C#

Lately I came across a requirement for an ability to remotely turn on computers in our company. Couple of team members (including me...) tend to work from home sometimes so they leave their PCs running when they leave the office so the next day they could access it over Remote Desktop. Do you spot a problem already? To be honest I did not realise this was a problem either ... until an electricity bill came in. The workstation PCs are running nonstop (no one really bothers to switch them off, what if they did not go to the office tomorrow ...), which obviously has very negative impact on the electricity consumption in our office.

So it was clear we need to do something about it. One can switch off a PC using Remote Desktop very easily (you can do it directly from Start menu), but having ability to switch off a computer remotely is useless unless you can then remotely switch on the computer again. And that is where Wake on LAN finds its place.

"Magic Packet"

Wake On LAN (sometimes referred as WOL or WoL) is a marketing term used for ability to bring computer out of Stand-By mode by sending it a special packet, called "Magic Packet".

When you shutdown Windows, all modern ATX-power based PCs do not switch off completely. Instead they enter a Stand-By mode, which means RAM, CPU and hard drives are switched off, but motherboard itself and a network card are still powered. To determine if your network card supports WOL, shut down your PC and check the Link LED on the network card - if it is still active, your network card is still powered and should support Wake on LAN.

Even though a PC is shut down, the network card is listening on the data layer (usually Ethernet) level and scans incoming packets for special character sequence. If it detects the sequence, it will turn on the PC. This sequence, called Magic Packet, has following structure:

MagicPacket

Follow up:

The packet begins with 6 bytes trailer of FF bytes which is followed by 16 times repeated MAC address of the target device (i.e. the device that should be switched on). MAC Address is used as an identifier in the packet, because that is the only valuable identification that is available when the PC is not running. MAC Address is assigned by the manufacturer (it is a layer 2 identifier) and it stored in the flash memory of the network card itself, so the network card can perform the comparison very easily. It cannot use an IP address, because network card simply does not have one when PC is not running - IP address is a layer 3 identifier, which means it is assigned by the OS.

You may also ask why the MAC address is repeated 16 times - it looks like unnecessary data duplication. Well it is not. As mentioned above the network card scans all packets that are coming in and it does not support any protocols of higher levels (TCP, HTTP, etc.) - it will literally go through all bytes in the packet and if it finds the "magic packet" sequence anywhere in the data or even a packet header, it will turn on the PC. Imagine that the packet did not repeat the MAC Address, so it would only utilise 6 bytes of FF and then 6 bytes of the MAC address. I can guarantee you that this 12 bytes combination will sooner or later appear in your network communication (in a file transfer, incoming email, a picture, etc.). 12 bytes is just not enough, which is why the MAC address is repeated 16 times giving the packet solid 102 bytes. The probability that those 102 bytes will unintentionally appear in transferred data is exponentially lower (there are 256^102 different packets which should be safe enough).

Broadcasting Magic Packet

So to switch on a PC through Wake on LAN it should be enough to somehow get a packet including the "magic packet" sequence to the device that I want to switch on. Since we know that the network card is scanning all incoming packets, it is not really important which type of packet I will send as long as it reaches the device.

Since I want to be able to switch on any device in my LAN, the best "container" for the magic packet sequence is an UDP broadcast packet. UDP is a TCP/IP service without any guarantee for delivery, however it does require any handshake like TCP, so a packet can be sent without "opening a connection". UDP broadcast packet is a special type of UDP packet sent to IP address 255.255.255.255 which tells every switch in the way to send this packet to every port so effectively this packet should reach each device in local network, which is exactly what we need from our Magic Packet.

 

Wake On Lan Packet Spreading

The source device will broadcast the magic packet to IP 255.255.255.255 and this packet will be spread in local network. Routers are set not to transfer broadcast messages, so the target device must be placed before any router. The broadcast packet will eventually reach the target device, which will detect its MAC address in the packet and will turn on itself.

C# Implementation

Now we now how everything works so putting everything together in the form of C# code should be just a piece of cake. At first, we need to create the magic packet:

byte[] macAddress = new byte[] {0x00, 0xe1, 0xff, 0x65, 0x23, 0x10};

//Construct the packet
List<byte> packet = new List<byte>();

//Trailer of 6 FF packets
for (int i = 0; i < 6; i++)
packet.Add(0xFF);

//Repeat 16 time the MAC address (which is 6 bytes)
for (int i = 0; i < 16; i++)
packet.AddRange(macAddress);

Now we have the packet data, so we just need to send it inside UDP packet. For this purpose the UdpClient class from System.Net.Sockets will come handy:

//Send the packet to broadcast address
UdpClient client = new UdpClient();
client.Connect(IPAddress.Broadcast, 7); //Any UDP port will work, but 7 is my lucky number ...
client.Send(packet.ToArray(), packet.Count);

You can find the complete class here - PowerManager.cs.

Obtaining MAC Address

The code above assumes that you already know MAC address of the device that you want to turn on. There are several ways how you can obtain the MAC address of target device. You can obviously run the command ipconfig /all on directly on the PC and look for the Physical Address entry of your network adapter.

But since we are talking about doing stuff remotely, I will show you how you can get a MAC address remotely. We will use ARP protocol to obtain MAC address by given IP address or hostname. The main purpose of ARP protocol is to translate an IP address into MAC address which is exactly what we need. We will use Windows API function called SendARP for this purpose:

DWORD SendARP(
__in IPAddr DestIP,
__in IPAddr SrcIP,
__out PULONG pMacAddr,
__inout PULONG PhyAddrLen
);

The method accepts destination IP address (DestIP parameter) and it will fill array of 6 bytes (pointed by pMacAddr parameter) which represents the MAC address of the device. To call this method from .NET, we will use PInvoke call:

[DllImport("iphlpapi.dll", ExactSpelling = true)]
static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);

static byte[] GetMACAddress(string hostNameOrAddress)
{
IPHostEntry hostEntry = Dns.GetHostEntry(hostNameOrAddress);
if (hostEntry.AddressList.Length == 0)
  return null; // We were not able to resolve given hostname / address

byte[] macAddr = new byte[6];
uint macAddrLen = (uint)macAddr.Length;
if (SendARP((int)hostEntry.AddressList[0].Address, 0, macAddr, ref macAddrLen) != 0)
  return null; // The SendARP call failed

return macAddr;
}

Putting it all together

Now we have everything ready to switch on a PC remotely, except for the target PC itself. On most systems, the Wake On LAN is disabled by default, so you need to enable it. First and foremost, you need to check your BIOS to make sure that Wake On LAN is enabled. Name of this entry will be different depending on your motherboard manufacturer, but it will be most likely located in Power Management of your BIOS.

As a next step, you need to enable the WOL for specified network card directly inside Windows. Open your Device Manager (go to Control Panel, select System, go to Hardware tab and click on Device Manager button) and select the network card which will receive the magic packet. In the Power Management tab, select "Allow this device to bring this computer out of standby", as shown on the following picture:

Enabling Network Card Power Management

Click OK and you are ready your brand new Wake On LAN feature.

A propos: The end of the story

The reason why I underwent all this WOL pain was the ability to remotely turn on and off PCs in our office (and to protect the environment and our electricity bills) so you may wonder how I solved it. Basically I made a simple web site which lists our workstation computers in the office. This web site runs on our server in the office (which has to run 24/7) and if you want to turn on your PC you would just go to that site and click on "Wake Up" button which then sends a Magic Packet to the PC.

Wake On LAN manager

LukeN 080612

Edit 080723: Full source code of web site can be found here.

Edit 080921: Database script is here.

Technorati:

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/skins/_item_feedback.inc.php on line 156

Contact Us


Are you interested in professional services of the developers who publish on this blog? Contact us on our web site now.

XML Feeds

Add to Technorati Favorites

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/plugins/_calendar.plugin.php on line 190

Deprecated: Assigning the return value of new by reference is deprecated in /mnt/data/accounts/m/memos/data/www/blog/plugins/_calendar.plugin.php on line 905
April 2014
Mon Tue Wed Thu Fri Sat Sun
 << <   > >>
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30