diff --git a/guacamole-common/src/main/java/org/apache/guacamole/net/DelegatingGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/net/DelegatingGuacamoleSocket.java new file mode 100644 index 000000000..b519629dd --- /dev/null +++ b/guacamole-common/src/main/java/org/apache/guacamole/net/DelegatingGuacamoleSocket.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.net; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.io.GuacamoleReader; +import org.apache.guacamole.io.GuacamoleWriter; + +/** + * GuacamoleSocket implementation which simply delegates all function calls to + * an underlying GuacamoleSocket. + */ +public class DelegatingGuacamoleSocket implements GuacamoleSocket { + + /** + * The wrapped socket. + */ + private final GuacamoleSocket socket; + + /** + * Wraps the given GuacamoleSocket such that all function calls against + * this DelegatingGuacamoleSocket will be delegated to it. + * + * @param socket + * The GuacamoleSocket to wrap. + */ + public DelegatingGuacamoleSocket(GuacamoleSocket socket) { + this.socket = socket; + } + + /** + * Returns the underlying GuacamoleSocket wrapped by this + * DelegatingGuacamoleSocket. + * + * @return + * The GuacamoleSocket wrapped by this DelegatingGuacamoleSocket. + */ + protected GuacamoleSocket getDelegateSocket() { + return socket; + } + + @Override + public String getProtocol() { + return socket.getProtocol(); + } + + @Override + public GuacamoleReader getReader() { + return socket.getReader(); + } + + @Override + public GuacamoleWriter getWriter() { + return socket.getWriter(); + } + + @Override + public void close() throws GuacamoleException { + socket.close(); + } + + @Override + public boolean isOpen() { + return socket.isOpen(); + } + +} diff --git a/guacamole-common/src/main/java/org/apache/guacamole/net/GuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/net/GuacamoleSocket.java index 4d084e465..af068faea 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/net/GuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/net/GuacamoleSocket.java @@ -29,6 +29,24 @@ import org.apache.guacamole.io.GuacamoleWriter; */ public interface GuacamoleSocket { + /** + * Returns the name of the protocol to be used. If the protocol is not + * known or the implementation refuses to reveal the underlying protocol, + * null is returned. + * + *

Implementations should aim to expose the name of the + * underlying protocol, such that protocol-specific responses like the + * "required" and "argv" instructions can be handled correctly by code + * consuming the GuacamoleSocket. + * + * @return + * The name of the protocol to be used, or null if this information is + * not available. + */ + public default String getProtocol() { + return null; + } + /** * Returns a GuacamoleReader which can be used to read from the * Guacamole instruction stream associated with the connection diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java index fe4efca36..6cf3d7b3c 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/ConfiguredGuacamoleSocket.java @@ -24,6 +24,7 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.io.GuacamoleReader; import org.apache.guacamole.io.GuacamoleWriter; +import org.apache.guacamole.net.DelegatingGuacamoleSocket; import org.apache.guacamole.net.GuacamoleSocket; /** @@ -36,12 +37,7 @@ import org.apache.guacamole.net.GuacamoleSocket; * this GuacamoleSocket from manually controlling the initial protocol * handshake. */ -public class ConfiguredGuacamoleSocket implements GuacamoleSocket { - - /** - * The wrapped socket. - */ - private GuacamoleSocket socket; +public class ConfiguredGuacamoleSocket extends DelegatingGuacamoleSocket { /** * The configuration to use when performing the Guacamole protocol @@ -125,7 +121,7 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { GuacamoleConfiguration config, GuacamoleClientInformation info) throws GuacamoleException { - this.socket = socket; + super(socket); this.config = config; // Get reader and writer @@ -268,23 +264,8 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket { } @Override - public GuacamoleWriter getWriter() { - return socket.getWriter(); - } - - @Override - public GuacamoleReader getReader() { - return socket.getReader(); - } - - @Override - public void close() throws GuacamoleException { - socket.close(); - } - - @Override - public boolean isOpen() { - return socket.isOpen(); + public String getProtocol() { + return getConfiguration().getProtocol(); } } diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/FailoverGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/FailoverGuacamoleSocket.java index 3c64c51e7..15414c0f5 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/FailoverGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/FailoverGuacamoleSocket.java @@ -28,7 +28,7 @@ import org.apache.guacamole.GuacamoleUpstreamNotFoundException; import org.apache.guacamole.GuacamoleUpstreamTimeoutException; import org.apache.guacamole.GuacamoleUpstreamUnavailableException; import org.apache.guacamole.io.GuacamoleReader; -import org.apache.guacamole.io.GuacamoleWriter; +import org.apache.guacamole.net.DelegatingGuacamoleSocket; import org.apache.guacamole.net.GuacamoleSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory; * constructor, allowing a different socket to be substituted prior to * fulfilling the connection. */ -public class FailoverGuacamoleSocket implements GuacamoleSocket { +public class FailoverGuacamoleSocket extends DelegatingGuacamoleSocket { /** * Logger for this class. @@ -54,11 +54,6 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { */ private static final int DEFAULT_INSTRUCTION_QUEUE_LIMIT = 131072; - /** - * The wrapped socket being used. - */ - private final GuacamoleSocket socket; - /** * Queue of all instructions read while this FailoverGuacamoleSocket was * being constructed. @@ -158,6 +153,8 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { final int instructionQueueLimit) throws GuacamoleException, GuacamoleUpstreamException { + super(socket); + int totalQueueSize = 0; GuacamoleInstruction instruction; @@ -189,8 +186,6 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { } - this.socket = socket; - } /** @@ -230,7 +225,7 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { @Override public boolean available() throws GuacamoleException { - return !instructionQueue.isEmpty() || socket.getReader().available(); + return !instructionQueue.isEmpty() || getDelegateSocket().getReader().available(); } @Override @@ -244,7 +239,7 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { return instruction.toString().toCharArray(); } - return socket.getReader().read(); + return getDelegateSocket().getReader().read(); } @@ -258,7 +253,7 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { if (!instructionQueue.isEmpty()) return instructionQueue.remove(); - return socket.getReader().readInstruction(); + return getDelegateSocket().getReader().readInstruction(); } @@ -269,19 +264,4 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket { return queuedReader; } - @Override - public GuacamoleWriter getWriter() { - return socket.getWriter(); - } - - @Override - public void close() throws GuacamoleException { - socket.close(); - } - - @Override - public boolean isOpen() { - return socket.isOpen(); - } - } diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/FilteredGuacamoleSocket.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/FilteredGuacamoleSocket.java index 5e541d0e3..c3bfefd2b 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/FilteredGuacamoleSocket.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/FilteredGuacamoleSocket.java @@ -19,21 +19,16 @@ package org.apache.guacamole.protocol; -import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.io.GuacamoleReader; import org.apache.guacamole.io.GuacamoleWriter; +import org.apache.guacamole.net.DelegatingGuacamoleSocket; import org.apache.guacamole.net.GuacamoleSocket; /** * Implementation of GuacamoleSocket which allows individual instructions to be * intercepted, overridden, etc. */ -public class FilteredGuacamoleSocket implements GuacamoleSocket { - - /** - * Wrapped GuacamoleSocket. - */ - private final GuacamoleSocket socket; +public class FilteredGuacamoleSocket extends DelegatingGuacamoleSocket { /** * A reader for the wrapped GuacamoleSocket which may be filtered. @@ -58,7 +53,8 @@ public class FilteredGuacamoleSocket implements GuacamoleSocket { * instructions, if any. */ public FilteredGuacamoleSocket(GuacamoleSocket socket, GuacamoleFilter readFilter, GuacamoleFilter writeFilter) { - this.socket = socket; + + super(socket); // Apply filter to reader if (readFilter != null) @@ -84,14 +80,4 @@ public class FilteredGuacamoleSocket implements GuacamoleSocket { return writer; } - @Override - public void close() throws GuacamoleException { - socket.close(); - } - - @Override - public boolean isOpen() { - return socket.isOpen(); - } - } diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleConfiguration.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleConfiguration.java index 48d7e523c..5c960661a 100644 --- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleConfiguration.java +++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleConfiguration.java @@ -92,8 +92,7 @@ public class GuacamoleConfiguration implements Serializable { /** * Sets the ID of the connection being joined, if any. If no connection - * is being joined, this value must be omitted, and the protocol must be - * set instead. + * is being joined, this value must be omitted. * * @param connectionID The ID of the connection being joined. */ @@ -103,15 +102,34 @@ public class GuacamoleConfiguration implements Serializable { /** * Returns the name of the protocol to be used. - * @return The name of the protocol to be used. + * + * @return + * The name of the protocol to be used. */ public String getProtocol() { return protocol; } /** - * Sets the name of the protocol to be used. - * @param protocol The name of the protocol to be used. + * Sets the name of the protocol to be used. If no connection is being + * joined (a new connection is being established), this value must be set. + * + *

If a connection is being joined, this value should still be + * set to ensure that protocol-specific responses like the + * "required" and "argv" instructions can be understood in their proper + * context by other code that may consume this GuacamoleConfiguration like + * {@link ConfiguredGuacamoleSocket}. + * + *

If this value is unavailable or remains unset, it is still possible + * to join an established connection using + * {@link #setConnectionID(java.lang.String)}, however protocol-specific + * responses like the "required" and "argv" instructions might not be + * possible to handle correctly if the underlying protocol is not made + * available through some other means to the client receiving those + * responses. + * + * @param protocol + * The name of the protocol to be used. */ public void setProtocol(String protocol) { this.protocol = protocol;