/*
* Copyright (c) 2010 Ecole des Mines de Nantes.
*
* This file is part of Entropy.
*
* Entropy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Entropy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Entropy. If not, see <http://www.gnu.org/licenses/>.
*/
package entropy.execution.driver;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import entropy.plan.action.Startup;
/**
* Driver to boot a node using Wake-On-Lan.
* As this method is not sure, the magic packet can be sent multiple times.
* @author Fabien Hermenier
*
*/
public class WoLStartup extends Driver {
/**
* Default destination port to send the magic packet.
*/
public static final int DEFAULT_PORT = 9;
/**
* The number of magic packets to send.
*/
private int nbPackets;
/**
* Default number of magic packets to send.
*/
public static final int DEFAULT_NB_PACKETS = 10;
/**
* The action to execute.
*/
private Startup st;
/**
* Make a new concrete startup action.
* @param action the startup action
*/
public WoLStartup(Startup action) {
super(action);
this.st = action;
this.nbPackets = DEFAULT_NB_PACKETS;
}
/**
* Set the number of packets to send.
* @param nb a positive
*/
public void setNbPackets(int nb) {
this.nbPackets = nb;
}
/**
* Parse the MAC address.
* @param mac the mac in a String format: 6 hexadecimal number each separated by "-" or ":"
* @return a array of 6 bytes
*/
private static byte[] getMacBytes(String mac) {
byte[] bytes = new byte[6];
String[] hex = mac.split("(\\:|\\-)");
if (hex.length != 6) {
throw new NumberFormatException("Invalid MAC address.");
}
for (int i = 0; i < 6; i++) {
bytes[i] = (byte) Integer.parseInt(hex[i], 16);
}
return bytes;
}
/**
* Execute the startup action by sending magic packets.
* @throws DriverException if an error occurs.
*/
@Override
public void execute() throws DriverException {
try {
InetAddress ip = InetAddress.getByName(this.st.getNode().getName());
String mac = this.st.getNode().getMACAddress();
if (mac == null) {
throw new DriverException(this, "Unable to get the MAC Address of the node '" + this.st.getNode().getName() + "'");
}
byte[] macBytes = getMacBytes(mac);
byte[] bytes = new byte[6 + 16 * macBytes.length];
for (int i = 0; i < 6; i++) {
bytes[i] = (byte) 0xff;
}
for (int i = 6; i < bytes.length; i += macBytes.length) {
System.arraycopy(macBytes, 0, bytes, i, macBytes.length);
}
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, ip, DEFAULT_PORT);
DatagramSocket socket = new DatagramSocket();
for (int i = 0; i < this.getNbPackets(); i++) {
socket.send(packet);
}
socket.close();
} catch (IOException e) {
throw new DriverException(this, e.getMessage(), e);
} catch (NumberFormatException e) {
throw new DriverException(this, "Failed at sending the magic packet", e);
}
}
/**
* Get the number of magic packets that are sent.
* @return a positive integer
*/
public int getNbPackets() {
return this.nbPackets;
}
@Override
public String toString() {
return "wol(" + this.st.toString() + ")";
}
}