From 11b29d8709fdb156644d93b35715e28c8491a6c2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 May 2011 23:05:32 -0700 Subject: [PATCH] Major refactor of API (new interfaces, semantic changes) --- .../guacamole/GuacamoleClient.java | 134 ----------------- .../{net => }/GuacamoleProperties.java | 2 +- .../guacamole/io/GuacamoleReader.java | 30 ++++ .../guacamole/io/GuacamoleWriter.java | 31 ++++ .../ReaderGuacamoleReader.java} | 140 ++++++++++-------- .../guacamole/io/WriterGuacamoleWriter.java | 59 ++++++++ .../net/AbstractGuacamoleSocket.java | 69 +++++++++ ...camoleTunnel.java => GuacamoleSocket.java} | 40 ++--- .../guacamole/net/GuacamoleTunnel.java | 77 ++++++++++ .../guacamole/net/TCPGuacamoleSocket.java | 95 ++++++++++++ .../{net => protocol}/Configuration.java | 2 +- .../{ => protocol}/GuacamoleInstruction.java | 2 +- .../{net => servlet}/GuacamoleSession.java | 4 +- .../GuacamoleTunnelServlet.java | 29 ++-- 14 files changed, 468 insertions(+), 246 deletions(-) delete mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleClient.java rename guacamole-common/src/main/java/net/sourceforge/guacamole/{net => }/GuacamoleProperties.java (99%) create mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/io/GuacamoleReader.java create mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/io/GuacamoleWriter.java rename guacamole-common/src/main/java/net/sourceforge/guacamole/{GuacamoleTCPClient.java => io/ReaderGuacamoleReader.java} (53%) create mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/io/WriterGuacamoleWriter.java create mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/net/AbstractGuacamoleSocket.java rename guacamole-common/src/main/java/net/sourceforge/guacamole/net/{tunnel/GuacamoleTunnel.java => GuacamoleSocket.java} (52%) create mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleTunnel.java create mode 100644 guacamole-common/src/main/java/net/sourceforge/guacamole/net/TCPGuacamoleSocket.java rename guacamole-common/src/main/java/net/sourceforge/guacamole/{net => protocol}/Configuration.java (96%) rename guacamole-common/src/main/java/net/sourceforge/guacamole/{ => protocol}/GuacamoleInstruction.java (98%) rename guacamole-common/src/main/java/net/sourceforge/guacamole/{net => servlet}/GuacamoleSession.java (95%) rename guacamole-common/src/main/java/net/sourceforge/guacamole/{net/tunnel => servlet}/GuacamoleTunnelServlet.java (90%) diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleClient.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleClient.java deleted file mode 100644 index ac1176975..000000000 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleClient.java +++ /dev/null @@ -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 . - */ - -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 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. + */ + +public interface GuacamoleReader { + + public char[] read() throws GuacamoleException; + public GuacamoleInstruction readInstruction() throws GuacamoleException; + +} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/io/GuacamoleWriter.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/io/GuacamoleWriter.java new file mode 100644 index 000000000..2d0168ed1 --- /dev/null +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/io/GuacamoleWriter.java @@ -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 . + */ + +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; + +} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleTCPClient.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/io/ReaderGuacamoleReader.java similarity index 53% rename from guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleTCPClient.java rename to guacamole-common/src/main/java/net/sourceforge/guacamole/io/ReaderGuacamoleReader.java index 0a1c254e7..a99f4055f 100644 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleTCPClient.java +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/io/ReaderGuacamoleReader.java @@ -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 . */ -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 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; + + } + } diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/io/WriterGuacamoleWriter.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/io/WriterGuacamoleWriter.java new file mode 100644 index 000000000..db6fc849b --- /dev/null +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/io/WriterGuacamoleWriter.java @@ -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 . + */ + +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()); + } + +} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/AbstractGuacamoleSocket.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/AbstractGuacamoleSocket.java new file mode 100644 index 000000000..3d999ce06 --- /dev/null +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/AbstractGuacamoleSocket.java @@ -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 . + */ + +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. */ -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; } diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleTunnel.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleTunnel.java new file mode 100644 index 000000000..3d586ff41 --- /dev/null +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleTunnel.java @@ -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 . + */ + +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; + } + +} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/TCPGuacamoleSocket.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/TCPGuacamoleSocket.java new file mode 100644 index 000000000..15feafb34 --- /dev/null +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/net/TCPGuacamoleSocket.java @@ -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 . + */ + +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; + } + + +} diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/Configuration.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/protocol/Configuration.java similarity index 96% rename from guacamole-common/src/main/java/net/sourceforge/guacamole/net/Configuration.java rename to guacamole-common/src/main/java/net/sourceforge/guacamole/protocol/Configuration.java index b086cf1ac..7e4362590 100644 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/Configuration.java +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/protocol/Configuration.java @@ -1,5 +1,5 @@ -package net.sourceforge.guacamole.net; +package net.sourceforge.guacamole.protocol; import java.util.HashMap; diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleInstruction.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/protocol/GuacamoleInstruction.java similarity index 98% rename from guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleInstruction.java rename to guacamole-common/src/main/java/net/sourceforge/guacamole/protocol/GuacamoleInstruction.java index d6d3e9c62..153b9e20f 100644 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/GuacamoleInstruction.java +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/protocol/GuacamoleInstruction.java @@ -1,5 +1,5 @@ -package net.sourceforge.guacamole; +package net.sourceforge.guacamole.protocol; import java.util.HashMap; diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleSession.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/servlet/GuacamoleSession.java similarity index 95% rename from guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleSession.java rename to guacamole-common/src/main/java/net/sourceforge/guacamole/servlet/GuacamoleSession.java index 7cd90d93a..dcaaf394d 100644 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/GuacamoleSession.java +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/servlet/GuacamoleSession.java @@ -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 . */ -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 { diff --git a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/tunnel/GuacamoleTunnelServlet.java b/guacamole-common/src/main/java/net/sourceforge/guacamole/servlet/GuacamoleTunnelServlet.java similarity index 90% rename from guacamole-common/src/main/java/net/sourceforge/guacamole/net/tunnel/GuacamoleTunnelServlet.java rename to guacamole-common/src/main/java/net/sourceforge/guacamole/servlet/GuacamoleTunnelServlet.java index 92ee60505..7848b2431 100644 --- a/guacamole-common/src/main/java/net/sourceforge/guacamole/net/tunnel/GuacamoleTunnelServlet.java +++ b/guacamole-common/src/main/java/net/sourceforge/guacamole/servlet/GuacamoleTunnelServlet.java @@ -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 . */ +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(); + } }