Removed old Java client, added new experimental PHP client.
@@ -1,11 +0,0 @@
|
||||
|
||||
.PHONY: client clean
|
||||
|
||||
all: client
|
||||
|
||||
client:
|
||||
ant war
|
||||
|
||||
clean:
|
||||
ant clean
|
||||
|
@@ -1,13 +0,0 @@
|
||||
servlet.api.jar=/usr/share/tomcat6/lib/servlet-api.jar
|
||||
|
||||
src.dir=src
|
||||
web.dir=web
|
||||
|
||||
build.dir=build
|
||||
dist.dir=dist
|
||||
doc.dir=doc
|
||||
|
||||
guac.version=0.3.0rc1
|
||||
tar.dir=guacamole-${guac.version}
|
||||
tar.src.dir=guacamole-src
|
||||
|
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<project name="guacamole" default="compile" basedir=".">
|
||||
|
||||
<property file="ant/build.properties"/>
|
||||
|
||||
<target name="clean" description="Removes build and dist dirs.">
|
||||
<delete dir="${build.dir}"/>
|
||||
<delete dir="${dist.dir}"/>
|
||||
<delete dir="${tar.dir}"/>
|
||||
<delete dir="${tar.src.dir}"/>
|
||||
<delete file="${tar.dir}.tar.gz"/>
|
||||
</target>
|
||||
|
||||
<target name="init" description="Creates build and dist dirs.">
|
||||
<mkdir dir="${build.dir}"/>
|
||||
<mkdir dir="${build.dir}/WEB-INF/classes"/>
|
||||
<mkdir dir="${dist.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compiles Guacamole."
|
||||
depends="init">
|
||||
<copy todir="${build.dir}">
|
||||
<fileset dir="${web.dir}"/>
|
||||
</copy>
|
||||
|
||||
<!-- Replace __GUAC_VERSION with declared version -->
|
||||
<replace dir="${build.dir}" value="${guac.version}">
|
||||
<include name="**/*.html"/>
|
||||
<replacetoken><![CDATA[__GUAC_VERSION]]></replacetoken>
|
||||
</replace>
|
||||
|
||||
<javac srcdir="${src.dir}" destdir="${build.dir}/WEB-INF/classes"
|
||||
classpath="${servlet.api.jar}">
|
||||
<compilerarg value="-Xlint:unchecked"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="war" description="Builds Guacamole .war file."
|
||||
depends="compile">
|
||||
<war destfile="${dist.dir}/guacamole.war"
|
||||
webxml="${build.dir}/WEB-INF/web.xml">
|
||||
<fileset dir="${build.dir}">
|
||||
<exclude name="META-INF/**"/>
|
||||
</fileset>
|
||||
</war>
|
||||
</target>
|
||||
|
||||
<target name="tar" description="Build distributable .tar.gz file"
|
||||
depends="war">
|
||||
<mkdir dir="${tar.dir}"/>
|
||||
|
||||
<mkdir dir="${tar.src.dir}"/>
|
||||
<copy todir="${tar.src.dir}">
|
||||
<fileset dir=".">
|
||||
<exclude name=".git/**"/>
|
||||
<exclude name="**/.svn"/>
|
||||
<exclude name="${tar.dir}/**"/>
|
||||
<exclude name="${tar.src.dir}/**"/>
|
||||
<exclude name="${dist.dir}/**"/>
|
||||
<exclude name="${build.dir}/**"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<tar basedir="." includes="${tar.src.dir}/**" destfile="${tar.dir}/${tar.src.dir}.tar" longfile="gnu"/>
|
||||
<delete dir="${tar.src.dir}"/>
|
||||
|
||||
<copy todir="${tar.dir}">
|
||||
<fileset file="${doc.dir}/example/guacamole.xml"/>
|
||||
<fileset file="${doc.dir}/example/guacamole-users.xml"/>
|
||||
<fileset file="${dist.dir}/guacamole.war"/>
|
||||
<fileset file="LICENSE.txt"/>
|
||||
</copy>
|
||||
|
||||
<tar basedir="." includes="${tar.dir}/**" destfile="${tar.dir}.tar.gz" compression="gzip" longfile="gnu"/>
|
||||
</target>
|
||||
|
||||
</project>
|
@@ -1,6 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
|
||||
<tomcat-users>
|
||||
<role rolename="guacamole"/>
|
||||
<user username="guacamole" password="changeme" roles="guacamole"/>
|
||||
</tomcat-users>
|
@@ -1,75 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Guacamole - Pure JavaScript/HTML VNC Client
|
||||
Copyright (C) 2010 Michael Jumper
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<Context antiJARLocking="true" path="/guacamole" docBase="/var/lib/guacamole/guacamole.war">
|
||||
|
||||
<!-- Change the lines below to match your VNC server -->
|
||||
<Parameter name="host" value="localhost"/>
|
||||
<Parameter name="port" value="5900"/>
|
||||
|
||||
|
||||
<!-- Password (VNC Authentication)
|
||||
|
||||
Uncomment and change the line below if your VNC server is
|
||||
password protected. -->
|
||||
|
||||
<!--
|
||||
<Parameter name="password" value="PASSWORD"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Bits-per-pixel
|
||||
|
||||
This parameter controls what color depth should be
|
||||
requested from the VNC server.
|
||||
|
||||
Valid values are "8", "16", or "24". -->
|
||||
|
||||
<!--
|
||||
<Parameter name="bpp" value="24"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Output (to web client) bits-per-pixel.
|
||||
|
||||
This parameter controls what color depth will be used
|
||||
in the images sent to the web-based client.
|
||||
|
||||
Valid values are "8" or "24". -->
|
||||
|
||||
<!--
|
||||
<Parameter name="output-bpp" value="24"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Swap red and blue components. Some VNC servers may not honor
|
||||
the client's request for certain pixel formats, instead
|
||||
returning RGB as BGR.
|
||||
|
||||
If colors look strange (blues look red or brown) when using
|
||||
Guacamole, uncomment and set this parameter to true. -->
|
||||
|
||||
<!--
|
||||
<Parameter name="swap-red-blue" value="false"/>
|
||||
-->
|
||||
|
||||
<Realm className="org.apache.catalina.realm.MemoryRealm" pathname="conf/guacamole-users.xml"/>
|
||||
</Context>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 208 B After Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
Before Width: | Height: | Size: 71 B After Width: | Height: | Size: 71 B |
Before Width: | Height: | Size: 72 B After Width: | Height: | Size: 72 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
@@ -186,38 +186,9 @@ function VNCClient(display) {
|
||||
|
||||
// Add event to queue, restart send loop if finished.
|
||||
outputMessageBuffer += message;
|
||||
if (sendingMessages == 0)
|
||||
sendPendingMessages();
|
||||
|
||||
}
|
||||
|
||||
function sendPendingMessages() {
|
||||
|
||||
if (outputMessageBuffer.length > 0) {
|
||||
|
||||
sendingMessages = 1;
|
||||
|
||||
var message_xmlhttprequest = new XMLHttpRequest();
|
||||
message_xmlhttprequest.open("POST", "inbound");
|
||||
message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
message_xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length);
|
||||
|
||||
// Once response received, send next queued event.
|
||||
message_xmlhttprequest.onreadystatechange = function() {
|
||||
if (message_xmlhttprequest.readyState == 4)
|
||||
sendPendingMessages();
|
||||
}
|
||||
|
||||
message_xmlhttprequest.send(outputMessageBuffer);
|
||||
outputMessageBuffer = ""; // Clear buffer
|
||||
|
||||
}
|
||||
else
|
||||
sendingMessages = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*****************************************/
|
||||
/*** Clipboard ***/
|
||||
/*****************************************/
|
||||
@@ -301,7 +272,7 @@ function VNCClient(display) {
|
||||
function parseResponse() {
|
||||
|
||||
// Start next request as soon as possible
|
||||
if (xmlhttprequest.readyState >= 2 && nextRequest == null)
|
||||
if (xmlhttprequest.readyState >= 2 && nextRequest == null && uuid)
|
||||
nextRequest = makeRequest();
|
||||
|
||||
// Parse stream when data is received and when complete.
|
||||
@@ -378,10 +349,19 @@ function VNCClient(display) {
|
||||
|
||||
function makeRequest() {
|
||||
|
||||
if (uuid)
|
||||
outputMessageBuffer = "resume:" + uuid + ";" + outputMessageBuffer;
|
||||
|
||||
outputMessageBuffer += "pause;";
|
||||
|
||||
// Download self
|
||||
var xmlhttprequest = new XMLHttpRequest();
|
||||
xmlhttprequest.open("POST", "instructions");
|
||||
xmlhttprequest.send(null);
|
||||
xmlhttprequest.open("POST", "tunnel.php");
|
||||
xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length);
|
||||
|
||||
xmlhttprequest.send(outputMessageBuffer);
|
||||
outputMessageBuffer = "";
|
||||
|
||||
return xmlhttprequest;
|
||||
|
||||
@@ -438,8 +418,14 @@ function VNCClient(display) {
|
||||
|
||||
}
|
||||
|
||||
var uuid = null;
|
||||
|
||||
var instructionHandlers = {
|
||||
|
||||
"uuid": function(parameters) {
|
||||
uuid = parameters[0];
|
||||
},
|
||||
|
||||
"error": function(parameters) {
|
||||
showError(unescapeGuacamoleString(parameters[0]));
|
||||
},
|
||||
@@ -559,16 +545,8 @@ function VNCClient(display) {
|
||||
|
||||
this.connect = function() {
|
||||
|
||||
var message = "connect;";
|
||||
|
||||
setState(STATE_CONNECTING);
|
||||
|
||||
// Send connect message (synchronously... as necessary until handoff is implemented)
|
||||
var connect_xmlhttprequest = new XMLHttpRequest();
|
||||
connect_xmlhttprequest.open("POST", "inbound", false);
|
||||
connect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
connect_xmlhttprequest.setRequestHeader("Content-length", message.length);
|
||||
connect_xmlhttprequest.send(message);
|
||||
sendMessage("connect;");
|
||||
|
||||
// Start reading data
|
||||
setState(STATE_WAITING);
|
||||
@@ -583,15 +561,9 @@ function VNCClient(display) {
|
||||
if (currentState != STATE_DISCONNECTED
|
||||
&& currentState != STATE_DISCONNECTING) {
|
||||
|
||||
var message = "disconnect;";
|
||||
setState(STATE_DISCONNECTING);
|
||||
|
||||
// Send disconnect message (synchronously... as necessary until handoff is implemented)
|
||||
var disconnect_xmlhttprequest = new XMLHttpRequest();
|
||||
disconnect_xmlhttprequest.open("POST", "inbound", false);
|
||||
disconnect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
disconnect_xmlhttprequest.setRequestHeader("Content-length", message.length);
|
||||
disconnect_xmlhttprequest.send(message);
|
||||
sendMessage("disconnect;");
|
||||
|
||||
setState(STATE_DISCONNECTED);
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
import net.sourceforge.guacamole.event.KeyEvent;
|
||||
import net.sourceforge.guacamole.event.PointerEvent;
|
||||
|
||||
public abstract class Client {
|
||||
|
||||
public abstract void write(char[] chunk, int off, int len) throws GuacamoleException;
|
||||
public abstract char[] read() throws GuacamoleException;
|
||||
public abstract void disconnect() throws GuacamoleException;
|
||||
|
||||
}
|
@@ -1,133 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
import net.sourceforge.guacamole.event.EventQueue;
|
||||
import net.sourceforge.guacamole.event.EventHandler;
|
||||
import net.sourceforge.guacamole.event.KeyEvent;
|
||||
import net.sourceforge.guacamole.event.PointerEvent;
|
||||
|
||||
public class GuacamoleClient extends Client {
|
||||
|
||||
private Socket sock;
|
||||
private Reader input;
|
||||
private Writer output;
|
||||
|
||||
public GuacamoleClient(String hostname, int port) throws GuacamoleException {
|
||||
|
||||
try {
|
||||
sock = new Socket(InetAddress.getByName(hostname), port);
|
||||
input = new InputStreamReader(sock.getInputStream());
|
||||
output = new OutputStreamWriter(sock.getOutputStream());
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void write(char[] chunk, int off, int len) throws GuacamoleException {
|
||||
try {
|
||||
output.write(chunk, off, len);
|
||||
output.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() throws GuacamoleException {
|
||||
try {
|
||||
sock.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int usedLength = 0;
|
||||
private char[] buffer = new char[20000];
|
||||
|
||||
public char[] read() throws GuacamoleException {
|
||||
|
||||
try {
|
||||
|
||||
// While we're blocking, or input is available
|
||||
for (;;) {
|
||||
|
||||
// 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;
|
||||
|
||||
int prevLength = usedLength;
|
||||
usedLength += numRead;
|
||||
|
||||
for (int i=usedLength-1; i>=prevLength; i--) {
|
||||
|
||||
char readChar = buffer[i];
|
||||
|
||||
// If end of instruction, return it.
|
||||
if (readChar == ';') {
|
||||
|
||||
// Get instruction
|
||||
char[] chunk = new char[i+1];
|
||||
System.arraycopy(buffer, 0, chunk, 0, i+1);
|
||||
|
||||
// Reset buffer
|
||||
usedLength -= i+1;
|
||||
System.arraycopy(buffer, i+1, buffer, 0, usedLength);
|
||||
|
||||
// Return instruction string
|
||||
return chunk;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // End read loop
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class GuacamoleException extends Exception {
|
||||
|
||||
public GuacamoleException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public GuacamoleException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public GuacamoleException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.event;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public abstract class Event implements Comparable<Event> {
|
||||
|
||||
private long time;
|
||||
private int index;
|
||||
|
||||
public Event(int index) {
|
||||
this.time = System.currentTimeMillis();
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) return false;
|
||||
if (getClass() != o.getClass()) return false;
|
||||
return getIndex() == ((Event) o).getIndex();
|
||||
}
|
||||
|
||||
public int compareTo(Event e) {
|
||||
return getIndex() - e.getIndex();
|
||||
}
|
||||
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.event;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface EventHandler<E extends Event> {
|
||||
|
||||
public void handle(E e) throws IOException;
|
||||
|
||||
}
|
@@ -1,191 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.event;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
public class EventQueue<E extends Event> {
|
||||
|
||||
private int nextIndex = 0;
|
||||
private final PriorityQueue<E> queue = new PriorityQueue<E>();
|
||||
private EventHandler<E> handler;
|
||||
|
||||
private final int deadline;
|
||||
|
||||
private AutoflushThread autoflush = new AutoflushThread();
|
||||
|
||||
private class AutoflushThread extends Thread {
|
||||
|
||||
private IOException error;
|
||||
private long deadline;
|
||||
private static final long ONE_YEAR = 31536000;
|
||||
|
||||
private boolean killed = false;
|
||||
|
||||
public AutoflushThread() {
|
||||
this.deadline = ONE_YEAR;
|
||||
start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (!killed) {
|
||||
try {
|
||||
if (deadline > 0) sleep(deadline);
|
||||
dropPendingEvents();
|
||||
flush();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
// Interrupt indicates event handled, or thread killed
|
||||
if (killed) return;
|
||||
}
|
||||
catch (IOException e) {
|
||||
error = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setDeadline(long deadline) {
|
||||
this.deadline = deadline;
|
||||
interrupt();
|
||||
}
|
||||
|
||||
public void checkError() throws IOException {
|
||||
if (error != null) throw error;
|
||||
}
|
||||
|
||||
public void kill() {
|
||||
killed = true;
|
||||
interrupt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void close() {
|
||||
autoflush.kill();
|
||||
}
|
||||
|
||||
// Starts autoflush wait thread for any waiting events on the queue
|
||||
private void startDeadlineAutoflush() {
|
||||
synchronized (queue) {
|
||||
|
||||
// No need to autoflush if nothing waiting
|
||||
if (queue.size() == 0) return;
|
||||
|
||||
// Get waiting event
|
||||
E waiting = queue.peek();
|
||||
|
||||
if (waiting != null) {
|
||||
long untilDeadline = deadline + waiting.getTime() - System.currentTimeMillis();
|
||||
|
||||
// Start autoflush thread which waits for time remaining until next
|
||||
// event's deadline.
|
||||
autoflush.setDeadline(untilDeadline);
|
||||
}
|
||||
else
|
||||
autoflush.setDeadline(AutoflushThread.ONE_YEAR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public EventQueue(EventHandler<E> handler, int deadline) {
|
||||
this.handler = handler;
|
||||
this.deadline = deadline;
|
||||
}
|
||||
|
||||
public void add(E event) throws IOException {
|
||||
synchronized (queue) {
|
||||
|
||||
autoflush.checkError();
|
||||
|
||||
if (event.getIndex() < nextIndex) {
|
||||
//System.err.println("Past event dropped.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == null)
|
||||
throw new Error("Cannot add null event.");
|
||||
|
||||
queue.add(event);
|
||||
}
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
private E next() {
|
||||
synchronized (queue) {
|
||||
// If no events, return nothing.
|
||||
if (queue.size() == 0) return null;
|
||||
|
||||
// If still waiting for true next event, return nothing.
|
||||
E event = queue.peek();
|
||||
if (event.getIndex() != nextIndex)
|
||||
return null;
|
||||
|
||||
// If event found, expect next event, remove and return current.
|
||||
queue.remove();
|
||||
nextIndex++;
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
// Return number of waiting events
|
||||
public int getWaiting() {
|
||||
synchronized (queue) {
|
||||
// If no events, then none waiting.
|
||||
if (queue.size() == 0) return 0;
|
||||
|
||||
// If we have the next event, then none waiting.
|
||||
E event = queue.peek();
|
||||
if (event.getIndex() == nextIndex)
|
||||
return 0;
|
||||
|
||||
// Otherwise, all events are waiting.
|
||||
return queue.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Stop waiting for any unreceived events
|
||||
private void dropPendingEvents() {
|
||||
synchronized (queue) {
|
||||
// If no events, nothing needs to be changed;
|
||||
if (queue.size() == 0) return;
|
||||
|
||||
// Otherwise, update nextIndex to index of next event
|
||||
E event = queue.peek();
|
||||
nextIndex = event.getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to flush queue
|
||||
// If any events remain, an autoflush thread is started.
|
||||
private void flush() throws IOException {
|
||||
synchronized (queue) {
|
||||
E nextEvent;
|
||||
while ((nextEvent = next()) != null)
|
||||
handler.handle(nextEvent);
|
||||
}
|
||||
|
||||
// Start autoflush thread for any remaining events.
|
||||
startDeadlineAutoflush();
|
||||
}
|
||||
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
package net.sourceforge.guacamole.event;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class KeyEvent extends Event {
|
||||
|
||||
private int keysym;
|
||||
private boolean pressed;
|
||||
|
||||
public KeyEvent(int index, int keysym, boolean pressed) {
|
||||
super(index);
|
||||
this.keysym = keysym;
|
||||
this.pressed = pressed;
|
||||
}
|
||||
|
||||
public int getKeySym() {
|
||||
return keysym;
|
||||
}
|
||||
|
||||
public boolean getPressed() {
|
||||
return pressed;
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
package net.sourceforge.guacamole.event;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class PointerEvent extends Event {
|
||||
|
||||
private boolean leftButtonPressed;
|
||||
private boolean middleButtonPressed;
|
||||
private boolean rightButtonPressed;
|
||||
private boolean upButtonPressed;
|
||||
private boolean downButtonPressed;
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public PointerEvent(int index, boolean leftButtonPressed, boolean middleButtonPressed, boolean rightButtonPressed, boolean upButtonPressed, boolean downButtonPressed, int x, int y) {
|
||||
super(index);
|
||||
this.leftButtonPressed = leftButtonPressed;
|
||||
this.middleButtonPressed = middleButtonPressed;
|
||||
this.rightButtonPressed = rightButtonPressed;
|
||||
this.upButtonPressed = upButtonPressed;
|
||||
this.downButtonPressed = downButtonPressed;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public boolean isLeftButtonPressed() {
|
||||
return leftButtonPressed;
|
||||
}
|
||||
|
||||
public boolean isMiddleButtonPressed() {
|
||||
return middleButtonPressed;
|
||||
}
|
||||
|
||||
public boolean isRightButtonPressed() {
|
||||
return rightButtonPressed;
|
||||
}
|
||||
|
||||
public boolean isUpButtonPressed() {
|
||||
return upButtonPressed;
|
||||
}
|
||||
|
||||
public boolean isDownButtonPressed() {
|
||||
return downButtonPressed;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
package net.sourceforge.guacamole.net;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class Base64 {
|
||||
|
||||
private static String characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
public static String toString(byte[] data) {
|
||||
|
||||
StringBuffer buff = new StringBuffer();
|
||||
for (int i=0; i<data.length; i+=3) {
|
||||
|
||||
int a = data[i];
|
||||
int b = 0; if (i+1 < data.length) b = data[i+1];
|
||||
int c = 0; if (i+2 < data.length) c = data[i+2];
|
||||
|
||||
buff.append(characters.charAt(
|
||||
(a & 0xFC) >> 2
|
||||
));
|
||||
|
||||
buff.append(characters.charAt(
|
||||
((a & 0x03) << 4) |
|
||||
((b & 0xF0) >> 4)
|
||||
));
|
||||
|
||||
if (i+1 < data.length)
|
||||
buff.append(characters.charAt(
|
||||
((b & 0x0F) << 2) |
|
||||
((c & 0xC0) >> 6)
|
||||
));
|
||||
else
|
||||
buff.append('=');
|
||||
|
||||
if (i+2 < data.length)
|
||||
buff.append(characters.charAt(
|
||||
(c & 0x3F)
|
||||
));
|
||||
else
|
||||
buff.append('=');
|
||||
|
||||
}
|
||||
|
||||
return buff.toString();
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,130 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.net;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
|
||||
public abstract class Configuration {
|
||||
|
||||
private ServletContext context;
|
||||
|
||||
protected String humanReadableList(Object... values) {
|
||||
|
||||
String list = "";
|
||||
for (int i=0; i<values.length; i++) {
|
||||
|
||||
if (i >= 1)
|
||||
list += ", ";
|
||||
|
||||
if (i == values.length -1)
|
||||
list += " or ";
|
||||
|
||||
list += "\"" + values[i] + "\"";
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
protected String readParameter(String name, String defaultValue, String... allowedValues) throws GuacamoleException {
|
||||
|
||||
String value = context.getInitParameter(name);
|
||||
|
||||
// Use default if not specified
|
||||
if (value == null) {
|
||||
if (defaultValue == null)
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// If not restricted to certain values, just return whatever is given.
|
||||
if (allowedValues.length == 0)
|
||||
return value;
|
||||
|
||||
// If restricted, only return value within given list
|
||||
for (String allowedValue : allowedValues)
|
||||
if (value.equals(allowedValue))
|
||||
return value;
|
||||
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" must be " + humanReadableList((Object) allowedValues));
|
||||
}
|
||||
|
||||
protected boolean readBooleanParameter(String name, Boolean defaultValue) throws GuacamoleException {
|
||||
|
||||
String value = context.getInitParameter(name);
|
||||
|
||||
// Use default if not specified
|
||||
if (value == null) {
|
||||
if (defaultValue == null)
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
value = value.trim();
|
||||
if (value.equals("true"))
|
||||
return true;
|
||||
|
||||
if (value.equals("false"))
|
||||
return false;
|
||||
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" must be \"true\" or \"false\".");
|
||||
|
||||
}
|
||||
|
||||
protected int readIntParameter(String name, Integer defaultValue, Integer... allowedValues) throws GuacamoleException {
|
||||
|
||||
String parmString = context.getInitParameter(name);
|
||||
|
||||
// Use default if not specified
|
||||
if (parmString== null) {
|
||||
if (defaultValue == null)
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" is required.");
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
int value = Integer.parseInt(parmString);
|
||||
|
||||
// If not restricted to certain values, just return whatever is given.
|
||||
if (allowedValues.length == 0)
|
||||
return value;
|
||||
|
||||
// If restricted, only return value within given list
|
||||
for (int allowedValue : allowedValues)
|
||||
if (value == allowedValue)
|
||||
return value;
|
||||
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" must be " + humanReadableList((Object) allowedValues));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new GuacamoleException("Parameter \"" + name + "\" must be an integer.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Configuration(ServletContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.net;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
|
||||
public class GuacamoleConfiguration extends Configuration {
|
||||
|
||||
private String hostname;
|
||||
private int port;
|
||||
|
||||
public GuacamoleConfiguration(ServletContext context) throws GuacamoleException {
|
||||
|
||||
super(context);
|
||||
|
||||
hostname = context.getInitParameter("hostname");
|
||||
port = readIntParameter("port", null);
|
||||
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.net;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
|
||||
public abstract class GuacamoleServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
try {
|
||||
handleRequest(req, resp);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
try {
|
||||
handleRequest(req, resp);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleRequest(HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||
GuacamoleSession session = new GuacamoleSession(request.getSession(shouldCreateSession()));
|
||||
handleRequest(session, request, response);
|
||||
}
|
||||
|
||||
protected abstract void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException;
|
||||
|
||||
protected boolean shouldCreateSession() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@@ -1,147 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.net;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
import javax.servlet.http.HttpSessionBindingListener;
|
||||
import net.sourceforge.guacamole.Client;
|
||||
import net.sourceforge.guacamole.GuacamoleClient;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
import net.sourceforge.guacamole.event.KeyEvent;
|
||||
import net.sourceforge.guacamole.event.PointerEvent;
|
||||
|
||||
public class GuacamoleSession {
|
||||
|
||||
private GuacamoleConfiguration config;
|
||||
private final HttpSession session;
|
||||
private Client client;
|
||||
private ReentrantLock instructionStreamLock;
|
||||
|
||||
private class SessionClient extends Client implements HttpSessionBindingListener {
|
||||
|
||||
private Client client;
|
||||
|
||||
public SessionClient(Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public void valueBound(HttpSessionBindingEvent event) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public void valueUnbound(HttpSessionBindingEvent event) {
|
||||
try {
|
||||
disconnect();
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
public void write(char[] data, int off, int len) throws GuacamoleException {
|
||||
client.write(data, off, len);
|
||||
}
|
||||
|
||||
public char[] read() throws GuacamoleException {
|
||||
return client.read();
|
||||
}
|
||||
|
||||
public void disconnect() throws GuacamoleException {
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public GuacamoleSession(HttpSession session) throws GuacamoleException {
|
||||
|
||||
if (session == null)
|
||||
throw new GuacamoleException("User has no session.");
|
||||
|
||||
this.session = session;
|
||||
synchronized (session) {
|
||||
|
||||
// Read configuration parameters
|
||||
ServletContext context = session.getServletContext();
|
||||
config = new GuacamoleConfiguration(context);
|
||||
|
||||
client = (Client) session.getAttribute("CLIENT");
|
||||
instructionStreamLock = (ReentrantLock) session.getAttribute("INSTRUCTION_STREAM_LOCK");
|
||||
}
|
||||
}
|
||||
|
||||
public void connect() throws GuacamoleException {
|
||||
synchronized (session) {
|
||||
|
||||
if (client != null)
|
||||
client.disconnect();
|
||||
|
||||
|
||||
client = new SessionClient(
|
||||
new GuacamoleClient (
|
||||
config.getHostname(),
|
||||
config.getPort()
|
||||
)
|
||||
);
|
||||
|
||||
session.setAttribute("CLIENT", client);
|
||||
|
||||
instructionStreamLock = new ReentrantLock();
|
||||
session.setAttribute("INSTRUCTION_STREAM_LOCK", instructionStreamLock);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
synchronized (session) {
|
||||
return client != null;
|
||||
}
|
||||
}
|
||||
|
||||
public GuacamoleConfiguration getConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public Client getClient() {
|
||||
synchronized (session) {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
session.invalidate();
|
||||
}
|
||||
|
||||
public void disconnect() throws GuacamoleException {
|
||||
if (client != null) {
|
||||
client.disconnect();
|
||||
|
||||
session.removeAttribute("CLIENT");
|
||||
client = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ReentrantLock getInstructionStreamLock() {
|
||||
return instructionStreamLock;
|
||||
}
|
||||
|
||||
}
|
@@ -1,132 +0,0 @@
|
||||
|
||||
package net.sourceforge.guacamole.net;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import net.sourceforge.guacamole.Client;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public abstract class XMLGuacamoleServlet extends GuacamoleServlet {
|
||||
|
||||
@Override
|
||||
protected final void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||
|
||||
response.setContentType("text/xml");
|
||||
response.setHeader("Cache-Control", "no-store");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
|
||||
try {
|
||||
|
||||
// Create document
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document document = documentBuilder.newDocument();
|
||||
|
||||
// Root element
|
||||
Element root = document.createElement("guacamole");
|
||||
document.appendChild(root);
|
||||
|
||||
try {
|
||||
handleRequest(session, request, root);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
addFatalError(root, t.getMessage());
|
||||
|
||||
// FATAL error ... try to disconnect
|
||||
if (session != null) {
|
||||
Client client = session.getClient();
|
||||
try {
|
||||
if (client != null)
|
||||
client.disconnect();
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
addFatalError(root, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up transformer
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
|
||||
// Write XML using transformer
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
StreamResult result = new StreamResult(bos);
|
||||
DOMSource source = new DOMSource(document);
|
||||
transformer.transform(source, result);
|
||||
|
||||
|
||||
bos.flush();
|
||||
|
||||
byte[] xmlData = bos.toByteArray();
|
||||
response.setContentLength(xmlData.length);
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
outputStream.write(xmlData);
|
||||
|
||||
// Close stream
|
||||
outputStream.close();
|
||||
}
|
||||
catch (ParserConfigurationException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
catch (TransformerConfigurationException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
catch (TransformerException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void addFatalError(Element root, String message) {
|
||||
Element error = root.getOwnerDocument().createElement("error");
|
||||
error.setAttribute("type", "fatal");
|
||||
error.setTextContent(message);
|
||||
root.appendChild(error);
|
||||
}
|
||||
|
||||
protected abstract void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException;
|
||||
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
package net.sourceforge.guacamole.net.input;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||
import net.sourceforge.guacamole.net.XMLGuacamoleServlet;
|
||||
|
||||
public class Inbound extends XMLGuacamoleServlet {
|
||||
|
||||
protected boolean shouldCreateSession() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(GuacamoleSession session, ServletRequest request, Element root) throws GuacamoleException {
|
||||
|
||||
if (!session.isConnected())
|
||||
session.connect();
|
||||
|
||||
// Send data
|
||||
try {
|
||||
|
||||
Reader input = request.getReader();
|
||||
char[] buffer = new char[8192];
|
||||
|
||||
int length;
|
||||
while ((length = input.read(buffer, 0, buffer.length)) != -1)
|
||||
session.getClient().write(buffer, 0, length);
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException("I/O Error sending data to server: " + e.getMessage(), e);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
throw new GuacamoleException("Error sending data to server: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,97 +0,0 @@
|
||||
package net.sourceforge.guacamole.net.output;
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import java.io.Writer;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import net.sourceforge.guacamole.Client;
|
||||
import net.sourceforge.guacamole.net.GuacamoleServlet;
|
||||
import net.sourceforge.guacamole.GuacamoleException;
|
||||
import net.sourceforge.guacamole.net.GuacamoleSession;
|
||||
|
||||
|
||||
public class InstructionStream extends GuacamoleServlet {
|
||||
|
||||
@Override
|
||||
protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException {
|
||||
|
||||
ReentrantLock instructionStreamLock = session.getInstructionStreamLock();
|
||||
instructionStreamLock.lock();
|
||||
|
||||
try {
|
||||
|
||||
response.setContentType("text/plain");
|
||||
Writer out = response.getWriter();
|
||||
|
||||
try {
|
||||
|
||||
// Query new update from server
|
||||
Client client = session.getClient();
|
||||
|
||||
// For all messages, until another stream is ready (we send at least one message)
|
||||
char[] message;
|
||||
while ((message = client.read()) != null) {
|
||||
|
||||
// Get message output bytes
|
||||
out.write(message, 0, message.length);
|
||||
out.flush();
|
||||
response.flushBuffer();
|
||||
|
||||
// No more messages another stream can take over
|
||||
if (instructionStreamLock.hasQueuedThreads())
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
session.disconnect();
|
||||
throw new GuacamoleException("Disconnected.");
|
||||
}
|
||||
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
out.write("error:" + e.getMessage() + ";");
|
||||
out.flush();
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
// End-of-instructions marker
|
||||
out.write(';');
|
||||
out.flush();
|
||||
response.flushBuffer();
|
||||
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
throw new GuacamoleException("UTF-8 not supported by Java.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException("I/O error writing to servlet output stream.", e);
|
||||
}
|
||||
finally {
|
||||
instructionStreamLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
35
guacamole/client/tunnel.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
# End all output buffers
|
||||
while (@ob_end_flush());
|
||||
|
||||
# Create socket
|
||||
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
|
||||
if (!$socket) {
|
||||
die("error:Could not create socket.;");
|
||||
}
|
||||
|
||||
# Open connection
|
||||
$result = socket_connect($socket, "localhost", 2222);
|
||||
if (!$result) {
|
||||
die("error:Could not connect: " . socket_strerror(socket_last_error()) . ";");
|
||||
}
|
||||
|
||||
# Socket should block
|
||||
socket_set_block($socket);
|
||||
|
||||
# Write all data sent here
|
||||
socket_write($socket, file_get_contents("php://input"));
|
||||
|
||||
# Read until EOF
|
||||
while (($buffer = socket_read($socket, 8192))) {
|
||||
echo $buffer;
|
||||
flush();
|
||||
}
|
||||
|
||||
echo ";";
|
||||
|
||||
# Close socket
|
||||
socket_close($socket);
|
||||
|
||||
?>
|
@@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Guacamole - Pure JavaScript/HTML VNC Client
|
||||
Copyright (C) 2010 Michael Jumper
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
<!-- Basic config -->
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
<session-config>
|
||||
<session-timeout>
|
||||
30
|
||||
</session-timeout>
|
||||
</session-config>
|
||||
<!-- Servlets -->
|
||||
<servlet>
|
||||
<description>Instruction stream servlet.</description>
|
||||
<servlet-name>InstructionStream</servlet-name>
|
||||
<servlet-class>net.sourceforge.guacamole.net.output.InstructionStream</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>InstructionStream</servlet-name>
|
||||
<url-pattern>/instructions</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<description>Input servlet.</description>
|
||||
<servlet-name>Inbound</servlet-name>
|
||||
<servlet-class>net.sourceforge.guacamole.net.input.Inbound</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Inbound</servlet-name>
|
||||
<url-pattern>/inbound</url-pattern>
|
||||
</servlet-mapping>
|
||||
<security-constraint>
|
||||
<display-name>Guacamole Access Restrictions</display-name>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Guacamole</web-resource-name>
|
||||
<description>All servlets/pages within Guacamole.</description>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<description>Only allow Guacamole users access.</description>
|
||||
<role-name>guacamole</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>Guacamole</realm-name>
|
||||
</login-config>
|
||||
<security-role>
|
||||
<description>Guacamole</description>
|
||||
<role-name>guacamole</role-name>
|
||||
</security-role>
|
||||
</web-app>
|