diff --git a/guacamole/client/javascript/guacamole.js b/guacamole/client/javascript/guacamole.js index 0878e0501..a057aee4c 100644 --- a/guacamole/client/javascript/guacamole.js +++ b/guacamole/client/javascript/guacamole.js @@ -273,7 +273,7 @@ function VNCClient(display) { // Start next request as soon as possible if (xmlhttprequest.readyState >= 2 && nextRequest == null && uuid) - nextRequest = makeRequest("resume:" + uuid + ";yield;"); + nextRequest = makeRequest("transfer:out," + uuid + ";"); // Parse stream when data is received and when complete. if (xmlhttprequest.readyState == 3 || diff --git a/guacamole/libguac/include/client.h b/guacamole/libguac/include/client.h index 6ef30e092..a92396bff 100644 --- a/guacamole/libguac/include/client.h +++ b/guacamole/libguac/include/client.h @@ -62,7 +62,8 @@ struct guac_client { * their own mechanism of I/O for their protocol. The GUACIO structure is * used only to communicate conveniently with the Guacamole web-client. */ - GUACIO* io; + GUACIO* io_in; + GUACIO* io_out; /** * Semaphore which will be locked while I/O is owned. diff --git a/guacamole/libguac/src/client.c b/guacamole/libguac/src/client.c index 72a2d4280..d370f6a70 100644 --- a/guacamole/libguac/src/client.c +++ b/guacamole/libguac/src/client.c @@ -56,12 +56,16 @@ void guac_free_png_buffer(png_byte** png_buffer, int h) { } -void __guac_set_client_io(guac_client* client, GUACIO* io) { - sem_wait(&(client->io_lock)); /* Acquire I/O */ - client->io = io; +void __guac_set_client_io_out(guac_client* client, GUACIO* io) { + client->io_out = io; } -void __guac_release_client_io(guac_client* client) { +void __guac_set_client_io_in(guac_client* client, GUACIO* io) { + sem_wait(&(client->io_lock)); /* Acquire I/O */ + client->io_in = io; +} + +void __guac_release_client_io_in(guac_client* client) { sem_post(&(client->io_lock)); } @@ -72,7 +76,7 @@ guac_client* __guac_alloc_client(GUACIO* io) { memset(client, 0, sizeof(guac_client)); /* Init new client */ - client->io = io; + client->io_in = client->io_out = io; uuid_generate(client->uuid); sem_init(&(client->io_lock), 0, 0); /* I/O starts locked */ @@ -114,7 +118,7 @@ guac_client* guac_get_client(int client_fd, guac_client_registry* registry, guac /* Send UUID to web-client */ guac_send_uuid(io, client->uuid); - guac_flush(client->io); + guac_flush(io); } if (client_init(client, argc, scratch_argv) != 0) @@ -124,17 +128,28 @@ guac_client* guac_get_client(int client_fd, guac_client_registry* registry, guac } /* resume -> resume existing connection (when that connection pauses) */ - if (strcmp(instruction.opcode, "resume") == 0) { + if (strcmp(instruction.opcode, "transfer") == 0) { if (registry) { client = guac_find_client( registry, - (unsigned char*) guac_decode_base64_inplace(instruction.argv[0]) + (unsigned char*) guac_decode_base64_inplace(instruction.argv[1]) ); if (client) { - __guac_set_client_io(client, io); + + if (strcmp(instruction.argv[0], "in") == 0) + __guac_set_client_io_in(client, io); + + else if (strcmp(instruction.argv[0], "out") == 0) + __guac_set_client_io_out(client, io); + + else if (strcmp(instruction.argv[0], "both") == 0) { + __guac_set_client_io_in(client, io); + __guac_set_client_io_out(client, io); + } + return NULL; /* Returning NULL, so old client loop is used */ /* FIXME: Fix semantics of returning NULL vs ptr. This function needs redocumentation, and callers * need to lose their "error" handling. */ @@ -173,7 +188,9 @@ void guac_free_client(guac_client* client, guac_client_registry* registry) { syslog(LOG_ERR, "Error calling client free handler"); } - guac_close(client->io); + if (client->io_in != client->io_out) + guac_close(client->io_in); + guac_close(client->io_out); guac_remove_client(registry, client->uuid); @@ -196,9 +213,20 @@ void guac_start_client(guac_client* client) { for (;;) { /* Accept changes to client I/O only before handling messages */ - if (client_copy.io != client->io) { - guac_close_final(client_copy.io); /* Close old I/O and fd */ - client_copy.io = client->io; + if (client_copy.io_in != client->io_in) { + /* Close and free previous I/O if unused */ + if (client_copy.io_in != client_copy.io_out + && client_copy.io_in != client->io_out) + guac_close_final(client_copy.io_in); + client_copy.io_in = client->io_in; + } + + if (client_copy.io_out != client->io_out) { + /* Close and free previous I/O if unused */ + if (client_copy.io_out != client_copy.io_in + && client_copy.io_out != client->io_in) + guac_close_final(client_copy.io_out); + client_copy.io_out = client->io_out; } /* Handle server messages */ @@ -210,14 +238,14 @@ void guac_start_client(guac_client* client) { return; } - guac_flush(client_copy.io); + guac_flush(client_copy.io_out); } - wait_result = guac_instructions_waiting(client_copy.io); + wait_result = guac_instructions_waiting(client_copy.io_in); if (wait_result > 0) { int retval; - retval = guac_read_instruction(client_copy.io, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */ + retval = guac_read_instruction(client_copy.io_in, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */ if (retval > 0) { @@ -274,7 +302,7 @@ void guac_start_client(guac_client* client) { else if (strcmp(instruction.opcode, "yield") == 0) { /* Allow other connection to take over I/O */ - __guac_release_client_io(client); + __guac_release_client_io_in(client); } @@ -283,7 +311,7 @@ void guac_start_client(guac_client* client) { return; } - } while ((retval = guac_read_instruction(client_copy.io, &instruction)) > 0); + } while ((retval = guac_read_instruction(client_copy.io_in, &instruction)) > 0); if (retval < 0) { syslog(LOG_ERR, "Error reading instruction from stream"); diff --git a/guacamole/vnc/src/vnc_client.c b/guacamole/vnc/src/vnc_client.c index c3fcb7c7b..ec613b41f 100644 --- a/guacamole/vnc/src/vnc_client.c +++ b/guacamole/vnc/src/vnc_client.c @@ -49,7 +49,7 @@ void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) { int dx, dy; guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT); - GUACIO* io = gc->io; + GUACIO* io = gc->io_out; png_byte** png_buffer = ((vnc_guac_client_data*) gc->data)->png_buffer_alpha; png_byte* row; @@ -110,7 +110,7 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) { int dx, dy; guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT); - GUACIO* io = gc->io; + GUACIO* io = gc->io_out; png_byte** png_buffer = ((vnc_guac_client_data*) gc->data)->png_buffer; png_byte* row; @@ -167,7 +167,7 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) { void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT); - GUACIO* io = gc->io; + GUACIO* io = gc->io_out; guac_send_copy(io, src_x, src_y, w, h, dest_x, dest_y); ((vnc_guac_client_data*) gc->data)->copy_rect_used = 1; @@ -187,7 +187,7 @@ char* guac_vnc_get_password(rfbClient* client) { void guac_vnc_cut_text(rfbClient* client, const char* text, int textlen) { guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT); - GUACIO* io = gc->io; + GUACIO* io = gc->io_out; guac_send_clipboard(io, text); @@ -335,10 +335,10 @@ int guac_client_init(guac_client* client, int argc, char** argv) { client->clipboard_handler = vnc_guac_client_clipboard_handler; /* Send name */ - guac_send_name(client->io, rfb_client->desktopName); + guac_send_name(client->io_out, rfb_client->desktopName); /* Send size */ - guac_send_size(client->io, rfb_client->width, rfb_client->height); + guac_send_size(client->io_out, rfb_client->width, rfb_client->height); return 0;