mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	Added tunnel registry and support for multiple tunnels per session.
This commit is contained in:
		| @@ -19,54 +19,16 @@ package net.sourceforge.guacamole.net; | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| import java.util.concurrent.locks.ReentrantLock; | ||||
| import net.sourceforge.guacamole.net.tunnel.GuacamoleTunnel; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.ConcurrentMap; | ||||
| import javax.servlet.http.HttpSession; | ||||
| import javax.servlet.http.HttpSessionBindingEvent; | ||||
| import javax.servlet.http.HttpSessionBindingListener; | ||||
| import net.sourceforge.guacamole.GuacamoleClient; | ||||
| import net.sourceforge.guacamole.GuacamoleTCPClient; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
|  | ||||
| public class GuacamoleSession { | ||||
|  | ||||
|     private final HttpSession session; | ||||
|     private SessionClient client; | ||||
|     private ReentrantLock instructionStreamLock; | ||||
|  | ||||
|     public class SessionClient extends GuacamoleClient implements HttpSessionBindingListener { | ||||
|  | ||||
|         private GuacamoleClient client; | ||||
|  | ||||
|         public SessionClient(GuacamoleClient client) { | ||||
|             this.client = client; | ||||
|         } | ||||
|  | ||||
|         public void valueBound(HttpSessionBindingEvent event) { | ||||
|             // Do nothing | ||||
|         } | ||||
|  | ||||
|         public void valueUnbound(HttpSessionBindingEvent event) { | ||||
|             try { | ||||
|                 disconnect(); | ||||
|             } | ||||
|             catch (GuacamoleException e) { | ||||
|                 // Ignore | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public void write(char[] data, int off, int len) throws GuacamoleException { | ||||
|             client.write(data, off, len); | ||||
|         } | ||||
|  | ||||
|         public char[] read() throws GuacamoleException { | ||||
|             return client.read(); | ||||
|         } | ||||
|  | ||||
|         public void disconnect() throws GuacamoleException { | ||||
|             client.disconnect(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private ConcurrentMap<String, GuacamoleTunnel> tunnels; | ||||
|  | ||||
|     public GuacamoleSession(HttpSession session) throws GuacamoleException { | ||||
|  | ||||
| @@ -77,57 +39,30 @@ public class GuacamoleSession { | ||||
|  | ||||
|         synchronized (session) { | ||||
|  | ||||
|             client = (SessionClient) session.getAttribute("CLIENT"); | ||||
|             instructionStreamLock = (ReentrantLock) session.getAttribute("INSTRUCTION_STREAM_LOCK"); | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void attachClient(GuacamoleTCPClient client) throws GuacamoleException { | ||||
|  | ||||
|         synchronized (session) { | ||||
|  | ||||
|             this.client = new SessionClient(client); | ||||
|             session.setAttribute("CLIENT", this.client); | ||||
|  | ||||
|             instructionStreamLock = new ReentrantLock(); | ||||
|             session.setAttribute("INSTRUCTION_STREAM_LOCK", instructionStreamLock); | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public SessionClient getClient() throws GuacamoleException { | ||||
|         synchronized (session) { | ||||
|  | ||||
|             if (client == null) | ||||
|                 throw new GuacamoleException("Client not yet attached."); | ||||
|  | ||||
|             return client; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void invalidate() { | ||||
|         session.invalidate(); | ||||
|     } | ||||
|  | ||||
|     public void detachClient() throws GuacamoleException { | ||||
|  | ||||
|         synchronized (session) { | ||||
|  | ||||
|             if (client != null) { | ||||
|                 client.disconnect(); | ||||
|                 session.removeAttribute("CLIENT"); | ||||
|                 client = null; | ||||
|             tunnels = (ConcurrentMap<String, GuacamoleTunnel>) session.getAttribute("GUAC_TUNNELS"); | ||||
|             if (tunnels == null) { | ||||
|                 tunnels = new ConcurrentHashMap<String, GuacamoleTunnel>(); | ||||
|                 session.setAttribute("GUAC_TUNNELS", tunnels); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public ReentrantLock getInstructionStreamLock() { | ||||
|         return instructionStreamLock; | ||||
|     public void invalidate() { | ||||
|         session.invalidate(); | ||||
|     } | ||||
|  | ||||
|     public void attachTunnel(GuacamoleTunnel tunnel) throws GuacamoleException { | ||||
|         tunnels.put(tunnel.getUUID().toString(), tunnel); | ||||
|     } | ||||
|  | ||||
|     public void detachTunnel(GuacamoleTunnel tunnel) throws GuacamoleException { | ||||
|         tunnels.remove(tunnel.getUUID().toString()); | ||||
|     } | ||||
|  | ||||
|     public GuacamoleTunnel getTunnel(String tunnelUUID) { | ||||
|         return tunnels.get(tunnelUUID); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,53 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net.tunnel; | ||||
|  | ||||
| /* | ||||
|  *  Guacamole - Clientless Remote Desktop | ||||
|  *  Copyright (C) 2010  Michael Jumper | ||||
|  * | ||||
|  *  This program is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU Affero General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU Affero General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU Affero General Public License | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| import java.util.UUID; | ||||
| import java.util.concurrent.locks.ReentrantLock; | ||||
| import net.sourceforge.guacamole.GuacamoleClient; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
|  | ||||
| public class GuacamoleTunnel { | ||||
|  | ||||
|     private UUID uuid; | ||||
|     private GuacamoleClient client; | ||||
|     private ReentrantLock instructionStreamLock; | ||||
|  | ||||
|     public GuacamoleTunnel(GuacamoleClient client) throws GuacamoleException { | ||||
|  | ||||
|         this.client = client; | ||||
|         instructionStreamLock = new ReentrantLock(); | ||||
|         uuid = UUID.randomUUID(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public GuacamoleClient getClient() throws GuacamoleException { | ||||
|         return client; | ||||
|     } | ||||
|  | ||||
|     public ReentrantLock getInstructionStreamLock() { | ||||
|         return instructionStreamLock; | ||||
|     } | ||||
|  | ||||
|     public UUID getUUID() { | ||||
|         return uuid; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -54,14 +54,25 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|             if (query == null) | ||||
|                 throw new GuacamoleException("No query string provided."); | ||||
|  | ||||
|             if (query.equals("connect")) | ||||
|                 doConnect(request, response); | ||||
|             if (query.equals("connect")) { | ||||
|  | ||||
|             else if(query.equals("read")) | ||||
|                 doRead(request, response); | ||||
|                 GuacamoleTunnel tunnel = doConnect(request); | ||||
|                 if (tunnel != null) { | ||||
|                     try { | ||||
|                         response.getWriter().println(tunnel.getUUID().toString()); | ||||
|                     } | ||||
|                     catch (IOException e) { | ||||
|                         throw new GuacamoleException(e); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             else if(query.equals("write")) | ||||
|                 doWrite(request, response); | ||||
|             } | ||||
|  | ||||
|             else if(query.startsWith("read:")) | ||||
|                 doRead(request, response, query.substring(5)); | ||||
|  | ||||
|             else if(query.startsWith("write:")) | ||||
|                 doWrite(request, response, query.substring(6)); | ||||
|  | ||||
|             else | ||||
|                 throw new GuacamoleException("Invalid tunnel operation: " + query); | ||||
| @@ -72,14 +83,18 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     protected abstract void doConnect(HttpServletRequest request, HttpServletResponse response) throws GuacamoleException; | ||||
|     protected abstract GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException; | ||||
|  | ||||
|     protected void doRead(HttpServletRequest request, HttpServletResponse response) throws GuacamoleException { | ||||
|     protected void doRead(HttpServletRequest request, HttpServletResponse response, String tunnelUUID) throws GuacamoleException { | ||||
|  | ||||
|         HttpSession httpSession = request.getSession(false); | ||||
|         GuacamoleSession session = new GuacamoleSession(httpSession); | ||||
|  | ||||
|         ReentrantLock instructionStreamLock = session.getInstructionStreamLock(); | ||||
|         GuacamoleTunnel tunnel = session.getTunnel(tunnelUUID); | ||||
|         if (tunnel == null) | ||||
|             throw new GuacamoleException("No such tunnel."); | ||||
|  | ||||
|         ReentrantLock instructionStreamLock = tunnel.getInstructionStreamLock(); | ||||
|         instructionStreamLock.lock(); | ||||
|  | ||||
|         try { | ||||
| @@ -94,7 +109,7 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|             try { | ||||
|  | ||||
|                 // Query new update from server | ||||
|                 GuacamoleClient client = session.getClient(); | ||||
|                 GuacamoleClient client = tunnel.getClient(); | ||||
|  | ||||
|                 // For all messages, until another stream is ready (we send at least one message) | ||||
|                 char[] message; | ||||
| @@ -112,7 +127,7 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|                 } | ||||
|  | ||||
|                 if (message == null) { | ||||
|                     session.detachClient(); | ||||
|                     session.detachTunnel(tunnel); | ||||
|                     throw new GuacamoleException("Disconnected."); | ||||
|                 } | ||||
|  | ||||
| @@ -141,11 +156,15 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     protected void doWrite(HttpServletRequest request, HttpServletResponse response) throws GuacamoleException { | ||||
|     protected void doWrite(HttpServletRequest request, HttpServletResponse response, String tunnelUUID) throws GuacamoleException { | ||||
|  | ||||
|         HttpSession httpSession = request.getSession(false); | ||||
|         GuacamoleSession session = new GuacamoleSession(httpSession); | ||||
|  | ||||
|         GuacamoleTunnel tunnel = session.getTunnel(tunnelUUID); | ||||
|         if (tunnel == null) | ||||
|             throw new GuacamoleException("No such tunnel."); | ||||
|  | ||||
|         // We still need to set the content type to avoid the default of | ||||
|         // text/html, as such a content type would cause some browsers to | ||||
|         // attempt to parse the result, even though the JavaScript client | ||||
| @@ -156,12 +175,14 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|         // Send data | ||||
|         try { | ||||
|  | ||||
|             GuacamoleClient client = tunnel.getClient(); | ||||
|  | ||||
|             Reader input = request.getReader(); | ||||
|             char[] buffer = new char[8192]; | ||||
|  | ||||
|             int length; | ||||
|             while ((length = input.read(buffer, 0, buffer.length)) != -1) | ||||
|                 session.getClient().write(buffer, 0, length); | ||||
|                 client.write(buffer, 0, length); | ||||
|  | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user