diff --git a/src/common/common/recording.h b/src/common/common/recording.h index 71d8fbc7..0305a83c 100644 --- a/src/common/common/recording.h +++ b/src/common/common/recording.h @@ -42,6 +42,21 @@ */ #define GUAC_COMMON_RECORDING_MAX_NAME_LENGTH 2048 +/** + * An in-progress session recording, attached to a guac_client instance such + * that output Guacamole instructions may be dynamically intercepted and + * written to a file. + */ +typedef struct guac_common_recording { + + /** + * The guac_socket which writes directly to the recording file, rather than + * to any particular user. + */ + guac_socket* socket; + +} guac_common_recording; + /** * Replaces the socket of the given client such that all further Guacamole * protocol output will be copied into a file within the given path and having @@ -68,11 +83,23 @@ * exist. * * @return - * Zero if the recording file has been successfully created and a recording - * will be written, non-zero otherwise. + * A new guac_common_recording structure representing the in-progress + * recording if the recording file has been successfully created and a + * recording will be written, NULL otherwise. */ -int guac_common_recording_create(guac_client* client, const char* path, - const char* name, int create_path); +guac_common_recording* guac_common_recording_create(guac_client* client, + const char* path, const char* name, int create_path); + +/** + * Frees the resources associated with the given in-progress recording. Note + * that, due to the manner that recordings are attached to the guac_client, the + * underlying guac_socket is not freed. The guac_socket will be automatically + * freed when the guac_client is freed. + * + * @param recording + * The guac_common_recording to free. + */ +void guac_common_recording_free(guac_common_recording* recording); #endif diff --git a/src/common/recording.c b/src/common/recording.c index 6b1dcccc..274ac6de 100644 --- a/src/common/recording.c +++ b/src/common/recording.c @@ -133,8 +133,8 @@ static int guac_common_recording_open(const char* path, } -int guac_common_recording_create(guac_client* client, const char* path, - const char* name, int create_path) { +guac_common_recording* guac_common_recording_create(guac_client* client, + const char* path, const char* name, int create_path) { char filename[GUAC_COMMON_RECORDING_MAX_NAME_LENGTH]; @@ -146,7 +146,7 @@ int guac_common_recording_create(guac_client* client, const char* path, #endif guac_client_log(client, GUAC_LOG_ERROR, "Creation of recording failed: %s", strerror(errno)); - return 1; + return NULL; } /* Attempt to open recording file */ @@ -154,18 +154,26 @@ int guac_common_recording_create(guac_client* client, const char* path, if (fd == -1) { guac_client_log(client, GUAC_LOG_ERROR, "Creation of recording failed: %s", strerror(errno)); - return 1; + return NULL; } - /* Replace client socket with wrapped socket */ - client->socket = guac_socket_tee(client->socket, guac_socket_open(fd)); + /* Create recording structure with reference to underlying socket */ + guac_common_recording* recording = malloc(sizeof(guac_common_recording)); + recording->socket = guac_socket_open(fd); + + /* Replace client socket with wrapped recording socket */ + client->socket = guac_socket_tee(client->socket, recording->socket); /* Recording creation succeeded */ guac_client_log(client, GUAC_LOG_INFO, "Recording of session will be saved to \"%s\".", filename); - return 0; + return recording; } +void guac_common_recording_free(guac_common_recording* recording) { + free(recording); +} + diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index d12efbaa..6b9a0a6b 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -20,6 +20,7 @@ #include "config.h" #include "audio_input.h" +#include "common/recording.h" #include "client.h" #include "rdp.h" #include "rdp_disp.h" @@ -122,6 +123,10 @@ int guac_rdp_client_free_handler(guac_client* client) { guac_common_ssh_uninit(); #endif + /* Clean up recording, if in progress */ + if (rdp_client->recording != NULL) + guac_common_recording_free(rdp_client->recording); + /* Clean up audio stream, if allocated */ if (rdp_client->audio != NULL) guac_audio_stream_free(rdp_client->audio); diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index f21e30c5..a0de94da 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -668,7 +668,7 @@ static int guac_rdp_handle_connection(guac_client* client) { /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { - guac_common_recording_create(client, + rdp_client->recording = guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); diff --git a/src/protocols/rdp/rdp.h b/src/protocols/rdp/rdp.h index 943155dd..1d2eb110 100644 --- a/src/protocols/rdp/rdp.h +++ b/src/protocols/rdp/rdp.h @@ -26,6 +26,7 @@ #include "common/clipboard.h" #include "common/display.h" #include "common/list.h" +#include "common/recording.h" #include "common/surface.h" #include "keyboard.h" #include "rdp_disp.h" @@ -143,6 +144,12 @@ typedef struct guac_rdp_client { guac_common_ssh_sftp_filesystem* sftp_filesystem; #endif + /** + * The in-progress session recording, or NULL if no recording is in + * progress. + */ + guac_common_recording* recording; + /** * Display size update module. */ diff --git a/src/protocols/ssh/client.c b/src/protocols/ssh/client.c index 12eb1b71..47b5978f 100644 --- a/src/protocols/ssh/client.c +++ b/src/protocols/ssh/client.c @@ -20,6 +20,7 @@ #include "config.h" #include "client.h" +#include "common/recording.h" #include "common-ssh/sftp.h" #include "ssh.h" #include "terminal/terminal.h" @@ -88,6 +89,10 @@ int guac_ssh_client_free_handler(guac_client* client) { guac_common_ssh_destroy_session(ssh_client->sftp_session); } + /* Clean up recording, if in progress */ + if (ssh_client->recording != NULL) + guac_common_recording_free(ssh_client->recording); + /* Free interactive SSH session */ if (ssh_client->session != NULL) guac_common_ssh_destroy_session(ssh_client->session); diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 6575d9f3..d1b90413 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -193,7 +193,7 @@ void* ssh_client_thread(void* data) { /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { - guac_common_recording_create(client, + ssh_client->recording = guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); diff --git a/src/protocols/ssh/ssh.h b/src/protocols/ssh/ssh.h index 032e9209..0a89a2d1 100644 --- a/src/protocols/ssh/ssh.h +++ b/src/protocols/ssh/ssh.h @@ -22,6 +22,7 @@ #include "config.h" +#include "common/recording.h" #include "common-ssh/sftp.h" #include "common-ssh/ssh.h" #include "common-ssh/user.h" @@ -93,6 +94,12 @@ typedef struct guac_ssh_client { */ guac_terminal* term; + /** + * The in-progress session recording, or NULL if no recording is in + * progress. + */ + guac_common_recording* recording; + } guac_ssh_client ; /** diff --git a/src/protocols/telnet/client.c b/src/protocols/telnet/client.c index 2a53d263..3f64f1c2 100644 --- a/src/protocols/telnet/client.c +++ b/src/protocols/telnet/client.c @@ -19,6 +19,7 @@ #include "config.h" #include "client.h" +#include "common/recording.h" #include "settings.h" #include "telnet.h" #include "terminal/terminal.h" @@ -71,6 +72,10 @@ int guac_telnet_client_free_handler(guac_client* client) { if (telnet_client->socket_fd != -1) close(telnet_client->socket_fd); + /* Clean up recording, if in progress */ + if (telnet_client->recording != NULL) + guac_common_recording_free(telnet_client->recording); + /* Kill terminal */ guac_terminal_free(telnet_client->term); diff --git a/src/protocols/telnet/telnet.c b/src/protocols/telnet/telnet.c index 82f6dd4d..e135e3ed 100644 --- a/src/protocols/telnet/telnet.c +++ b/src/protocols/telnet/telnet.c @@ -467,7 +467,7 @@ void* guac_telnet_client_thread(void* data) { /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { - guac_common_recording_create(client, + telnet_client->recording = guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); diff --git a/src/protocols/telnet/telnet.h b/src/protocols/telnet/telnet.h index 8259507e..24ad4a8f 100644 --- a/src/protocols/telnet/telnet.h +++ b/src/protocols/telnet/telnet.h @@ -21,6 +21,7 @@ #define GUAC_TELNET_H #include "config.h" +#include "common/recording.h" #include "settings.h" #include "terminal/terminal.h" @@ -69,7 +70,13 @@ typedef struct guac_telnet_client { * The terminal which will render all output from the telnet client. */ guac_terminal* term; - + + /** + * The in-progress session recording, or NULL if no recording is in + * progress. + */ + guac_common_recording* recording; + } guac_telnet_client; /** diff --git a/src/protocols/vnc/client.c b/src/protocols/vnc/client.c index 00b90154..9cc85a18 100644 --- a/src/protocols/vnc/client.c +++ b/src/protocols/vnc/client.c @@ -19,6 +19,7 @@ #include "config.h" +#include "common/recording.h" #include "client.h" #include "user.h" #include "vnc.h" @@ -102,6 +103,10 @@ int guac_vnc_client_free_handler(guac_client* client) { guac_common_ssh_uninit(); #endif + /* Clean up recording, if in progress */ + if (vnc_client->recording != NULL) + guac_common_recording_free(vnc_client->recording); + /* Free clipboard */ if (vnc_client->clipboard != NULL) guac_common_clipboard_free(vnc_client->clipboard); diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index 38c7cd60..bc8b5e43 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -303,7 +303,7 @@ void* guac_vnc_client_thread(void* data) { /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { - guac_common_recording_create(client, + vnc_client->recording = guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); diff --git a/src/protocols/vnc/vnc.h b/src/protocols/vnc/vnc.h index 0edbcd47..ce2d20af 100644 --- a/src/protocols/vnc/vnc.h +++ b/src/protocols/vnc/vnc.h @@ -25,6 +25,7 @@ #include "common/clipboard.h" #include "common/display.h" #include "common/iconv.h" +#include "common/recording.h" #include "common/surface.h" #include "settings.h" @@ -110,6 +111,12 @@ typedef struct guac_vnc_client { guac_common_ssh_sftp_filesystem* sftp_filesystem; #endif + /** + * The in-progress session recording, or NULL if no recording is in + * progress. + */ + guac_common_recording* recording; + /** * Clipboard encoding-specific reader. */