mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	GUACAMOLE-1: Refactor org.glyptodon package/groupId to org.apache.
This commit is contained in:
		| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when data has been submitted with an unsupported | ||||
|  * mimetype. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleClientBadTypeException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientBadTypeException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientBadTypeException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientBadTypeException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleClientBadTypeException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientBadTypeException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientBadTypeException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_BAD_TYPE; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A generic exception thrown when part of the Guacamole API encounters | ||||
|  * an error in the client's request. Such an error, if correctable, usually | ||||
|  * requires correction on the client side, not the server. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleClientException extends GuacamoleException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleClientException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_BAD_REQUEST; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,73 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when the client has sent too much data. This | ||||
|  * usually indicates that a server-side buffer is not large enough to | ||||
|  * accommodate the data, or protocol specifications prohibit data of the size | ||||
|  * received. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleClientOverrunException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientOverrunException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientOverrunException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientOverrunException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleClientOverrunException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientOverrunException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientOverrunException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_OVERRUN; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,70 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when the client is taking too long to respond. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleClientTimeoutException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientTimeoutException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientTimeoutException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientTimeoutException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleClientTimeoutException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientTimeoutException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientTimeoutException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_TIMEOUT; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when too many requests have been received | ||||
|  * by the current client, and further requests are being rejected, either | ||||
|  * temporarily or permanently. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleClientTooManyException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientTooManyException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientTooManyException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientTooManyException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleClientTooManyException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleClientTooManyException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleClientTooManyException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_TOO_MANY; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when an operation cannot be performed because | ||||
|  * its corresponding connection is closed. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleConnectionClosedException extends GuacamoleServerException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleConnectionClosedException with the given message | ||||
|      * and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleConnectionClosedException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleConnectionClosedException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleConnectionClosedException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleConnectionClosedException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleConnectionClosedException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.SERVER_ERROR; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,77 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A generic exception thrown when parts of the Guacamole API encounter | ||||
|  * errors. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleException extends Exception { | ||||
|      | ||||
|     /** | ||||
|      * Creates a new GuacamoleException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the Guacamole status associated with this exception. This status | ||||
|      * can then be easily translated into an HTTP error code or Guacamole | ||||
|      * protocol error code. | ||||
|      *  | ||||
|      * @return The corresponding Guacamole status. | ||||
|      */ | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.SERVER_ERROR; | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when a resource has been requested, but that | ||||
|  * resource is locked or currently in use, and cannot be accessed by the | ||||
|  * current user. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleResourceConflictException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleResourceConflictException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleResourceConflictException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleResourceConflictException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleResourceConflictException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleResourceConflictException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleResourceConflictException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.RESOURCE_CONFLICT; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A generic exception thrown when part of the Guacamole API fails to find | ||||
|  * a requested resource, such as a configuration or tunnel. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleResourceNotFoundException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleResourceNotFoundException with the given message | ||||
|      * and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleResourceNotFoundException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleResourceNotFoundException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleResourceNotFoundException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleResourceNotFoundException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleResourceNotFoundException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.RESOURCE_NOT_FOUND; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A security-related exception thrown when parts of the Guacamole API is | ||||
|  * denying access to a resource. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleSecurityException extends GuacamoleClientException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleSecurityException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleSecurityException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleSecurityException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleSecurityException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleSecurityException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleSecurityException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_FORBIDDEN; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when the server is too busy to service the | ||||
|  * request. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleServerBusyException extends GuacamoleServerException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleServerBusyException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleServerBusyException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleServerBusyException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleServerBusyException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleServerBusyException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleServerBusyException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.SERVER_BUSY; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A generic exception thrown when part of the Guacamole API encounters | ||||
|  * an unexpected, internal error. An internal error, if correctable, would | ||||
|  * require correction on the server side, not the client. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleServerException extends GuacamoleException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleServerException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleServerException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleServerException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleServerException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleServerException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleServerException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.SERVER_ERROR; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A security-related exception thrown when parts of the Guacamole API is | ||||
|  * denying access to a resource, but access MAY be granted were the user | ||||
|  * authorized (logged in). | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleUnauthorizedException extends GuacamoleSecurityException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUnauthorizedException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUnauthorizedException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUnauthorizedException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleUnauthorizedException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUnauthorizedException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUnauthorizedException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.CLIENT_UNAUTHORIZED; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which is thrown when the requested operation is unsupported | ||||
|  * or unimplemented. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleUnsupportedException extends GuacamoleServerException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUnsupportedException with the given message and cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUnsupportedException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUnsupportedException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleUnsupportedException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUnsupportedException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUnsupportedException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.UNSUPPORTED; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which indicates than an upstream server (such as the remote | ||||
|  * desktop) is returning an error or is otherwise unreachable. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleUpstreamException extends GuacamoleException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUpstreamException with the given message and | ||||
|      * cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUpstreamException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUpstreamException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleUpstreamException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUpstreamException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUpstreamException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.UPSTREAM_ERROR; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * An exception which indicates than an upstream server (such as the remote | ||||
|  * desktop) is taking too long to respond. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleUpstreamTimeoutException extends GuacamoleUpstreamException { | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUpstreamException with the given message and | ||||
|      * cause. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUpstreamTimeoutException(String message, Throwable cause) { | ||||
|         super(message, cause); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUpstreamException with the given message. | ||||
|      * | ||||
|      * @param message A human readable description of the exception that | ||||
|      *                occurred. | ||||
|      */ | ||||
|     public GuacamoleUpstreamTimeoutException(String message) { | ||||
|         super(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleUpstreamException with the given cause. | ||||
|      * | ||||
|      * @param cause The cause of this exception. | ||||
|      */ | ||||
|     public GuacamoleUpstreamTimeoutException(Throwable cause) { | ||||
|         super(cause); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleStatus getStatus() { | ||||
|         return GuacamoleStatus.UPSTREAM_TIMEOUT; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,75 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.io; | ||||
|  | ||||
|  | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.protocol.GuacamoleInstruction; | ||||
|  | ||||
| /** | ||||
|  * Provides abstract and raw character read access to a stream of Guacamole | ||||
|  * instructions. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public interface GuacamoleReader { | ||||
|  | ||||
|     /** | ||||
|      * Returns whether instruction data is available for reading. Note that | ||||
|      * this does not guarantee an entire instruction is available. If a full | ||||
|      * instruction is not available, this function can return true, and a call | ||||
|      * to read() will still block. | ||||
|      * | ||||
|      * @return true if instruction data is available for reading, false | ||||
|      *         otherwise. | ||||
|      * @throws GuacamoleException If an error occurs while checking for | ||||
|      *                            available data. | ||||
|      */ | ||||
|     public boolean available() throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Reads at least one complete Guacamole instruction, returning a buffer | ||||
|      * containing one or more complete Guacamole instructions and no | ||||
|      * incomplete Guacamole instructions. This function will block until at | ||||
|      * least one complete instruction is available. | ||||
|      * | ||||
|      * @return A buffer containing at least one complete Guacamole instruction, | ||||
|      *         or null if no more instructions are available for reading. | ||||
|      * @throws GuacamoleException If an error occurs while reading from the | ||||
|      *                            stream. | ||||
|      */ | ||||
|     public char[] read() throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Reads exactly one complete Guacamole instruction and returns the fully | ||||
|      * parsed instruction. | ||||
|      * | ||||
|      * @return The next complete instruction from the stream, fully parsed, or | ||||
|      *         null if no more instructions are available for reading. | ||||
|      * @throws GuacamoleException If an error occurs while reading from the | ||||
|      *                            stream, or if the instruction cannot be | ||||
|      *                            parsed. | ||||
|      */ | ||||
|     public GuacamoleInstruction readInstruction() throws GuacamoleException; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.io; | ||||
|  | ||||
|  | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.protocol.GuacamoleInstruction; | ||||
|  | ||||
| /** | ||||
|  * Provides abstract and raw character write access to a stream of Guacamole | ||||
|  * instructions. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public interface GuacamoleWriter { | ||||
|  | ||||
|     /** | ||||
|      * Writes a portion of the given array of characters to the Guacamole | ||||
|      * instruction stream. The portion must contain only complete Guacamole | ||||
|      * instructions. | ||||
|      * | ||||
|      * @param chunk An array of characters containing Guacamole instructions. | ||||
|      * @param off The start offset of the portion of the array to write. | ||||
|      * @param len The length of the portion of the array to write. | ||||
|      * @throws GuacamoleException If an error occurred while writing the | ||||
|      *                            portion of the array specified. | ||||
|      */ | ||||
|     public void write(char[] chunk, int off, int len) throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Writes the entire given array of characters to the Guacamole instruction | ||||
|      * stream. The array must consist only of complete Guacamole instructions. | ||||
|      * | ||||
|      * @param chunk An array of characters consisting only of complete | ||||
|      *              Guacamole instructions. | ||||
|      * @throws GuacamoleException If an error occurred while writing the | ||||
|      *                            the specified array. | ||||
|      */ | ||||
|     public void write(char[] chunk) throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Writes the given fully parsed instruction to the Guacamole instruction | ||||
|      * stream. | ||||
|      * | ||||
|      * @param instruction The Guacamole instruction to write. | ||||
|      * @throws GuacamoleException If an error occurred while writing the | ||||
|      *                            instruction. | ||||
|      */ | ||||
|     public void writeInstruction(GuacamoleInstruction instruction) throws GuacamoleException; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,272 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.io; | ||||
|  | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.net.SocketException; | ||||
| import java.net.SocketTimeoutException; | ||||
| import java.util.Deque; | ||||
| import java.util.LinkedList; | ||||
| import org.apache.guacamole.GuacamoleConnectionClosedException; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
| import org.apache.guacamole.GuacamoleUpstreamTimeoutException; | ||||
| import org.apache.guacamole.protocol.GuacamoleInstruction; | ||||
|  | ||||
| /** | ||||
|  * A GuacamoleReader which wraps a standard Java Reader, using that Reader as | ||||
|  * the Guacamole instruction stream. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class ReaderGuacamoleReader implements GuacamoleReader { | ||||
|  | ||||
|     /** | ||||
|      * Wrapped Reader to be used for all input. | ||||
|      */ | ||||
|     private Reader input; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new ReaderGuacamoleReader which will use the given Reader as | ||||
|      * the Guacamole instruction stream. | ||||
|      * | ||||
|      * @param input The Reader to use as the Guacamole instruction stream. | ||||
|      */ | ||||
|     public ReaderGuacamoleReader(Reader input) { | ||||
|         this.input = input; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * The location within the received data buffer that parsing should begin | ||||
|      * when more data is read. | ||||
|      */ | ||||
|     private int parseStart; | ||||
|  | ||||
|     /** | ||||
|      * The buffer holding all received, unparsed data. | ||||
|      */ | ||||
|     private char[] buffer = new char[20480]; | ||||
|  | ||||
|     /** | ||||
|      * The number of characters currently used within the data buffer. All | ||||
|      * other characters within the buffer are free space available for | ||||
|      * future reads. | ||||
|      */ | ||||
|     private int usedLength = 0; | ||||
|  | ||||
|     @Override | ||||
|     public boolean available() throws GuacamoleException { | ||||
|         try { | ||||
|             return input.ready() || usedLength != 0; | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public char[] read() throws GuacamoleException { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             // While we're blocking, or input is available | ||||
|             for (;;) { | ||||
|  | ||||
|                 // Length of element | ||||
|                 int elementLength = 0; | ||||
|  | ||||
|                 // Resume where we left off | ||||
|                 int i = parseStart; | ||||
|  | ||||
|                 // Parse instruction in buffer | ||||
|                 while (i < usedLength) { | ||||
|  | ||||
|                     // Read character | ||||
|                     char readChar = buffer[i++]; | ||||
|  | ||||
|                     // If digit, update length | ||||
|                     if (readChar >= '0' && readChar <= '9') | ||||
|                         elementLength = elementLength * 10 + readChar - '0'; | ||||
|  | ||||
|                     // If not digit, check for end-of-length character | ||||
|                     else if (readChar == '.') { | ||||
|  | ||||
|                         // Check if element present in buffer | ||||
|                         if (i + elementLength < usedLength) { | ||||
|  | ||||
|                             // Get terminator | ||||
|                             char terminator = buffer[i + elementLength]; | ||||
|  | ||||
|                             // Move to character after terminator | ||||
|                             i += elementLength + 1; | ||||
|  | ||||
|                             // Reset length | ||||
|                             elementLength = 0; | ||||
|  | ||||
|                             // Continue here if necessary | ||||
|                             parseStart = i; | ||||
|  | ||||
|                             // If terminator is semicolon, we have a full | ||||
|                             // instruction. | ||||
|                             if (terminator == ';') { | ||||
|  | ||||
|                                 // Copy instruction data | ||||
|                                 char[] instruction = new char[i]; | ||||
|                                 System.arraycopy(buffer, 0, instruction, 0, i); | ||||
|  | ||||
|                                 // Update buffer | ||||
|                                 usedLength -= i; | ||||
|                                 parseStart = 0; | ||||
|                                 System.arraycopy(buffer, i, buffer, 0, usedLength); | ||||
|  | ||||
|                                 return instruction; | ||||
|  | ||||
|                             } | ||||
|  | ||||
|                             // Handle invalid terminator characters | ||||
|                             else if (terminator != ',') | ||||
|                                 throw new GuacamoleServerException("Element terminator of instruction was not ';' nor ','"); | ||||
|  | ||||
|                         } | ||||
|  | ||||
|                         // Otherwise, read more data | ||||
|                         else | ||||
|                             break; | ||||
|  | ||||
|                     } | ||||
|  | ||||
|                     // Otherwise, parse error | ||||
|                     else | ||||
|                         throw new GuacamoleServerException("Non-numeric character in element length."); | ||||
|  | ||||
|                 } | ||||
|  | ||||
|                 // If past threshold, resize buffer before reading | ||||
|                 if (usedLength > buffer.length/2) { | ||||
|                     char[] biggerBuffer = new char[buffer.length*2]; | ||||
|                     System.arraycopy(buffer, 0, biggerBuffer, 0, usedLength); | ||||
|                     buffer = biggerBuffer; | ||||
|                 } | ||||
|  | ||||
|                 // Attempt to fill buffer | ||||
|                 int numRead = input.read(buffer, usedLength, buffer.length - usedLength); | ||||
|                 if (numRead == -1) | ||||
|                     return null; | ||||
|  | ||||
|                 // Update used length | ||||
|                 usedLength += numRead; | ||||
|  | ||||
|             } // End read loop | ||||
|  | ||||
|         } | ||||
|         catch (SocketTimeoutException e) { | ||||
|             throw new GuacamoleUpstreamTimeoutException("Connection to guacd timed out.", e); | ||||
|         } | ||||
|         catch (SocketException e) { | ||||
|             throw new GuacamoleConnectionClosedException("Connection to guacd is closed.", e); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleInstruction readInstruction() throws GuacamoleException { | ||||
|  | ||||
|         // Get instruction | ||||
|         char[] instructionBuffer = read(); | ||||
|  | ||||
|         // If EOF, return EOF | ||||
|         if (instructionBuffer == null) | ||||
|             return null; | ||||
|  | ||||
|         // Start of element | ||||
|         int elementStart = 0; | ||||
|  | ||||
|         // Build list of elements | ||||
|         Deque<String> elements = new LinkedList<String>(); | ||||
|         while (elementStart < instructionBuffer.length) { | ||||
|  | ||||
|             // Find end of length | ||||
|             int lengthEnd = -1; | ||||
|             for (int i=elementStart; i<instructionBuffer.length; i++) { | ||||
|                 if (instructionBuffer[i] == '.') { | ||||
|                     lengthEnd = i; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // read() is required to return a complete instruction. If it does | ||||
|             // not, this is a severe internal error. | ||||
|             if (lengthEnd == -1) | ||||
|                 throw new GuacamoleServerException("Read returned incomplete instruction."); | ||||
|  | ||||
|             // Parse length | ||||
|             int length = Integer.parseInt(new String( | ||||
|                     instructionBuffer, | ||||
|                     elementStart, | ||||
|                     lengthEnd - elementStart | ||||
|             )); | ||||
|  | ||||
|             // Parse element from just after period | ||||
|             elementStart = lengthEnd + 1; | ||||
|             String element = new String( | ||||
|                     instructionBuffer, | ||||
|                     elementStart, | ||||
|                     length | ||||
|             ); | ||||
|  | ||||
|             // Append element to list of elements | ||||
|             elements.addLast(element); | ||||
|  | ||||
|             // Read terminator after element | ||||
|             elementStart += length; | ||||
|             char terminator = instructionBuffer[elementStart]; | ||||
|  | ||||
|             // Continue reading instructions after terminator | ||||
|             elementStart++; | ||||
|  | ||||
|             // If we've reached the end of the instruction | ||||
|             if (terminator == ';') | ||||
|                 break; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         // Pull opcode off elements list | ||||
|         String opcode = elements.removeFirst(); | ||||
|  | ||||
|         // Create instruction | ||||
|         GuacamoleInstruction instruction = new GuacamoleInstruction( | ||||
|                 opcode, | ||||
|                 elements.toArray(new String[elements.size()]) | ||||
|         ); | ||||
|  | ||||
|         // Return parsed instruction | ||||
|         return instruction; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,86 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.io; | ||||
|  | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.Writer; | ||||
| import java.net.SocketException; | ||||
| import java.net.SocketTimeoutException; | ||||
| import org.apache.guacamole.GuacamoleConnectionClosedException; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
| import org.apache.guacamole.GuacamoleUpstreamTimeoutException; | ||||
| import org.apache.guacamole.protocol.GuacamoleInstruction; | ||||
|  | ||||
| /** | ||||
|  * A GuacamoleWriter which wraps a standard Java Writer, using that Writer as | ||||
|  * the Guacamole instruction stream. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class WriterGuacamoleWriter implements GuacamoleWriter { | ||||
|  | ||||
|     /** | ||||
|      * Wrapped Writer to be used for all output. | ||||
|      */ | ||||
|     private Writer output; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new WriterGuacamoleWriter which will use the given Writer as | ||||
|      * the Guacamole instruction stream. | ||||
|      * | ||||
|      * @param output The Writer to use as the Guacamole instruction stream. | ||||
|      */ | ||||
|     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 (SocketTimeoutException e) { | ||||
|             throw new GuacamoleUpstreamTimeoutException("Connection to guacd timed out.", e); | ||||
|         } | ||||
|         catch (SocketException e) { | ||||
|             throw new GuacamoleConnectionClosedException("Connection to guacd is closed.", e); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(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,27 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * All classes relating directly to data input or output. | ||||
|  */ | ||||
| package org.apache.guacamole.io; | ||||
|  | ||||
| @@ -0,0 +1,133 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
|  | ||||
| import java.util.concurrent.locks.ReentrantLock; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
|  | ||||
| /** | ||||
|  * Base GuacamoleTunnel implementation which synchronizes access to the | ||||
|  * underlying reader and writer with reentrant locks. Implementations need only | ||||
|  * provide the tunnel's UUID and socket. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public abstract class AbstractGuacamoleTunnel implements GuacamoleTunnel { | ||||
|  | ||||
|     /** | ||||
|      * Lock acquired when a read operation is in progress. | ||||
|      */ | ||||
|     private final ReentrantLock readerLock; | ||||
|  | ||||
|     /** | ||||
|      * Lock acquired when a write operation is in progress. | ||||
|      */ | ||||
|     private final ReentrantLock writerLock; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleTunnel which synchronizes access to the | ||||
|      * Guacamole instruction stream associated with the underlying | ||||
|      * GuacamoleSocket. | ||||
|      */ | ||||
|     public AbstractGuacamoleTunnel() { | ||||
|         readerLock = new ReentrantLock(); | ||||
|         writerLock = new ReentrantLock(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Acquires exclusive read access to the Guacamole instruction stream | ||||
|      * and returns a GuacamoleReader for reading from that stream. | ||||
|      * | ||||
|      * @return A GuacamoleReader for reading from the Guacamole instruction | ||||
|      *         stream. | ||||
|      */ | ||||
|     @Override | ||||
|     public GuacamoleReader acquireReader() { | ||||
|         readerLock.lock(); | ||||
|         return getSocket().getReader(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Relinquishes exclusive read access to the Guacamole instruction | ||||
|      * stream. This function should be called whenever a thread finishes using | ||||
|      * a GuacamoleTunnel's GuacamoleReader. | ||||
|      */ | ||||
|     @Override | ||||
|     public void releaseReader() { | ||||
|         readerLock.unlock(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns whether there are threads waiting for read access to the | ||||
|      * Guacamole instruction stream. | ||||
|      * | ||||
|      * @return true if threads are waiting for read access the Guacamole | ||||
|      *         instruction stream, false otherwise. | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean hasQueuedReaderThreads() { | ||||
|         return readerLock.hasQueuedThreads(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Acquires exclusive write access to the Guacamole instruction stream | ||||
|      * and returns a GuacamoleWriter for writing to that stream. | ||||
|      * | ||||
|      * @return A GuacamoleWriter for writing to the Guacamole instruction | ||||
|      *         stream. | ||||
|      */ | ||||
|     @Override | ||||
|     public GuacamoleWriter acquireWriter() { | ||||
|         writerLock.lock(); | ||||
|         return getSocket().getWriter(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Relinquishes exclusive write access to the Guacamole instruction | ||||
|      * stream. This function should be called whenever a thread finishes using | ||||
|      * a GuacamoleTunnel's GuacamoleWriter. | ||||
|      */ | ||||
|     @Override | ||||
|     public void releaseWriter() { | ||||
|         writerLock.unlock(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean hasQueuedWriterThreads() { | ||||
|         return writerLock.hasQueuedThreads(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws GuacamoleException { | ||||
|         getSocket().close(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isOpen() { | ||||
|         return getSocket().isOpen(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,104 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
| import java.util.UUID; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
|  | ||||
| /** | ||||
|  * GuacamoleTunnel implementation which simply delegates all function calls to | ||||
|  * an underlying GuacamoleTunnel. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class DelegatingGuacamoleTunnel implements GuacamoleTunnel { | ||||
|  | ||||
|     /** | ||||
|      * The wrapped GuacamoleTunnel. | ||||
|      */ | ||||
|     private final GuacamoleTunnel tunnel; | ||||
|  | ||||
|     /** | ||||
|      * Wraps the given tunnel such that all function calls against this tunnel | ||||
|      * will be delegated to it. | ||||
|      * | ||||
|      * @param tunnel | ||||
|      *     The GuacamoleTunnel to wrap. | ||||
|      */ | ||||
|     public DelegatingGuacamoleTunnel(GuacamoleTunnel tunnel) { | ||||
|         this.tunnel = tunnel; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleReader acquireReader() { | ||||
|         return tunnel.acquireReader(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void releaseReader() { | ||||
|         tunnel.releaseReader(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean hasQueuedReaderThreads() { | ||||
|         return tunnel.hasQueuedReaderThreads(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleWriter acquireWriter() { | ||||
|         return tunnel.acquireWriter(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void releaseWriter() { | ||||
|         tunnel.releaseWriter(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean hasQueuedWriterThreads() { | ||||
|         return tunnel.hasQueuedWriterThreads(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public UUID getUUID() { | ||||
|         return tunnel.getUUID(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleSocket getSocket() { | ||||
|         return tunnel.getSocket(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws GuacamoleException { | ||||
|         tunnel.close(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isOpen() { | ||||
|         return tunnel.isOpen(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,73 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
|  | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
|  | ||||
| /** | ||||
|  * Provides abstract socket-like access to a Guacamole connection. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public interface GuacamoleSocket { | ||||
|  | ||||
|     /** | ||||
|      * Returns a GuacamoleReader which can be used to read from the | ||||
|      * Guacamole instruction stream associated with the connection | ||||
|      * represented by this GuacamoleSocket. | ||||
|      * | ||||
|      * @return A GuacamoleReader which can be used to read from the | ||||
|      *         Guacamole instruction stream. | ||||
|      */ | ||||
|     public GuacamoleReader getReader(); | ||||
|  | ||||
|     /** | ||||
|      * Returns a GuacamoleWriter which can be used to write to the | ||||
|      * Guacamole instruction stream associated with the connection | ||||
|      * represented by this GuacamoleSocket. | ||||
|      * | ||||
|      * @return A GuacamoleWriter which can be used to write to the | ||||
|      *         Guacamole instruction stream. | ||||
|      */ | ||||
|     public GuacamoleWriter getWriter(); | ||||
|  | ||||
|     /** | ||||
|      * Releases all resources in use by the connection represented by this | ||||
|      * GuacamoleSocket. | ||||
|      * | ||||
|      * @throws GuacamoleException If an error occurs while releasing resources. | ||||
|      */ | ||||
|     public void close() throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Returns whether this GuacamoleSocket is open and can be used for reading | ||||
|      * and writing. | ||||
|      * | ||||
|      * @return true if this GuacamoleSocket is open, false otherwise. | ||||
|      */ | ||||
|     public boolean isOpen(); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,119 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
|  | ||||
| import java.util.UUID; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
|  | ||||
| /** | ||||
|  * Provides a unique identifier and synchronized access to the GuacamoleReader | ||||
|  * and GuacamoleWriter associated with a GuacamoleSocket. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public interface GuacamoleTunnel { | ||||
|  | ||||
|     /** | ||||
|      * Acquires exclusive read access to the Guacamole instruction stream | ||||
|      * and returns a GuacamoleReader for reading from that stream. | ||||
|      * | ||||
|      * @return A GuacamoleReader for reading from the Guacamole instruction | ||||
|      *         stream. | ||||
|      */ | ||||
|     GuacamoleReader acquireReader(); | ||||
|  | ||||
|     /** | ||||
|      * Relinquishes exclusive read access to the Guacamole instruction | ||||
|      * stream. This function should be called whenever a thread finishes using | ||||
|      * a GuacamoleTunnel's GuacamoleReader. | ||||
|      */ | ||||
|     void releaseReader(); | ||||
|  | ||||
|     /** | ||||
|      * Returns whether there are threads waiting for read access to the | ||||
|      * Guacamole instruction stream. | ||||
|      * | ||||
|      * @return true if threads are waiting for read access the Guacamole | ||||
|      *         instruction stream, false otherwise. | ||||
|      */ | ||||
|     boolean hasQueuedReaderThreads(); | ||||
|  | ||||
|     /** | ||||
|      * Acquires exclusive write access to the Guacamole instruction stream | ||||
|      * and returns a GuacamoleWriter for writing to that stream. | ||||
|      * | ||||
|      * @return A GuacamoleWriter for writing to the Guacamole instruction | ||||
|      *         stream. | ||||
|      */ | ||||
|     GuacamoleWriter acquireWriter(); | ||||
|  | ||||
|     /** | ||||
|      * Relinquishes exclusive write access to the Guacamole instruction | ||||
|      * stream. This function should be called whenever a thread finishes using | ||||
|      * a GuacamoleTunnel's GuacamoleWriter. | ||||
|      */ | ||||
|     void releaseWriter(); | ||||
|  | ||||
|     /** | ||||
|      * Returns whether there are threads waiting for write access to the | ||||
|      * Guacamole instruction stream. | ||||
|      * | ||||
|      * @return true if threads are waiting for write access the Guacamole | ||||
|      *         instruction stream, false otherwise. | ||||
|      */ | ||||
|     boolean hasQueuedWriterThreads(); | ||||
|  | ||||
|     /** | ||||
|      * Returns the unique identifier associated with this GuacamoleTunnel. | ||||
|      * | ||||
|      * @return The unique identifier associated with this GuacamoleTunnel. | ||||
|      */ | ||||
|     UUID getUUID(); | ||||
|  | ||||
|     /** | ||||
|      * Returns the GuacamoleSocket used by this GuacamoleTunnel for reading | ||||
|      * and writing. | ||||
|      * | ||||
|      * @return The GuacamoleSocket used by this GuacamoleTunnel. | ||||
|      */ | ||||
|     GuacamoleSocket getSocket(); | ||||
|  | ||||
|     /** | ||||
|      * Release all resources allocated to this GuacamoleTunnel. | ||||
|      * | ||||
|      * @throws GuacamoleException if an error occurs while releasing | ||||
|      *                            resources. | ||||
|      */ | ||||
|     void close() throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Returns whether this GuacamoleTunnel is open, or has been closed. | ||||
|      * | ||||
|      * @return true if this GuacamoleTunnel is open, false if it is closed. | ||||
|      */ | ||||
|     boolean isOpen(); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,150 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
|  | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.ReaderGuacamoleReader; | ||||
| import org.apache.guacamole.io.WriterGuacamoleWriter; | ||||
| import org.apache.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 java.net.SocketTimeoutException; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
| import org.apache.guacamole.GuacamoleUpstreamTimeoutException; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * Provides abstract socket-like access to a Guacamole connection over a given | ||||
|  * hostname and port. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class InetGuacamoleSocket implements GuacamoleSocket { | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private Logger logger = LoggerFactory.getLogger(InetGuacamoleSocket.class); | ||||
|  | ||||
|     /** | ||||
|      * The GuacamoleReader this socket should read from. | ||||
|      */ | ||||
|     private GuacamoleReader reader; | ||||
|  | ||||
|     /** | ||||
|      * The GuacamoleWriter this socket should write to. | ||||
|      */ | ||||
|     private GuacamoleWriter writer; | ||||
|  | ||||
|     /** | ||||
|      * The number of milliseconds to wait for data on the TCP socket before | ||||
|      * timing out. | ||||
|      */ | ||||
|     private static final int SOCKET_TIMEOUT = 15000; | ||||
|  | ||||
|     /** | ||||
|      * The TCP socket that the GuacamoleReader and GuacamoleWriter exposed | ||||
|      * by this class should affect. | ||||
|      */ | ||||
|     private Socket sock; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new InetGuacamoleSocket which reads and writes instructions | ||||
|      * to the Guacamole instruction stream of the Guacamole proxy server | ||||
|      * running at the given hostname and port. | ||||
|      * | ||||
|      * @param hostname The hostname of the Guacamole proxy server to connect to. | ||||
|      * @param port The port of the Guacamole proxy server to connect to. | ||||
|      * @throws GuacamoleException If an error occurs while connecting to the | ||||
|      *                            Guacamole proxy server. | ||||
|      */ | ||||
|     public InetGuacamoleSocket(String hostname, int port) throws GuacamoleException { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             logger.debug("Connecting to guacd at {}:{}.", hostname, port); | ||||
|  | ||||
|             // 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(),   "UTF-8")); | ||||
|             writer = new WriterGuacamoleWriter(new OutputStreamWriter(sock.getOutputStream(), "UTF-8")); | ||||
|  | ||||
|         } | ||||
|         catch (SocketTimeoutException e) { | ||||
|             throw new GuacamoleUpstreamTimeoutException("Connection timed out.", e); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws GuacamoleException { | ||||
|         try { | ||||
|             logger.debug("Closing socket to guacd."); | ||||
|             sock.close(); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleReader getReader() { | ||||
|         return reader; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleWriter getWriter() { | ||||
|         return writer; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isOpen() { | ||||
|         return !sock.isClosed(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,149 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.net.InetAddress; | ||||
| import java.net.InetSocketAddress; | ||||
| import java.net.Socket; | ||||
| import java.net.SocketAddress; | ||||
| import javax.net.SocketFactory; | ||||
| import javax.net.ssl.SSLSocketFactory; | ||||
| 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.io.ReaderGuacamoleReader; | ||||
| import org.apache.guacamole.io.WriterGuacamoleWriter; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * Provides abstract socket-like access to a Guacamole connection over SSL to | ||||
|  * a given hostname and port. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class SSLGuacamoleSocket implements GuacamoleSocket { | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private Logger logger = LoggerFactory.getLogger(SSLGuacamoleSocket.class); | ||||
|  | ||||
|     /** | ||||
|      * The GuacamoleReader this socket should read from. | ||||
|      */ | ||||
|     private GuacamoleReader reader; | ||||
|  | ||||
|     /** | ||||
|      * The GuacamoleWriter this socket should write to. | ||||
|      */ | ||||
|     private GuacamoleWriter writer; | ||||
|  | ||||
|     /** | ||||
|      * The number of milliseconds to wait for data on the TCP socket before | ||||
|      * timing out. | ||||
|      */ | ||||
|     private static final int SOCKET_TIMEOUT = 15000; | ||||
|  | ||||
|     /** | ||||
|      * The TCP socket that the GuacamoleReader and GuacamoleWriter exposed | ||||
|      * by this class should affect. | ||||
|      */ | ||||
|     private Socket sock; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new SSLGuacamoleSocket which reads and writes instructions | ||||
|      * to the Guacamole instruction stream of the Guacamole proxy server | ||||
|      * running at the given hostname and port using SSL. | ||||
|      * | ||||
|      * @param hostname The hostname of the Guacamole proxy server to connect to. | ||||
|      * @param port The port of the Guacamole proxy server to connect to. | ||||
|      * @throws GuacamoleException If an error occurs while connecting to the | ||||
|      *                            Guacamole proxy server. | ||||
|      */ | ||||
|     public SSLGuacamoleSocket(String hostname, int port) throws GuacamoleException { | ||||
|  | ||||
|         // Get factory for SSL sockets | ||||
|         SocketFactory socket_factory = SSLSocketFactory.getDefault(); | ||||
|          | ||||
|         try { | ||||
|  | ||||
|             logger.debug("Connecting to guacd at {}:{} via SSL/TLS.", | ||||
|                     hostname, port); | ||||
|  | ||||
|             // Get address | ||||
|             SocketAddress address = new InetSocketAddress( | ||||
|                 InetAddress.getByName(hostname), | ||||
|                 port | ||||
|             ); | ||||
|  | ||||
|             // Connect with timeout | ||||
|             sock = socket_factory.createSocket(); | ||||
|             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(),   "UTF-8")); | ||||
|             writer = new WriterGuacamoleWriter(new OutputStreamWriter(sock.getOutputStream(), "UTF-8")); | ||||
|  | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws GuacamoleException { | ||||
|         try { | ||||
|             logger.debug("Closing socket to guacd."); | ||||
|             sock.close(); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             throw new GuacamoleServerException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleReader getReader() { | ||||
|         return reader; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleWriter getWriter() { | ||||
|         return writer; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isOpen() { | ||||
|         return !sock.isClosed(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,69 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
|  | ||||
| import java.util.UUID; | ||||
|  | ||||
| /** | ||||
|  * GuacamoleTunnel implementation which uses a provided socket. The UUID of | ||||
|  * the tunnel will be randomly generated. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class SimpleGuacamoleTunnel extends AbstractGuacamoleTunnel { | ||||
|  | ||||
|     /** | ||||
|      * The UUID associated with this tunnel. Every tunnel must have a | ||||
|      * corresponding UUID such that tunnel read/write requests can be | ||||
|      * directed to the proper tunnel. | ||||
|      */ | ||||
|     private final UUID uuid = UUID.randomUUID(); | ||||
|  | ||||
|     /** | ||||
|      * The GuacamoleSocket that tunnel should use for communication on | ||||
|      * behalf of the connecting user. | ||||
|      */ | ||||
|     private final GuacamoleSocket socket; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleTunnel which synchronizes access to the | ||||
|      * Guacamole instruction stream associated with the given GuacamoleSocket. | ||||
|      * | ||||
|      * @param socket The GuacamoleSocket to provide synchronized access for. | ||||
|      */ | ||||
|     public SimpleGuacamoleTunnel(GuacamoleSocket socket) { | ||||
|         this.socket = socket; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public UUID getUUID() { | ||||
|         return uuid; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleSocket getSocket() { | ||||
|         return socket; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Classes which apply to network-specific concepts, such as low-level sockets | ||||
|  * and tunnels. | ||||
|  */ | ||||
| package org.apache.guacamole.net; | ||||
|  | ||||
| @@ -0,0 +1,29 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * All classes which apply generally across the Guacamole web application | ||||
|  * and all other web applications which use the API provided by the | ||||
|  * Guacamole project. | ||||
|  */ | ||||
| package org.apache.guacamole; | ||||
|  | ||||
| @@ -0,0 +1,249 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
|  | ||||
| import java.util.List; | ||||
| 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.GuacamoleSocket; | ||||
|  | ||||
| /** | ||||
|  * A GuacamoleSocket which pre-configures the connection based on a given | ||||
|  * GuacamoleConfiguration, completing the initial protocol handshake before | ||||
|  * accepting data for read or write. | ||||
|  * | ||||
|  * This is useful for forcing a connection to the Guacamole proxy server with | ||||
|  * a specific configuration while disallowing the client that will be using | ||||
|  * this GuacamoleSocket from manually controlling the initial protocol | ||||
|  * handshake. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class ConfiguredGuacamoleSocket implements GuacamoleSocket { | ||||
|  | ||||
|     /** | ||||
|      * The wrapped socket. | ||||
|      */ | ||||
|     private GuacamoleSocket socket; | ||||
|  | ||||
|     /** | ||||
|      * The configuration to use when performing the Guacamole protocol | ||||
|      * handshake. | ||||
|      */ | ||||
|     private GuacamoleConfiguration config; | ||||
|  | ||||
|     /** | ||||
|      * The unique identifier associated with this connection, as determined | ||||
|      * by the "ready" instruction received from the Guacamole proxy. | ||||
|      */ | ||||
|     private String id; | ||||
|      | ||||
|     /** | ||||
|      * Waits for the instruction having the given opcode, returning that | ||||
|      * instruction once it has been read. If the instruction is never read, | ||||
|      * an exception is thrown. | ||||
|      *  | ||||
|      * @param reader The reader to read instructions from. | ||||
|      * @param opcode The opcode of the instruction we are expecting. | ||||
|      * @return The instruction having the given opcode. | ||||
|      * @throws GuacamoleException If an error occurs while reading, or if | ||||
|      *                            the expected instruction is not read. | ||||
|      */ | ||||
|     private GuacamoleInstruction expect(GuacamoleReader reader, String opcode) | ||||
|         throws GuacamoleException { | ||||
|  | ||||
|         // Wait for an instruction | ||||
|         GuacamoleInstruction instruction = reader.readInstruction(); | ||||
|         if (instruction == null) | ||||
|             throw new GuacamoleServerException("End of stream while waiting for \"" + opcode + "\"."); | ||||
|  | ||||
|         // Ensure instruction has expected opcode | ||||
|         if (!instruction.getOpcode().equals(opcode)) | ||||
|             throw new GuacamoleServerException("Expected \"" + opcode + "\" instruction but instead received \"" + instruction.getOpcode() + "\"."); | ||||
|  | ||||
|         return instruction; | ||||
|  | ||||
|     } | ||||
|   | ||||
|     /** | ||||
|      * Creates a new ConfiguredGuacamoleSocket which uses the given | ||||
|      * GuacamoleConfiguration to complete the initial protocol handshake over | ||||
|      * the given GuacamoleSocket. A default GuacamoleClientInformation object | ||||
|      * is used to provide basic client information. | ||||
|      * | ||||
|      * @param socket The GuacamoleSocket to wrap. | ||||
|      * @param config The GuacamoleConfiguration to use to complete the initial | ||||
|      *               protocol handshake. | ||||
|      * @throws GuacamoleException If an error occurs while completing the | ||||
|      *                            initial protocol handshake. | ||||
|      */ | ||||
|     public ConfiguredGuacamoleSocket(GuacamoleSocket socket, | ||||
|             GuacamoleConfiguration config) throws GuacamoleException { | ||||
|         this(socket, config, new GuacamoleClientInformation()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new ConfiguredGuacamoleSocket which uses the given | ||||
|      * GuacamoleConfiguration and GuacamoleClientInformation to complete the | ||||
|      * initial protocol handshake over the given GuacamoleSocket. | ||||
|      * | ||||
|      * @param socket The GuacamoleSocket to wrap. | ||||
|      * @param config The GuacamoleConfiguration to use to complete the initial | ||||
|      *               protocol handshake. | ||||
|      * @param info The GuacamoleClientInformation to use to complete the initial | ||||
|      *             protocol handshake. | ||||
|      * @throws GuacamoleException If an error occurs while completing the | ||||
|      *                            initial protocol handshake. | ||||
|      */ | ||||
|     public ConfiguredGuacamoleSocket(GuacamoleSocket socket, | ||||
|             GuacamoleConfiguration config, | ||||
|             GuacamoleClientInformation info) throws GuacamoleException { | ||||
|  | ||||
|         this.socket = socket; | ||||
|         this.config = config; | ||||
|  | ||||
|         // Get reader and writer | ||||
|         GuacamoleReader reader = socket.getReader(); | ||||
|         GuacamoleWriter writer = socket.getWriter(); | ||||
|  | ||||
|         // Get protocol / connection ID | ||||
|         String select_arg = config.getConnectionID(); | ||||
|         if (select_arg == null) | ||||
|             select_arg = config.getProtocol(); | ||||
|  | ||||
|         // Send requested protocol or connection ID | ||||
|         writer.writeInstruction(new GuacamoleInstruction("select", select_arg)); | ||||
|  | ||||
|         // Wait for server args | ||||
|         GuacamoleInstruction args = expect(reader, "args"); | ||||
|  | ||||
|         // Build args list off provided names and config | ||||
|         List<String> arg_names = args.getArgs(); | ||||
|         String[] arg_values = new String[arg_names.size()]; | ||||
|         for (int i=0; i<arg_names.size(); i++) { | ||||
|  | ||||
|             // Retrieve argument name | ||||
|             String arg_name = arg_names.get(i); | ||||
|  | ||||
|             // Get defined value for name | ||||
|             String value = config.getParameter(arg_name); | ||||
|  | ||||
|             // If value defined, set that value | ||||
|             if (value != null) arg_values[i] = value; | ||||
|  | ||||
|             // Otherwise, leave value blank | ||||
|             else arg_values[i] = ""; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         // Send size | ||||
|         writer.writeInstruction( | ||||
|             new GuacamoleInstruction( | ||||
|                 "size", | ||||
|                 Integer.toString(info.getOptimalScreenWidth()), | ||||
|                 Integer.toString(info.getOptimalScreenHeight()), | ||||
|                 Integer.toString(info.getOptimalResolution()) | ||||
|             ) | ||||
|         ); | ||||
|  | ||||
|         // Send supported audio formats | ||||
|         writer.writeInstruction( | ||||
|                 new GuacamoleInstruction( | ||||
|                     "audio", | ||||
|                     info.getAudioMimetypes().toArray(new String[0]) | ||||
|                 )); | ||||
|  | ||||
|         // Send supported video formats | ||||
|         writer.writeInstruction( | ||||
|                 new GuacamoleInstruction( | ||||
|                     "video", | ||||
|                     info.getVideoMimetypes().toArray(new String[0]) | ||||
|                 )); | ||||
|  | ||||
|         // Send supported image formats | ||||
|         writer.writeInstruction( | ||||
|                 new GuacamoleInstruction( | ||||
|                     "image", | ||||
|                     info.getImageMimetypes().toArray(new String[0]) | ||||
|                 )); | ||||
|  | ||||
|         // Send args | ||||
|         writer.writeInstruction(new GuacamoleInstruction("connect", arg_values)); | ||||
|  | ||||
|         // Wait for ready, store ID | ||||
|         GuacamoleInstruction ready = expect(reader, "ready"); | ||||
|  | ||||
|         List<String> ready_args = ready.getArgs(); | ||||
|         if (ready_args.isEmpty()) | ||||
|             throw new GuacamoleServerException("No connection ID received"); | ||||
|  | ||||
|         id = ready.getArgs().get(0); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the GuacamoleConfiguration used to configure this | ||||
|      * ConfiguredGuacamoleSocket. | ||||
|      * | ||||
|      * @return The GuacamoleConfiguration used to configure this | ||||
|      *         ConfiguredGuacamoleSocket. | ||||
|      */ | ||||
|     public GuacamoleConfiguration getConfiguration() { | ||||
|         return config; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the unique ID associated with the Guacamole connection | ||||
|      * negotiated by this ConfiguredGuacamoleSocket. The ID is provided by | ||||
|      * the "ready" instruction returned by the Guacamole proxy. | ||||
|      *  | ||||
|      * @return The ID of the negotiated Guacamole connection. | ||||
|      */ | ||||
|     public String getConnectionID() { | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     @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(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,99 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
|  | ||||
| /** | ||||
|  * GuacamoleReader which applies a given GuacamoleFilter to observe or alter all | ||||
|  * read instructions. Instructions may also be dropped or denied by the the | ||||
|  * filter. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class FilteredGuacamoleReader implements GuacamoleReader { | ||||
|  | ||||
|     /** | ||||
|      * The wrapped GuacamoleReader. | ||||
|      */ | ||||
|     private final GuacamoleReader reader; | ||||
|  | ||||
|     /** | ||||
|      * The filter to apply when reading instructions. | ||||
|      */ | ||||
|     private final GuacamoleFilter filter; | ||||
|  | ||||
|     /** | ||||
|      * Wraps the given GuacamoleReader, applying the given filter to all read | ||||
|      * instructions. Future reads will return only instructions which pass | ||||
|      * the filter. | ||||
|      * | ||||
|      * @param reader The GuacamoleReader to wrap. | ||||
|      * @param filter The filter which dictates which instructions are read, and | ||||
|      *               how. | ||||
|      */ | ||||
|     public FilteredGuacamoleReader(GuacamoleReader reader, GuacamoleFilter filter) { | ||||
|         this.reader = reader; | ||||
|         this.filter = filter; | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public boolean available() throws GuacamoleException { | ||||
|         return reader.available(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public char[] read() throws GuacamoleException { | ||||
|  | ||||
|         GuacamoleInstruction filteredInstruction = readInstruction(); | ||||
|         if (filteredInstruction == null) | ||||
|             return null; | ||||
|  | ||||
|         return filteredInstruction.toString().toCharArray(); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleInstruction readInstruction() throws GuacamoleException { | ||||
|  | ||||
|         GuacamoleInstruction filteredInstruction; | ||||
|  | ||||
|         // Read and filter instructions until no instructions are dropped | ||||
|         do { | ||||
|  | ||||
|             // Read next instruction | ||||
|             GuacamoleInstruction unfilteredInstruction = reader.readInstruction(); | ||||
|             if (unfilteredInstruction == null) | ||||
|                 return null; | ||||
|  | ||||
|             // Apply filter | ||||
|             filteredInstruction = filter.filter(unfilteredInstruction); | ||||
|  | ||||
|         } while (filteredInstruction == null); | ||||
|  | ||||
|         return filteredInstruction; | ||||
|          | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,102 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| 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.GuacamoleSocket; | ||||
|  | ||||
| /** | ||||
|  * Implementation of GuacamoleSocket which allows individual instructions to be | ||||
|  * intercepted, overridden, etc. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class FilteredGuacamoleSocket implements GuacamoleSocket { | ||||
|  | ||||
|     /** | ||||
|      * Wrapped GuacamoleSocket. | ||||
|      */ | ||||
|     private final GuacamoleSocket socket; | ||||
|  | ||||
|     /** | ||||
|      * A reader for the wrapped GuacamoleSocket which may be filtered. | ||||
|      */ | ||||
|     private final GuacamoleReader reader; | ||||
|      | ||||
|     /** | ||||
|      * A writer for the wrapped GuacamoleSocket which may be filtered. | ||||
|      */ | ||||
|     private final GuacamoleWriter writer; | ||||
|      | ||||
|     /** | ||||
|      * Creates a new FilteredGuacamoleSocket which uses the given filters to | ||||
|      * determine whether instructions read/written are allowed through, | ||||
|      * modified, etc. If reads or writes should be unfiltered, simply specify | ||||
|      * null rather than a particular filter. | ||||
|      * | ||||
|      * @param socket The GuacamoleSocket to wrap. | ||||
|      * @param readFilter The GuacamoleFilter to apply to all read instructions, | ||||
|      *                   if any. | ||||
|      * @param writeFilter The GuacamoleFilter to apply to all written  | ||||
|      *                    instructions, if any. | ||||
|      */ | ||||
|     public FilteredGuacamoleSocket(GuacamoleSocket socket, GuacamoleFilter readFilter, GuacamoleFilter writeFilter) { | ||||
|         this.socket = socket; | ||||
|  | ||||
|         // Apply filter to reader | ||||
|         if (readFilter != null) | ||||
|             reader = new FilteredGuacamoleReader(socket.getReader(), readFilter); | ||||
|         else | ||||
|             reader = socket.getReader(); | ||||
|  | ||||
|         // Apply filter to writer | ||||
|         if (writeFilter != null) | ||||
|             writer = new FilteredGuacamoleWriter(socket.getWriter(), writeFilter); | ||||
|         else | ||||
|             writer = socket.getWriter(); | ||||
|  | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public GuacamoleReader getReader() { | ||||
|         return reader; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleWriter getWriter() { | ||||
|         return writer; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void close() throws GuacamoleException { | ||||
|         socket.close(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean isOpen() { | ||||
|         return socket.isOpen(); | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,107 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
|  | ||||
| /** | ||||
|  * GuacamoleWriter which applies a given GuacamoleFilter to observe or alter | ||||
|  * all written instructions. Instructions may also be dropped or denied by | ||||
|  * the filter. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class FilteredGuacamoleWriter implements GuacamoleWriter { | ||||
|  | ||||
|     /** | ||||
|      * The wrapped GuacamoleWriter. | ||||
|      */ | ||||
|     private final GuacamoleWriter writer; | ||||
|  | ||||
|     /** | ||||
|      * The filter to apply when writing instructions. | ||||
|      */ | ||||
|     private final GuacamoleFilter filter; | ||||
|  | ||||
|     /** | ||||
|      * Parser for reading instructions prior to writing, such that they can be | ||||
|      * passed on to the filter. | ||||
|      */ | ||||
|     private final GuacamoleParser parser = new GuacamoleParser(); | ||||
|      | ||||
|     /** | ||||
|      * Wraps the given GuacamoleWriter, applying the given filter to all written  | ||||
|      * instructions. Future writes will only write instructions which pass | ||||
|      * the filter. | ||||
|      * | ||||
|      * @param writer The GuacamoleWriter to wrap. | ||||
|      * @param filter The filter which dictates which instructions are written, | ||||
|      *               and how. | ||||
|      */ | ||||
|     public FilteredGuacamoleWriter(GuacamoleWriter writer, GuacamoleFilter filter) { | ||||
|         this.writer = writer; | ||||
|         this.filter = filter; | ||||
|     } | ||||
|   | ||||
|     @Override | ||||
|     public void write(char[] chunk, int offset, int length) throws GuacamoleException { | ||||
|  | ||||
|         // Write all data in chunk | ||||
|         while (length > 0) { | ||||
|  | ||||
|             // Pass as much data through the parser as possible | ||||
|             int parsed; | ||||
|             while ((parsed = parser.append(chunk, offset, length)) != 0) { | ||||
|                 offset += parsed; | ||||
|                 length -= parsed; | ||||
|             } | ||||
|  | ||||
|             // If no instruction is available, it must be incomplete | ||||
|             if (!parser.hasNext()) | ||||
|                 throw new GuacamoleServerException("Filtered write() contained an incomplete instruction."); | ||||
|  | ||||
|             // Write single instruction through filter | ||||
|             writeInstruction(parser.next()); | ||||
|  | ||||
|         } | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void write(char[] chunk) throws GuacamoleException { | ||||
|         write(chunk, 0, chunk.length); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeInstruction(GuacamoleInstruction instruction) throws GuacamoleException { | ||||
|  | ||||
|         // Write instruction only if not dropped | ||||
|         GuacamoleInstruction filteredInstruction = filter.filter(instruction); | ||||
|         if (filteredInstruction != null) | ||||
|             writer.writeInstruction(filteredInstruction); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,153 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * An abstract representation of Guacamole client information, including all | ||||
|  * information required by the Guacamole protocol during the preamble. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleClientInformation { | ||||
|  | ||||
|     /** | ||||
|      * The optimal screen width requested by the client, in pixels. | ||||
|      */ | ||||
|     private int optimalScreenWidth  = 1024; | ||||
|  | ||||
|     /** | ||||
|      * The optimal screen height requested by the client, in pixels. | ||||
|      */ | ||||
|     private int optimalScreenHeight = 768; | ||||
|  | ||||
|     /** | ||||
|      * The resolution of the optimal dimensions given, in DPI. | ||||
|      */ | ||||
|     private int optimalResolution = 96; | ||||
|  | ||||
|     /** | ||||
|      * The list of audio mimetypes reported by the client to be supported. | ||||
|      */ | ||||
|     private final List<String> audioMimetypes = new ArrayList<String>(); | ||||
|  | ||||
|     /** | ||||
|      * The list of video mimetypes reported by the client to be supported. | ||||
|      */ | ||||
|     private final List<String> videoMimetypes = new ArrayList<String>(); | ||||
|  | ||||
|     /** | ||||
|      * The list of image mimetypes reported by the client to be supported. | ||||
|      */ | ||||
|     private final List<String> imageMimetypes = new ArrayList<String>(); | ||||
|  | ||||
|     /** | ||||
|      * Returns the optimal screen width requested by the client, in pixels. | ||||
|      * @return The optimal screen width requested by the client, in pixels. | ||||
|      */ | ||||
|     public int getOptimalScreenWidth() { | ||||
|         return optimalScreenWidth; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the client's optimal screen width. | ||||
|      * @param optimalScreenWidth The optimal screen width of the client. | ||||
|      */ | ||||
|     public void setOptimalScreenWidth(int optimalScreenWidth) { | ||||
|         this.optimalScreenWidth = optimalScreenWidth; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the optimal screen height requested by the client, in pixels. | ||||
|      * @return The optimal screen height requested by the client, in pixels. | ||||
|      */ | ||||
|     public int getOptimalScreenHeight() { | ||||
|         return optimalScreenHeight; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the client's optimal screen height. | ||||
|      * @param optimalScreenHeight The optimal screen height of the client. | ||||
|      */ | ||||
|     public void setOptimalScreenHeight(int optimalScreenHeight) { | ||||
|         this.optimalScreenHeight = optimalScreenHeight; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the resolution of the screen if the optimal width and height are | ||||
|      * used, in DPI. | ||||
|      *  | ||||
|      * @return The optimal screen resolution. | ||||
|      */ | ||||
|     public int getOptimalResolution() { | ||||
|         return optimalResolution; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the resolution of the screen if the optimal width and height are | ||||
|      * used, in DPI. | ||||
|      *  | ||||
|      * @param optimalResolution The optimal screen resolution in DPI. | ||||
|      */ | ||||
|     public void setOptimalResolution(int optimalResolution) { | ||||
|         this.optimalResolution = optimalResolution; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the list of audio mimetypes supported by the client. To add or | ||||
|      * removed supported mimetypes, the list returned by this function can be | ||||
|      * modified. | ||||
|      * | ||||
|      * @return The set of audio mimetypes supported by the client. | ||||
|      */ | ||||
|     public List<String> getAudioMimetypes() { | ||||
|         return audioMimetypes; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the list of video mimetypes supported by the client. To add or | ||||
|      * removed supported mimetypes, the list returned by this function can be | ||||
|      * modified. | ||||
|      * | ||||
|      * @return The set of video mimetypes supported by the client. | ||||
|      */ | ||||
|     public List<String> getVideoMimetypes() { | ||||
|         return videoMimetypes; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the list of image mimetypes supported by the client. To add or | ||||
|      * removed supported mimetypes, the list returned by this function can be | ||||
|      * modified. | ||||
|      * | ||||
|      * @return | ||||
|      *     The set of image mimetypes supported by the client. | ||||
|      */ | ||||
|     public List<String> getImageMimetypes() { | ||||
|         return imageMimetypes; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,192 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
|  | ||||
| /** | ||||
|  * All information necessary to complete the initial protocol handshake of a | ||||
|  * Guacamole session. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleConfiguration implements Serializable { | ||||
|  | ||||
|     /** | ||||
|      * Identifier unique to this version of GuacamoleConfiguration. | ||||
|      */ | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * The ID of the connection being joined. If this value is present, | ||||
|      * the protocol need not be specified. | ||||
|      */ | ||||
|     private String connectionID; | ||||
|      | ||||
|     /** | ||||
|      * The name of the protocol associated with this configuration. | ||||
|      */ | ||||
|     private String protocol; | ||||
|  | ||||
|     /** | ||||
|      * Map of all associated parameter values, indexed by parameter name. | ||||
|      */ | ||||
|     private final Map<String, String> parameters = new HashMap<String, String>(); | ||||
|  | ||||
|     /** | ||||
|      * Creates a new, blank GuacamoleConfiguration with its protocol, connection | ||||
|      * ID, and parameters unset. | ||||
|      */ | ||||
|     public GuacamoleConfiguration() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Copies the given GuacamoleConfiguration, creating a new, indepedent | ||||
|      * GuacamoleConfiguration containing the same protocol, connection ID, | ||||
|      * and parameter values, if any. | ||||
|      * | ||||
|      * @param config The GuacamoleConfiguration to copy. | ||||
|      */ | ||||
|     public GuacamoleConfiguration(GuacamoleConfiguration config) { | ||||
|  | ||||
|         // Copy protocol and connection ID | ||||
|         protocol = config.getProtocol(); | ||||
|         connectionID = config.getConnectionID(); | ||||
|  | ||||
|         // Copy parameter values | ||||
|         for (String name : config.getParameterNames()) | ||||
|             parameters.put(name, config.getParameter(name)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the ID of the connection being joined, if any. If no connection | ||||
|      * is being joined, this returns null, and the protocol must be set. | ||||
|      * | ||||
|      * @return The ID of the connection being joined, or null if no connection | ||||
|      *         is being joined. | ||||
|      */ | ||||
|     public String getConnectionID() { | ||||
|         return connectionID; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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. | ||||
|      * | ||||
|      * @param connectionID The ID of the connection being joined. | ||||
|      */ | ||||
|     public void setConnectionID(String connectionID) { | ||||
|         this.connectionID = connectionID; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns 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. | ||||
|      */ | ||||
|     public void setProtocol(String protocol) { | ||||
|         this.protocol = protocol; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the value set for the parameter with the given name, if any. | ||||
|      * @param name The name of the parameter to return the value for. | ||||
|      * @return The value of the parameter with the given name, or null if | ||||
|      *         that parameter has not been set. | ||||
|      */ | ||||
|     public String getParameter(String name) { | ||||
|         return parameters.get(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the value for the parameter with the given name. | ||||
|      * | ||||
|      * @param name The name of the parameter to set the value for. | ||||
|      * @param value The value to set for the parameter with the given name. | ||||
|      */ | ||||
|     public void setParameter(String name, String value) { | ||||
|         parameters.put(name, value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removes the value set for the parameter with the given name. | ||||
|      * | ||||
|      * @param name The name of the parameter to remove the value of. | ||||
|      */ | ||||
|     public void unsetParameter(String name) { | ||||
|         parameters.remove(name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a set of all currently defined parameter names. Each name | ||||
|      * corresponds to a parameter that has a value set on this | ||||
|      * GuacamoleConfiguration via setParameter(). | ||||
|      * | ||||
|      * @return A set of all currently defined parameter names. | ||||
|      */ | ||||
|     public Set<String> getParameterNames() { | ||||
|         return Collections.unmodifiableSet(parameters.keySet()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a map which contains parameter name/value pairs as key/value | ||||
|      * pairs. Changes to this map will affect the parameters stored within | ||||
|      * this configuration. | ||||
|      * | ||||
|      * @return | ||||
|      *     A map which contains all parameter name/value pairs as key/value | ||||
|      *     pairs. | ||||
|      */ | ||||
|     public Map<String, String> getParameters() { | ||||
|         return parameters; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Replaces all current parameters with the parameters defined within the | ||||
|      * given map. Key/value pairs within the map represent parameter name/value | ||||
|      * pairs. | ||||
|      * | ||||
|      * @param parameters | ||||
|      *     A map which contains all parameter name/value pairs as key/value | ||||
|      *     pairs. | ||||
|      */ | ||||
|     public void setParameters(Map<String, String> parameters) { | ||||
|         this.parameters.clear(); | ||||
|         this.parameters.putAll(parameters); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,51 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
|  | ||||
| /** | ||||
|  * Interface which provides for the filtering of individual instructions. Each | ||||
|  * filtered instruction may be allowed through untouched, modified, replaced, | ||||
|  * dropped, or explicitly denied. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public interface GuacamoleFilter { | ||||
|  | ||||
|     /** | ||||
|      * Applies the filter to the given instruction, returning the original | ||||
|      * instruction, a modified version of the original, or null, depending | ||||
|      * on the implementation. | ||||
|      * | ||||
|      * @param instruction The instruction to filter. | ||||
|      * @return The original instruction, if the instruction is to be allowed, | ||||
|      *         a modified version of the instruction, if the instruction is | ||||
|      *         to be overridden, or null, if the instruction is to be dropped. | ||||
|      * @throws GuacamoleException If an error occurs filtering the instruction, | ||||
|      *                            or if the instruction must be explicitly | ||||
|      *                            denied. | ||||
|      */ | ||||
|     public GuacamoleInstruction filter(GuacamoleInstruction instruction) throws GuacamoleException; | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,127 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * An abstract representation of a Guacamole instruction, as defined by the | ||||
|  * Guacamole protocol. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleInstruction { | ||||
|  | ||||
|     /** | ||||
|      * The opcode of this instruction. | ||||
|      */ | ||||
|     private String opcode; | ||||
|  | ||||
|     /** | ||||
|      * All arguments of this instruction, in order. | ||||
|      */ | ||||
|     private List<String> args; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleInstruction having the given Operation and | ||||
|      * list of arguments values. | ||||
|      * | ||||
|      * @param opcode The opcode of the instruction to create. | ||||
|      * @param args The list of argument values to provide in the new | ||||
|      *             instruction if any. | ||||
|      */ | ||||
|     public GuacamoleInstruction(String opcode, String... args) { | ||||
|         this.opcode = opcode; | ||||
|         this.args = Collections.unmodifiableList(Arrays.asList(args)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleInstruction having the given Operation and | ||||
|      * list of arguments values. The list given will be used to back the | ||||
|      * internal list of arguments and the list returned by getArgs(). | ||||
|      * | ||||
|      * @param opcode The opcode of the instruction to create. | ||||
|      * @param args The list of argument values to provide in the new | ||||
|      *             instruction if any. | ||||
|      */ | ||||
|     public GuacamoleInstruction(String opcode, List<String> args) { | ||||
|         this.opcode = opcode; | ||||
|         this.args = Collections.unmodifiableList(args); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the opcode associated with this GuacamoleInstruction. | ||||
|      * @return The opcode associated with this GuacamoleInstruction. | ||||
|      */ | ||||
|     public String getOpcode() { | ||||
|         return opcode; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a List of all argument values specified for this | ||||
|      * GuacamoleInstruction. Note that the List returned is immutable. | ||||
|      * Attempts to modify the list will result in exceptions. | ||||
|      * | ||||
|      * @return A List of all argument values specified for this | ||||
|      *         GuacamoleInstruction. | ||||
|      */ | ||||
|     public List<String> getArgs() { | ||||
|         return args; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns this GuacamoleInstruction in the form it would be sent over the | ||||
|      * Guacamole protocol. | ||||
|      * | ||||
|      * @return This GuacamoleInstruction in the form it would be sent over the | ||||
|      *         Guacamole protocol. | ||||
|      */ | ||||
|     @Override | ||||
|     public String toString() { | ||||
|  | ||||
|         StringBuilder buff = new StringBuilder(); | ||||
|  | ||||
|         // Write opcode | ||||
|         buff.append(opcode.length()); | ||||
|         buff.append('.'); | ||||
|         buff.append(opcode); | ||||
|  | ||||
|         // Write argument values | ||||
|         for (String value : args) { | ||||
|             buff.append(','); | ||||
|             buff.append(value.length()); | ||||
|             buff.append('.'); | ||||
|             buff.append(value); | ||||
|         } | ||||
|  | ||||
|         // Write terminator | ||||
|         buff.append(';'); | ||||
|  | ||||
|         return buff.toString(); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,244 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
|  | ||||
| /** | ||||
|  * Parser for the Guacamole protocol. Arbitrary instruction data is appended, | ||||
|  * and instructions are returned as a result. Invalid instructions result in | ||||
|  * exceptions. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public class GuacamoleParser implements Iterator<GuacamoleInstruction> { | ||||
|  | ||||
|     /** | ||||
|      * The maximum number of characters per instruction. | ||||
|      */ | ||||
|     public static final int INSTRUCTION_MAX_LENGTH = 8192; | ||||
|  | ||||
|     /** | ||||
|      * The maximum number of digits to allow per length prefix. | ||||
|      */ | ||||
|     public static final int INSTRUCTION_MAX_DIGITS = 5; | ||||
|  | ||||
|     /** | ||||
|      * The maximum number of elements per instruction, including the opcode. | ||||
|      */ | ||||
|     public static final int INSTRUCTION_MAX_ELEMENTS = 64; | ||||
|  | ||||
|     /** | ||||
|      * All possible states of the instruction parser. | ||||
|      */  | ||||
|     private enum State { | ||||
|  | ||||
|         /** | ||||
|          * The parser is currently waiting for data to complete the length prefix | ||||
|          * of the current element of the instruction. | ||||
|          */ | ||||
|         PARSING_LENGTH, | ||||
|  | ||||
|         /** | ||||
|          * The parser has finished reading the length prefix and is currently | ||||
|          * waiting for data to complete the content of the instruction. | ||||
|          */ | ||||
|         PARSING_CONTENT, | ||||
|  | ||||
|         /** | ||||
|          * The instruction has been fully parsed. | ||||
|          */ | ||||
|         COMPLETE, | ||||
|  | ||||
|         /** | ||||
|          * The instruction cannot be parsed because of a protocol error. | ||||
|          */ | ||||
|         ERROR | ||||
|              | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * The latest parsed instruction, if any. | ||||
|      */ | ||||
|     private GuacamoleInstruction parsedInstruction; | ||||
|  | ||||
|     /** | ||||
|      * The parse state of the instruction. | ||||
|      */ | ||||
|     private State state = State.PARSING_LENGTH; | ||||
|  | ||||
|     /** | ||||
|      * The length of the current element, if known. | ||||
|      */ | ||||
|     private int elementLength = 0; | ||||
|  | ||||
|     /** | ||||
|      * The number of elements currently parsed. | ||||
|      */ | ||||
|     private int elementCount = 0; | ||||
|  | ||||
|     /** | ||||
|      * All currently parsed elements. | ||||
|      */ | ||||
|     private final String elements[] = new String[INSTRUCTION_MAX_ELEMENTS]; | ||||
|  | ||||
|     /** | ||||
|      * Appends data from the given buffer to the current instruction. | ||||
|      *  | ||||
|      * @param chunk The buffer containing the data to append. | ||||
|      * @param offset The offset within the buffer where the data begins. | ||||
|      * @param length The length of the data to append. | ||||
|      * @return The number of characters appended, or 0 if complete instructions | ||||
|      *         have already been parsed and must be read via next() before | ||||
|      *         more data can be appended. | ||||
|      * @throws GuacamoleException If an error occurs while parsing the new data. | ||||
|      */ | ||||
|     public int append(char chunk[], int offset, int length) throws GuacamoleException { | ||||
|  | ||||
|         int charsParsed = 0; | ||||
|  | ||||
|         // Do not exceed maximum number of elements | ||||
|         if (elementCount == INSTRUCTION_MAX_ELEMENTS && state != State.COMPLETE) { | ||||
|             state = State.ERROR; | ||||
|             throw new GuacamoleServerException("Instruction contains too many elements."); | ||||
|         } | ||||
|  | ||||
|         // Parse element length | ||||
|         if (state == State.PARSING_LENGTH) { | ||||
|  | ||||
|             int parsedLength = elementLength; | ||||
|             while (charsParsed < length) { | ||||
|  | ||||
|                 // Pull next character | ||||
|                 char c = chunk[offset + charsParsed++]; | ||||
|  | ||||
|                 // If digit, add to length | ||||
|                 if (c >= '0' && c <= '9') | ||||
|                     parsedLength = parsedLength*10 + c - '0'; | ||||
|  | ||||
|                 // If period, switch to parsing content | ||||
|                 else if (c == '.') { | ||||
|                     state = State.PARSING_CONTENT; | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 // If not digit, parse error | ||||
|                 else { | ||||
|                     state = State.ERROR; | ||||
|                     throw new GuacamoleServerException("Non-numeric character in element length."); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|             // If too long, parse error | ||||
|             if (parsedLength > INSTRUCTION_MAX_LENGTH) { | ||||
|                 state = State.ERROR; | ||||
|                 throw new GuacamoleServerException("Instruction exceeds maximum length."); | ||||
|             } | ||||
|  | ||||
|             // Save length | ||||
|             elementLength = parsedLength; | ||||
|  | ||||
|         } // end parse length | ||||
|  | ||||
|         // Parse element content, if available | ||||
|         if (state == State.PARSING_CONTENT && charsParsed + elementLength + 1 <= length) { | ||||
|  | ||||
|             // Read element | ||||
|             String element = new String(chunk, offset + charsParsed, elementLength); | ||||
|             charsParsed += elementLength; | ||||
|             elementLength = 0; | ||||
|  | ||||
|             // Read terminator char following element | ||||
|             char terminator = chunk[offset + charsParsed++]; | ||||
|  | ||||
|             // Add element to currently parsed elements | ||||
|             elements[elementCount++] = element; | ||||
|              | ||||
|             // If semicolon, store end-of-instruction | ||||
|             if (terminator == ';') { | ||||
|                 state = State.COMPLETE; | ||||
|                 parsedInstruction = new GuacamoleInstruction(elements[0], | ||||
|                         Arrays.asList(elements).subList(1, elementCount)); | ||||
|             } | ||||
|  | ||||
|             // If comma, move on to next element | ||||
|             else if (terminator == ',') | ||||
|                 state = State.PARSING_LENGTH; | ||||
|  | ||||
|             // Otherwise, parse error | ||||
|             else { | ||||
|                 state = State.ERROR; | ||||
|                 throw new GuacamoleServerException("Element terminator of instruction was not ';' nor ','"); | ||||
|             } | ||||
|  | ||||
|         } // end parse content | ||||
|  | ||||
|         return charsParsed; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Appends data from the given buffer to the current instruction. | ||||
|      *  | ||||
|      * @param chunk The data to append. | ||||
|      * @return The number of characters appended, or 0 if complete instructions | ||||
|      *         have already been parsed and must be read via next() before | ||||
|      *         more data can be appended. | ||||
|      * @throws GuacamoleException If an error occurs while parsing the new data. | ||||
|      */    | ||||
|     public int append(char chunk[]) throws GuacamoleException { | ||||
|         return append(chunk, 0, chunk.length); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean hasNext() { | ||||
|         return state == State.COMPLETE; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleInstruction next() { | ||||
|  | ||||
|         // No instruction to return if not yet complete | ||||
|         if (state != State.COMPLETE) | ||||
|             return null; | ||||
|          | ||||
|         // Reset for next instruction. | ||||
|         state = State.PARSING_LENGTH; | ||||
|         elementCount = 0; | ||||
|         elementLength = 0; | ||||
|          | ||||
|         return parsedInstruction; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void remove() { | ||||
|         throw new UnsupportedOperationException("GuacamoleParser does not support remove()."); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,173 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
| /** | ||||
|  * All possible statuses returned by various Guacamole instructions, each having | ||||
|  * a corresponding code. | ||||
|  *  | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public enum GuacamoleStatus { | ||||
|  | ||||
|     /** | ||||
|      * The operation succeeded. | ||||
|      */ | ||||
|     SUCCESS(200, 1000, 0x0000), | ||||
|  | ||||
|     /** | ||||
|      * The requested operation is unsupported. | ||||
|      */ | ||||
|     UNSUPPORTED(501, 1011, 0x0100), | ||||
|  | ||||
|     /** | ||||
|      * The operation could not be performed due to an internal failure. | ||||
|      */ | ||||
|     SERVER_ERROR(500, 1011, 0x0200), | ||||
|  | ||||
|     /** | ||||
|      * The operation could not be performed as the server is busy. | ||||
|      */ | ||||
|     SERVER_BUSY(503, 1008, 0x0201), | ||||
|  | ||||
|     /** | ||||
|      * The operation could not be performed because the upstream server is not | ||||
|      * responding. | ||||
|      */ | ||||
|     UPSTREAM_TIMEOUT(504, 1011, 0x0202), | ||||
|  | ||||
|     /** | ||||
|      * The operation was unsuccessful due to an error or otherwise unexpected | ||||
|      * condition of the upstream server. | ||||
|      */ | ||||
|     UPSTREAM_ERROR(502, 1011, 0x0203), | ||||
|  | ||||
|     /** | ||||
|      * The operation could not be performed as the requested resource does not | ||||
|      * exist. | ||||
|      */ | ||||
|     RESOURCE_NOT_FOUND(404, 1002, 0x0204), | ||||
|  | ||||
|     /** | ||||
|      * The operation could not be performed as the requested resource is already | ||||
|      * in use. | ||||
|      */ | ||||
|     RESOURCE_CONFLICT(409, 1008, 0x0205), | ||||
|  | ||||
|     /** | ||||
|      * The operation could not be performed because bad parameters were given. | ||||
|      */ | ||||
|     CLIENT_BAD_REQUEST(400, 1002, 0x0300), | ||||
|  | ||||
|     /** | ||||
|      * Permission was denied to perform the operation, as the user is not yet | ||||
|      * authorized (not yet logged in, for example). As HTTP 401 has implications | ||||
|      * for HTTP-specific authorization schemes, this status continues to map to | ||||
|      * HTTP 403 ("Forbidden"). To do otherwise would risk unintended effects. | ||||
|      */ | ||||
|     CLIENT_UNAUTHORIZED(403, 1008, 0x0301), | ||||
|  | ||||
|     /** | ||||
|      * Permission was denied to perform the operation, and this operation will | ||||
|      * not be granted even if the user is authorized. | ||||
|      */ | ||||
|     CLIENT_FORBIDDEN(403, 1008, 0x0303), | ||||
|  | ||||
|     /** | ||||
|      * The client took too long to respond. | ||||
|      */ | ||||
|     CLIENT_TIMEOUT(408, 1002, 0x0308), | ||||
|  | ||||
|     /** | ||||
|      * The client sent too much data. | ||||
|      */ | ||||
|     CLIENT_OVERRUN(413, 1009, 0x030D), | ||||
|  | ||||
|     /** | ||||
|      * The client sent data of an unsupported or unexpected type. | ||||
|      */ | ||||
|     CLIENT_BAD_TYPE(415, 1003, 0x030F), | ||||
|  | ||||
|     /** | ||||
|      * The operation failed because the current client is already using too | ||||
|      * many resources. | ||||
|      */ | ||||
|     CLIENT_TOO_MANY(429, 1008, 0x031D); | ||||
|  | ||||
|     /** | ||||
|      * The most applicable HTTP error code. | ||||
|      */ | ||||
|     private final int http_code; | ||||
|  | ||||
|     /** | ||||
|      * The most applicable WebSocket error code. | ||||
|      */ | ||||
|     private final int websocket_code; | ||||
|      | ||||
|     /** | ||||
|      * The Guacamole protocol status code. | ||||
|      */ | ||||
|     private final int guac_code; | ||||
|  | ||||
|     /** | ||||
|      * Initializes a GuacamoleStatusCode with the given HTTP and Guacamole | ||||
|      * status/error code values. | ||||
|      *  | ||||
|      * @param http_code The most applicable HTTP error code. | ||||
|      * @param websocket_code The most applicable WebSocket error code. | ||||
|      * @param guac_code The Guacamole protocol status code. | ||||
|      */ | ||||
|     private GuacamoleStatus(int http_code, int websocket_code, int guac_code) { | ||||
|         this.http_code = http_code; | ||||
|         this.websocket_code = websocket_code; | ||||
|         this.guac_code = guac_code; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the most applicable HTTP error code. | ||||
|      *  | ||||
|      * @return The most applicable HTTP error code. | ||||
|      */ | ||||
|     public int getHttpStatusCode() { | ||||
|         return http_code; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the most applicable HTTP error code. | ||||
|      *  | ||||
|      * @return The most applicable HTTP error code. | ||||
|      */ | ||||
|     public int getWebSocketCode() { | ||||
|         return websocket_code; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the corresponding Guacamole protocol status code. | ||||
|      *  | ||||
|      * @return The corresponding Guacamole protocol status code. | ||||
|      */ | ||||
|     public int getGuacamoleStatusCode() { | ||||
|         return guac_code; | ||||
|     } | ||||
|      | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Classes relating directly to the Guacamole protocol. | ||||
|  */ | ||||
| package org.apache.guacamole.protocol; | ||||
|  | ||||
| @@ -0,0 +1,78 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.servlet; | ||||
|  | ||||
| import org.apache.guacamole.net.DelegatingGuacamoleTunnel; | ||||
| import org.apache.guacamole.net.GuacamoleTunnel; | ||||
|  | ||||
| /** | ||||
|  * Tracks the last time a particular GuacamoleTunnel was accessed. This | ||||
|  * information is not necessary for tunnels associated with WebSocket | ||||
|  * connections, as each WebSocket connection has its own read thread which | ||||
|  * continuously checks the state of the tunnel and which will automatically | ||||
|  * timeout when the underlying socket times out, but the HTTP tunnel has no | ||||
|  * such thread. Because the HTTP tunnel requires the stream to be split across | ||||
|  * multiple requests, tracking of activity on the tunnel must be performed | ||||
|  * independently of the HTTP requests. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| class GuacamoleHTTPTunnel extends DelegatingGuacamoleTunnel { | ||||
|  | ||||
|     /** | ||||
|      * The last time this tunnel was accessed. | ||||
|      */ | ||||
|     private long lastAccessedTime; | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleHTTPTunnel which wraps the given tunnel. | ||||
|      * Absolutely all function calls on this new GuacamoleHTTPTunnel will be | ||||
|      * delegated to the underlying GuacamoleTunnel. | ||||
|      * | ||||
|      * @param wrappedTunnel | ||||
|      *     The GuacamoleTunnel to wrap within this GuacamoleHTTPTunnel. | ||||
|      */ | ||||
|     public GuacamoleHTTPTunnel(GuacamoleTunnel wrappedTunnel) { | ||||
|         super(wrappedTunnel); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Updates this tunnel, marking it as recently accessed. | ||||
|      */ | ||||
|     public void access() { | ||||
|         lastAccessedTime = System.currentTimeMillis(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the time this tunnel was last accessed, as the number of | ||||
|      * milliseconds since midnight January 1, 1970 GMT. Tunnel access must | ||||
|      * be explicitly marked through calls to the access() function. | ||||
|      * | ||||
|      * @return | ||||
|      *     The time this tunnel was last accessed. | ||||
|      */ | ||||
|     public long getLastAccessedTime() { | ||||
|         return lastAccessedTime; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,213 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.servlet; | ||||
|  | ||||
| import java.util.Iterator; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.ConcurrentMap; | ||||
| import java.util.concurrent.Executors; | ||||
| import java.util.concurrent.ScheduledExecutorService; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.net.GuacamoleTunnel; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * Map-style object which tracks in-use HTTP tunnels, automatically removing | ||||
|  * and closing tunnels which have not been used recently. This class is | ||||
|  * intended for use only within the GuacamoleHTTPTunnelServlet implementation, | ||||
|  * and has no real utility outside that implementation. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| class GuacamoleHTTPTunnelMap { | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private static final Logger logger = LoggerFactory.getLogger(GuacamoleHTTPTunnelMap.class); | ||||
|  | ||||
|     /** | ||||
|      * The number of seconds to wait between tunnel accesses before timing out | ||||
|      * Note that this will be enforced only within a factor of 2. If a tunnel | ||||
|      * is unused, it will take between TUNNEL_TIMEOUT and TUNNEL_TIMEOUT*2 | ||||
|      * seconds before that tunnel is closed and removed. | ||||
|      */ | ||||
|     private static final int TUNNEL_TIMEOUT = 15; | ||||
|  | ||||
|     /** | ||||
|      * Executor service which runs the periodic tunnel timeout task. | ||||
|      */ | ||||
|     private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); | ||||
|  | ||||
|     /** | ||||
|      * Map of all tunnels that are using HTTP, indexed by tunnel UUID. | ||||
|      */ | ||||
|     private final ConcurrentMap<String, GuacamoleHTTPTunnel> tunnelMap = | ||||
|             new ConcurrentHashMap<String, GuacamoleHTTPTunnel>(); | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleHTTPTunnelMap which automatically closes and | ||||
|      * removes HTTP tunnels which are no longer in use. | ||||
|      */ | ||||
|     public GuacamoleHTTPTunnelMap() { | ||||
|  | ||||
|         // Check for unused tunnels every few seconds | ||||
|         executor.scheduleAtFixedRate( | ||||
|             new TunnelTimeoutTask(TUNNEL_TIMEOUT * 1000l), | ||||
|             TUNNEL_TIMEOUT, TUNNEL_TIMEOUT, TimeUnit.SECONDS); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Task which iterates through all registered tunnels, removing and those | ||||
|      * tunnels which have not been accessed for a given number of milliseconds. | ||||
|      */ | ||||
|     private class TunnelTimeoutTask implements Runnable { | ||||
|  | ||||
|         /** | ||||
|          * The maximum amount of time to allow between accesses to any one | ||||
|          * HTTP tunnel, in milliseconds. | ||||
|          */ | ||||
|         private final long tunnelTimeout; | ||||
|  | ||||
|         /** | ||||
|          * Creates a new task which automatically closes and removes tunnels | ||||
|          * which have not been accessed for at least the given number of | ||||
|          * milliseconds. | ||||
|          * | ||||
|          * @param tunnelTimeout | ||||
|          *     The maximum amount of time to allow between separate tunnel | ||||
|          *     read/write requests, in milliseconds. | ||||
|          */ | ||||
|         public TunnelTimeoutTask(long tunnelTimeout) { | ||||
|             this.tunnelTimeout = tunnelTimeout; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|  | ||||
|             // Get current time | ||||
|             long now = System.currentTimeMillis(); | ||||
|  | ||||
|             // For each tunnel, close and remove any tunnels which have expired | ||||
|             Iterator<Map.Entry<String, GuacamoleHTTPTunnel>> entries = tunnelMap.entrySet().iterator(); | ||||
|             while (entries.hasNext()) { | ||||
|  | ||||
|                 Map.Entry<String, GuacamoleHTTPTunnel> entry = entries.next(); | ||||
|                 GuacamoleHTTPTunnel tunnel = entry.getValue(); | ||||
|  | ||||
|                 // Get elapsed time since last access | ||||
|                 long age = now - tunnel.getLastAccessedTime(); | ||||
|  | ||||
|                 // If tunnel is too old, close and remove it | ||||
|                 if (age >= tunnelTimeout) { | ||||
|  | ||||
|                     // Remove old entry | ||||
|                     logger.debug("HTTP tunnel \"{}\" has timed out.", entry.getKey()); | ||||
|                     entries.remove(); | ||||
|  | ||||
|                     // Attempt to close tunnel | ||||
|                     try { | ||||
|                         tunnel.close(); | ||||
|                     } | ||||
|                     catch (GuacamoleException e) { | ||||
|                         logger.debug("Unable to close expired HTTP tunnel.", e); | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|  | ||||
|             } // end for each tunnel | ||||
|  | ||||
|         } // end timeout task run() | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the GuacamoleTunnel having the given UUID, wrapped within a | ||||
|      * GuacamoleHTTPTunnel. If the no tunnel having the given UUID is | ||||
|      * available, null is returned. | ||||
|      * | ||||
|      * @param uuid | ||||
|      *     The UUID of the tunnel to retrieve. | ||||
|      * | ||||
|      * @return | ||||
|      *     The GuacamoleTunnel having the given UUID, wrapped within a | ||||
|      *     GuacamoleHTTPTunnel, if such a tunnel exists, or null if there is no | ||||
|      *     such tunnel. | ||||
|      */ | ||||
|     public GuacamoleHTTPTunnel get(String uuid) { | ||||
|  | ||||
|         // Update the last access time | ||||
|         GuacamoleHTTPTunnel tunnel = tunnelMap.get(uuid); | ||||
|         if (tunnel != null) | ||||
|             tunnel.access(); | ||||
|  | ||||
|         // Return tunnel, if any | ||||
|         return tunnel; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Registers that a new connection has been established using HTTP via the | ||||
|      * given GuacamoleTunnel. | ||||
|      * | ||||
|      * @param uuid | ||||
|      *     The UUID of the tunnel being added (registered). | ||||
|      * | ||||
|      * @param tunnel | ||||
|      *     The GuacamoleTunnel being registered, its associated connection | ||||
|      *     having just been established via HTTP. | ||||
|      */ | ||||
|     public void put(String uuid, GuacamoleTunnel tunnel) { | ||||
|         tunnelMap.put(uuid, new GuacamoleHTTPTunnel(tunnel)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removes the GuacamoleTunnel having the given UUID, if such a tunnel | ||||
|      * exists. The original tunnel is returned wrapped within a | ||||
|      * GuacamoleHTTPTunnel. | ||||
|      * | ||||
|      * @param uuid | ||||
|      *     The UUID of the tunnel to remove (deregister). | ||||
|      * | ||||
|      * @return | ||||
|      *     The GuacamoleTunnel having the given UUID, if such a tunnel exists, | ||||
|      *     wrapped within a GuacamoleHTTPTunnel, or null if no such tunnel | ||||
|      *     exists and no removal was performed. | ||||
|      */ | ||||
|     public GuacamoleHTTPTunnel remove(String uuid) { | ||||
|         return tunnelMap.remove(uuid); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shuts down this tunnel map, disallowing future tunnels from being | ||||
|      * registered and reclaiming any resources. | ||||
|      */ | ||||
|     public void shutdown() { | ||||
|         executor.shutdownNow(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,526 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.servlet; | ||||
|  | ||||
| import java.io.BufferedWriter; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.io.Reader; | ||||
| import java.io.Writer; | ||||
| import javax.servlet.ServletException; | ||||
| import javax.servlet.http.HttpServlet; | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import org.apache.guacamole.GuacamoleClientException; | ||||
| import org.apache.guacamole.GuacamoleConnectionClosedException; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleResourceNotFoundException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
| import org.apache.guacamole.net.GuacamoleTunnel; | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * A HttpServlet implementing and abstracting the operations required by the | ||||
|  * HTTP implementation of the JavaScript Guacamole client's tunnel. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet { | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private final Logger logger = LoggerFactory.getLogger(GuacamoleHTTPTunnelServlet.class); | ||||
|  | ||||
|     /** | ||||
|      * Map of absolutely all active tunnels using HTTP, indexed by tunnel UUID. | ||||
|      */ | ||||
|     private final GuacamoleHTTPTunnelMap tunnels = new GuacamoleHTTPTunnelMap(); | ||||
|  | ||||
|     /** | ||||
|      * The prefix of the query string which denotes a tunnel read operation. | ||||
|      */ | ||||
|     private static final String READ_PREFIX  = "read:"; | ||||
|  | ||||
|     /** | ||||
|      * The prefix of the query string which denotes a tunnel write operation. | ||||
|      */ | ||||
|     private static final String WRITE_PREFIX = "write:"; | ||||
|  | ||||
|     /** | ||||
|      * The length of the read prefix, in characters. | ||||
|      */ | ||||
|     private static final int READ_PREFIX_LENGTH = READ_PREFIX.length(); | ||||
|  | ||||
|     /** | ||||
|      * The length of the write prefix, in characters. | ||||
|      */ | ||||
|     private static final int WRITE_PREFIX_LENGTH = WRITE_PREFIX.length(); | ||||
|  | ||||
|     /** | ||||
|      * The length of every tunnel UUID, in characters. | ||||
|      */ | ||||
|     private static final int UUID_LENGTH = 36; | ||||
|  | ||||
|     /** | ||||
|      * Registers the given tunnel such that future read/write requests to that | ||||
|      * tunnel will be properly directed. | ||||
|      * | ||||
|      * @param tunnel | ||||
|      *     The tunnel to register. | ||||
|      */ | ||||
|     protected void registerTunnel(GuacamoleTunnel tunnel) { | ||||
|         tunnels.put(tunnel.getUUID().toString(), tunnel); | ||||
|         logger.debug("Registered tunnel \"{}\".", tunnel.getUUID()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Deregisters the given tunnel such that future read/write requests to | ||||
|      * that tunnel will be rejected. | ||||
|      * | ||||
|      * @param tunnel | ||||
|      *     The tunnel to deregister. | ||||
|      */ | ||||
|     protected void deregisterTunnel(GuacamoleTunnel tunnel) { | ||||
|         tunnels.remove(tunnel.getUUID().toString()); | ||||
|         logger.debug("Deregistered tunnel \"{}\".", tunnel.getUUID()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the tunnel with the given UUID, if it has been registered with | ||||
|      * registerTunnel() and not yet deregistered with deregisterTunnel(). | ||||
|      * | ||||
|      * @param tunnelUUID | ||||
|      *     The UUID of registered tunnel. | ||||
|      * | ||||
|      * @return | ||||
|      *     The tunnel corresponding to the given UUID. | ||||
|      * | ||||
|      * @throws GuacamoleException | ||||
|      *     If the requested tunnel does not exist because it has not yet been | ||||
|      *     registered or it has been deregistered. | ||||
|      */ | ||||
|     protected GuacamoleTunnel getTunnel(String tunnelUUID) | ||||
|             throws GuacamoleException { | ||||
|  | ||||
|         // Pull tunnel from map | ||||
|         GuacamoleTunnel tunnel = tunnels.get(tunnelUUID); | ||||
|         if (tunnel == null) | ||||
|             throw new GuacamoleResourceNotFoundException("No such tunnel."); | ||||
|  | ||||
|         return tunnel; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||||
|         handleTunnelRequest(request, response); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { | ||||
|         handleTunnelRequest(request, response); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sends an error on the given HTTP response using the information within | ||||
|      * the given GuacamoleStatus. | ||||
|      * | ||||
|      * @param response | ||||
|      *     The HTTP response to use to send the error. | ||||
|      * | ||||
|      * @param guacStatus | ||||
|      *     The status to send | ||||
|      * | ||||
|      * @param message | ||||
|      *     A human-readable message that can be presented to the user. | ||||
|      * | ||||
|      * @throws ServletException | ||||
|      *     If an error prevents sending of the error code. | ||||
|      */ | ||||
|     protected void sendError(HttpServletResponse response, | ||||
|             GuacamoleStatus guacStatus, String message) | ||||
|             throws ServletException { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             // If response not committed, send error code and message | ||||
|             if (!response.isCommitted()) { | ||||
|                 response.addHeader("Guacamole-Status-Code", Integer.toString(guacStatus.getGuacamoleStatusCode())); | ||||
|                 response.addHeader("Guacamole-Error-Message", message); | ||||
|                 response.sendError(guacStatus.getHttpStatusCode()); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         catch (IOException ioe) { | ||||
|  | ||||
|             // If unable to send error at all due to I/O problems, | ||||
|             // rethrow as servlet exception | ||||
|             throw new ServletException(ioe); | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Dispatches every HTTP GET and POST request to the appropriate handler | ||||
|      * function based on the query string. | ||||
|      * | ||||
|      * @param request | ||||
|      *     The HttpServletRequest associated with the GET or POST request | ||||
|      *     received. | ||||
|      * | ||||
|      * @param response | ||||
|      *     The HttpServletResponse associated with the GET or POST request | ||||
|      *     received. | ||||
|      * | ||||
|      * @throws ServletException | ||||
|      *     If an error occurs while servicing the request. | ||||
|      */ | ||||
|     protected void handleTunnelRequest(HttpServletRequest request, | ||||
|             HttpServletResponse response) throws ServletException { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             String query = request.getQueryString(); | ||||
|             if (query == null) | ||||
|                 throw new GuacamoleClientException("No query string provided."); | ||||
|  | ||||
|             // If connect operation, call doConnect() and return tunnel UUID | ||||
|             // in response. | ||||
|             if (query.equals("connect")) { | ||||
|  | ||||
|                 GuacamoleTunnel tunnel = doConnect(request); | ||||
|                 if (tunnel != null) { | ||||
|  | ||||
|                     // Register newly-created tunnel | ||||
|                     registerTunnel(tunnel); | ||||
|  | ||||
|                     try { | ||||
|                         // Ensure buggy browsers do not cache response | ||||
|                         response.setHeader("Cache-Control", "no-cache"); | ||||
|  | ||||
|                         // Send UUID to client | ||||
|                         response.getWriter().print(tunnel.getUUID().toString()); | ||||
|                     } | ||||
|                     catch (IOException e) { | ||||
|                         throw new GuacamoleServerException(e); | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|  | ||||
|                 // Failed to connect | ||||
|                 else | ||||
|                     throw new GuacamoleResourceNotFoundException("No tunnel created."); | ||||
|  | ||||
|             } | ||||
|  | ||||
|             // If read operation, call doRead() with tunnel UUID, ignoring any | ||||
|             // characters following the tunnel UUID. | ||||
|             else if(query.startsWith(READ_PREFIX)) | ||||
|                 doRead(request, response, query.substring( | ||||
|                         READ_PREFIX_LENGTH, | ||||
|                         READ_PREFIX_LENGTH + UUID_LENGTH)); | ||||
|  | ||||
|             // If write operation, call doWrite() with tunnel UUID, ignoring any | ||||
|             // characters following the tunnel UUID. | ||||
|             else if(query.startsWith(WRITE_PREFIX)) | ||||
|                 doWrite(request, response, query.substring( | ||||
|                         WRITE_PREFIX_LENGTH, | ||||
|                         WRITE_PREFIX_LENGTH + UUID_LENGTH)); | ||||
|  | ||||
|             // Otherwise, invalid operation | ||||
|             else | ||||
|                 throw new GuacamoleClientException("Invalid tunnel operation: " + query); | ||||
|         } | ||||
|  | ||||
|         // Catch any thrown guacamole exception and attempt to pass within the | ||||
|         // HTTP response, logging each error appropriately. | ||||
|         catch (GuacamoleClientException e) { | ||||
|             logger.warn("HTTP tunnel request rejected: {}", e.getMessage()); | ||||
|             sendError(response, e.getStatus(), e.getMessage()); | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             logger.error("HTTP tunnel request failed: {}", e.getMessage()); | ||||
|             logger.debug("Internal error in HTTP tunnel.", e); | ||||
|             sendError(response, e.getStatus(), "Internal server error."); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called whenever the JavaScript Guacamole client makes a connection | ||||
|      * request via HTTP. It it up to the implementor of this function to define | ||||
|      * what conditions must be met for a tunnel to be configured and returned | ||||
|      * as a result of this connection request (whether some sort of credentials | ||||
|      * must be specified, for example). | ||||
|      * | ||||
|      * @param request | ||||
|      *     The HttpServletRequest associated with the connection request | ||||
|      *     received. Any parameters specified along with the connection request | ||||
|      *     can be read from this object. | ||||
|      * | ||||
|      * @return | ||||
|      *     A newly constructed GuacamoleTunnel if successful, null otherwise. | ||||
|      * | ||||
|      * @throws GuacamoleException | ||||
|      *     If an error occurs while constructing the GuacamoleTunnel, or if the | ||||
|      *     conditions required for connection are not met. | ||||
|      */ | ||||
|     protected abstract GuacamoleTunnel doConnect(HttpServletRequest request) | ||||
|             throws GuacamoleException; | ||||
|  | ||||
|     /** | ||||
|      * Called whenever the JavaScript Guacamole client makes a read request. | ||||
|      * This function should in general not be overridden, as it already | ||||
|      * contains a proper implementation of the read operation. | ||||
|      * | ||||
|      * @param request | ||||
|      *     The HttpServletRequest associated with the read request received. | ||||
|      * | ||||
|      * @param response | ||||
|      *     The HttpServletResponse associated with the write request received. | ||||
|      *     Any data to be sent to the client in response to the write request | ||||
|      *     should be written to the response body of this HttpServletResponse. | ||||
|      * | ||||
|      * @param tunnelUUID | ||||
|      *     The UUID of the tunnel to read from, as specified in the write | ||||
|      *     request. This tunnel must have been created by a previous call to | ||||
|      *     doConnect(). | ||||
|      * | ||||
|      * @throws GuacamoleException | ||||
|      *     If an error occurs while handling the read request. | ||||
|      */ | ||||
|     protected void doRead(HttpServletRequest request, | ||||
|             HttpServletResponse response, String tunnelUUID) | ||||
|             throws GuacamoleException { | ||||
|  | ||||
|         // Get tunnel, ensure tunnel exists | ||||
|         GuacamoleTunnel tunnel = getTunnel(tunnelUUID); | ||||
|  | ||||
|         // Ensure tunnel is open | ||||
|         if (!tunnel.isOpen()) | ||||
|             throw new GuacamoleResourceNotFoundException("Tunnel is closed."); | ||||
|  | ||||
|         // Obtain exclusive read access | ||||
|         GuacamoleReader reader = tunnel.acquireReader(); | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             // Note that although we are sending text, Webkit browsers will | ||||
|             // buffer 1024 bytes before starting a normal stream if we use | ||||
|             // anything but application/octet-stream. | ||||
|             response.setContentType("application/octet-stream"); | ||||
|             response.setHeader("Cache-Control", "no-cache"); | ||||
|  | ||||
|             // Get writer for response | ||||
|             Writer out = new BufferedWriter(new OutputStreamWriter( | ||||
|                     response.getOutputStream(), "UTF-8")); | ||||
|  | ||||
|             // Stream data to response, ensuring output stream is closed | ||||
|             try { | ||||
|  | ||||
|                 // Deregister tunnel and throw error if we reach EOF without | ||||
|                 // having ever sent any data | ||||
|                 char[] message = reader.read(); | ||||
|                 if (message == null) | ||||
|                     throw new GuacamoleConnectionClosedException("Tunnel reached end of stream."); | ||||
|  | ||||
|                 // For all messages, until another stream is ready (we send at least one message) | ||||
|                 do { | ||||
|  | ||||
|                     // Get message output bytes | ||||
|                     out.write(message, 0, message.length); | ||||
|  | ||||
|                     // Flush if we expect to wait | ||||
|                     if (!reader.available()) { | ||||
|                         out.flush(); | ||||
|                         response.flushBuffer(); | ||||
|                     } | ||||
|  | ||||
|                     // No more messages another stream can take over | ||||
|                     if (tunnel.hasQueuedReaderThreads()) | ||||
|                         break; | ||||
|  | ||||
|                 } while (tunnel.isOpen() && (message = reader.read()) != null); | ||||
|  | ||||
|                 // Close tunnel immediately upon EOF | ||||
|                 if (message == null) { | ||||
|                     deregisterTunnel(tunnel); | ||||
|                     tunnel.close(); | ||||
|                 } | ||||
|  | ||||
|                 // End-of-instructions marker | ||||
|                 out.write("0.;"); | ||||
|                 out.flush(); | ||||
|                 response.flushBuffer(); | ||||
|             } | ||||
|  | ||||
|             // Send end-of-stream marker and close tunnel if connection is closed | ||||
|             catch (GuacamoleConnectionClosedException e) { | ||||
|  | ||||
|                 // Deregister and close | ||||
|                 deregisterTunnel(tunnel); | ||||
|                 tunnel.close(); | ||||
|  | ||||
|                 // End-of-instructions marker | ||||
|                 out.write("0.;"); | ||||
|                 out.flush(); | ||||
|                 response.flushBuffer(); | ||||
|  | ||||
|             } | ||||
|  | ||||
|             catch (GuacamoleException e) { | ||||
|  | ||||
|                 // Deregister and close | ||||
|                 deregisterTunnel(tunnel); | ||||
|                 tunnel.close(); | ||||
|  | ||||
|                 throw e; | ||||
|             } | ||||
|  | ||||
|             // Always close output stream | ||||
|             finally { | ||||
|                 out.close(); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|  | ||||
|             // Log typically frequent I/O error if desired | ||||
|             logger.debug("Error writing to servlet output stream", e); | ||||
|  | ||||
|             // Deregister and close | ||||
|             deregisterTunnel(tunnel); | ||||
|             tunnel.close(); | ||||
|  | ||||
|         } | ||||
|         finally { | ||||
|             tunnel.releaseReader(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called whenever the JavaScript Guacamole client makes a write request. | ||||
|      * This function should in general not be overridden, as it already | ||||
|      * contains a proper implementation of the write operation. | ||||
|      * | ||||
|      * @param request | ||||
|      *     The HttpServletRequest associated with the write request received. | ||||
|      *     Any data to be written will be specified within the body of this | ||||
|      *     request. | ||||
|      * | ||||
|      * @param response | ||||
|      *     The HttpServletResponse associated with the write request received. | ||||
|      * | ||||
|      * @param tunnelUUID | ||||
|      *     The UUID of the tunnel to write to, as specified in the write | ||||
|      *     request. This tunnel must have been created by a previous call to | ||||
|      *     doConnect(). | ||||
|      * | ||||
|      * @throws GuacamoleException | ||||
|      *     If an error occurs while handling the write request. | ||||
|      */ | ||||
|     protected void doWrite(HttpServletRequest request, | ||||
|             HttpServletResponse response, String tunnelUUID) | ||||
|             throws GuacamoleException { | ||||
|  | ||||
|         GuacamoleTunnel tunnel = getTunnel(tunnelUUID); | ||||
|  | ||||
|         // 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 | ||||
|         // does not explicitly request such parsing. | ||||
|         response.setContentType("application/octet-stream"); | ||||
|         response.setHeader("Cache-Control", "no-cache"); | ||||
|         response.setContentLength(0); | ||||
|  | ||||
|         // Send data | ||||
|         try { | ||||
|  | ||||
|             // Get writer from tunnel | ||||
|             GuacamoleWriter writer = tunnel.acquireWriter(); | ||||
|  | ||||
|             // Get input reader for HTTP stream | ||||
|             Reader input = new InputStreamReader( | ||||
|                     request.getInputStream(), "UTF-8"); | ||||
|  | ||||
|             // Transfer data from input stream to tunnel output, ensuring | ||||
|             // input is always closed | ||||
|             try { | ||||
|  | ||||
|                 // Buffer | ||||
|                 int length; | ||||
|                 char[] buffer = new char[8192]; | ||||
|  | ||||
|                 // Transfer data using buffer | ||||
|                 while (tunnel.isOpen() && | ||||
|                         (length = input.read(buffer, 0, buffer.length)) != -1) | ||||
|                     writer.write(buffer, 0, length); | ||||
|  | ||||
|             } | ||||
|  | ||||
|             // Close input stream in all cases | ||||
|             finally { | ||||
|                 input.close(); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         catch (GuacamoleConnectionClosedException e) { | ||||
|             logger.debug("Connection to guacd closed.", e); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|  | ||||
|             // Deregister and close | ||||
|             deregisterTunnel(tunnel); | ||||
|             tunnel.close(); | ||||
|  | ||||
|             throw new GuacamoleServerException("I/O Error sending data to server: " + e.getMessage(), e); | ||||
|         } | ||||
|         finally { | ||||
|             tunnel.releaseWriter(); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void destroy() { | ||||
|         tunnels.shutdown(); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * \example ExampleTunnelServlet.java | ||||
|  * | ||||
|  * A basic example demonstrating extending GuacamoleTunnelServlet and | ||||
|  * implementing doConnect() to configure the Guacamole connection as | ||||
|  * desired. | ||||
|  */ | ||||
|  | ||||
| @@ -0,0 +1,101 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.servlet; | ||||
|  | ||||
| import javax.servlet.http.HttpSession; | ||||
| import org.apache.guacamole.net.GuacamoleTunnel; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * Provides abstract access to the tunnels associated with a Guacamole session. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| @Deprecated | ||||
| public class GuacamoleSession { | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private final Logger logger = LoggerFactory.getLogger(GuacamoleSession.class); | ||||
|  | ||||
|     /** | ||||
|      * Creates a new GuacamoleSession. In prior versions of Guacamole, the | ||||
|      * GuacamoleSession object stored the tunnels associated with a particular | ||||
|      * user's use of the HTTP tunnel. The HTTP tunnel now stores all of these | ||||
|      * tunnels itself, and thus this class is no longer necessary. Its use will | ||||
|      * result in a warning being logged, and its functions will have no effect. | ||||
|      * | ||||
|      * @param session | ||||
|      *     The HttpSession that older versions of Guacamole would use as tunnel | ||||
|      *     storage. This parameter is now ignored, and the GuacamoleSession | ||||
|      *     class overall is deprecated. | ||||
|      */ | ||||
|     public GuacamoleSession(HttpSession session) { | ||||
|         logger.warn("GuacamoleSession is deprecated. It is no longer " | ||||
|                   + "necessary and its use will have no effect."); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Attaches the given tunnel to this GuacamoleSession. The GuacamoleSession | ||||
|      * class is now deprecated, and this function has no effect. | ||||
|      * | ||||
|      * @param tunnel | ||||
|      *     The tunnel to attach to this GucacamoleSession. | ||||
|      */ | ||||
|     public void attachTunnel(GuacamoleTunnel tunnel) { | ||||
|         // Deprecated - no effect | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Detaches the given tunnel to this GuacamoleSession. The GuacamoleSession | ||||
|      * class is now deprecated, and this function has no effect. | ||||
|      * | ||||
|      * @param tunnel | ||||
|      *     The tunnel to detach to this GucacamoleSession. | ||||
|      */ | ||||
|     public void detachTunnel(GuacamoleTunnel tunnel) { | ||||
|         // Deprecated - no effect | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the tunnel with the given UUID attached to this GuacamoleSession, | ||||
|      * if any. The GuacamoleSession class is now deprecated, and this function | ||||
|      * has no effect. It will ALWAYS return null. | ||||
|      * | ||||
|      * @param tunnelUUID | ||||
|      *     The UUID of an attached tunnel. | ||||
|      * | ||||
|      * @return | ||||
|      *     The tunnel corresponding to the given UUID, if attached, or null if | ||||
|      *     if no such tunnel is attached. | ||||
|      */ | ||||
|     public GuacamoleTunnel getTunnel(String tunnelUUID) { | ||||
|  | ||||
|         // Deprecated - no effect | ||||
|         return null; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Copyright (C) 2013 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Classes which build upon the Java Servlet API, providing an HTTP-based | ||||
|  * tunnel and session management. | ||||
|  */ | ||||
| package org.apache.guacamole.servlet; | ||||
|  | ||||
| @@ -0,0 +1,246 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.apache.guacamole.websocket; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import javax.websocket.CloseReason; | ||||
| import javax.websocket.CloseReason.CloseCode; | ||||
| import javax.websocket.Endpoint; | ||||
| import javax.websocket.EndpointConfig; | ||||
| import javax.websocket.MessageHandler; | ||||
| import javax.websocket.OnClose; | ||||
| import javax.websocket.OnMessage; | ||||
| import javax.websocket.OnOpen; | ||||
| import javax.websocket.RemoteEndpoint; | ||||
| import javax.websocket.Session; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.io.GuacamoleReader; | ||||
| import org.apache.guacamole.io.GuacamoleWriter; | ||||
| import org.apache.guacamole.net.GuacamoleTunnel; | ||||
| import org.apache.guacamole.GuacamoleClientException; | ||||
| import org.apache.guacamole.GuacamoleConnectionClosedException; | ||||
| import org.apache.guacamole.protocol.GuacamoleStatus; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * A WebSocket implementation of GuacamoleTunnel functionality, compatible with | ||||
|  * the Guacamole.WebSocketTunnel object included with the JavaScript API. | ||||
|  * Messages sent/received are simply chunks of the Guacamole protocol | ||||
|  * instruction stream. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| public abstract class GuacamoleWebSocketTunnelEndpoint extends Endpoint { | ||||
|  | ||||
|     /** | ||||
|      * The default, minimum buffer size for instructions. | ||||
|      */ | ||||
|     private static final int BUFFER_SIZE = 8192; | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private final Logger logger = LoggerFactory.getLogger(GuacamoleWebSocketTunnelEndpoint.class); | ||||
|  | ||||
|     /** | ||||
|      * The underlying GuacamoleTunnel. WebSocket reads/writes will be handled | ||||
|      * as reads/writes to this tunnel. | ||||
|      */ | ||||
|     private GuacamoleTunnel tunnel; | ||||
|      | ||||
|     /** | ||||
|      * Sends the given status on the given WebSocket connection and closes the | ||||
|      * connection. | ||||
|      * | ||||
|      * @param session The outbound WebSocket connection to close. | ||||
|      * @param guac_status The status to send. | ||||
|      */ | ||||
|     private void closeConnection(Session session, GuacamoleStatus guac_status) { | ||||
|  | ||||
|         try { | ||||
|             CloseCode code = CloseReason.CloseCodes.getCloseCode(guac_status.getWebSocketCode()); | ||||
|             String message = Integer.toString(guac_status.getGuacamoleStatusCode()); | ||||
|             session.close(new CloseReason(code, message)); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             logger.debug("Unable to close WebSocket connection.", e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a new tunnel for the given session. How this tunnel is created | ||||
|      * or retrieved is implementation-dependent. | ||||
|      * | ||||
|      * @param session The session associated with the active WebSocket | ||||
|      *                connection. | ||||
|      * @param config Configuration information associated with the instance of | ||||
|      *               the endpoint created for handling this single connection. | ||||
|      * @return A connected tunnel, or null if no such tunnel exists. | ||||
|      * @throws GuacamoleException If an error occurs while retrieving the | ||||
|      *                            tunnel, or if access to the tunnel is denied. | ||||
|      */ | ||||
|     protected abstract GuacamoleTunnel createTunnel(Session session, EndpointConfig config) | ||||
|             throws GuacamoleException; | ||||
|  | ||||
|     @Override | ||||
|     @OnOpen | ||||
|     public void onOpen(final Session session, EndpointConfig config) { | ||||
|  | ||||
|         try { | ||||
|  | ||||
|             // Get tunnel | ||||
|             tunnel = createTunnel(session, config); | ||||
|             if (tunnel == null) { | ||||
|                 closeConnection(session, GuacamoleStatus.RESOURCE_NOT_FOUND); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage()); | ||||
|             logger.debug("Error connecting WebSocket tunnel.", e); | ||||
|             closeConnection(session, e.getStatus()); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Manually register message handler | ||||
|         session.addMessageHandler(new MessageHandler.Whole<String>() { | ||||
|  | ||||
|             @Override | ||||
|             public void onMessage(String message) { | ||||
|                 GuacamoleWebSocketTunnelEndpoint.this.onMessage(message); | ||||
|             } | ||||
|  | ||||
|         }); | ||||
|  | ||||
|         // Prepare read transfer thread | ||||
|         Thread readThread = new Thread() { | ||||
|  | ||||
|             /** | ||||
|              * Remote (client) side of this connection | ||||
|              */ | ||||
|             private final RemoteEndpoint.Basic remote = session.getBasicRemote(); | ||||
|                  | ||||
|             @Override | ||||
|             public void run() { | ||||
|  | ||||
|                 StringBuilder buffer = new StringBuilder(BUFFER_SIZE); | ||||
|                 GuacamoleReader reader = tunnel.acquireReader(); | ||||
|                 char[] readMessage; | ||||
|  | ||||
|                 try { | ||||
|  | ||||
|                     try { | ||||
|  | ||||
|                         // Attempt to read | ||||
|                         while ((readMessage = reader.read()) != null) { | ||||
|  | ||||
|                             // Buffer message | ||||
|                             buffer.append(readMessage); | ||||
|  | ||||
|                             // Flush if we expect to wait or buffer is getting full | ||||
|                             if (!reader.available() || buffer.length() >= BUFFER_SIZE) { | ||||
|                                 remote.sendText(buffer.toString()); | ||||
|                                 buffer.setLength(0); | ||||
|                             } | ||||
|  | ||||
|                         } | ||||
|  | ||||
|                         // No more data | ||||
|                         closeConnection(session, GuacamoleStatus.SUCCESS); | ||||
|  | ||||
|                     } | ||||
|  | ||||
|                     // Catch any thrown guacamole exception and attempt | ||||
|                     // to pass within the WebSocket connection, logging | ||||
|                     // each error appropriately. | ||||
|                     catch (GuacamoleClientException e) { | ||||
|                         logger.info("WebSocket connection terminated: {}", e.getMessage()); | ||||
|                         logger.debug("WebSocket connection terminated due to client error.", e); | ||||
|                         closeConnection(session, e.getStatus()); | ||||
|                     } | ||||
|                     catch (GuacamoleConnectionClosedException e) { | ||||
|                         logger.debug("Connection to guacd closed.", e); | ||||
|                         closeConnection(session, GuacamoleStatus.SUCCESS); | ||||
|                     } | ||||
|                     catch (GuacamoleException e) { | ||||
|                         logger.error("Connection to guacd terminated abnormally: {}", e.getMessage()); | ||||
|                         logger.debug("Internal error during connection to guacd.", e); | ||||
|                         closeConnection(session, e.getStatus()); | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|                 catch (IOException e) { | ||||
|                     logger.debug("I/O error prevents further reads.", e); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         readThread.start(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @OnMessage | ||||
|     public void onMessage(String message) { | ||||
|  | ||||
|         // Ignore inbound messages if there is no associated tunnel | ||||
|         if (tunnel == null) | ||||
|             return; | ||||
|  | ||||
|         GuacamoleWriter writer = tunnel.acquireWriter(); | ||||
|  | ||||
|         try { | ||||
|             // Write received message | ||||
|             writer.write(message.toCharArray()); | ||||
|         } | ||||
|         catch (GuacamoleConnectionClosedException e) { | ||||
|             logger.debug("Connection to guacd closed.", e); | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             logger.debug("WebSocket tunnel write failed.", e); | ||||
|         } | ||||
|  | ||||
|         tunnel.releaseWriter(); | ||||
|  | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     @OnClose | ||||
|     public void onClose(Session session, CloseReason closeReason) { | ||||
|  | ||||
|         try { | ||||
|             if (tunnel != null) | ||||
|                 tunnel.close(); | ||||
|         } | ||||
|         catch (GuacamoleException e) { | ||||
|             logger.debug("Unable to close WebSocket tunnel.", e); | ||||
|         } | ||||
|          | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user