CrossJeeves Works!

This commit is contained in:
Flare Microsystems
2024-11-13 20:05:59 -08:00
parent f768ec0aa5
commit fd13c3d046
34 changed files with 399 additions and 103 deletions

View File

@@ -2,7 +2,7 @@
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="lib" path="/tool/junit4/mockito-core-2.28.2.jar"/>
<classpathentry kind="lib" path="/tool/junit4/byte-buddy-1.9.16.jar"/>

View File

@@ -1,11 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.5
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -11,4 +11,9 @@ public class AgentInfo {
this.addr = addr;
this.port = port;
}
public String toString()
{
return addr.toString() + " " + port;
}
}

View File

@@ -18,14 +18,16 @@ public class CrossJeevesClient {
}
public void beginJob() {
System.out.println("Trying to connect to agent");
for(int i = 0; i < MAX_ATTEMPTS; i++)
{
for(AgentInfo agent : agentList)
{
System.out.println("Trying agent " + agent.toString());
int exitCode = ClientHandler.connect(agent.addr, agent.port, script);
if(ErrorCodes.getErrorCode(exitCode) == null || ErrorCodes.getErrorCode(exitCode).isTerminal)
{
System.out.println("Recieved terminal exit code " + exitCode);
System.err.println("Recieved terminal exit code " + exitCode);
System.exit(exitCode);
}
else if(exitCode == ErrorCodes.OK.id)
@@ -34,7 +36,19 @@ public class CrossJeevesClient {
System.exit(0);
}
}
try
{
Thread.sleep(1000L);
System.out.println("Failed every agent, retrying...");
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.err.println("Failed every attempt!");
System.exit(ErrorCodes.CONNECT_FAILED.id);
}
}

View File

@@ -49,6 +49,7 @@ public class CrossJeevesHost {
//TODO properties!
ServerHandler handler = new ServerHandler(sock, this, new Properties());
connections.add(handler);
handler.init();
}
catch (IOException ex)
{

View File

@@ -52,10 +52,10 @@ public class CrossJeevesMain {
System.out.println("IP must be specified");
System.exit(1);
}
String ipStr = args[0];
String ipStr = agentArgs[0];
String portStr = "10801";
if(args.length >= 2)
portStr = args[1];
if(agentArgs.length >= 2)
portStr = agentArgs[1];
try
{
int port = Integer.parseInt(portStr);

View File

@@ -22,8 +22,11 @@ import org.xml.sax.InputSource;
import com.flaremicro.crossjeeves.net.ErrorCodes;
import com.flaremicro.crossjeeves.net.NetworkHandler;
import com.flaremicro.crossjeeves.net.StreamForwarder;
import com.flaremicro.crossjeeves.net.packet.Packet;
import com.flaremicro.crossjeeves.net.packet.Packet3Clone;
import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry;
import com.flaremicro.util.Util;
import com.flaremicro.util.ZipUtils;
public class ScriptProcessor {
@@ -34,6 +37,7 @@ public class ScriptProcessor {
private Random random = new Random();
private Thread executionThread = null;
private File workspace = null;
private File workingDirectory = null;
private boolean terminated = false;
public ScriptProcessor(NetworkHandler netHandler, File workspace, Properties properties) {
@@ -65,6 +69,7 @@ public class ScriptProcessor {
}
public void processScript(String script) throws ScriptProcessingException {
workingDirectory = workspace;
if(terminated)
throw new ScriptProcessingException("Processor has been terminated");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
@@ -76,6 +81,19 @@ public class ScriptProcessor {
NodeList nodeList = doc.getDocumentElement().getChildNodes();
processScriptNodes(nodeList);
}
catch (ScriptProcessingException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new ScriptProcessingException("Script threw an exception during processing" ,ex);
}
}
private void processScriptNodes(NodeList nodeList) throws ScriptProcessingException {
for (int i = 0; i < nodeList.getLength(); i++)
{
if(terminated)
@@ -114,6 +132,11 @@ public class ScriptProcessor {
{
powershellProcessor(e);
}
else if (name.equalsIgnoreCase("dir"))
{
dirProcessor(e);
}
else if (name.equalsIgnoreCase("artifacts"))
{
artifactProcessor(e);
@@ -124,14 +147,13 @@ public class ScriptProcessor {
}
}
}
catch (ScriptProcessingException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new ScriptProcessingException("Script threw an exception during processing" ,ex);
}
private void dirProcessor(Element e) throws ScriptProcessingException {
NodeList nodeList = e.getChildNodes();
File lastWorkingDirectory = this.workingDirectory;
this.workingDirectory = new File(workingDirectory, this.requireAttribute(e, "path"));
this.processScriptNodes(nodeList);
this.workingDirectory = lastWorkingDirectory;
}
public void environmentProcessor(Element e) throws ScriptProcessingException {
@@ -167,7 +189,7 @@ public class ScriptProcessor {
File file = netHandler.waitForFile(id);
if (file == null)
throw new ScriptProcessingException("File failed to transfer");
if(!ZipUtils.unzipDirectory(file, workspace));
if(!ZipUtils.unzipDirectory(file, workspace))
throw new ScriptProcessingException("File failed to decompress");
}
@@ -204,8 +226,10 @@ public class ScriptProcessor {
public int beginProcess(String... args) throws ScriptProcessingException {
ProcessBuilder processBuilder = new ProcessBuilder(args);
processBuilder.directory(workspace);
Map<String, String> environment = processBuilder.environment();
for (Entry<String, String> set : currentEnvironment.entrySet())
{
environment.put(set.getKey(), set.getValue());
@@ -216,13 +240,31 @@ public class ScriptProcessor {
try
{
runningProcess = processBuilder.start();
return runningProcess.exitValue();
StreamForwarder stdOutForwarder = new StreamForwarder(netHandler, runningProcess.getInputStream(), Packet7LogEntry.STD_OUT);
StreamForwarder stdErrForwarder = new StreamForwarder(netHandler, runningProcess.getErrorStream(), Packet7LogEntry.STD_ERR);
stdOutForwarder.startAsync();
stdErrForwarder.startAsync();
int exit = runningProcess.waitFor();
stdOutForwarder.end();
stdErrForwarder.end();
return exit;
}
catch (IOException ex)
{
runningProcess = null;
throw new ScriptProcessingException("Unable to run batch script: " + ex.getMessage(), ex);
}
catch (InterruptedException ex)
{
runningProcess.destroy();
runningProcess = null;
throw new ScriptProcessingException("Batch script interrupted: " + ex.getMessage(), ex);
}
}
private void batchProcessor(Element e) throws ScriptProcessingException {
@@ -267,10 +309,11 @@ public class ScriptProcessor {
try
{
processScript(script);
netHandler.disconnect(ErrorCodes.OK.id, "Script completed successfully!");
}
catch (ScriptProcessingException e)
{
netHandler.disconnect(ErrorCodes.SCRIPT_ERROR.id, e.toString());
netHandler.disconnect(ErrorCodes.SCRIPT_ERROR.id, Util.getStackTrace(e));
e.printStackTrace();
}
finally

View File

@@ -18,6 +18,7 @@ import com.flaremicro.crossjeeves.net.packet.Packet3Clone;
import com.flaremicro.crossjeeves.net.packet.Packet4FileData;
import com.flaremicro.crossjeeves.net.packet.Packet5Artifact;
import com.flaremicro.crossjeeves.net.packet.Packet6Disconnect;
import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry;
import com.flaremicro.util.Util;
import com.flaremicro.util.ZipUtils;
@@ -30,6 +31,7 @@ public class ClientHandler extends NetworkHandler {
}
private void init() {
System.out.println("CrossJeeves connected! Sending Identify packet...");
enqueue(new Packet0Identify(0));
this.beginWriteThread();
this.beginReading();
@@ -48,6 +50,7 @@ public class ClientHandler extends NetworkHandler {
}
else
{
System.out.println("Got good identify packet response! Sending script...");
enqueue(new Packet2Script(script));
}
}
@@ -147,4 +150,12 @@ public class ClientHandler extends NetworkHandler {
}
}
@Override
public void handlePacket(Packet7LogEntry packet) {
if(packet.getStdOutput() == Packet7LogEntry.STD_ERR)
System.err.println(packet.getLogEntry());
else
System.out.println(packet.getLogEntry());
}
}

View File

@@ -4,11 +4,14 @@ package com.flaremicro.crossjeeves.net;
* Consider replacing with enum in the near future.
*/
public class ErrorCodes {
private static final ErrorCodes codes[] = new ErrorCodes[13];
public static final ErrorCodes OK = new ErrorCodes(0, false);
public static final ErrorCodes READ_FAILED = new ErrorCodes(1, false);
public static final ErrorCodes WRITE_FAILED = new ErrorCodes(2, false);
public static final ErrorCodes THREAD_INTERRUPTED = new ErrorCodes(3, false);
public static final ErrorCodes SCRIPT_ERROR = new ErrorCodes(4, false);
public static final ErrorCodes SCRIPT_ERROR = new ErrorCodes(4, true);
public static final ErrorCodes FILE_DOWNLOAD_FAILURE = new ErrorCodes(5, false);
public static final ErrorCodes FILE_UPLOAD_FAILURE = new ErrorCodes(6, false);
public static final ErrorCodes INVALID_PACKET_RECIEVED = new ErrorCodes(7, false);
@@ -18,8 +21,6 @@ public class ErrorCodes {
public static final ErrorCodes AGENT_TERMINATED = new ErrorCodes(11, false);
public static final ErrorCodes CONNECT_FAILED = new ErrorCodes(12, false);
private static final ErrorCodes codes[] = new ErrorCodes[12];
public final int id;
public final boolean isTerminal;
public ErrorCodes(int id, boolean isTerminal)

View File

@@ -22,6 +22,7 @@ import com.flaremicro.crossjeeves.net.packet.Packet3Clone;
import com.flaremicro.crossjeeves.net.packet.Packet4FileData;
import com.flaremicro.crossjeeves.net.packet.Packet5Artifact;
import com.flaremicro.crossjeeves.net.packet.Packet6Disconnect;
import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry;
import com.flaremicro.util.Util;
import static com.flaremicro.crossjeeves.net.ErrorCodes.*;
@@ -31,6 +32,7 @@ public abstract class NetworkHandler {
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private Thread writeThread;
private Thread readThread;
private int exitCode = 0;
private HashMap<Long, FileTransferInfo> downloadQueue = new HashMap<Long, FileTransferInfo>();
@@ -49,7 +51,11 @@ public abstract class NetworkHandler {
{
while (true)
{
synchronized (downloadComplete)
{
if (!downloadComplete.containsKey(fileId))
downloadComplete.wait();
}
File file = downloadComplete.get(fileId);
if (file != null)
return file;
@@ -67,7 +73,14 @@ public abstract class NetworkHandler {
}
public void enqueue(Packet packet) {
outbox.add(packet);
try
{
outbox.put(packet);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void process(Packet packet) {
@@ -75,14 +88,18 @@ public abstract class NetworkHandler {
}
public void disconnect(int code, String message) {
if (isConnected())
{
System.out.println("Disconnect code " + code + ": " + message);
doDisconnect(code);
}
}
protected void doDisconnect(int exitCode) {
this.exitCode = exitCode;
connected = false;
readThread.interrupt();
if (writeThread != null)
writeThread.interrupt();
Util.cleanClose(in);
Util.cleanClose(out);
Util.cleanClose(socket);
@@ -98,7 +115,7 @@ public abstract class NetworkHandler {
try
{
int opcode = in.readByte();
Packet packet = Packet.opToPacket.get(opcode);
Packet packet = Packet.opToPacket.get((byte) opcode);
if (packet != null)
{
packet = packet.cloneTypeOnly();
@@ -107,15 +124,32 @@ public abstract class NetworkHandler {
}
}
catch (IOException e)
{
if (connected)
{
e.printStackTrace();
disconnect(READ_FAILED.id, e.toString());
}
}
}
}
protected void beginReadThread() {
if (readThread == null)
{
readThread = new Thread(new Runnable() {
public void run() {
beginReading();
}
});
readThread.start();
}
}
protected void beginWriteThread() {
readThread = new Thread(new Runnable() {
if (writeThread == null)
{
writeThread = new Thread(new Runnable() {
public void run() {
while (connected)
{
@@ -136,14 +170,19 @@ public abstract class NetworkHandler {
}
}
catch (InterruptedException e)
{
if (connected)
{
disconnect(THREAD_INTERRUPTED.id, e.toString());
e.printStackTrace();
}
}
}
writeThread = null;
}
});
readThread.start();
writeThread.start();
}
}
public abstract void handlePacket(Packet packet);
@@ -162,6 +201,8 @@ public abstract class NetworkHandler {
public abstract void handlePacket(Packet6Disconnect packet);
public abstract void handlePacket(Packet7LogEntry packet);
public abstract void handlePacket(Packet127KeepAlive packet);
public void clearFile(long fileId) {
@@ -203,8 +244,11 @@ public abstract class NetworkHandler {
{
Util.cleanClose(fileTransferInfo);
this.downloadComplete.put(fileId, fileTransferInfo.file);
synchronized (this.downloadComplete)
{
this.downloadComplete.notifyAll();
}
}
else
{
fileTransferInfo.outputStream.write(chunk);

View File

@@ -19,6 +19,7 @@ import com.flaremicro.crossjeeves.net.packet.Packet3Clone;
import com.flaremicro.crossjeeves.net.packet.Packet5Artifact;
import com.flaremicro.crossjeeves.net.packet.Packet4FileData;
import com.flaremicro.crossjeeves.net.packet.Packet6Disconnect;
import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry;
public class ServerHandler extends NetworkHandler {
private CrossJeevesHost host;
@@ -31,6 +32,20 @@ public class ServerHandler extends NetworkHandler {
this.scriptProcessor = new ScriptProcessor(this, workspace, properties);
}
public void disconnect(int code, String message) {
enqueue(new Packet6Disconnect(code, message));
try
{
Thread.sleep(1000L);
}
catch (InterruptedException e)
{
if(isConnected())
e.printStackTrace();
}
super.disconnect(code, message);
}
@Override
protected void doDisconnect(int exitCode)
{
@@ -46,6 +61,7 @@ public class ServerHandler extends NetworkHandler {
@Override
public void handlePacket(Packet0Identify packet) {
System.out.println("Got valid identify packet with flags " + packet.getFlags() + " and version " + packet.getProtocolVersion());
enqueue(new Packet0Identify(0));
}
@@ -61,7 +77,14 @@ public class ServerHandler extends NetworkHandler {
@Override
public void handlePacket(Packet3Clone packet) {
disconnect(INVALID_PACKET_RECIEVED.id, "Recieved invalid packet " + packet.getId() + " (Clone)");
try
{
this.beginFile(packet.getFileID(), packet.getFileSize());
}
catch (IOException e)
{
disconnect(FILE_DOWNLOAD_FAILURE.id, "Failed to start download of transferred file");
}
}
@Override
@@ -92,4 +115,15 @@ public class ServerHandler extends NetworkHandler {
doDisconnect(packet.getCode());
}
public void init() {
this.beginWriteThread();
this.beginReadThread();
}
@Override
public void handlePacket(Packet7LogEntry packet) {
// TODO Auto-generated method stub
}
}

View File

@@ -0,0 +1,98 @@
package com.flaremicro.crossjeeves.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry;
import com.flaremicro.util.Util;
/* TODO
* Forward output from entire process, rather than just from started processes?
*/
public class StreamForwarder {
private InnerThread innerThread;
public StreamForwarder(NetworkHandler handler, InputStream processInput, byte stdType) {
innerThread = new InnerThread(handler, processInput, stdType);
}
public void startAsync() {
innerThread.start();
}
public void end() {
innerThread.stop();
}
private class InnerThread implements Runnable {
private Thread parent = null;
private final NetworkHandler handler;
private final InputStream processInput;
private final byte stdType;
private boolean isRunning = false;
public InnerThread(NetworkHandler handler, InputStream processInput, byte stdType) {
this.handler = handler;
this.processInput = processInput;
this.stdType = stdType;
}
public void stop() {
isRunning = false;
}
public void start() {
if (!isRunning && parent != null)
{
isRunning = true;
parent = new Thread(this);
parent.start();
}
}
public void print(String s)
{
if(stdType == Packet7LogEntry.STD_ERR)
System.err.println(s);
else
System.out.println(s);
}
@Override
public void run() {
BufferedReader reader = null;
try
{
reader = new BufferedReader(new InputStreamReader(processInput));
String line;
while (isRunning && (line = reader.readLine()) != null)
{
handler.enqueue(new Packet7LogEntry(stdType, line));
print(line);
}
if (processInput.available() > 0)
{
byte[] remaining = new byte[processInput.available()];
processInput.read(remaining);
line = new String(remaining);
print(line);
handler.enqueue(new Packet7LogEntry(stdType, line));
}
parent = null;
}
catch (IOException ex)
{
ex.printStackTrace();
handler.enqueue(new Packet7LogEntry(stdType, "Error occured:" + ex.toString() + ", logging ended."));
print("Error occured, logging ended.");
}
finally
{
Util.cleanClose(reader);
}
}
}
}

View File

@@ -1,29 +1,31 @@
package com.flaremicro.util;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipFile;
public class Util {
public static Map<String, String> parseArgs(String[] args, boolean toLowercaseKey, boolean exceptOnDuplicateKey)
{
public static Map<String, String> parseArgs(String[] args, boolean toLowercaseKey, boolean exceptOnDuplicateKey) {
Map<String, String> map = new HashMap<String, String>();
for (String arg : args)
{
System.out.println(arg);
String key, value;
if (arg.contains("="))
{
String[] param = arg.split("=", 1);
String[] param = arg.split("=", 2);
key = param[0];
value = param[1];
}
else
{
key = arg;
value = "isset";
value = "";
}
if (!map.containsKey(value))
{
@@ -78,4 +80,26 @@ public class Util {
}
}
}
/**
* Get the stacktrace of a {@link Throwable}.
* The stacktrace will be returned in the form of a string.
*/
public static String getStackTrace(Throwable ex) {
if (ex == null)
return "";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter printWriter = new PrintWriter(baos, true);
ex.printStackTrace(printWriter);
String stackTrace = baos.toString();
try
{
printWriter.close();
baos.close();
}
catch (IOException dontCare)
{
}
return stackTrace;
}
}

1
txt.txt Normal file
View File

@@ -0,0 +1 @@
there should be some output

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1 @@