diff --git a/configure.ac b/configure.ac index 63fada60..3ad1d2a5 100644 --- a/configure.ac +++ b/configure.ac @@ -62,6 +62,10 @@ AC_CHECK_LIB([pthread], [pthread_create], [PTHREAD_LIBS=-lpthread AC_DEFINE([HAVE_LIBPTHREAD],, [Whether libpthread was found])]) +# libossp-uuid +AC_CHECK_LIB([ossp-uuid], [uuid_create], [UUID_LIBS=-lossp-uuid], + AC_MSG_ERROR("The OSSP UUID library is required")) + # cunit AC_CHECK_LIB([cunit], [CU_run_test], [CUNIT_LIBS=-lcunit]) @@ -73,6 +77,7 @@ AC_SUBST(MATH_LIBS) AC_SUBST(PNG_LIBS) AC_SUBST(CAIRO_LIBS) AC_SUBST(PTHREAD_LIBS) +AC_SUBST(UUID_LIBS) AC_SUBST(CUNIT_LIBS) # Library functions diff --git a/src/guacd/daemon.c b/src/guacd/daemon.c index b7071aa0..0bce88d2 100644 --- a/src/guacd/daemon.c +++ b/src/guacd/daemon.c @@ -182,6 +182,12 @@ void guacd_handle_connection(guac_socket* socket) { /* Get client */ client = guac_client_alloc(); + if (client == NULL) { + guacd_log_guac_error("Client could not be allocated"); + guac_socket_free(socket); + return; + } + client->socket = socket; client->log_info_handler = guacd_client_log_info; client->log_error_handler = guacd_client_log_error; @@ -230,6 +236,8 @@ void guacd_handle_connection(guac_socket* socket) { return; } + guacd_log_info("Connection ID is \"%s\"", client->connection_id); + /* Start client threads */ guacd_log_info("Starting client"); if (guacd_client_start(client)) diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am index d1aae7a4..1ea68671 100644 --- a/src/libguac/Makefile.am +++ b/src/libguac/Makefile.am @@ -88,6 +88,6 @@ noinst_HEADERS += ogg_encoder.h endif lib_LTLIBRARIES = libguac.la -libguac_la_LDFLAGS = -version-info 7:0:0 @PTHREAD_LIBS@ @CAIRO_LIBS@ @PNG_LIBS@ @VORBIS_LIBS@ -libguac_la_LIBADD = @LIBADD_DLOPEN@ +libguac_la_LDFLAGS = -version-info 7:0:0 @PTHREAD_LIBS@ @CAIRO_LIBS@ @PNG_LIBS@ @VORBIS_LIBS@ @UUID_LIBS@ +libguac_la_LIBADD = @LIBADD_DLOPEN@ diff --git a/src/libguac/client.c b/src/libguac/client.c index c5d30560..79200eae 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -33,6 +33,8 @@ #include "stream.h" #include "timestamp.h" +#include + #include #include #include @@ -115,6 +117,64 @@ void guac_client_free_stream(guac_client* client, guac_stream* stream) { } +/** + * Returns a newly allocated string containing a guaranteed-unique connection + * identifier string which is 37 characters long and begins with a '$' + * character. If an error occurs, NULL is returned, and no memory is + * allocated. + */ +static char* __guac_generate_connection_id() { + + char* buffer; + char* identifier; + size_t identifier_length; + + uuid_t* uuid; + + /* Attempt to create UUID object */ + if (uuid_create(&uuid) != UUID_RC_OK) { + guac_error = GUAC_STATUS_NO_MEMORY; + guac_error_message = "Could not allocate memory for UUID"; + return NULL; + } + + /* Generate random UUID */ + if (uuid_make(uuid, UUID_MAKE_V4) != UUID_RC_OK) { + uuid_destroy(uuid); + guac_error = GUAC_STATUS_NO_MEMORY; + guac_error_message = "UUID generation failed"; + return NULL; + } + + /* Allocate buffer for future formatted ID */ + buffer = malloc(UUID_LEN_STR + 2); + if (buffer == NULL) { + uuid_destroy(uuid); + guac_error = GUAC_STATUS_NO_MEMORY; + guac_error_message = "Could not allocate memory for connection ID"; + return NULL; + } + + identifier = &(buffer[1]); + identifier_length = UUID_LEN_STR + 1; + + /* Build connection ID from UUID */ + if (uuid_export(uuid, UUID_FMT_STR, &identifier, &identifier_length) != UUID_RC_OK) { + free(buffer); + uuid_destroy(uuid); + guac_error = GUAC_STATUS_BAD_STATE; + guac_error_message = "Conversion of UUID to connection ID failed"; + return NULL; + } + + uuid_destroy(uuid); + + buffer[0] = '$'; + buffer[UUID_LEN_STR + 1] = '\0'; + return buffer; + +} + guac_client* guac_client_alloc() { int i; @@ -135,6 +195,13 @@ guac_client* guac_client_alloc() { client->state = GUAC_CLIENT_RUNNING; + /* Generate ID */ + client->connection_id = __guac_generate_connection_id(); + if (client->connection_id == NULL) { + free(client); + return NULL; + } + /* Allocate buffer and layer pools */ client->__buffer_pool = guac_pool_alloc(GUAC_BUFFER_POOL_INITIAL_SIZE); client->__layer_pool = guac_pool_alloc(GUAC_BUFFER_POOL_INITIAL_SIZE); diff --git a/src/libguac/guacamole/client.h b/src/libguac/guacamole/client.h index 3bf0dd94..d9bb06bd 100644 --- a/src/libguac/guacamole/client.h +++ b/src/libguac/guacamole/client.h @@ -419,6 +419,15 @@ struct guac_client { */ guac_stream* __input_streams; + /** + * The unique identifier allocated for the connection, which may + * be used within the Guacamole protocol to refer to this connection. + * This identifier is guaranteed to be unique from all existing + * connections and will not collide with any available protocol + * names. + */ + char* connection_id; + }; /**