From 89026feb96d6c628315bfb6f070e9e6dda1bce3e Mon Sep 17 00:00:00 2001 From: gustavorag Date: Mon, 14 Dec 2015 16:43:45 -0300 Subject: [PATCH 1/5] =?UTF-8?q?Altera=C3=A7=C3=A3o=20do=20nioWorkers=20par?= =?UTF-8?q?a=20o=20valor=207.=20Melhoria=20de=20desempenho=20do=20reverse?= =?UTF-8?q?=20tunnel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/fogbowcloud/ssh/TunnelServer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelServer.java index d609575..7f4fa6f 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelServer.java @@ -158,6 +158,7 @@ public String getName() { sshServer.setUserAuthFactories(userAuthenticators); sshServer.setHost(sshTunnelHost == null ? "0.0.0.0" : sshTunnelHost); sshServer.setPort(sshTunnelPort); + sshServer.setNioWorkers(7); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { From 07c444f5d0d435e31f1fd4e684504b36062f98ae Mon Sep 17 00:00:00 2001 From: gustavorag Date: Thu, 28 Jan 2016 09:55:12 -0300 Subject: [PATCH 2/5] Change reverse tunnel to create multiples SSH Servers to balance connections demand. --- reverse-tunnel.conf.example | 5 +- src/main/java/org/fogbowcloud/ssh/Main.java | 13 +- .../org/fogbowcloud/ssh/TunnelHttpServer.java | 178 ++++++++++++++++-- .../org/fogbowcloud/ssh/TunnelServer.java | 74 +++++++- src/main/java/org/fogbowcloud/ssh/Utils.java | 20 ++ 5 files changed, 265 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/fogbowcloud/ssh/Utils.java diff --git a/reverse-tunnel.conf.example b/reverse-tunnel.conf.example index 7b73fca..e6361e8 100644 --- a/reverse-tunnel.conf.example +++ b/reverse-tunnel.conf.example @@ -1,6 +1,7 @@ -tunnel_port=2222 +tunnel_port_range=2222:2242 tunnel_host=0.0.0.0 http_port=2223 external_port_range=20000:30000 host_key_path=hostkey.ser -idle_token_timeout=86400 \ No newline at end of file +idle_token_timeout=86400 +ports_per_ssh_server=5 \ No newline at end of file diff --git a/src/main/java/org/fogbowcloud/ssh/Main.java b/src/main/java/org/fogbowcloud/ssh/Main.java index 4374066..db04ce8 100644 --- a/src/main/java/org/fogbowcloud/ssh/Main.java +++ b/src/main/java/org/fogbowcloud/ssh/Main.java @@ -11,13 +11,15 @@ public static void main(String[] args) throws IOException { FileInputStream input = new FileInputStream(args[0]); properties.load(input); - String tunnelPort = properties.getProperty("tunnel_port"); + String tunnelPortRange = properties.getProperty("tunnel_port_range"); + String[] tunnelPortRangeSplit = tunnelPortRange.split(":"); String tunnelHost = properties.getProperty("tunnel_host"); String httpPort = properties.getProperty("http_port"); String externalPortRange = properties.getProperty("external_port_range"); String[] externalRangeSplit = externalPortRange.split(":"); String externalHostKeyPath = properties.getProperty("host_key_path"); String idleTokenTimeoutStr = properties.getProperty("idle_token_timeout"); + String portsPerShhServer = properties.getProperty("ports_per_ssh_server"); Long idleTokenTimeout = null; if (idleTokenTimeoutStr != null) { idleTokenTimeout = Long.parseLong(idleTokenTimeoutStr) * 1000; @@ -26,12 +28,15 @@ public static void main(String[] args) throws IOException { TunnelHttpServer tunnelHttpServer = new TunnelHttpServer( Integer.parseInt(httpPort), tunnelHost, - Integer.parseInt(tunnelPort), + Integer.parseInt(tunnelPortRangeSplit[0]), + Integer.parseInt(tunnelPortRangeSplit[1]), Integer.parseInt(externalRangeSplit[0]), Integer.parseInt(externalRangeSplit[1]), idleTokenTimeout, - externalHostKeyPath); + externalHostKeyPath, + Integer.parseInt(portsPerShhServer)); tunnelHttpServer.start(); + } -} +} \ No newline at end of file diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java index aebad94..d3888f4 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java @@ -5,7 +5,10 @@ import java.io.ObjectInputStream; import java.io.UnsupportedEncodingException; import java.security.KeyPair; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.apache.sshd.common.util.Base64; import org.json.JSONObject; @@ -14,19 +17,38 @@ import fi.iki.elonen.NanoHTTPD.Response.Status; public class TunnelHttpServer extends NanoHTTPD { - - private TunnelServer tunneling; + + //private TunnelServer tunneling; + + private Map tunnelServers = new HashMap(); + private String hostKeyPath; private KeyPair kp; + + private int lowerPort; + private int higherPort; + private String sshTunnelHost; + private int lowerSshTunnelPort; + private int higherSshTunnelPort; + private Long idleTokenTimeout; + + private int portsPerShhServer; - public TunnelHttpServer(int httpPort, String sshTunnelHost, int sshTunnelPort, - int lowerPort, int higherPort, Long idleTokenTimeout, String hostKeyPath) { + public TunnelHttpServer(int httpPort, String sshTunnelHost, int lowerSshTunnelPort, int higherSshTunnelPort, + int lowerPort, int higherPort, Long idleTokenTimeout, String hostKeyPath, int portsPerShhServer) { super(httpPort); this.hostKeyPath = hostKeyPath; + + this.lowerPort = lowerPort; + this.higherPort = higherPort; + this.sshTunnelHost = sshTunnelHost; + this.lowerSshTunnelPort = lowerSshTunnelPort; + this.higherSshTunnelPort = higherSshTunnelPort; + this.idleTokenTimeout = idleTokenTimeout; + this.portsPerShhServer = portsPerShhServer; + try { - this.tunneling = new TunnelServer(sshTunnelHost, sshTunnelPort, - lowerPort, higherPort, idleTokenTimeout, hostKeyPath); - this.tunneling.start(); + this.createNewTunnelServer(); } catch (IOException e) { e.printStackTrace(); } @@ -50,10 +72,13 @@ public Response serve(IHTTPSession session) { if (method.equals(Method.GET)) { if (splitUri.length == 4 && splitUri[3].equals("all")) { - Map ports = this.tunneling.getPortByPrefix(tokenId); + Map ports = new HashMap(); + for(TunnelServer tunneling : tunnelServers.values()){ + ports.putAll(tunneling.getPortByPrefix(tokenId)); + } return new NanoHTTPD.Response(new JSONObject(ports).toString()); } else { - Integer port = this.tunneling.getPort(tokenId); + Integer port = this.getPortByTokenId(tokenId); if (port == null) { return new NanoHTTPD.Response(Status.NOT_FOUND, MIME_PLAINTEXT, "404 Port Not Found"); @@ -61,13 +86,52 @@ public Response serve(IHTTPSession session) { return new NanoHTTPD.Response(port.toString()); } } - if (method.equals(Method.POST)) { - Integer port = this.tunneling.createPort(tokenId); - if (port == null) { + + //TODO verify if the request can request new port. (ports quota per instance.) + Integer instancePort = null ; + Integer sshServerPort = null ; + + if(tunnelServers.values() != null && !tunnelServers.values().isEmpty()){ + for(TunnelServer tunneling : tunnelServers.values()){ + instancePort = tunneling.createPort(tokenId); + if(instancePort != null){ + sshServerPort = tunneling.getSshTunnelPort(); + break; + } + } + } + + if (instancePort == null) { + try { + TunnelServer tunneling = this.createNewTunnelServer(); + if(tunneling != null){ + instancePort = tunneling.createPort(tokenId); + sshServerPort = tunneling.getSshTunnelPort(); + } + } catch (IOException e) { + return new NanoHTTPD.Response(Status.INTERNAL_ERROR, MIME_PLAINTEXT, ""); + } + } + + if (instancePort == null) { return new NanoHTTPD.Response(Status.INTERNAL_ERROR, MIME_PLAINTEXT, ""); } - return new NanoHTTPD.Response(port.toString()); + //Return format: instancePort:sshTunnelServerPort (int:int) + return new NanoHTTPD.Response(instancePort.toString()+":"+sshServerPort.toString()); + } + + if (method.equals(Method.DELETE)) { + + if (splitUri.length == 4) { + String portNumber = splitUri[3]; + if(Utils.isNumber(portNumber)){ + if(this.releaseInstancePort(tokenId, Integer.parseInt(portNumber))){ + return new NanoHTTPD.Response(Status.OK, MIME_PLAINTEXT, "OK"); + } + } + } + return new NanoHTTPD.Response(Status.METHOD_NOT_ALLOWED, MIME_PLAINTEXT, "Token can not delete this port"); } return new NanoHTTPD.Response(Status.METHOD_NOT_ALLOWED, MIME_PLAINTEXT, ""); @@ -105,5 +169,91 @@ public Response serve(IHTTPSession session) { return new NanoHTTPD.Response(Status.METHOD_NOT_ALLOWED, MIME_PLAINTEXT, ""); } + + //TODO: Create new method to create a new TunnelServer. + private TunnelServer createNewTunnelServer() throws IOException{ + + //Setting available ports to this tunnel server + int initialPort = 0; + int endPort = 0; + int sshTunnelPort = 0; + + Set usedInitialPorts = new HashSet(); + for (TunnelServer tunnelServer : tunnelServers.values()) { + usedInitialPorts.add(new Integer(tunnelServer.getLowerPort())); + } + + for(int port = lowerPort; port < higherPort; port+=portsPerShhServer){ + if(!usedInitialPorts.contains(new Integer(port))){ + initialPort = port; + break; + } + } + + if(initialPort == 0){ + return null; + } + + endPort = initialPort+(portsPerShhServer-1); + if(endPort > higherPort){ + endPort = higherPort; + } + + //Setting the port that this tunnel Server listening to manage connections requests. + for(int port = lowerSshTunnelPort ; port <= higherSshTunnelPort ; port++){ + if(!tunnelServers.containsKey(new Integer(port))){ + sshTunnelPort = port; + break; + } + } -} + if(sshTunnelPort == 0){ + return null; + } + + TunnelServer tunneling = new TunnelServer(sshTunnelHost, sshTunnelPort, + initialPort, endPort, idleTokenTimeout, hostKeyPath); + + tunnelServers.put(new Integer(sshTunnelPort), tunneling); + tunneling.start(); + + return tunneling; + } + + private Integer getPortByTokenId(String tokenId){ + for(TunnelServer tunneling : tunnelServers.values()){ + if(tunneling.getPort(tokenId) != null){ + return tunneling.getPort(tokenId); + } + } + return null; + } + + //TODO: Create new method to validate if the requester have available quota to request new port. + private boolean releaseInstancePort(String tokenId, Integer port){ + for(TunnelServer tunneling : tunnelServers.values()){ + + Integer actualPort = tunneling.getAllPorts().get(tokenId); + + if( actualPort != null && (actualPort.compareTo(port)== 0) ){ + tunneling.releasePort(port); + if(tunneling.getTotalUsedPorts() == 0){ + try { + this.removeTunnelServer(tunneling); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return true; + } + } + return false; + } + + private void removeTunnelServer(TunnelServer tunneling) throws InterruptedException{ + if(tunneling != null){ + tunneling.stop(); + tunnelServers.remove(tunneling.getSshTunnelPort()); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelServer.java index 7f4fa6f..ff9477c 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelServer.java @@ -53,12 +53,14 @@ public Token(Integer port) { private SshServer sshServer; private String sshTunnelHost; - private int sshTunnelPort; - private int lowerPort; - private int higherPort; + private final int sshTunnelPort; + private final int lowerPort; + private final int higherPort; private String hostKeyPath; private Long idleTokenTimeout; + private int nioWorkers; + public TunnelServer(String sshTunnelHost, int sshTunnelPort, int lowerPort, int higherPort, Long idleTokenTimeout, String hostKeyPath) { this.sshTunnelHost = sshTunnelHost; @@ -68,6 +70,7 @@ public TunnelServer(String sshTunnelHost, int sshTunnelPort, int lowerPort, this.idleTokenTimeout = idleTokenTimeout == null ? TOKEN_EXPIRATION_TIMEOUT : idleTokenTimeout; this.hostKeyPath = hostKeyPath; + this.nioWorkers = (higherPort - lowerPort)+2; //+2 is to have a secure margin of works for ports. If number of ports is 5, workers will be set to 6; } public synchronized Integer createPort(String token) { @@ -158,7 +161,7 @@ public String getName() { sshServer.setUserAuthFactories(userAuthenticators); sshServer.setHost(sshTunnelHost == null ? "0.0.0.0" : sshTunnelHost); sshServer.setPort(sshTunnelPort); - sshServer.setNioWorkers(7); + sshServer.setNioWorkers(nioWorkers); executor.scheduleWithFixedDelay(new Runnable() { @Override public void run() { @@ -268,4 +271,65 @@ public Map getPortByPrefix(String tokenId) { return portsByPrefix; } -} + //TODO: Create a method that return boolean for server busy (reached port limit) or not. + public boolean isServerBusy(){ + for (int port = lowerPort; port <= higherPort; port++) { + if (!isTaken(port)) { + return false; + } + } + return true; + } + + //TODO: Create a new method to remove a token and release the relative port. + public void removeToken(String tokenId){ + tokens.remove(tokenId); + + } + + public void releasePort(Integer port){ + if(port != null){ + String tokenToRemove = null; + for(Entry e : tokens.entrySet()){ + if(port.compareTo(e.getValue().port) == 0){ + tokenToRemove = e.getKey(); + break; + } + } + + if(this.getActiveSession(port.intValue()) != null){ + this.getActiveSession(port.intValue()).close(true); + } + tokens.remove(tokenToRemove); + } + } + + public void stop() throws InterruptedException{ + + List activeSessions = sshServer.getActiveSessions(); + if(activeSessions != null && !activeSessions.isEmpty()){ + for (AbstractSession session : activeSessions) { + session.close(true); + } + } + sshServer.stop(true); + + } + + public int getTotalUsedPorts(){ + return tokens.size(); + } + + public int getLowerPort() { + return lowerPort; + } + + public int getHigherPort() { + return higherPort; + } + + public int getSshTunnelPort() { + return sshTunnelPort; + } + +} \ No newline at end of file diff --git a/src/main/java/org/fogbowcloud/ssh/Utils.java b/src/main/java/org/fogbowcloud/ssh/Utils.java new file mode 100644 index 0000000..97f2989 --- /dev/null +++ b/src/main/java/org/fogbowcloud/ssh/Utils.java @@ -0,0 +1,20 @@ +package org.fogbowcloud.ssh; + +import java.math.BigDecimal; + +public class Utils { + + public static boolean isNumber(String value){ + if(value != null){ + try{ + BigDecimal bd = new BigDecimal(value); + bd = null; + return true; + }catch(NumberFormatException nfe){ + return false; + } + } + return false; + } + +} From a9b6693f6a68b3aaca75fa711a63dca652423b26 Mon Sep 17 00:00:00 2001 From: gustavorag Date: Fri, 29 Jan 2016 14:31:01 -0300 Subject: [PATCH 3/5] Fixing concurrent problem with TunnelServer map. --- src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java index d3888f4..d147483 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java @@ -9,6 +9,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.apache.sshd.common.util.Base64; import org.json.JSONObject; @@ -20,7 +21,7 @@ public class TunnelHttpServer extends NanoHTTPD { //private TunnelServer tunneling; - private Map tunnelServers = new HashMap(); + private Map tunnelServers = new ConcurrentHashMap(); private String hostKeyPath; private KeyPair kp; From 61f5b7f5650c6067b04047bc81034668d57f8c6a Mon Sep 17 00:00:00 2001 From: gustavorag Date: Tue, 2 Feb 2016 11:54:23 -0300 Subject: [PATCH 4/5] Implementation of scheduler process to remove inactive SSH Servers --- .../org/fogbowcloud/ssh/TunnelHttpServer.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java index d147483..88543fc 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java @@ -5,12 +5,19 @@ import java.io.ObjectInputStream; import java.io.UnsupportedEncodingException; import java.security.KeyPair; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.log4j.Logger; import org.apache.sshd.common.util.Base64; import org.json.JSONObject; @@ -20,6 +27,8 @@ public class TunnelHttpServer extends NanoHTTPD { //private TunnelServer tunneling; + private static final int SSH_SERVER_VERIFICATION_TIME = 60000; + private static final Logger LOGGER = Logger.getLogger(TunnelHttpServer.class); private Map tunnelServers = new ConcurrentHashMap(); @@ -34,6 +43,8 @@ public class TunnelHttpServer extends NanoHTTPD { private Long idleTokenTimeout; private int portsPerShhServer; + + private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); public TunnelHttpServer(int httpPort, String sshTunnelHost, int lowerSshTunnelPort, int higherSshTunnelPort, int lowerPort, int higherPort, Long idleTokenTimeout, String hostKeyPath, int portsPerShhServer) { @@ -49,7 +60,32 @@ public TunnelHttpServer(int httpPort, String sshTunnelHost, int lowerSshTunnelPo this.portsPerShhServer = portsPerShhServer; try { + this.createNewTunnelServer(); + + executor.scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + + List tunnelsToRemove = new ArrayList(); + + for(Entry entry : tunnelServers.entrySet()){ + if(entry.getValue().getTotalUsedPorts() <= 0){ + tunnelsToRemove.add(entry.getValue()); + } + } + + for(TunnelServer tunneling : tunnelsToRemove){ + try { + removeTunnelServer(tunneling); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + }, SSH_SERVER_VERIFICATION_TIME, SSH_SERVER_VERIFICATION_TIME, TimeUnit.MILLISECONDS); + } catch (IOException e) { e.printStackTrace(); } @@ -254,6 +290,7 @@ private boolean releaseInstancePort(String tokenId, Integer port){ private void removeTunnelServer(TunnelServer tunneling) throws InterruptedException{ if(tunneling != null){ tunneling.stop(); + LOGGER.warn("Removing ssh server with port: "+tunneling.getSshTunnelPort()); tunnelServers.remove(tunneling.getSshTunnelPort()); } } From 5f1c77fbf96ed1992ee45dc47ee30980408bd3db Mon Sep 17 00:00:00 2001 From: gustavorag Date: Wed, 3 Feb 2016 16:00:53 -0300 Subject: [PATCH 5/5] Add parameterized interval time to check ssh servers. --- reverse-tunnel.conf.example | 5 ++-- src/main/java/org/fogbowcloud/ssh/Main.java | 5 +++- .../org/fogbowcloud/ssh/TunnelHttpServer.java | 24 +++++++++++-------- .../org/fogbowcloud/ssh/TunnelServer.java | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/reverse-tunnel.conf.example b/reverse-tunnel.conf.example index e6361e8..22e3bcc 100644 --- a/reverse-tunnel.conf.example +++ b/reverse-tunnel.conf.example @@ -1,7 +1,8 @@ -tunnel_port_range=2222:2242 +tunnel_port_range=2224:2242 tunnel_host=0.0.0.0 http_port=2223 external_port_range=20000:30000 host_key_path=hostkey.ser idle_token_timeout=86400 -ports_per_ssh_server=5 \ No newline at end of file +ports_per_ssh_server=5 +check_ssh_servers_interval=120 \ No newline at end of file diff --git a/src/main/java/org/fogbowcloud/ssh/Main.java b/src/main/java/org/fogbowcloud/ssh/Main.java index db04ce8..3afea94 100644 --- a/src/main/java/org/fogbowcloud/ssh/Main.java +++ b/src/main/java/org/fogbowcloud/ssh/Main.java @@ -25,6 +25,9 @@ public static void main(String[] args) throws IOException { idleTokenTimeout = Long.parseLong(idleTokenTimeoutStr) * 1000; } + String checkSSHServersIntervalStr = properties.getProperty("check_ssh_servers_interval"); + int checkSSHServersInterval = Integer.parseInt(checkSSHServersIntervalStr); + TunnelHttpServer tunnelHttpServer = new TunnelHttpServer( Integer.parseInt(httpPort), tunnelHost, @@ -34,7 +37,7 @@ public static void main(String[] args) throws IOException { Integer.parseInt(externalRangeSplit[1]), idleTokenTimeout, externalHostKeyPath, - Integer.parseInt(portsPerShhServer)); + Integer.parseInt(portsPerShhServer), checkSSHServersInterval); tunnelHttpServer.start(); } diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java index 88543fc..390c87d 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelHttpServer.java @@ -27,7 +27,7 @@ public class TunnelHttpServer extends NanoHTTPD { //private TunnelServer tunneling; - private static final int SSH_SERVER_VERIFICATION_TIME = 60000; + private static final int SSH_SERVER_VERIFICATION_TIME = 300; private static final Logger LOGGER = Logger.getLogger(TunnelHttpServer.class); private Map tunnelServers = new ConcurrentHashMap(); @@ -41,13 +41,14 @@ public class TunnelHttpServer extends NanoHTTPD { private int lowerSshTunnelPort; private int higherSshTunnelPort; private Long idleTokenTimeout; + private int checkSSHServersInterval; private int portsPerShhServer; private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); public TunnelHttpServer(int httpPort, String sshTunnelHost, int lowerSshTunnelPort, int higherSshTunnelPort, - int lowerPort, int higherPort, Long idleTokenTimeout, String hostKeyPath, int portsPerShhServer) { + int lowerPort, int higherPort, Long idleTokenTimeout, String hostKeyPath, int portsPerShhServer, int checkSSHServersInterval) { super(httpPort); this.hostKeyPath = hostKeyPath; @@ -58,6 +59,7 @@ public TunnelHttpServer(int httpPort, String sshTunnelHost, int lowerSshTunnelPo this.higherSshTunnelPort = higherSshTunnelPort; this.idleTokenTimeout = idleTokenTimeout; this.portsPerShhServer = portsPerShhServer; + this.checkSSHServersInterval = checkSSHServersInterval == 0 ? SSH_SERVER_VERIFICATION_TIME : checkSSHServersInterval; try { @@ -70,7 +72,7 @@ public void run() { List tunnelsToRemove = new ArrayList(); for(Entry entry : tunnelServers.entrySet()){ - if(entry.getValue().getTotalUsedPorts() <= 0){ + if(entry.getValue().getActiveTokensNumber() <= 0){ tunnelsToRemove.add(entry.getValue()); } } @@ -79,15 +81,15 @@ public void run() { try { removeTunnelServer(tunneling); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } } } - }, SSH_SERVER_VERIFICATION_TIME, SSH_SERVER_VERIFICATION_TIME, TimeUnit.MILLISECONDS); + }, this.checkSSHServersInterval, this.checkSSHServersInterval, TimeUnit.SECONDS); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } } @@ -147,12 +149,12 @@ public Response serve(IHTTPSession session) { sshServerPort = tunneling.getSshTunnelPort(); } } catch (IOException e) { - return new NanoHTTPD.Response(Status.INTERNAL_ERROR, MIME_PLAINTEXT, ""); + return new NanoHTTPD.Response(Status.INTERNAL_ERROR, MIME_PLAINTEXT, "Error while creating shh server to handle new port."); } } if (instancePort == null) { - return new NanoHTTPD.Response(Status.INTERNAL_ERROR, MIME_PLAINTEXT, ""); + return new NanoHTTPD.Response(Status.FORBIDDEN, MIME_PLAINTEXT, "Token [" + tokenId + "] didn't get any port. All ssh servers are busy."); } //Return format: instancePort:sshTunnelServerPort (int:int) return new NanoHTTPD.Response(instancePort.toString()+":"+sshServerPort.toString()); @@ -207,7 +209,6 @@ public Response serve(IHTTPSession session) { return new NanoHTTPD.Response(Status.METHOD_NOT_ALLOWED, MIME_PLAINTEXT, ""); } - //TODO: Create new method to create a new TunnelServer. private TunnelServer createNewTunnelServer() throws IOException{ //Setting available ports to this tunnel server @@ -267,6 +268,9 @@ private Integer getPortByTokenId(String tokenId){ } //TODO: Create new method to validate if the requester have available quota to request new port. + + + private boolean releaseInstancePort(String tokenId, Integer port){ for(TunnelServer tunneling : tunnelServers.values()){ @@ -274,7 +278,7 @@ private boolean releaseInstancePort(String tokenId, Integer port){ if( actualPort != null && (actualPort.compareTo(port)== 0) ){ tunneling.releasePort(port); - if(tunneling.getTotalUsedPorts() == 0){ + if(tunneling.getActiveTokensNumber() == 0){ try { this.removeTunnelServer(tunneling); } catch (InterruptedException e) { diff --git a/src/main/java/org/fogbowcloud/ssh/TunnelServer.java b/src/main/java/org/fogbowcloud/ssh/TunnelServer.java index ff9477c..028e9c0 100644 --- a/src/main/java/org/fogbowcloud/ssh/TunnelServer.java +++ b/src/main/java/org/fogbowcloud/ssh/TunnelServer.java @@ -316,7 +316,7 @@ public void stop() throws InterruptedException{ } - public int getTotalUsedPorts(){ + public int getActiveTokensNumber(){ return tokens.size(); }