Sending Wake-on-LAN Magic Packets from C#

I present, with little introduction, the MACAddress class. Within you will find simple test and conversion methods, with a single, simple to use method for sending a WOL ‘Magic’ Packet.

 

// MACAddress Class (Sending WOL 'Magic' Packets)
// Written by John Storer II (Feb 20, 2012)
//
// Feel free to use/modify this code as you wish, without liability.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace SendWOLPacket
{
    public class MACAddress
    {
        /// <summary>
        /// Test a MACAddress byte Array.
        /// </summary>
        /// <param name="macAddress"></param>
        /// <returns></returns>
        public static bool Test(byte[] macAddress) {
            if (macAddress == null) return false;
            if (macAddress.Length != 6) return false;

            return true;
        }

        /// <summary>
        /// Test a MACAddress string.
        /// </summary>
        /// <param name="macAddress"></param>
        /// <returns></returns>
        public static bool Test(string macAddress) {
            var valid_chars = "0123456789ABCDEFabcdef";

            if (string.IsNullOrEmpty(macAddress)) return false;
            if (macAddress.Length != 12) return false;

            foreach (var c in macAddress) {
                if (valid_chars.IndexOf(c) < 0) {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Parse a MACAddress string into a byte array.
        /// </summary>
        /// <param name="macAddress"></param>
        /// <returns></returns>
        public static byte[] Parse(string macAddress) {
            byte[] mac = new byte[6];

            if (!Test(macAddress))
                throw new ArgumentException(
                    "Invalid MACAddress string.",
                    "macAddress",
                    null);

            for (var i = 0; i < 6; i++) {
                var t = macAddress.Substring((i * 2), 2);
                mac[i] = Convert.ToByte(t, 16);
            }

            return mac;
        }

        /// <summary>
        /// Attempt to parse a MACAddress string
        ///   without throwing an Exception.
        /// </summary>
        /// <param name="macAddress"></param>
        /// <param name="Address"></param>
        /// <returns></returns>
        public static bool TryParse(string macAddress, out byte[] Address) {
            try {
                Address = Parse(macAddress);
                return true;
            }
            catch {
                Address = null;
                return false;
            }
        }

        /// <summary>
        /// Convert a byte array MACAddress to a string.
        /// </summary>
        /// <param name="macAddress"></param>
        /// <returns></returns>
        public static string ToString(byte[] macAddress) {
            if (!Test(macAddress))
                throw new ArgumentException(
                    "Invalid MACAddress byte array.",
                    "macAddress",
                    null);

            return BitConverter.ToString(macAddress).Replace("-", "");
        }


        /// <summary>
        /// Sends a Wake-On-LAN 'magic' packet to
        ///   the specified MACAddress string.
        /// </summary>
        /// <param name="macAddress"></param>
        public static void SendWOLPacket(string macAddress) {

            if (!Test(macAddress))
                throw new ArgumentException(
                    "Invalid MACAddress string.",
                    "macAddress",
                    null);
            
            byte[] mac = Parse(macAddress);

            SendWOLPacket(mac);
        }

        /// <summary>
        /// Sends a Wake-On-LAN 'magic' packet to
        ///   the specified MACAddress byte array.
        /// </summary>
        /// <param name="macAddress"></param>
        public static void SendWOLPacket(byte[] macAddress) {

            if (!Test(macAddress))
                throw new ArgumentException(
                    "Invalid MACAddress byte array.",
                    "macAddress",
                    null);

            // WOL 'magic' packet is sent over UDP.
            using (UdpClient client = new UdpClient()) {

                // Send to: 255.255.255.0:40000 over UDP.
                client.Connect(IPAddress.Broadcast, 40000);

                // Two parts to a 'magic' packet:
                //     First is 0xFFFFFFFFFFFF,
                //     Second is 16 * MACAddress.
                byte[] packet = new byte[17 * 6];

                // Set to: 0xFFFFFFFFFFFF.
                for (int i = 0; i < 6; i++) {
                    packet[i] = 0xFF;
                }

                // Set to: 16 * MACAddress
                for (int i = 1; i <= 16; i++) {
                    for (int j = 0; j < 6; j++) {
                        packet[i * 6 + j] = macAddress[j];
                    }
                }

                // Send WOL 'magic' packet.
                client.Send(packet, packet.Length);
            }
        }

    }
}

Using this code is as simple as (assuming you have a form, a button named bSend and a text box named tbMACAddress):

private void bSend_Click(object sender, EventArgs e) {
    try {
        MACAddress.SendWOLPacket(tbMACAddress.Text);

        MessageBox.Show(
            string.Format("Packet Sent to '{0}'", tbMACAddress.Text));
    }
    catch (Exception Error) {
        MessageBox.Show(
            string.Format("Error:\n\n{0}", Error.Message), "Error");
    }
            
}

Why write a class to send WOL Packets? Mainly because I needed to wake up a PC at home remotely, if I really needed it. Also, someone here at work said, “I need to send WOL to this laptop, but I don’t have the Altiris Console handy,” to which I replied:

Challenge Accepted

Because who doesn't like a good challenge?

Folders, files and poorly described exceptions

You know, sometimes exceptions returned in C# are so irritatingly vague or indirect that it takes longer than I’d like to solve the problem.

For example, I’ve been attempting to loop through a large set of directories on a network share, for a list of users in Active Directory. I have both an File/Folder indexing library, and an Active Directory library to help speed up development.

foreach (User Account in Accounts) {
    if (!Directory.Exists(Account.HomeDirectory)) continue;

    List<DirectoryInfo> folders = new List<DirectoryInfo>();
    List<FileInfo> files = new List<FileInfo>();

    Folders.Index(
        new DirectoryInfo(Account.HomeDirectory),
        ref folders,
        ref files);

    files.Reverse();
    folders.Reverse();

    foreach (FileInfo fi in files) {
        if (fi.Exists) fi.Delete();
    }

    foreach (DirectoryInfo di in folders) {
        if (di.Exists) di.Delete(true);
    }
}

Irritatingly, it kept returning a “Access is denied” error on the first folder that it attempted to delete. I, of course, have had not nearly enough sleep to deal with this sort of obscure issue, but I plowed on. I ran the code under a domain admin account; that didn’t fix it. I added the existence checks and a bit of debugging output to find where it was failing exactly.

Unable to force the issue, I checked the folder that it was failing on, and the folder was “root\My Videos”. Properties showed “Read-only for files in this folder”.

*facepalm*

Here’s the fixed code. Essentially it sets the FileAttributes of the files and folders it attempts to delete to FileAttributes.Normal, thereby bypassing the “Access is Denied” error (which IMHO should be a “Unable to delete – folder is read-only”!) and allowing the deletion.

foreach (User Account in Accounts) {
    if (!Directory.Exists(Account.HomeDirectory)) continue;

    List<DirectoryInfo> folders = new List<DirectoryInfo>();
    List<FileInfo> files = new List<FileInfo>();

    Folders.Index(
        new DirectoryInfo(Account.HomeDirectory),
        ref folders,
        ref files);

    files.Reverse();
    folders.Reverse();

    foreach (FileInfo fi in files) {
        fi.Attributes = FileAttributes.Normal;
        if (fi.Exists) fi.Delete();
    }

    foreach (DirectoryInfo di in folders) {
        di.Attributes = FileAttributes.Normal;
        if (di.Exists) di.Delete(true);
    }
}

I’m guessing that if I still have issues, I’ll probably have to take ownership of the files/folders to delete them. Not a great start to the day.

Update 1:

I found what looks to be a “Privilege Enabling” library. This is definitely something I shall be adding to my toolkit.

public static void TakeOwnership(DirectoryInfo di) {
    Process p = Process.GetCurrentProcess();

    using (new ProcessPrivileges.PrivilegeEnabler(p, Privilege.TakeOwnership)) {
        DirectorySecurity ds = di.GetAccessControl();
        ds.SetOwner(WindowsIdentity.GetCurrent().User);
        di.SetAccessControl(ds);
    }
}

Update 2:

Wow. After trying to take ownership as above, I still had difficulties with certain “RECYCLER” files/folders, and taking ownership apparently wasn’t enough. Here’s the full-on, brute-force, take-control method:

public static void TakeOwnership(ref DirectoryInfo di) {
    Process p = Process.GetCurrentProcess();
    SecurityIdentifier si = WindowsIdentity.GetCurrent().User;

    // Raise the process' access privileges.
    using (new ProcessPrivileges.PrivilegeEnabler(p, Privilege.TakeOwnership, Privilege.Security)) {
        // Get access rules.
        DirectorySecurity ds = di.GetAccessControl();

        // Take "full control" of everything.        
        FileSystemAccessRule fsaRule = new FileSystemAccessRule(
            si,
            FileSystemRights.Delete | FileSystemRights.Modify,
            InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
            PropagationFlags.None,
            AccessControlType.Allow);

        // Remove previous access rules.
        ds.PurgeAccessRules(si);

        // Add the new access rules.
        ds.AddAccessRule(fsaRule);

        // Take ownership
        ds.SetOwner(si);

        // Set the access rules to the object.
        di.SetAccessControl(ds);
    }
}

Comments Off

Rendering Hair

Ever found that your character’s hair looks unrealistic, especially when it is supposed to be long and free-flowing (I’m lookin’ at you, Dead Space. Intro sequence = most unrealistic real time hair ever.)

Finally, we can have realistic hair in real time in our games. This looks amazing! (and must totally be viewed in HD)

So unfortunate that this couldn’t be ported back to existing games. But I can’t wait to see this used in an RPG. I imagine the JRPG crowds will love something like this.

Comments Off

Upgrades and Data Constraints (The hidden TextArea trick)

Oh, the joys of updating or upgrading software that is not of your own work. Makes you truly realize how lucky you are for all that education you slept through in college.

Occasionally, I’ll get projects both inside and outside of work to add functionality to an existing application, sometimes without there being an internal development kit (meaning: creating an outside application to handle the new stuff externally).

There’s a large software package that I’ve been working on in my job for the last year that contains a sometimes useful internal “language” (thought it’s not truly a language, more like a markup set, with a way to write SQL commands to show tabular (or sometimes not so tabular) data) which allows me to retrieve information on a HTML page.

Well, we’re in the process of upgrading the software (which will occur during the summer, I hope), and so the data must translate between iterations. But due to the time difference, sometimes there is functionality in the newer version that does not exist in the older, and I have to find a way of mimicking the functionality.

If you have ever needed to store tabular data, such as when you have to store a list of check box values for one parent record,  into a single (usually co-opted) text field and all you have is HTML/JavaScript to use, you’re in luck. Explanation below.

In my example, you are recording which check boxes have been checked from a list of twenty, each labeled “Value 01″ thru “value 20″. Their values are 01 through 20. They are all named “datacbs”.

First, find a way of placing the data into a Text Area (or a hidden field): these unlimited spaces are great for storing a large amount of data. Hide the text area with a small piece of markup: style="display: none;", which you can then remove during testing.

Second, agree on a separator character (the most commonly used one is a comma). If you have multiple values per entry (such as an id and a value) choose two (like a comma to separate id from value, and a semicolon to separate complete entries) and then make sure everyone uses these rules.

Now the decision. If your check boxes are dynamic, you’ll need to include the ids and the values. Mine are static, so I will only need to include the values. I separate the values with a comma, since I know that none of my values will ever have a comma in it.

Set up the check boxes on the HTML page with the hidden text area:

<div id="divCBFields">
    <input name="datacbs" type="checkbox" value="1" />Value 01<br />
    <input name="datacbs" type="checkbox" value="2" />Value 02<br />
    <input name="datacbs" type="checkbox" value="3" />Value 03<br />
    ...
    <input name="datacbs" type="checkbox" value="20" />Value 20<br />
</div>
<textarea id="storeddata" name="storeddata"> </textarea>

Now for the JavaScript. You’ll need three functions: One to read the data and populate the checkboxes correctly, one to modify the text area after a click is registered on a check box, and one to add the event listeners to the check boxes.

The first, the AddListener() function, should be run in the body “onload” event (or in an in-place script block). Note that I gave the check boxes all the same name; this will make life much easier if the number of check boxes ever change.

function AddListeners() {
    var cbs = document.getElementsByName("datacbs");

    for (var i = 0; i < cbs.length; i++) {
        if (cbs[i].type == "checkbox") {
            if (cbs[i].attachEvent)
                cbs[i].attachEvent('onclick', updateTAData);
            else if (cbs[i].addEventListener)
                cbs[i].addEventListener('click', updateTAData, false);
        }
    }
}

Note that in this method, I attach a new event (without overwriting what’s already attached) to each check box.

The next method, updateTAData(), is the method that will be called every time a check box in the div container is clicked. It will take the value of the check box and add it to the text area data.

function updateTAData() {
    var finalval = "";
    var storeddata = document.getElementById("storeddata");
    var cbs = document.getElementsByName("datacbs");

    for (var i = 0; i < cbs.length; i++) {
        if (cbs[i].type == "checkbox" && cbs[i].checked) {
            if (finalval.length > 0) finalval += ",";
            finalval += cbs[i].value;
        }
    }

    storeddata.value = finalval;
}

You shouldn’t have any problem with this structure, especially if you want the check boxes spread over multiple containers, as long as you do as I did and name them all the same. There is also code out there for “getElementsByClassName()” that will allow you to assign a class to each checkbox and then gather them from that, but I am going bare-bones here. it’s your choice which you want to do. I personally choose it this way because I know that these check boxes are going to be the only thing named with this name (sometimes, you can’t tell if dynamic controls are created with a name you’re using in your code – best to be on the safe side and choose a longer, individual name)

The last function, readTAData(), is used after loading (which is handled like the event-attachment code; you can place it in the body onload event, or you can run it from a script block at the bottom of the page (or at least after the check boxes and text area).

function readTAData() {
    var storeddata = document.getElementById("storeddata");
    var cbs = document.getElementsByName("datacbs");

    var dataparts = storeddata.value.split(",");    for (var i = 0; i < dataparts.length; i++) {
        for (var a = 0; a < cbs.length; a++) {
            if (cbs[a].value == dataparts[i]) {
                cbs[a].checked = true;
                continue;
            }
        }
    }
}

Note that I have to loop through the entire list of check boxes for each value. (I included the “continue;” command to make the inner loop break and continue on to the next value from the outer loop. This speeds up the process a little). It’s not terribly fast, but it will work for a small set of check boxes. If you need to use a larger amount of check boxes (say, in the hundreds), you can always grab a nice search algorithm to speed things along.

Finally, if you hadn’t already put the two methods into the onload event of the body, you can simply add the following to the bottom of the HTML page (before the ending </body> tag, but below the text area and check boxes) to run the code on load.

<script language="javascript">
    AddListeners();
    readTAData();
</script>

Here endeth the lesson. That’s all that’s needed. If you don’t hide your text area, you can click the check boxes and watch it update the field. It’s quite neat. While anything I use is obviously going to be a little more intensely optimized and include application-specific code, this little “tutorial” should give you a good start on handling a set of data like this. Normally, and I can’t stress this enough, if you have multiple bits of data that references one object, don’t store it like this unless you don’t have a choice; create a new table and index it. Every time I see something like this I feel a little dirty, but sometimes you don’t have a choice.

Comments Off