summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2020-07-20 17:01:17 +0200
committerSimon Rettberg2020-07-20 17:01:17 +0200
commita39496a125170163a93c557547156f7073c0e532 (patch)
tree52f21e0458243bbabe739630e5ada1d9e8e876ae
parentFix off-by-one when displaying tunnel count on close event (diff)
downloadbwlp-guacamole-ext-a39496a125170163a93c557547156f7073c0e532.tar.gz
bwlp-guacamole-ext-a39496a125170163a93c557547156f7073c0e532.tar.xz
bwlp-guacamole-ext-a39496a125170163a93c557547156f7073c0e532.zip
Refine timeout handling of dead/removed clients
A client that was just claimed gets a one minute grace period before the "no active tunnel detection" can kick in. This prevents a race where the client gets claimed and then a json update is performed before the tunnel connection is established. Also the removal of clients that are missing from the remote meta data is hopefully more robust now, not removing a client as long as there is an active user and an open tunnel connection.
-rw-r--r--src/main/java/de/bwlehrpool/bwlp_guac/AvailableClient.java49
1 files changed, 36 insertions, 13 deletions
diff --git a/src/main/java/de/bwlehrpool/bwlp_guac/AvailableClient.java b/src/main/java/de/bwlehrpool/bwlp_guac/AvailableClient.java
index 5371547..aa7506d 100644
--- a/src/main/java/de/bwlehrpool/bwlp_guac/AvailableClient.java
+++ b/src/main/java/de/bwlehrpool/bwlp_guac/AvailableClient.java
@@ -36,7 +36,15 @@ public class AvailableClient implements Cloneable {
private WrappedConnection connection;
+ /**
+ * TS when to delete this entry, or 0 = never
+ */
private long deadline;
+
+ /**
+ * TA when to release this client if it's claimed, but state is not occupied
+ */
+ private long idleClaimTimeout;
private long lastConnectionCheck;
@@ -60,9 +68,9 @@ public class AvailableClient implements Cloneable {
* can't possibly be in use by the old user anymore.
*/
public synchronized void update(JsonClient source) {
- if (this.inUseBy != null && source.state != State.OCCUPIED && !TunnelListener.hasTunnel(this.inUseBy)) {
- LOGGER.info("Free client blocked by a disconnected user detected.");
- LOGGER.info("Client " + this + " is available again");
+ if (this.inUseBy != null && source.state != State.OCCUPIED && !TunnelListener.hasTunnel(this.inUseBy)
+ && System.currentTimeMillis() > this.idleClaimTimeout) {
+ LOGGER.info("Client " + this + " is available again (free client blocked by a user)");
this.inUseBy = null;
if (this.connection != null) {
this.connection.invalidate();
@@ -70,19 +78,20 @@ public class AvailableClient implements Cloneable {
}
if (this.password == null || !this.password.equals(source.password)) {
- if (source.state != State.OCCUPIED) {
- if (this.inUseBy != null) {
- LOGGER.info("Client " + this + " is available again");
- this.inUseBy = null;
- if (this.connection != null) this.connection.invalidate();
+ if (source.state != State.OCCUPIED && this.inUseBy != null) {
+ LOGGER.info("Client " + this + " is available again");
+ this.inUseBy = null;
+ if (this.connection != null) {
+ this.connection.invalidate();
}
}
this.lastConnectionCheck = 0;
this.password = source.password;
}
- if (this.inUseBy == null || source.state != State.IDLE)
+ if (this.inUseBy == null || source.state != State.IDLE) {
this.state = source.state;
+ }
this.deadline = 0;
}
@@ -95,6 +104,7 @@ public class AvailableClient implements Cloneable {
return false;
this.inUseBy = user;
this.state = State.OCCUPIED;
+ this.idleClaimTimeout = System.currentTimeMillis() + 60000; // Give connect and login some time
return true;
}
@@ -113,7 +123,9 @@ public class AvailableClient implements Cloneable {
public synchronized void releaseConnection(String expectedOwner) {
if (isInUseBy(expectedOwner)) {
- if (this.connection != null) this.connection.invalidate();
+ if (this.connection != null) {
+ this.connection.invalidate();
+ }
LOGGER.info("Prematurely releasing client " + this);
this.inUseBy = null;
} else {
@@ -123,14 +135,25 @@ public class AvailableClient implements Cloneable {
/**
* If this connection is not returned by the sat server anymore, we keep it
- * around for another 5 minutes just in case.
+ * around as long as there is someone using it, with some safety buffer.
*/
public boolean isTimeout(long NOW) {
if (deadline == 0) {
- deadline = NOW + 300000;
+ deadline = NOW + 120000; // Was recently updated from remote, set 2min timeout
+ return false;
+ }
+ if (NOW < deadline) // Not timed out yet, no need to recheck
return false;
+ long remaining = deadline - NOW;
+ if (remaining < 120000) {
+ synchronized (this) {
+ if (this.inUseBy != null && TunnelListener.hasTunnel(this.inUseBy)) {
+ deadline = NOW + 600000; // Another 10 minutes since the tunnel is active
+ LOGGER.info("Extending deadline of vanished client, because it's in use: " + this);
+ }
+ }
}
- return deadline < NOW;
+ return NOW > deadline;
}
@Override