mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	Major refactor of API (new interfaces, semantic changes)
This commit is contained in:
		| @@ -1,134 +0,0 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole; | ||||
|  | ||||
| import java.util.LinkedList; | ||||
| import net.sourceforge.guacamole.GuacamoleInstruction.Operation; | ||||
| import net.sourceforge.guacamole.net.Configuration; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| public abstract class GuacamoleClient { | ||||
|  | ||||
|     public abstract void write(char[] chunk, int off, int len) throws GuacamoleException; | ||||
|  | ||||
|     public void write(char[] chunk) throws GuacamoleException { | ||||
|         write(chunk, 0, chunk.length); | ||||
|     } | ||||
|  | ||||
|     public void write(GuacamoleInstruction instruction) throws GuacamoleException { | ||||
|         write(instruction.toString().toCharArray()); | ||||
|     } | ||||
|  | ||||
|     public abstract char[] read() throws GuacamoleException; | ||||
|  | ||||
|     private int instructionStart; | ||||
|     private char[] buffer; | ||||
|  | ||||
|     public GuacamoleInstruction readInstruction() throws GuacamoleException { | ||||
|  | ||||
|         // Fill buffer if not already filled | ||||
|         if (buffer == null) { | ||||
|             buffer = read(); | ||||
|             instructionStart = 0; | ||||
|         } | ||||
|  | ||||
|         // Locate end-of-opcode and end-of-instruction | ||||
|         int opcodeEnd = -1; | ||||
|         int instructionEnd = -1; | ||||
|  | ||||
|         for (int i=instructionStart; i<buffer.length; i++) { | ||||
|  | ||||
|             char c = buffer[i]; | ||||
|  | ||||
|             if (c == ':') | ||||
|                 opcodeEnd = i; | ||||
|  | ||||
|             else if (c == ';') { | ||||
|                 instructionEnd = i; | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|         // If no end-of-instruction marker, malformed. | ||||
|         if (instructionEnd == -1) | ||||
|             throw new GuacamoleException("Malformed instruction."); | ||||
|  | ||||
|         // If no end-of-opcode marker, end is end-of-instruction | ||||
|         if (opcodeEnd == -1) | ||||
|             opcodeEnd = instructionEnd; | ||||
|  | ||||
|         // Parse opcode | ||||
|         String opcode = new String(buffer, instructionStart, opcodeEnd - instructionStart); | ||||
|  | ||||
|         // Parse args | ||||
|         String[] args; | ||||
|         if (instructionEnd > opcodeEnd) | ||||
|             args = new String(buffer, opcodeEnd+1, instructionEnd - opcodeEnd - 1).split(","); | ||||
|         else | ||||
|             args = new String[0]; | ||||
|  | ||||
|         // Create instruction | ||||
|         GuacamoleInstruction instruction = new GuacamoleInstruction( | ||||
|                 Operation.fromOpcode(opcode), | ||||
|                 args | ||||
|         ); | ||||
|  | ||||
|         // Advance buffer | ||||
|         instructionStart = instructionEnd + 1; | ||||
|         if (instructionStart >= buffer.length) | ||||
|             buffer = null; | ||||
|  | ||||
|         return instruction; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public abstract void disconnect() throws GuacamoleException; | ||||
|  | ||||
|     public void connect(Configuration config) throws GuacamoleException { | ||||
|  | ||||
|         // Send protocol | ||||
|         write(new GuacamoleInstruction(Operation.CLIENT_SELECT, config.getProtocol())); | ||||
|  | ||||
|         // Wait for server args | ||||
|         GuacamoleInstruction instruction; | ||||
|         do { | ||||
|             instruction = readInstruction(); | ||||
|         } while (instruction.getOperation() != Operation.SERVER_ARGS); | ||||
|  | ||||
|         // Build args list off provided names and config | ||||
|         String[] args = new String[instruction.getArgs().length]; | ||||
|         for (int i=0; i<instruction.getArgs().length; i++) { | ||||
|  | ||||
|             String requiredArg = instruction.getArgs()[i]; | ||||
|  | ||||
|             String value = config.getParameter(requiredArg); | ||||
|             if (value != null) | ||||
|                 args[i] = value; | ||||
|             else | ||||
|                 args[i] = ""; | ||||
|              | ||||
|         } | ||||
|  | ||||
|         // Send args | ||||
|         write(new GuacamoleInstruction(Operation.CLIENT_CONNECT, args)); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| 
 | ||||
| package net.sourceforge.guacamole.net; | ||||
| package net.sourceforge.guacamole; | ||||
| 
 | ||||
| /* | ||||
|  *  Guacamole - Clientless Remote Desktop | ||||
| @@ -0,0 +1,30 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.io; | ||||
|  | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| public interface GuacamoleReader { | ||||
|  | ||||
|     public char[] read() throws GuacamoleException; | ||||
|     public GuacamoleInstruction readInstruction() throws GuacamoleException; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.io; | ||||
|  | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| public interface GuacamoleWriter { | ||||
|  | ||||
|     public void write(char[] chunk, int off, int len) throws GuacamoleException; | ||||
|     public void write(char[] chunk) throws GuacamoleException; | ||||
|     public void writeInstruction(GuacamoleInstruction instruction) throws GuacamoleException; | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,13 @@ | ||||
| 
 | ||||
| package net.sourceforge.guacamole; | ||||
| package net.sourceforge.guacamole.io; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.Writer; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction.Operation; | ||||
| import net.sourceforge.guacamole.protocol.Configuration; | ||||
| 
 | ||||
| /* | ||||
|  *  Guacamole - Clientless Remote Desktop | ||||
| @@ -19,77 +27,21 @@ package net.sourceforge.guacamole; | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.InetAddress; | ||||
| import java.net.Socket; | ||||
| public class ReaderGuacamoleReader implements GuacamoleReader { | ||||
| 
 | ||||
| import java.io.Reader; | ||||
| import java.io.InputStreamReader; | ||||
| 
 | ||||
| import java.io.Writer; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.net.InetSocketAddress; | ||||
| import java.net.SocketAddress; | ||||
| 
 | ||||
| 
 | ||||
| public class GuacamoleTCPClient extends GuacamoleClient { | ||||
| 
 | ||||
|     private static final int SOCKET_TIMEOUT = 15000; | ||||
| 
 | ||||
|     private Socket sock; | ||||
|     private Reader input; | ||||
|     private Writer output; | ||||
| 
 | ||||
|     public GuacamoleTCPClient(String hostname, int port) throws GuacamoleException { | ||||
| 
 | ||||
|         try { | ||||
| 
 | ||||
|             // Get address | ||||
|             SocketAddress address = new InetSocketAddress( | ||||
|                     InetAddress.getByName(hostname), | ||||
|                     port | ||||
|             ); | ||||
| 
 | ||||
|             // Connect with timeout | ||||
|             sock = new Socket(); | ||||
|             sock.connect(address, SOCKET_TIMEOUT); | ||||
| 
 | ||||
|             // Set read timeout | ||||
|             sock.setSoTimeout(SOCKET_TIMEOUT); | ||||
| 
 | ||||
|             // On successful connect, retrieve I/O streams | ||||
|             input = new InputStreamReader(sock.getInputStream()); | ||||
|             output = new OutputStreamWriter(sock.getOutputStream()); | ||||
| 
 | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException(e); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public void write(char[] chunk, int off, int len) throws GuacamoleException { | ||||
|         try { | ||||
|             output.write(chunk, off, len); | ||||
|             output.flush(); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void disconnect() throws GuacamoleException { | ||||
|         try { | ||||
|             sock.close(); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException(e); | ||||
|         } | ||||
|     public ReaderGuacamoleReader(Reader input) { | ||||
|         this.input = input; | ||||
|     } | ||||
| 
 | ||||
|     private int usedLength = 0; | ||||
|     private char[] buffer = new char[20000]; | ||||
| 
 | ||||
|     private int instructionStart; | ||||
|     private char[] instructionBuffer; | ||||
| 
 | ||||
|     @Override | ||||
|     public char[] read() throws GuacamoleException { | ||||
| 
 | ||||
|         try { | ||||
| @@ -142,4 +94,64 @@ public class GuacamoleTCPClient extends GuacamoleClient { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public GuacamoleInstruction readInstruction() throws GuacamoleException { | ||||
| 
 | ||||
|         // Fill instructionBuffer if not already filled | ||||
|         if (instructionBuffer == null) { | ||||
|             instructionBuffer = read(); | ||||
|             instructionStart = 0; | ||||
|         } | ||||
| 
 | ||||
|         // Locate end-of-opcode and end-of-instruction | ||||
|         int opcodeEnd = -1; | ||||
|         int instructionEnd = -1; | ||||
| 
 | ||||
|         for (int i=instructionStart; i<instructionBuffer.length; i++) { | ||||
| 
 | ||||
|             char c = instructionBuffer[i]; | ||||
| 
 | ||||
|             if (c == ':') | ||||
|                 opcodeEnd = i; | ||||
| 
 | ||||
|             else if (c == ';') { | ||||
|                 instructionEnd = i; | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         // If no end-of-instruction marker, malformed. | ||||
|         if (instructionEnd == -1) | ||||
|             throw new GuacamoleException("Malformed instruction."); | ||||
| 
 | ||||
|         // If no end-of-opcode marker, end is end-of-instruction | ||||
|         if (opcodeEnd == -1) | ||||
|             opcodeEnd = instructionEnd; | ||||
| 
 | ||||
|         // Parse opcode | ||||
|         String opcode = new String(instructionBuffer, instructionStart, opcodeEnd - instructionStart); | ||||
| 
 | ||||
|         // Parse args | ||||
|         String[] args; | ||||
|         if (instructionEnd > opcodeEnd) | ||||
|             args = new String(instructionBuffer, opcodeEnd+1, instructionEnd - opcodeEnd - 1).split(","); | ||||
|         else | ||||
|             args = new String[0]; | ||||
| 
 | ||||
|         // Create instruction | ||||
|         GuacamoleInstruction instruction = new GuacamoleInstruction( | ||||
|                 Operation.fromOpcode(opcode), | ||||
|                 args | ||||
|         ); | ||||
| 
 | ||||
|         // Advance instructionBuffer | ||||
|         instructionStart = instructionEnd + 1; | ||||
|         if (instructionStart >= instructionBuffer.length) | ||||
|             instructionBuffer = null; | ||||
| 
 | ||||
|         return instruction; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @@ -0,0 +1,59 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.io; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.Writer; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction.Operation; | ||||
| import net.sourceforge.guacamole.protocol.Configuration; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| public class WriterGuacamoleWriter implements GuacamoleWriter { | ||||
|  | ||||
|     private Writer output; | ||||
|  | ||||
|     public WriterGuacamoleWriter(Writer output) { | ||||
|         this.output = output; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void write(char[] chunk, int off, int len) throws GuacamoleException { | ||||
|         try { | ||||
|             output.write(chunk, off, len); | ||||
|             output.flush(); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void write(char[] chunk) throws GuacamoleException { | ||||
|         write(chunk, 0, chunk.length); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeInstruction(GuacamoleInstruction instruction) throws GuacamoleException { | ||||
|         write(instruction.toString().toCharArray()); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,69 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| import net.sourceforge.guacamole.io.GuacamoleReader; | ||||
| import net.sourceforge.guacamole.io.GuacamoleWriter; | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.Writer; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction; | ||||
| import net.sourceforge.guacamole.protocol.GuacamoleInstruction.Operation; | ||||
| import net.sourceforge.guacamole.protocol.Configuration; | ||||
|  | ||||
| /* | ||||
|  *  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/>. | ||||
|  */ | ||||
|  | ||||
| public abstract class AbstractGuacamoleSocket implements GuacamoleSocket { | ||||
|  | ||||
|     @Override | ||||
|     public void connect(Configuration config) throws GuacamoleException { | ||||
|  | ||||
|         // Get reader and writer | ||||
|         GuacamoleReader reader = getReader(); | ||||
|         GuacamoleWriter writer = getWriter(); | ||||
|  | ||||
|         // Send protocol | ||||
|         writer.writeInstruction(new GuacamoleInstruction(Operation.CLIENT_SELECT, config.getProtocol())); | ||||
|  | ||||
|         // Wait for server args | ||||
|         GuacamoleInstruction instruction; | ||||
|         do { | ||||
|             instruction = reader.readInstruction(); | ||||
|         } while (instruction.getOperation() != Operation.SERVER_ARGS); | ||||
|  | ||||
|         // Build args list off provided names and config | ||||
|         String[] args = new String[instruction.getArgs().length]; | ||||
|         for (int i=0; i<instruction.getArgs().length; i++) { | ||||
|  | ||||
|             String requiredArg = instruction.getArgs()[i]; | ||||
|  | ||||
|             String value = config.getParameter(requiredArg); | ||||
|             if (value != null) | ||||
|                 args[i] = value; | ||||
|             else | ||||
|                 args[i] = ""; | ||||
|              | ||||
|         } | ||||
|  | ||||
|         // Send args | ||||
|         writer.writeInstruction(new GuacamoleInstruction(Operation.CLIENT_CONNECT, args)); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,10 @@ | ||||
| 
 | ||||
| package net.sourceforge.guacamole.net.tunnel; | ||||
| package net.sourceforge.guacamole.net; | ||||
| 
 | ||||
| import net.sourceforge.guacamole.protocol.Configuration; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.io.GuacamoleReader; | ||||
| import net.sourceforge.guacamole.io.GuacamoleWriter; | ||||
| 
 | ||||
| /* | ||||
|  *  Guacamole - Clientless Remote Desktop | ||||
| @@ -19,35 +24,12 @@ package net.sourceforge.guacamole.net.tunnel; | ||||
|  *  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 interface GuacamoleSocket { | ||||
| 
 | ||||
| public class GuacamoleTunnel { | ||||
|     public GuacamoleReader getReader(); | ||||
|     public GuacamoleWriter getWriter(); | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
|     public void connect(Configuration config) throws GuacamoleException; | ||||
|     public void disconnect() throws GuacamoleException; | ||||
| 
 | ||||
| } | ||||
| @@ -0,0 +1,77 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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.GuacamoleException; | ||||
| import net.sourceforge.guacamole.io.GuacamoleReader; | ||||
| import net.sourceforge.guacamole.net.GuacamoleSocket; | ||||
| import net.sourceforge.guacamole.io.GuacamoleWriter; | ||||
|  | ||||
| public class GuacamoleTunnel { | ||||
|  | ||||
|     private UUID uuid; | ||||
|     private GuacamoleSocket socket; | ||||
|  | ||||
|     private ReentrantLock readerLock; | ||||
|     private ReentrantLock writerLock; | ||||
|  | ||||
|     public GuacamoleTunnel(GuacamoleSocket socket) throws GuacamoleException { | ||||
|  | ||||
|         this.socket = socket; | ||||
|         uuid = UUID.randomUUID(); | ||||
|  | ||||
|         readerLock = new ReentrantLock(); | ||||
|         writerLock = new ReentrantLock(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public GuacamoleReader acquireReader() { | ||||
|         readerLock.lock(); | ||||
|         return socket.getReader(); | ||||
|     } | ||||
|  | ||||
|     public void releaseReader() { | ||||
|         readerLock.unlock(); | ||||
|     } | ||||
|  | ||||
|     public boolean hasQueuedReaderThreads() { | ||||
|         return readerLock.hasQueuedThreads(); | ||||
|     } | ||||
|  | ||||
|     public GuacamoleWriter acquireWriter() { | ||||
|         writerLock.lock(); | ||||
|         return socket.getWriter(); | ||||
|     } | ||||
|  | ||||
|     public void releaseWriter() { | ||||
|         writerLock.unlock(); | ||||
|     } | ||||
|  | ||||
|     public boolean hasQueuedWriterThreads() { | ||||
|         return writerLock.hasQueuedThreads(); | ||||
|     } | ||||
|  | ||||
|     public UUID getUUID() { | ||||
|         return uuid; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,95 @@ | ||||
|  | ||||
| package net.sourceforge.guacamole.net; | ||||
|  | ||||
| /* | ||||
|  *  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 net.sourceforge.guacamole.io.GuacamoleReader; | ||||
| import net.sourceforge.guacamole.io.ReaderGuacamoleReader; | ||||
| import net.sourceforge.guacamole.io.WriterGuacamoleWriter; | ||||
| import net.sourceforge.guacamole.io.GuacamoleWriter; | ||||
| import java.io.IOException; | ||||
| import java.net.InetAddress; | ||||
| import java.net.Socket; | ||||
|  | ||||
| import java.io.InputStreamReader; | ||||
|  | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.net.InetSocketAddress; | ||||
| import java.net.SocketAddress; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
|  | ||||
|  | ||||
| public class TCPGuacamoleSocket extends AbstractGuacamoleSocket { | ||||
|  | ||||
|     private GuacamoleReader reader; | ||||
|     private GuacamoleWriter writer; | ||||
|  | ||||
|     private static final int SOCKET_TIMEOUT = 15000; | ||||
|     private Socket sock; | ||||
|  | ||||
|     public TCPGuacamoleSocket(String hostname, int port) throws GuacamoleException { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             // Get address | ||||
|             SocketAddress address = new InetSocketAddress( | ||||
|                     InetAddress.getByName(hostname), | ||||
|                     port | ||||
|             ); | ||||
|  | ||||
|             // Connect with timeout | ||||
|             sock = new Socket(); | ||||
|             sock.connect(address, SOCKET_TIMEOUT); | ||||
|  | ||||
|             // Set read timeout | ||||
|             sock.setSoTimeout(SOCKET_TIMEOUT); | ||||
|  | ||||
|             // On successful connect, retrieve I/O streams | ||||
|             reader = new ReaderGuacamoleReader(new InputStreamReader(sock.getInputStream())); | ||||
|             writer = new WriterGuacamoleWriter(new OutputStreamWriter(sock.getOutputStream())); | ||||
|  | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException(e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void disconnect() throws GuacamoleException { | ||||
|         try { | ||||
|             sock.close(); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleReader getReader() { | ||||
|         return reader; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleWriter getWriter() { | ||||
|         return writer; | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| 
 | ||||
| package net.sourceforge.guacamole.net; | ||||
| package net.sourceforge.guacamole.protocol; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| 
 | ||||
| @@ -1,5 +1,5 @@ | ||||
| 
 | ||||
| package net.sourceforge.guacamole; | ||||
| package net.sourceforge.guacamole.protocol; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| 
 | ||||
| @@ -1,5 +1,5 @@ | ||||
| 
 | ||||
| package net.sourceforge.guacamole.net; | ||||
| package net.sourceforge.guacamole.servlet; | ||||
| 
 | ||||
| /* | ||||
|  *  Guacamole - Clientless Remote Desktop | ||||
| @@ -19,11 +19,11 @@ package net.sourceforge.guacamole.net; | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| import net.sourceforge.guacamole.net.tunnel.GuacamoleTunnel; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.ConcurrentMap; | ||||
| import javax.servlet.http.HttpSession; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.net.GuacamoleTunnel; | ||||
| 
 | ||||
| public class GuacamoleSession { | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| package net.sourceforge.guacamole.net.tunnel; | ||||
| package net.sourceforge.guacamole.servlet; | ||||
| 
 | ||||
| /* | ||||
|  *  Guacamole - Clientless Remote Desktop | ||||
| @@ -18,20 +18,21 @@ package net.sourceforge.guacamole.net.tunnel; | ||||
|  *  along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| import net.sourceforge.guacamole.net.GuacamoleTunnel; | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.io.Writer; | ||||
| import java.util.concurrent.locks.ReentrantLock; | ||||
| import javax.servlet.ServletException; | ||||
| import javax.servlet.http.HttpServlet; | ||||
| 
 | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import javax.servlet.http.HttpSession; | ||||
| import net.sourceforge.guacamole.GuacamoleClient; | ||||
| import net.sourceforge.guacamole.GuacamoleException; | ||||
| import net.sourceforge.guacamole.net.GuacamoleSession; | ||||
| import net.sourceforge.guacamole.io.GuacamoleReader; | ||||
| import net.sourceforge.guacamole.net.GuacamoleSocket; | ||||
| import net.sourceforge.guacamole.io.GuacamoleWriter; | ||||
| 
 | ||||
| 
 | ||||
| public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
| @@ -127,8 +128,8 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|         if (tunnel == null) | ||||
|             throw new GuacamoleException("No such tunnel."); | ||||
| 
 | ||||
|         ReentrantLock instructionStreamLock = tunnel.getInstructionStreamLock(); | ||||
|         instructionStreamLock.lock(); | ||||
|         // Obtain exclusive read access | ||||
|         GuacamoleReader reader = tunnel.acquireReader(); | ||||
| 
 | ||||
|         try { | ||||
| 
 | ||||
| @@ -139,12 +140,9 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
| 
 | ||||
|             Writer out = response.getWriter(); | ||||
| 
 | ||||
|             // Query new update from server | ||||
|             GuacamoleClient client = tunnel.getClient(); | ||||
| 
 | ||||
|             // For all messages, until another stream is ready (we send at least one message) | ||||
|             char[] message; | ||||
|             while ((message = client.read()) != null) { | ||||
|             while ((message = reader.read()) != null) { | ||||
| 
 | ||||
|                 // Get message output bytes | ||||
|                 out.write(message, 0, message.length); | ||||
| @@ -152,7 +150,7 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|                 response.flushBuffer(); | ||||
| 
 | ||||
|                 // No more messages another stream can take over | ||||
|                 if (instructionStreamLock.hasQueuedThreads()) | ||||
|                 if (tunnel.hasQueuedReaderThreads()) | ||||
|                     break; | ||||
| 
 | ||||
|             } | ||||
| @@ -175,7 +173,7 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|             throw new GuacamoleException("I/O error writing to servlet output stream.", e); | ||||
|         } | ||||
|         finally { | ||||
|             instructionStreamLock.unlock(); | ||||
|             tunnel.releaseReader(); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| @@ -199,19 +197,22 @@ public abstract class GuacamoleTunnelServlet extends HttpServlet { | ||||
|         // Send data | ||||
|         try { | ||||
| 
 | ||||
|             GuacamoleClient client = tunnel.getClient(); | ||||
|             GuacamoleWriter writer = tunnel.acquireWriter(); | ||||
| 
 | ||||
|             Reader input = request.getReader(); | ||||
|             char[] buffer = new char[8192]; | ||||
| 
 | ||||
|             int length; | ||||
|             while ((length = input.read(buffer, 0, buffer.length)) != -1) | ||||
|                 client.write(buffer, 0, length); | ||||
|                 writer.write(buffer, 0, length); | ||||
| 
 | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleException("I/O Error sending data to server: " + e.getMessage(), e); | ||||
|         } | ||||
|         finally { | ||||
|             tunnel.releaseWriter(); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
		Reference in New Issue
	
	Block a user