summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2020-01-10 10:38:33 +0100
committerSimon Rettberg2020-01-10 10:38:33 +0100
commitc6c44769e246d4d73f5beffe5b40f8097461b746 (patch)
tree909efe9479b6376318252474262fe4db42cc61e3
parent[MakeTarball] Task for creating tar from text/blob data (diff)
downloadtmlite-bwlp-c6c44769e246d4d73f5beffe5b40f8097461b746.tar.gz
tmlite-bwlp-c6c44769e246d4d73f5beffe5b40f8097461b746.tar.xz
tmlite-bwlp-c6c44769e246d4d73f5beffe5b40f8097461b746.zip
[WakeOnLan] Native Java implementation
Gets rid of any dependency on installed tools.
-rw-r--r--src/main/java/org/openslx/taskmanager/tasks/WakeOnLan.java140
1 files changed, 102 insertions, 38 deletions
diff --git a/src/main/java/org/openslx/taskmanager/tasks/WakeOnLan.java b/src/main/java/org/openslx/taskmanager/tasks/WakeOnLan.java
index 36ec7d6..74b776d 100644
--- a/src/main/java/org/openslx/taskmanager/tasks/WakeOnLan.java
+++ b/src/main/java/org/openslx/taskmanager/tasks/WakeOnLan.java
@@ -1,30 +1,41 @@
package org.openslx.taskmanager.tasks;
-import java.util.Arrays;
+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.Exec;
-import org.openslx.satserver.util.Exec.ExecCallback;
import org.openslx.satserver.util.Util;
import org.openslx.taskmanager.api.AbstractTask;
import com.google.gson.annotations.Expose;
-public class WakeOnLan extends AbstractTask implements ExecCallback
+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 String[] cmdline;
private StatusObject status;
+ private byte[] buffer;
+
@Override
protected boolean initTask()
{
@@ -36,48 +47,101 @@ public class WakeOnLan extends AbstractTask implements ExecCallback
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;
- int xlen = Util.isEmpty( password ) ? 0 : 2;
- cmdline = new String[macs.length + 3 + xlen];
- cmdline[0] = "jawol";
- cmdline[1] = "-d";
- cmdline[2] = ip;
- if ( xlen != 0 ) {
- cmdline[3] = "-p";
- cmdline[4] = password;
+ 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;
+ }
}
- System.arraycopy( macs, 0, cmdline, 3 + xlen, macs.length );
- status.addMsg( "Command line: " + Arrays.toString( cmdline ) );
return true;
}
@Override
protected boolean execute()
{
- int ret;
- for ( int i = 0; i < 2; ++i ) {
- ret = Exec.sync( 1, this, cmdline );
- if ( ret != 0 )
- return false;
+ DatagramSocket sock = null;
+ try {
try {
- Thread.sleep( 800 );
- } catch ( InterruptedException e ) {
+ sock = new DatagramSocket();
+ sock.setBroadcast( true );
+ } catch ( SocketException e ) {
+ status.addMsg( "Cannot create UDP socket" );
+ return false;
}
- }
- return Exec.sync( 1, cmdline ) == 0;
- }
- @Override
- public void processStdOut( String line )
- {
- status.addMsg( line );
- }
+ // Sync bytes
+ for ( int i = 0; i < 6; ++i ) {
+ buffer[i] = -1;
+ }
- @Override
- public void processStdErr( String line )
- {
- status.addMsg( line );
+ // 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