From 60d78e22c7965057be51a108608cdaa9c584ce9b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 17 Sep 2010 22:05:23 -0700 Subject: [PATCH] Initial connect instruction support, connection UUIDs --- .../guacamole/net/GuacamoleSession.java | 12 ++++- .../guacamole/net/input/Inbound.java | 6 +++ .../net/output/InstructionStream.java | 7 +++ guacamole/client/web/javascript/guacamole.js | 31 +++++-------- guacamole/libguac/Makefile | 2 +- guacamole/libguac/client.c | 45 +++++++++++++++++-- guacamole/libguac/include/client.h | 7 +++ guacamole/libguac/include/protocol.h | 2 + guacamole/libguac/protocol.c | 11 +++++ 9 files changed, 98 insertions(+), 25 deletions(-) diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java b/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java index 52a7d0ac6..681b455e7 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java +++ b/guacamole/client/src/net/sourceforge/guacamole/net/GuacamoleSession.java @@ -111,6 +111,12 @@ public class GuacamoleSession { } } + public boolean isConnected() { + synchronized (session) { + return client != null; + } + } + public GuacamoleConfiguration getConfiguration() { return config; } @@ -126,8 +132,12 @@ public class GuacamoleSession { } public void disconnect() throws GuacamoleException { - if (client != null) + if (client != null) { client.disconnect(); + + session.removeAttribute("CLIENT"); + client = null; + } } public ReentrantLock getInstructionStreamLock() { diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java b/guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java index 4d3429410..7be7bc6cb 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java +++ b/guacamole/client/src/net/sourceforge/guacamole/net/input/Inbound.java @@ -30,10 +30,16 @@ 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 { diff --git a/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java b/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java index 33237d44a..bba89540c 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java +++ b/guacamole/client/src/net/sourceforge/guacamole/net/output/InstructionStream.java @@ -32,9 +32,16 @@ import net.sourceforge.guacamole.net.GuacamoleSession; public class InstructionStream extends GuacamoleServlet { + protected boolean shouldCreateSession() { + return true; + } + @Override protected void handleRequest(GuacamoleSession session, HttpServletRequest request, HttpServletResponse response) throws GuacamoleException { + if (!session.isConnected()) + session.connect(); + ReentrantLock instructionStreamLock = session.getInstructionStreamLock(); instructionStreamLock.lock(); diff --git a/guacamole/client/web/javascript/guacamole.js b/guacamole/client/web/javascript/guacamole.js index 83a65991a..c4ff7ca65 100644 --- a/guacamole/client/web/javascript/guacamole.js +++ b/guacamole/client/web/javascript/guacamole.js @@ -115,6 +115,10 @@ function VNCClient(display) { this.enableKeyboard(); function sendKeyEvent(pressed, keysym) { + // Do not send requests if not connected + if (!isConnected()) + return; + sendMessage("key:" + keysym + "," + pressed + ";"); } @@ -159,6 +163,10 @@ function VNCClient(display) { function sendMouseState(mouseState) { + // Do not send requests if not connected + if (!isConnected()) + return; + // Build mask var buttonMask = 0; if (mouseState.getLeft()) buttonMask |= 1; @@ -176,10 +184,6 @@ function VNCClient(display) { function sendMessage(message) { - // Do not send requests if not connected - if (!isConnected()) - return; - // Add event to queue, restart send loop if finished. outputMessageBuffer += message; if (sendingMessages == 0) @@ -189,10 +193,6 @@ function VNCClient(display) { function sendPendingMessages() { - // Do not send requests if not connected - if (!isConnected()) - return; - if (outputMessageBuffer.length > 0) { sendingMessages = 1; @@ -560,20 +560,11 @@ function VNCClient(display) { this.connect = function() { // Attempt connection - var connect_xmlhttprequest = new XMLHttpRequest(); - connect_xmlhttprequest.open("GET", "connect", false); - setState(STATE_CONNECTING); - connect_xmlhttprequest.send(null); + sendMessage("connect;"); // Start new guacamole session - // Handle result (and check for errors) - var message = new GuacamoleMessage(connect_xmlhttprequest.responseXML); - if (!message.hasErrors()) { - setState(STATE_WAITING); - handleResponse(makeRequest()); - } - else - handleErrors(message); + setState(STATE_WAITING); + handleResponse(makeRequest()); }; diff --git a/guacamole/libguac/Makefile b/guacamole/libguac/Makefile index 28fed66e0..a25bad3e0 100644 --- a/guacamole/libguac/Makefile +++ b/guacamole/libguac/Makefile @@ -1,6 +1,6 @@ CFLAGS=-O2 -fPIC -pedantic -Wall -Werror -Iinclude -LDFLAGS=-lpng +LDFLAGS=-lpng -luuid .PHONY: clean doc diff --git a/guacamole/libguac/client.c b/guacamole/libguac/client.c index a2550678c..10c291906 100644 --- a/guacamole/libguac/client.c +++ b/guacamole/libguac/client.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "guacio.h" #include "protocol.h" @@ -53,19 +54,57 @@ void guac_free_png_buffer(png_byte** png_buffer, int h) { } -guac_client* guac_get_client(int client_fd, guac_client_init_handler* client_init, const char* hostname, int port) { +guac_client* __guac_alloc_client(GUACIO* io) { + /* Allocate new client (not handoff) */ guac_client* client = malloc(sizeof(guac_client)); - client->io = guac_open(client_fd); + /* Init new client */ + client->io = io; + uuid_generate(client->uuid); + return client; +} + + +guac_client* guac_get_client(int client_fd, guac_client_init_handler* client_init, const char* hostname, int port) { + + guac_client* client; + GUACIO* io = guac_open(client_fd); + guac_instruction instruction; + + /* Wait for handshaking messages */ + for (;;) { + + int retval; + retval = guac_read_instruction(io, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */ + + if (retval > 0) { + + /* connect -> create new client connection */ + if (strcmp(instruction.opcode, "connect") == 0) { + client = __guac_alloc_client(io); + guac_send_uuid(io, client->uuid); + break; + } + + } + + if (retval < 0) + return NULL; /* EOF or error */ + + /* Otherwise, retval == 0 implies unfinished instruction */ + + } + + /* FIXME: hostname and port should not be required. Should be made available in some sort of client-contained argc/argv, specified after the protocol on the commandline */ client_init(client, hostname, port); guac_flush(client->io); - return client; } + void guac_free_client(guac_client* client) { if (client->free_handler) client->free_handler(client); diff --git a/guacamole/libguac/include/client.h b/guacamole/libguac/include/client.h index cbfc7746a..a70a4d537 100644 --- a/guacamole/libguac/include/client.h +++ b/guacamole/libguac/include/client.h @@ -21,6 +21,7 @@ #define _CLIENT_H #include +#include #include "guacio.h" @@ -46,6 +47,12 @@ typedef void guac_client_free_handler(void* client); */ struct guac_client { + /** + * UUID identifying this client. Useful when identifying a client + * for connection handoff/resume. + */ + uuid_t uuid; + /** * The GUACIO structure to be used to communicate with the web-client. It is * expected that the implementor of any Guacamole proxy client will provide diff --git a/guacamole/libguac/include/protocol.h b/guacamole/libguac/include/protocol.h index 6edb06ca4..1bfc8515e 100644 --- a/guacamole/libguac/include/protocol.h +++ b/guacamole/libguac/include/protocol.h @@ -21,6 +21,7 @@ #define __PROTOCOL_H #include +#include #include "guacio.h" @@ -40,6 +41,7 @@ char* guac_unescape_string_inplace(char* str); void guac_send_name(GUACIO* io, const char* name); void guac_send_error(GUACIO* io, const char* error); void guac_send_clipboard(GUACIO* io, const char* data); +void guac_send_uuid(GUACIO* io, uuid_t uuid); void guac_send_size(GUACIO* io, int w, int h); void guac_send_copy(GUACIO* io, int srcx, int srcy, int w, int h, int dstx, int dsty); void guac_send_png(GUACIO* io, int x, int y, png_byte** png_rows, int w, int h); diff --git a/guacamole/libguac/protocol.c b/guacamole/libguac/protocol.c index e0bb9096d..f09371e1d 100644 --- a/guacamole/libguac/protocol.c +++ b/guacamole/libguac/protocol.c @@ -26,6 +26,8 @@ #include #include +#include + #include "guacio.h" #include "protocol.h" @@ -154,6 +156,15 @@ void guac_send_size(GUACIO* io, int w, int h) { guac_write_string(io, ";"); } +void guac_send_uuid(GUACIO* io, uuid_t uuid) { + + guac_write_string(io, "uuid:"); + guac_write_base64(io, uuid, 16); + guac_flush_base64(io); + guac_write_string(io, ";"); + +} + void guac_send_clipboard(GUACIO* io, const char* data) { char* escaped = guac_escape_string(data);