Wake on Lan depuis votre téléphone

Soyez green, faites des économies d’énergie! Quoi, vous avez un serveur à la maison? assassin! Il ne sert pas forcément toute la journée en continu!

Oui, mais le problème c’est qu’on a pas forcément idée de quand on pourrait en avoir besoin… il faudrait pouvoir l’allumer et l’éteindre à distance juste quand on en a besoin. La fonction Wake-On-Lan de la majorité des cartes mères récentes (traduisez, ATX, ca fait quand même un bail) est là pour ça: elle permet en envoyant un “magic packet” sur le port ethernet de réveiller la machine: c’est comme appuyer sur le bouton “ON” à distance.

Ce qu’on va faire en quelques lignes, c’est écrire un petit programme qui nous permet de réveiller le PC ou son serveur à distance avec son téléphone mobile.

Le “magic packet” est composé de 6 fois 0xFF suivi de 16 fois l’adresse MAC de la machine à réveiller: facile à générer!

 Byte[] OutputBuffer = new Byte[102];

/* The first 6 bytes */
for (int i = 0; i < 6; i++)
    OutputBuffer[i] = 0xFF;

/* Then we parse the mac address, and put it into an intermediate buffer */
String StrippedMacAddress = Regex.Replace(tbMac.Text, "[^a-f0-9]", "");

if (StrippedMacAddress.Length != 12)
{
    MessageBox.Show("Please enter the mac address formatted as xx:xx:xx:xx:xx:xx");
    return;
}

Byte[] MacAddressBuffer = new Byte[6];
for (int i = 0; i < 6; i++)
{
    String s = StrippedMacAddress.Substring(i * 2, 2);
    MacAddressBuffer[i] = Byte.Parse(s, System.Globalization.NumberStyles.HexNumber);
}

/* Then we copy this Mac address 16 times */
for (int i = 6; i <= 96; i+=6)
    MacAddressBuffer.CopyTo(OutputBuffer, i);

Plusieurs choses à souligner dans ce petit bout de code:

  • D’abord l’utilisation de l’expression régulière permet de ne pas avoir à s’occuper de savoir comment l’utilisateur formatte son adresse mac (avec des :, ou des – ou des .). Ensuite on teste le nombre de caractères, c’est basique, et pas forcément élégant mais bon ca évite que l’utilisateur ne rentre n’importe quoi. Certes certain format “corrects” ne passeraient pas le test, mais on veut aussi garder le code simple :)
  • Pour la copie x16 de l’adresse MAC, il vaut mieux la convertir en tableau de byte avant… Dans le code dont je me suis inspiré, celui qui avait écrit le code refaisait un parsing de la chaine de caractère à chaque itération! Sur ce genre de petits bouts de code, le gain en optimisation n’est pas forcément critique, mais ca ne doit pas empêcher de faire les choses intelligement, car sur un téléphone mobile, il y a d’autres applications qui tournent en même temps! :)
  • Pour l’incrément de boucle, il peut paraitre étrange, à la base j’avais écrit ça:
 for (int i = 1; i <= 16; i++)
    MacAddressBuffer.CopyTo(OutputBuffer, i*6);

L’incrément est plus classique (i++) mais du coup on fait une multiplication à chaque fois. j’ai les multiplications en horreur (ça coute cher dans un micro embarqué) donc je préfère les éviter en utilisant i+=6. c’est surement du snobisme, mais bon… en attendant je gagne un tout petit peu de batterie :)

Bref, il reste à envoyer ce “magic packet”, et c’est l’affaire de quelques lignes:

 /* We're finally ready to send the packet, so let's do it! */
try
{
    IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(tbIpAddress.Text), int.Parse(tbPort.Text));
    UdpClient myUdpClient = new UdpClient();
    myUdpClient.Send(OutputBuffer, OutputBuffer.Length, remoteEndPoint);
    myUdpClient.Close();
}
catch (Exception ex)
{
    MessageBox.Show("Problem sending the WOL Datagram:\r\n" + ex.Message, "Datagram not sent", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
}

 

Je n’inclue pas le code du formulaire, archi-simple, qui contient 3 text box et deux soft keys (à préférer aux boutons, non disponible dans le SDK standard pour les terminaux sans touchscreen!): un pour quitter, un pour lancer envoyer le magic packet: Vous aurez compris que tbMac est la TextBox pour l’adresse MAC, tbIpAddress pour l’adresse IP, et tbPort le numéro de port.

Quoi, un numéro de port???

Ben oui, parce que le serveur il est derrière une box, et donc il faut paramétrer la box pour laisser passer le magic packet par un certain port: choisissez celui qui vous plait! en fait la machine à réveiller n’en a rien à faire, du port sur lequel elle reçoit le magic packet: c’est juste histoire de passer le firewall!

Merci Blaise pour l’idée, le bout de code de référence (même si c’était du VB!)!