Working pause/resume

This commit is contained in:
Michael Jumper
2010-09-22 18:16:39 +00:00
parent b6e7e8038e
commit 520d4cb789
2 changed files with 60 additions and 7 deletions

View File

@@ -64,6 +64,11 @@ struct guac_client {
*/ */
GUACIO* io; GUACIO* io;
/**
* Semaphore which will be locked while I/O is owned.
*/
sem_t io_lock;
/** /**
* Arbitrary reference to proxy client-specific data. Implementors of a * Arbitrary reference to proxy client-specific data. Implementors of a
* Guacamole proxy client can store any data they want here, which can then * Guacamole proxy client can store any data they want here, which can then

View File

@@ -56,6 +56,15 @@ 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_release_client_io(guac_client* client) {
sem_post(&(client->io_lock));
}
guac_client* __guac_alloc_client(GUACIO* io) { guac_client* __guac_alloc_client(GUACIO* io) {
/* Allocate new client (not handoff) */ /* Allocate new client (not handoff) */
@@ -65,6 +74,7 @@ guac_client* __guac_alloc_client(GUACIO* io) {
/* Init new client */ /* Init new client */
client->io = io; client->io = io;
uuid_generate(client->uuid); uuid_generate(client->uuid);
sem_init(&(client->io_lock), 0, 0); /* I/O starts locked */
return client; return client;
} }
@@ -113,7 +123,27 @@ guac_client* guac_get_client(int client_fd, guac_client_registry* registry, guac
break; break;
} }
/* TODO: implement handoff */ /* resume -> resume existing connection (when that connection pauses) */
if (strcmp(instruction.opcode, "resume") == 0) {
if (registry) {
client = guac_find_client(
registry,
(unsigned char*) guac_decode_base64_inplace(instruction.argv[0])
);
if (client) {
__guac_set_client_io(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. */
}
}
return NULL;
}
} }
@@ -153,30 +183,41 @@ void guac_free_client(guac_client* client, guac_client_registry* registry) {
void guac_start_client(guac_client* client) { void guac_start_client(guac_client* client) {
guac_client client_copy;
guac_instruction instruction; guac_instruction instruction;
GUACIO* io = client->io;
int wait_result; int wait_result;
/* Maintained copy of client used for all calls to handlers, thus changes to I/O
* are controlled without starvation-prone blocking
*/
memcpy(&client_copy, client, sizeof(guac_client));
/* VNC Client Loop */ /* VNC Client Loop */
for (;;) { for (;;) {
/* Accept changes to client I/O only before handling messages */
if (client_copy.io != client->io) {
guac_close(client_copy.io); /* Close old I/O */
client_copy.io = client->io;
}
/* Handle server messages */ /* Handle server messages */
if (client->handle_messages) { if (client->handle_messages) {
int retval = client->handle_messages(client); int retval = client->handle_messages(&client_copy);
if (retval) { if (retval) {
syslog(LOG_ERR, "Error handling server messages"); syslog(LOG_ERR, "Error handling server messages");
return; return;
} }
guac_flush(client->io); guac_flush(client_copy.io);
} }
wait_result = guac_instructions_waiting(io); wait_result = guac_instructions_waiting(client_copy.io);
if (wait_result > 0) { if (wait_result > 0) {
int retval; int retval;
retval = guac_read_instruction(io, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */ retval = guac_read_instruction(client_copy.io, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */
if (retval > 0) { if (retval > 0) {
@@ -230,12 +271,19 @@ void guac_start_client(guac_client* client) {
} }
} }
else if (strcmp(instruction.opcode, "pause") == 0) {
/* Allow other connection to take over I/O */
__guac_release_client_io(client);
}
else if (strcmp(instruction.opcode, "disconnect") == 0) { else if (strcmp(instruction.opcode, "disconnect") == 0) {
syslog(LOG_INFO, "Client requested disconnect"); syslog(LOG_INFO, "Client requested disconnect");
return; return;
} }
} while ((retval = guac_read_instruction(io, &instruction)) > 0); } while ((retval = guac_read_instruction(client_copy.io, &instruction)) > 0);
if (retval < 0) { if (retval < 0) {
syslog(LOG_ERR, "Error reading instruction from stream"); syslog(LOG_ERR, "Error reading instruction from stream");