diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4792ee0..a3da5c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,13 +17,8 @@ compile: tests: stage: test - script: - - "./certs-gen.sh" - - "./gradlew test" + script: "./gradlew test" package: stage: deploy - script: - - "./certs-gen.sh" - - "./gradlew build" - - "./package.sh" + script: "./package.sh" diff --git a/buildwrapper.sh b/buildwrapper.sh deleted file mode 100755 index 68d90e1..0000000 --- a/buildwrapper.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -./certs-gen.sh -./gradlew clean build -./package.sh diff --git a/certs-gen.sh b/certs-gen.sh index 81d28a2..2845f7c 100755 --- a/certs-gen.sh +++ b/certs-gen.sh @@ -13,7 +13,6 @@ if [ -z "$CLTNAME" ]; then CLTNAME=localhost fi - SERVER_CA_CN=jobserv-server-ca SERVER_PATH=resources/server CLIENT_CA_CN=jobserv-client-ca @@ -96,4 +95,3 @@ echo "[+] Converting private keys to X.509" openssl pkcs8 -topk8 -nocrypt -in $CLIENT_PATH/private.key -out $CLIENT_PATH/private.pem openssl pkcs8 -topk8 -nocrypt -in $SERVER_PATH/private.key -out $SERVER_PATH/private.pem openssl pkcs8 -topk8 -nocrypt -in $TEST_PATH/private.key -out $TEST_PATH/private.pem - diff --git a/src/main/java/JobServ/ProcessController.java b/src/main/java/JobServ/ProcessController.java index b576211..f7d4cef 100644 --- a/src/main/java/JobServ/ProcessController.java +++ b/src/main/java/JobServ/ProcessController.java @@ -8,14 +8,11 @@ package JobServ; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; +import java.io.BufferedReader; /* * ProcessController @@ -36,23 +33,18 @@ class ProcessController { private BufferedReader reader; private Process process; - private Boolean killedManually = false; - private Lock lock; - private int lockTimeout; // seconds + private Boolean killedManually = false; /* * Constructor * Takes a command and spawns it in a new process * Redirects IO streams and assigns a fake PID */ - public ProcessController(String command, int lockTimeout) throws IOException { + public ProcessController(String command) throws IOException { this.pid = ProcessController.nextPid; ProcessController.nextPid += 1; - this.lock = new ReentrantLock(); - this.lockTimeout = lockTimeout; - this.process = Runtime.getRuntime().exec(command); this.output = this.process.getOutputStream(); this.input = this.process.getInputStream(); @@ -62,28 +54,6 @@ class ProcessController { JobServServer.logger.write("Job " + String.valueOf(this.pid) + ": " + command); } - /* - * getLock() - * attempts to get the lock for lockTimeout seconds - * or throws exceptions if interrupted - */ - public boolean getLock() throws InterruptedException { - return this.lock.tryLock(this.lockTimeout, TimeUnit.SECONDS); - } - - /* - * releaseLock() - * releases lock on process - */ - public void releaseLock() { - try { - this.lock.unlock(); - - } catch (IllegalMonitorStateException e) { - JobServServer.logger.write("Thread tried to release a lock it didnt have! " + e.getMessage()); - } - } - /* * getPid() * returns translated pid of this process diff --git a/src/main/java/JobServ/ProcessManager.java b/src/main/java/JobServ/ProcessManager.java index 83ea830..14ac67d 100644 --- a/src/main/java/JobServ/ProcessManager.java +++ b/src/main/java/JobServ/ProcessManager.java @@ -40,6 +40,7 @@ class ProcessManager { * processMap */ protected ConcurrentHashMap processMap; + protected ConcurrentHashMap lockMap; private ExecutorService threadPool = Executors.newCachedThreadPool(); /* @@ -48,6 +49,7 @@ class ProcessManager { */ public ProcessManager() { processMap = new ConcurrentHashMap(); + lockMap = new ConcurrentHashMap(); /* TODO: In a long running server over a large period of time * It is possible that the streams used to redirect IO in the * Processes may become a significant use of resources. @@ -66,8 +68,12 @@ class ProcessManager { public int newProcess(String command) { try { - ProcessController newProc = new ProcessController(command, this.LOCK_TIMEOUT); + ProcessController newProc = new ProcessController(command); + // we dont need to lock the map yet + this.lockMap.put(newProc.getPid(), true); this.processMap.put(newProc.getPid(), newProc); + + this.releaseLock(newProc.getPid()); return newProc.getPid(); } catch (IOException e) { @@ -89,13 +95,14 @@ class ProcessManager { public int getProcessStatus(int pid) { try { if(!this.getLock(pid)) { - // lock could not be grabbed before timeout - JobServServer.logger.write("Timeout getting process status: " + String.valueOf(pid)); - return 4; + return 3; } - } catch (IndexOutOfBoundsException e) { - return 3; + } catch (TimeoutException e) { + // lock could not be grabbed before timeout + JobServServer.logger.write("Timeout getting process " + + String.valueOf(pid) + " status: " + e.getMessage()); + return 4; } ProcessController candidate = this.processMap.get(pid); @@ -116,12 +123,13 @@ class ProcessManager { public int getProcessReturn(int pid) { try { if(!this.getLock(pid)) { - JobServServer.logger.write("Timeout getting process return: " + String.valueOf(pid)); - return 259; + return 258; } - } catch (IndexOutOfBoundsException e) { - return 258; + } catch (TimeoutException e) { + JobServServer.logger.write("Timeout getting process " + + String.valueOf(pid) + " return: " + e.getMessage()); + return 259; } ProcessController candidate = this.processMap.get(pid); @@ -138,12 +146,13 @@ class ProcessManager { public String getProcessOutput(int pid, int lines) { try { if(!this.getLock(pid)) { - JobServServer.logger.write("Timeout getting process output: " + String.valueOf(pid)); - return "[-] SERVER: Timeout grabbing lock to access process information"; + return "[-] SERVER: Process not found"; } - } catch (IndexOutOfBoundsException e) { - return "[-] SERVER: Process not found"; + } catch (TimeoutException e) { + JobServServer.logger.write("Timeout getting process " + + String.valueOf(pid) + " output: " + e.getMessage()); + return "[-] SERVER: Timeout grabbing lock to access process information"; } ProcessController candidate = this.processMap.get(pid); @@ -163,13 +172,13 @@ class ProcessManager { public int killProcess(int pid) { try { if(!this.getLock(pid)) { - JobServServer.logger.write("Timeout killing process: " + String.valueOf(pid)); - return 3; + return 2; } - } catch (IndexOutOfBoundsException e) { - - return 2; + } catch (TimeoutException e) { + JobServServer.logger.write("Timeout killing process " + + String.valueOf(pid) + ": " + e.getMessage()); + return 3; } ProcessController candidate = this.processMap.get(pid); @@ -185,20 +194,45 @@ class ProcessManager { * Function is synchronized to prevent multiple threads accessing the same lock at once * (ConcurrentHashMap will report whatever lock value was last to successfully update) */ - protected synchronized Boolean getLock(int pid) throws IndexOutOfBoundsException { - ProcessController candidate = this.processMap.get(pid); - if (candidate == null) { - throw new IndexOutOfBoundsException(); + protected synchronized Boolean getLock(int pid) throws TimeoutException { + if (!lockMap.containsKey(pid)) { + return false; } + Future future = this.threadPool.submit( + new Callable() { + public Object call() { + while(lockMap.get(pid)) { + continue; // spin! + } + + lockMap.replace(pid, true); + return 1; + } + }); + try { - Boolean success = candidate.getLock(); - return success; + future.get(this.LOCK_TIMEOUT, TimeUnit.SECONDS); } catch (InterruptedException e) { JobServServer.logger.write("[!] Couldnt get lock " + String.valueOf(pid) + ": "+ e.getMessage()); + future.cancel(true); + + // in case lock was grabbed after exception + this.releaseLock(pid); return false; + + } catch (ExecutionException e) { + JobServServer.logger.write("[!] Couldnt get lock " + + String.valueOf(pid) + ": "+ e.getMessage()); + future.cancel(true); + + // in case lock was grabbed after exception + this.releaseLock(pid); + return false; + + // cancel the attempt to grab the lock } /* @@ -213,6 +247,8 @@ class ProcessManager { * mediate access to the ProcessManager * object for fresh calls as well. */ + + return true; } /* @@ -220,13 +256,7 @@ class ProcessManager { * releases mutex so other threads can operate on processqueue */ protected void releaseLock(int pid) { - ProcessController candidate = this.processMap.get(pid); - if (candidate == null) { - JobServServer.logger.write("Tried to release lock of process that doesnt exist!"); - return; - } - - candidate.releaseLock(); + this.lockMap.put(pid, false); } /* diff --git a/src/test/java/JobServ/ProcessManagerTestImplementation.java b/src/test/java/JobServ/ProcessManagerTestImplementation.java index de61a36..58594b5 100644 --- a/src/test/java/JobServ/ProcessManagerTestImplementation.java +++ b/src/test/java/JobServ/ProcessManagerTestImplementation.java @@ -27,10 +27,18 @@ class ProcessManagerTestImplementation extends ProcessManager { super.releaseLock(pid); + } catch (TimeoutException e) { + System.err.println("[!!] Long Call wasnt able to grab lock!"); + return; + } catch (InterruptedException e) { super.releaseLock(pid); // this doesnt happen, dont cancel this task System.err.println("[3] Released lock: interrupted"); return; } } + + public Boolean reportLockState(int pid) { + return super.lockMap.get(pid); + } }