package org.openslx.taskmanager.tasks; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openslx.satserver.util.Util; import org.openslx.taskmanager.api.AbstractTask; import com.google.gson.annotations.Expose; public class WakeOnLan extends AbstractTask { private static final Pattern RE_IPv4 = Pattern.compile( "^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$" ); private static final Pattern RE_MAC = Pattern.compile( "^([0-9a-f]{2})[:-]([0-9a-f]{2}+)[:-]([0-9a-f]{2}+)[:-]([0-9a-f]{2}+)[:-]([0-9a-f]{2}+)[:-]([0-9a-f]{2}+)$", Pattern.CASE_INSENSITIVE ); @Expose private String[] macs; @Expose private String ip; @Expose private String password; private StatusObject status; private byte[] buffer; @Override protected boolean initTask() { status = new StatusObject(); this.setStatusObject( status ); if ( macs == null || macs.length == 0 ) { status.addMsg( "Macs empty" ); } if ( Util.isEmpty( ip ) ) { status.addMsg( "IP empty" ); } int pwlen = 0; Matcher m = null; if ( !Util.isEmpty( password ) ) { m = RE_IPv4.matcher( password ); if ( m.matches() ) { pwlen = 4; } else { m = RE_MAC.matcher( password ); if ( m.matches() ) { pwlen = 6; } } if ( pwlen == 0 ) { status.addMsg( "Invalid password format: " + password ); } } if ( !Util.isEmpty( status.messages ) ) return false; buffer = new byte[ 17 * 6 + pwlen ]; if ( pwlen != 0 ) { try { for ( int i = 0; i < pwlen; ++i ) { int x = Integer.parseInt( m.group( i + 1 ), pwlen == 4 ? 10 : 16 ); buffer[17 * 6 + i] = (byte)x; } } catch ( Throwable t ) { status.addMsg( "Invalid octet in password" ); return false; } } return true; } @Override protected boolean execute() { DatagramSocket sock = null; try { try { sock = new DatagramSocket(); sock.setBroadcast( true ); } catch ( SocketException e ) { status.addMsg( "Cannot create UDP socket" ); return false; } // Sync bytes for ( int i = 0; i < 6; ++i ) { buffer[i] = -1; } // Repeat three times for ( int reps = 0; reps < 3; ++reps ) { if ( reps != 0 ) { try { Thread.sleep( 600 ); } catch ( InterruptedException t ) { Thread.currentThread().interrupt(); break; } } // For each MAC for ( int mi = 0; mi < macs.length; ++mi ) { Matcher m = RE_MAC.matcher( macs[mi] ); if ( !m.matches() ) { status.addMsg( "Cannot parse MAC address " + macs[mi] ); continue; } try { for ( int i = 0; i < 6; ++i ) { byte x = (byte)Integer.parseInt( m.group( i + 1 ), 16 ); for ( int offset = 0; offset < 16; ++offset ) { buffer[6 + offset * 6 + i] = x; } } } catch ( NumberFormatException e ) { status.addMsg( "Invalid octet in MAC address: " + macs[mi] ); continue; } DatagramPacket dp = new DatagramPacket( buffer, buffer.length, InetAddress.getByName( ip ), 9 ); try { sock.send( dp ); status.addMsg( "Sent packet to " + macs[mi] ); } catch ( IOException e ) { status.addMsg( "Error sending UDP packet to " + ip + "/" + macs[mi] + ": " + e.toString() ); } } } } catch ( UnknownHostException e ) { status.addMsg( "Cannot resolve " + ip ); return false; } finally { Util.multiClose( sock ); } return true; } class StatusObject { private String messages = ""; public void addMsg( String str ) { messages = messages + "\n" + str; } } }