From 16d335aa1926ab357c660eace256d85827be28bf Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 18 Sep 2010 00:21:49 -0700 Subject: [PATCH] Added client registry, added GUACIO transfer operation --- guacamole/libguac/client.c | 131 ++++++++++++++++++++++++++++- guacamole/libguac/guacio.c | 10 ++- guacamole/libguac/include/client.h | 71 +++++++++++++++- guacamole/libguac/include/guacio.h | 1 + guacamole/proxy/daemon.c | 11 ++- 5 files changed, 217 insertions(+), 7 deletions(-) diff --git a/guacamole/libguac/client.c b/guacamole/libguac/client.c index 21b802ce3..63dc374d5 100644 --- a/guacamole/libguac/client.c +++ b/guacamole/libguac/client.c @@ -27,6 +27,122 @@ #include "client.h" + +guac_client_registry_node* guac_create_client_registry() { + + guac_client_registry_node* registry = malloc(sizeof(guac_client_registry_node)); + + registry->used = 0; + memset(registry->next, 0, sizeof(registry->next)); + + return registry; + +} + +void guac_register_client(guac_client_registry_node* registry, guac_client* client) { + + guac_client_registry_node* current = registry; + int i; + unsigned char index; + + for (i=0; iuuid)[i]; + next = ((guac_client_registry_node**) current->next)[index]; + + /* If no node, allocate one */ + if (next == NULL) { + current->used++; + next = guac_create_client_registry(); + ((guac_client_registry_node**) current->next)[index] = next; + } + + current = next; + } + + /* Register client */ + index = ((unsigned char*) client->uuid)[i]; + ((guac_client**) current->next)[index] = client; + +} + +guac_client* guac_find_client(guac_client_registry_node* registry, uuid_t uuid) { + + guac_client_registry_node* current = registry; + int i; + unsigned char index; + + for (i=0; inext)[index]; + + /* If no node, client not registered */ + if (current == NULL) + return NULL; + + } + + /* Return client found (if any) */ + index = ((unsigned char*) uuid)[i]; + return ((guac_client**) current->next)[index]; + +} + +void guac_remove_client(guac_client_registry_node* registry, guac_client* client) { + + guac_client_registry_node* current = registry; + int i; + unsigned char index; + + for (i=0; iuuid)[i]; + current = ((guac_client_registry_node**) current->next)[index]; + + /* If no node, client not registered */ + if (current == NULL) + return; + + } + + /* Remove client, if registered */ + if (((guac_client**) current->next)[index]) { + ((guac_client**) current->next)[index] = NULL; + current->used--; + + /* FIXME: If no more clients at this node, clean up */ + if (current->used == 0) { + /* STUB */ + } + + } + +} + +void guac_cleanup_client_registry(guac_client_registry_node* registry) { + + int i; + for (i=0; inext); i++) { + + if (registry->next[i] != NULL) { + guac_cleanup_client_registry(registry->next[i]); + registry->next[i] = NULL; + } + + } + + free(registry); + +} + + + png_byte** guac_alloc_png_buffer(int w, int h, int bpp) { png_byte** png_buffer; @@ -67,7 +183,7 @@ guac_client* __guac_alloc_client(GUACIO* io) { } -guac_client* guac_get_client(int client_fd, guac_client_init_handler* client_init, const char* hostname, int port) { +guac_client* guac_get_client(int client_fd, guac_client_registry_node* registry, guac_client_init_handler* client_init, const char* hostname, int port) { guac_client* client; GUACIO* io = guac_open(client_fd); @@ -83,7 +199,15 @@ guac_client* guac_get_client(int client_fd, guac_client_init_handler* client_ini /* connect -> create new client connection */ if (strcmp(instruction.opcode, "connect") == 0) { + + /* Create new client */ client = __guac_alloc_client(io); + + /* Register client */ + if (registry) + guac_register_client(registry, client); + + /* Send UUID to web-client */ guac_send_uuid(io, client->uuid); break; } @@ -105,12 +229,15 @@ guac_client* guac_get_client(int client_fd, guac_client_init_handler* client_ini } -void guac_free_client(guac_client* client) { +void guac_free_client(guac_client* client, guac_client_registry_node* registry) { + if (client->free_handler) client->free_handler(client); guac_close(client->io); + guac_remove_client(registry, client); + free(client); } diff --git a/guacamole/libguac/guacio.c b/guacamole/libguac/guacio.c index 3c4567aa7..8bf04b7ce 100644 --- a/guacamole/libguac/guacio.c +++ b/guacamole/libguac/guacio.c @@ -49,12 +49,20 @@ GUACIO* guac_open(int fd) { io->instructionbuf_used_length = 0; /* Set limit */ - io->transfer_limit = 256; + io->transfer_limit = 0; return io; } +void guac_transfer(GUACIO* io, int fd) { + + guac_flush(io); + close(fd); + io->fd = fd; + +} + void guac_close(GUACIO* io) { guac_flush(io); free(io); diff --git a/guacamole/libguac/include/client.h b/guacamole/libguac/include/client.h index a70a4d537..c17a9c727 100644 --- a/guacamole/libguac/include/client.h +++ b/guacamole/libguac/include/client.h @@ -32,6 +32,7 @@ */ typedef struct guac_client guac_client; +typedef struct guac_client_registry_node guac_client_registry_node; typedef void guac_client_handle_messages(guac_client* client); typedef void guac_client_mouse_handler(guac_client* client, int x, int y, int button_mask); @@ -178,6 +179,7 @@ typedef void guac_client_init_handler(guac_client* client, const char* hostname, * Initialize and return a new guac_client using the specified client init handler (guac_client_init_handler). * This will normally be the guac_client_init function as provided by any of the pluggable proxy clients. * + * @param registry The registry to use to register/find the client we need to return. * @param client_fd The file descriptor associated with the socket associated with the connection to the * web-client tunnel. * @param client_init Function pointer to the client init handler which will initialize the new guac_client @@ -186,7 +188,7 @@ typedef void guac_client_init_handler(guac_client* client, const char* hostname, * @param port The port of the host that the proxy client should connect to. * @return A pointer to the newly initialized client. */ -guac_client* guac_get_client(int client_fd, guac_client_init_handler* client_init, const char* hostname, int port); +guac_client* guac_get_client(int client_fd, guac_client_registry_node* registry, guac_client_init_handler* client_init, const char* hostname, int port); /** * Enter the main network message handling loop for the given client. @@ -199,8 +201,9 @@ void guac_start_client(guac_client* client); * Free all resources associated with the given client. * * @param client The proxy client to free all reasources of. + * @param registry The registry to remove this client from when freed. */ -void guac_free_client(guac_client* client); +void guac_free_client(guac_client* client, guac_client_registry_node* registry); /** * Allocate a libpng-compatible buffer to hold raw image data. @@ -221,4 +224,68 @@ png_byte** guac_alloc_png_buffer(int w, int h, int bpp); */ void guac_free_png_buffer(png_byte** png_buffer, int h); + +/** + * Represents a single node of the Guacamole client registry. The + * Guacamole client registry contains references to all active clients, + * indexed by client UUID. + */ +struct guac_client_registry_node { + + /** + * The number of pointers used inside the next array. + */ + int used; + + /** + * The next guac_client_registry_node if currently looking at any byte + * of the UUID except the last, or the guac_client if looking at the + * last byte of the UUID. + */ + void* next[256]; + +}; + +/** + * Registers the given client in the client registry by that client's UUID. + * + * @param registry The registry to register the client within. + * @param client The client to register. + */ +void guac_register_client(guac_client_registry_node* registry, guac_client* client); + +/** + * Returns the client from the client registry associated with the given UUID. + * + * @param registry The registry to search. + * @param uuid The uuid of the client to lookup. + * @return The client, if found, or NULL if no such client has been registered. + */ +guac_client* guac_find_client(guac_client_registry_node* registry, uuid_t uuid); + +/** + * Removes the given client from the client registry. + * + * @param registry The registry to remove the client from. + * @param client The client to remove. + */ +void guac_remove_client(guac_client_registry_node* registry, guac_client* client); + +/** + * Creates a new client registry. + * + * @return The newly allocated and initialized registry. + */ +guac_client_registry_node* guac_create_client_registry(); + +/** + * Frees all memory associated with the given client registry. + * + * @param registry The registry to clean up. + */ +void guac_cleanup_client_registry(guac_client_registry_node* registry); + + + + #endif diff --git a/guacamole/libguac/include/guacio.h b/guacamole/libguac/include/guacio.h index c00119a2f..c1c9d7e8d 100644 --- a/guacamole/libguac/include/guacio.h +++ b/guacamole/libguac/include/guacio.h @@ -42,6 +42,7 @@ typedef struct GUACIO { } GUACIO; GUACIO* guac_open(int fd); +void guac_transfer(GUACIO* io, int fd); ssize_t guac_write_int(GUACIO* io, unsigned int i); ssize_t guac_write_string(GUACIO* io, const char* str); ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count); diff --git a/guacamole/proxy/daemon.c b/guacamole/proxy/daemon.c index 5787096a2..6c2055dee 100644 --- a/guacamole/proxy/daemon.c +++ b/guacamole/proxy/daemon.c @@ -30,6 +30,8 @@ int main(int argc, char* argv[]) { + guac_client_registry_node* registry; + /* Server */ int socket_fd; struct sockaddr_in server_addr; @@ -76,6 +78,9 @@ int main(int argc, char* argv[]) { fprintf(stderr, "[guacamole] listening on port %i, forwarding to %s:%i\n", listen_port, connect_host, connect_port); + /* Allocate registry */ + registry = guac_create_client_registry(); + /* Daemon loop */ for (;;) { @@ -134,9 +139,9 @@ int main(int argc, char* argv[]) { } /* Load and start client */ - client = guac_get_client(connected_socket_fd, alias.client_init, connect_host, connect_port); + client = guac_get_client(connected_socket_fd, registry, alias.client_init, connect_host, connect_port); guac_start_client(client); - guac_free_client(client); + guac_free_client(client, registry); /* Close socket */ if (close(connected_socket_fd) < 0) { @@ -156,6 +161,8 @@ int main(int argc, char* argv[]) { } + /* FIXME: Cleanup client registry (and all other objects) on exit */ + /* Close socket */ if (close(socket_fd) < 0) { perror("Error closing socket");