From e4cbb8b4e86ce57c0011fff7041f05b0ca5b0382 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 23 Nov 2011 00:01:27 -0800 Subject: [PATCH] Moved daemon functions from libguac --- guacd/Makefile.am | 5 +- guacd/include/client.h | 91 +++++++++++++++++++++ guacd/src/client.c | 179 +++++++++++++++++++++++++++++++++++++++++ guacd/src/daemon.c | 1 + 4 files changed, 274 insertions(+), 2 deletions(-) create mode 100644 guacd/include/client.h create mode 100644 guacd/src/client.c diff --git a/guacd/Makefile.am b/guacd/Makefile.am index ed7903bc..cd5989b2 100644 --- a/guacd/Makefile.am +++ b/guacd/Makefile.am @@ -37,12 +37,13 @@ AUTOMAKE_OPTIONS = foreign initdir = @init_dir@ -AM_CFLAGS = -Werror -Wall -pedantic +AM_CFLAGS = -Werror -Wall -pedantic -Iinclude sbin_PROGRAMS = guacd init_SCRIPTS = init.d/guacd -guacd_SOURCES = src/daemon.c +noinst_HEADERS = include/client.h +guacd_SOURCES = src/daemon.c src/client.c EXTRA_DIST = init.d/guacd.in CLEANFILES = $(init_SCRIPTS) diff --git a/guacd/include/client.h b/guacd/include/client.h new file mode 100644 index 00000000..495940a6 --- /dev/null +++ b/guacd/include/client.h @@ -0,0 +1,91 @@ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is guacd. + * + * The Initial Developer of the Original Code is + * Michael Jumper. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#ifndef _GUACD_CLIENT_H +#define _GUACD_CLIENT_H + +/** + * Provides functions and structures required for defining (and handling) a proxy client. + * + * @file client.h + */ + +/** + * The time to allow between sync responses in milliseconds. If a sync + * instruction is sent to the client and no response is received within this + * timeframe, server messages will not be handled until a sync instruction is + * received from the client. + */ +#define GUAC_SYNC_THRESHOLD 500 + +/** + * The time to allow between server sync messages in milliseconds. A sync + * message from the server will be sent every GUAC_SYNC_FREQUENCY milliseconds. + * As this will induce a response from a client that is not malfunctioning, + * this is used to detect when a client has died. This must be set to a + * reasonable value to avoid clients being disconnected unnecessarily due + * to timeout. + */ +#define GUAC_SYNC_FREQUENCY 5000 + +/** + * The amount of time to wait after handling server messages. If a client + * plugin has a message handler, and sends instructions when server messages + * are being handled, there will be a pause of this many milliseconds before + * the next call to the message handler. + */ +#define GUAC_SERVER_MESSAGE_HANDLE_FREQUENCY 50 + +/** + * The number of milliseconds to wait for messages in any phase before + * timing out and closing the connection with an error. + */ +#define GUAC_TIMEOUT 15000 + +/** + * The number of microseconds to wait for messages in any phase before + * timing out and closing the conncetion with an error. This is always + * equal to GUAC_TIMEOUT * 1000. + */ +#define GUAC_USEC_TIMEOUT (GUAC_TIMEOUT*1000) + + +void guac_client_stop(guac_client* client); +int guac_start_client(guac_client* client); + +#endif diff --git a/guacd/src/client.c b/guacd/src/client.c new file mode 100644 index 00000000..d7d1c979 --- /dev/null +++ b/guacd/src/client.c @@ -0,0 +1,179 @@ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is guacd. + * + * The Initial Developer of the Original Code is + * Michael Jumper. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include + +#include +#include +#include +#include + +#include "client.h" + +void guac_client_stop(guac_client* client) { + client->state = STOPPING; +} + +void* __guac_client_output_thread(void* data) { + + guac_client* client = (guac_client*) data; + GUACIO* io = client->io; + + guac_timestamp last_ping_timestamp = guac_current_timestamp(); + + /* Guacamole client output loop */ + while (client->state == RUNNING) { + + /* Occasionally ping client with repeat of last sync */ + guac_timestamp timestamp = guac_current_timestamp(); + if (timestamp - last_ping_timestamp > GUAC_SYNC_FREQUENCY) { + last_ping_timestamp = timestamp; + if ( + guac_send_sync(io, client->last_sent_timestamp) + || guac_flush(io) + ) { + guac_client_stop(client); + return NULL; + } + } + + /* Handle server messages */ + if (client->handle_messages) { + + /* Get previous GUACIO state */ + int last_total_written = io->total_written; + + /* Only handle messages if synced within threshold */ + if (client->last_sent_timestamp - client->last_received_timestamp + < GUAC_SYNC_THRESHOLD) { + + int retval = client->handle_messages(client); + if (retval) { + guac_log_error("Error handling server messages"); + guac_client_stop(client); + return NULL; + } + + /* If data was written during message handling */ + if (io->total_written != last_total_written) { + + /* Sleep as necessary */ + guac_sleep(GUAC_SERVER_MESSAGE_HANDLE_FREQUENCY); + + /* Send sync instruction */ + client->last_sent_timestamp = guac_current_timestamp(); + if (guac_send_sync(io, client->last_sent_timestamp)) { + guac_client_stop(client); + return NULL; + } + + } + + if (guac_flush(io)) { + guac_client_stop(client); + return NULL; + } + + } + + /* If sync threshold exceeded, don't spin waiting for resync */ + else + guac_sleep(GUAC_SERVER_MESSAGE_HANDLE_FREQUENCY); + + } + + /* If no message handler, just sleep until next sync ping */ + else + guac_sleep(GUAC_SYNC_FREQUENCY); + + } /* End of output loop */ + + guac_client_stop(client); + return NULL; + +} + +void* __guac_client_input_thread(void* data) { + + guac_client* client = (guac_client*) data; + GUACIO* io = client->io; + + guac_instruction instruction; + + /* Guacamole client input loop */ + while (client->state == RUNNING && guac_read_instruction(io, &instruction) > 0) { + + /* Call handler, stop on error */ + if (guac_client_handle_instruction(client, &instruction) < 0) { + guac_free_instruction_data(&instruction); + break; + } + + /* Free allocate instruction data */ + guac_free_instruction_data(&instruction); + + } + + guac_client_stop(client); + return NULL; + +} + +int guac_start_client(guac_client* client) { + + guac_thread input_thread, output_thread; + + if (guac_thread_create(&output_thread, __guac_client_output_thread, (void*) client)) { + return -1; + } + + if (guac_thread_create(&input_thread, __guac_client_input_thread, (void*) client)) { + guac_client_stop(client); + guac_thread_join(output_thread); + return -1; + } + + /* Wait for I/O threads */ + guac_thread_join(input_thread); + guac_thread_join(output_thread); + + /* Done */ + return 0; + +} + + diff --git a/guacd/src/daemon.c b/guacd/src/daemon.c index 261f51e0..75117163 100644 --- a/guacd/src/daemon.c +++ b/guacd/src/daemon.c @@ -51,6 +51,7 @@ #include #include +#include "client.h" typedef struct client_thread_data {