From d7a604c8b29574be21002ad5c90ff27d76301824 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 9 Sep 2016 10:44:16 -0700 Subject: [PATCH 1/3] GUACAMOLE-175: Move common core of guacd into libguacd utility library. --- Makefile.am | 8 +++-- configure.ac | 5 +++ src/guacd/Makefile.am | 20 ++++------- src/libguacd/Makefile.am | 50 ++++++++++++++++++++++++++++ src/{guacd => libguacd}/log.c | 0 src/{guacd => libguacd}/log.h | 0 src/{guacd => libguacd}/socket-ssl.c | 0 src/{guacd => libguacd}/socket-ssl.h | 0 src/{guacd => libguacd}/user.c | 0 src/{guacd => libguacd}/user.h | 0 10 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 src/libguacd/Makefile.am rename src/{guacd => libguacd}/log.c (100%) rename src/{guacd => libguacd}/log.h (100%) rename src/{guacd => libguacd}/socket-ssl.c (100%) rename src/{guacd => libguacd}/socket-ssl.h (100%) rename src/{guacd => libguacd}/user.c (100%) rename src/{guacd => libguacd}/user.h (100%) diff --git a/Makefile.am b/Makefile.am index 54899e99..78f76e1d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ ACLOCAL_AMFLAGS = -I m4 # Subprojects DIST_SUBDIRS = \ src/libguac \ + src/libguacd \ src/common \ src/common-ssh \ src/terminal \ @@ -33,9 +34,10 @@ DIST_SUBDIRS = \ src/protocols/vnc \ tests -SUBDIRS = \ - src/libguac \ - src/common \ +SUBDIRS = \ + src/libguac \ + src/common \ + src/libguacd \ tests if ENABLE_COMMON_SSH diff --git a/configure.ac b/configure.ac index 4c433591..a763d6a2 100644 --- a/configure.ac +++ b/configure.ac @@ -119,6 +119,10 @@ AC_SUBST([LIBGUAC_INCLUDE], '-I$(top_srcdir)/src/libguac') AC_SUBST([COMMON_LTLIB], '$(top_builddir)/src/common/libguac_common.la') AC_SUBST([COMMON_INCLUDE], '-I$(top_srcdir)/src/common') +# Common utility library for guacd implementations +AC_SUBST([LIBGUACD_LTLIB], '$(top_builddir)/src/libguacd/libguacd.la') +AC_SUBST([LIBGUACD_INCLUDE], '-I$(top_srcdir)/src/libguacd') + # Common base SSH client AC_SUBST([COMMON_SSH_LTLIB], '$(top_builddir)/src/common-ssh/libguac_common_ssh.la') AC_SUBST([COMMON_SSH_INCLUDE], '-I$(top_srcdir)/src/common-ssh') @@ -1101,6 +1105,7 @@ AC_CONFIG_FILES([Makefile src/common-ssh/Makefile src/terminal/Makefile src/libguac/Makefile + src/libguacd/Makefile src/guacd/Makefile src/guacenc/Makefile src/protocols/rdp/Makefile diff --git a/src/guacd/Makefile.am b/src/guacd/Makefile.am index 51e5f879..e25a1011 100644 --- a/src/guacd/Makefile.am +++ b/src/guacd/Makefile.am @@ -30,11 +30,9 @@ noinst_HEADERS = \ conf-file.h \ conf-parse.h \ connection.h \ - log.h \ move-fd.h \ proc.h \ - proc-map.h \ - user.h + proc-map.h guacd_SOURCES = \ conf-args.c \ @@ -42,19 +40,19 @@ guacd_SOURCES = \ conf-parse.c \ connection.c \ daemon.c \ - log.c \ move-fd.c \ proc.c \ - proc-map.c \ - user.c + proc-map.c guacd_CFLAGS = \ -Werror -Wall -pedantic \ @COMMON_INCLUDE@ \ + @LIBGUACD_INCLUDE@ \ @LIBGUAC_INCLUDE@ -guacd_LDADD = \ - @COMMON_LTLIB@ \ +guacd_LDADD = \ + @COMMON_LTLIB@ \ + @LIBGUACD_LTLIB@ \ @LIBGUAC_LTLIB@ guacd_LDFLAGS = \ @@ -68,12 +66,6 @@ EXTRA_DIST = \ CLEANFILES = $(init_SCRIPTS) -# SSL support -if ENABLE_SSL -noinst_HEADERS += socket-ssl.h -guacd_SOURCES += socket-ssl.c -endif - # Init script if ENABLE_INIT initdir = @init_dir@ diff --git a/src/libguacd/Makefile.am b/src/libguacd/Makefile.am new file mode 100644 index 00000000..9e20ceca --- /dev/null +++ b/src/libguacd/Makefile.am @@ -0,0 +1,50 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +AUTOMAKE_OPTIONS = foreign + +noinst_LTLIBRARIES = libguacd.la + +noinst_HEADERS = \ + log.h \ + user.h + +libguacd_la_SOURCES = \ + log.c \ + user.c + +libguacd_la_CFLAGS = \ + -Werror -Wall -pedantic \ + @COMMON_INCLUDE@ \ + @LIBGUAC_INCLUDE@ + +libguacd_la_LIBADD = \ + @COMMON_LTLIB@ \ + @LIBGUAC_LTLIB@ + +libguacd_la_LDFLAGS = \ + @PTHREAD_LIBS@ \ + @SSL_LIBS@ + +# SSL support +if ENABLE_SSL +noinst_HEADERS += socket-ssl.h +libguacd_la_SOURCES += socket-ssl.c +endif + diff --git a/src/guacd/log.c b/src/libguacd/log.c similarity index 100% rename from src/guacd/log.c rename to src/libguacd/log.c diff --git a/src/guacd/log.h b/src/libguacd/log.h similarity index 100% rename from src/guacd/log.h rename to src/libguacd/log.h diff --git a/src/guacd/socket-ssl.c b/src/libguacd/socket-ssl.c similarity index 100% rename from src/guacd/socket-ssl.c rename to src/libguacd/socket-ssl.c diff --git a/src/guacd/socket-ssl.h b/src/libguacd/socket-ssl.h similarity index 100% rename from src/guacd/socket-ssl.h rename to src/libguacd/socket-ssl.h diff --git a/src/guacd/user.c b/src/libguacd/user.c similarity index 100% rename from src/guacd/user.c rename to src/libguacd/user.c diff --git a/src/guacd/user.h b/src/libguacd/user.h similarity index 100% rename from src/guacd/user.h rename to src/libguacd/user.h From 45adc6359729d5f10636dd25488080c04b0463ea Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 10 Sep 2016 19:29:57 -0700 Subject: [PATCH 2/3] GUACAMOLE-175: Split logging between guacd and libguacd. --- src/guacd/Makefile.am | 2 + src/guacd/connection.c | 4 +- src/guacd/daemon.c | 2 +- src/guacd/log.c | 143 +++++++++++++++++++++++ src/{libguacd => guacd}/log.h | 8 -- src/guacd/proc-map.c | 2 +- src/guacd/proc-map.h | 2 +- src/guacd/proc.c | 2 +- src/libguacd/Makefile.am | 8 +- src/libguacd/libguacd/log.h | 36 ++++++ src/libguacd/{ => libguacd}/socket-ssl.h | 0 src/libguacd/{ => libguacd}/user.h | 4 +- src/libguacd/log.c | 115 +----------------- src/libguacd/socket-ssl.c | 2 +- src/libguacd/user.c | 4 +- 15 files changed, 197 insertions(+), 137 deletions(-) create mode 100644 src/guacd/log.c rename src/{libguacd => guacd}/log.h (86%) create mode 100644 src/libguacd/libguacd/log.h rename src/libguacd/{ => libguacd}/socket-ssl.h (100%) rename src/libguacd/{ => libguacd}/user.h (98%) diff --git a/src/guacd/Makefile.am b/src/guacd/Makefile.am index e25a1011..b9433e8c 100644 --- a/src/guacd/Makefile.am +++ b/src/guacd/Makefile.am @@ -30,6 +30,7 @@ noinst_HEADERS = \ conf-file.h \ conf-parse.h \ connection.h \ + log.h \ move-fd.h \ proc.h \ proc-map.h @@ -40,6 +41,7 @@ guacd_SOURCES = \ conf-parse.c \ connection.c \ daemon.c \ + log.c \ move-fd.c \ proc.c \ proc-map.c diff --git a/src/guacd/connection.c b/src/guacd/connection.c index 3ad8eae4..87efc5a7 100644 --- a/src/guacd/connection.c +++ b/src/guacd/connection.c @@ -22,9 +22,9 @@ #include "connection.h" #include "log.h" #include "move-fd.h" +#include "libguacd/user.h" #include "proc.h" #include "proc-map.h" -#include "user.h" #include #include @@ -36,7 +36,7 @@ #ifdef ENABLE_SSL #include -#include "socket-ssl.h" +#include "libguacd/socket-ssl.h" #endif #include diff --git a/src/guacd/daemon.c b/src/guacd/daemon.c index 7d978aa4..840c68f8 100644 --- a/src/guacd/daemon.c +++ b/src/guacd/daemon.c @@ -22,9 +22,9 @@ #include "connection.h" #include "conf-args.h" #include "conf-file.h" +#include "libguacd/user.h" #include "log.h" #include "proc-map.h" -#include "user.h" #ifdef ENABLE_SSL #include diff --git a/src/guacd/log.c b/src/guacd/log.c new file mode 100644 index 00000000..121bb699 --- /dev/null +++ b/src/guacd/log.c @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" +#include "log.h" + +#include +#include + +#include +#include +#include +#include + +int guacd_log_level = GUAC_LOG_INFO; + +void vguacd_log(guac_client_log_level level, const char* format, + va_list args) { + + const char* priority_name; + int priority; + + char message[2048]; + + /* Don't bother if the log level is too high */ + if (level > guacd_log_level) + return; + + /* Copy log message into buffer */ + vsnprintf(message, sizeof(message), format, args); + + /* Convert log level to syslog priority */ + switch (level) { + + /* Error log level */ + case GUAC_LOG_ERROR: + priority = LOG_ERR; + priority_name = "ERROR"; + break; + + /* Warning log level */ + case GUAC_LOG_WARNING: + priority = LOG_WARNING; + priority_name = "WARNING"; + break; + + /* Informational log level */ + case GUAC_LOG_INFO: + priority = LOG_INFO; + priority_name = "INFO"; + break; + + /* Debug log level */ + case GUAC_LOG_DEBUG: + priority = LOG_DEBUG; + priority_name = "DEBUG"; + break; + + /* Any unknown/undefined log level */ + default: + priority = LOG_INFO; + priority_name = "UNKNOWN"; + break; + } + + /* Log to syslog */ + syslog(priority, "%s", message); + + /* Log to STDERR */ + fprintf(stderr, GUACD_LOG_NAME "[%i]: %s:\t%s\n", + getpid(), priority_name, message); + +} + +void guacd_log(guac_client_log_level level, const char* format, ...) { + va_list args; + va_start(args, format); + vguacd_log(level, format, args); + va_end(args); +} + +void guacd_client_log(guac_client* client, guac_client_log_level level, + const char* format, va_list args) { + vguacd_log(level, format, args); +} + +void guacd_log_guac_error(guac_client_log_level level, const char* message) { + + if (guac_error != GUAC_STATUS_SUCCESS) { + + /* If error message provided, include in log */ + if (guac_error_message != NULL) + guacd_log(level, "%s: %s", + message, + guac_error_message); + + /* Otherwise just log with standard status string */ + else + guacd_log(level, "%s: %s", + message, + guac_status_string(guac_error)); + + } + + /* Just log message if no status code */ + else + guacd_log(level, "%s", message); + +} + +void guacd_log_handshake_failure() { + + if (guac_error == GUAC_STATUS_CLOSED) + guacd_log(GUAC_LOG_INFO, + "Guacamole connection closed during handshake"); + else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR) + guacd_log(GUAC_LOG_ERROR, + "Guacamole protocol violation. Perhaps the version of " + "guacamole-client is incompatible with this version of " + "guacd?"); + else + guacd_log(GUAC_LOG_WARNING, + "Guacamole handshake failed: %s", + guac_status_string(guac_error)); + +} + diff --git a/src/libguacd/log.h b/src/guacd/log.h similarity index 86% rename from src/libguacd/log.h rename to src/guacd/log.h index 09fe152b..58a87522 100644 --- a/src/libguacd/log.h +++ b/src/guacd/log.h @@ -62,14 +62,6 @@ void guacd_client_log(guac_client* client, guac_client_log_level level, */ void guacd_log_guac_error(guac_client_log_level level, const char* message); -/** - * Prints an error message using the logging facilities of the given client, - * automatically including any information present in guac_error. This function - * accepts parameters identically to printf. - */ -void guacd_client_log_guac_error(guac_client* client, - guac_client_log_level level, const char* message); - /** * Logs a reasonable explanatory message regarding handshake failure based on * the current value of guac_error. diff --git a/src/guacd/proc-map.c b/src/guacd/proc-map.c index c09c06a3..bbe50b3a 100644 --- a/src/guacd/proc-map.c +++ b/src/guacd/proc-map.c @@ -19,9 +19,9 @@ #include "config.h" #include "common/list.h" +#include "libguacd/user.h" #include "proc.h" #include "proc-map.h" -#include "user.h" #include diff --git a/src/guacd/proc-map.h b/src/guacd/proc-map.h index 123449dd..73132441 100644 --- a/src/guacd/proc-map.h +++ b/src/guacd/proc-map.h @@ -23,8 +23,8 @@ #include "config.h" #include "common/list.h" +#include "libguacd/user.h" #include "proc.h" -#include "user.h" #include diff --git a/src/guacd/proc.c b/src/guacd/proc.c index 5bf1e5c8..f4d7f2a4 100644 --- a/src/guacd/proc.c +++ b/src/guacd/proc.c @@ -19,11 +19,11 @@ #include "config.h" +#include "libguacd/user.h" #include "log.h" #include "move-fd.h" #include "proc.h" #include "proc-map.h" -#include "user.h" #include #include diff --git a/src/libguacd/Makefile.am b/src/libguacd/Makefile.am index 9e20ceca..23cab3b9 100644 --- a/src/libguacd/Makefile.am +++ b/src/libguacd/Makefile.am @@ -21,9 +21,9 @@ AUTOMAKE_OPTIONS = foreign noinst_LTLIBRARIES = libguacd.la -noinst_HEADERS = \ - log.h \ - user.h +noinst_HEADERS = \ + libguacd/log.h \ + libguacd/user.h libguacd_la_SOURCES = \ log.c \ @@ -44,7 +44,7 @@ libguacd_la_LDFLAGS = \ # SSL support if ENABLE_SSL -noinst_HEADERS += socket-ssl.h +noinst_HEADERS += libguacd/socket-ssl.h libguacd_la_SOURCES += socket-ssl.c endif diff --git a/src/libguacd/libguacd/log.h b/src/libguacd/libguacd/log.h new file mode 100644 index 00000000..2e65f5a3 --- /dev/null +++ b/src/libguacd/libguacd/log.h @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef LIBGUACD_LOG_H +#define LIBGUACD_LOG_H + +#include "config.h" + +#include + +/** + * Prints an error message using the logging facilities of the given client, + * automatically including any information present in guac_error. This function + * accepts parameters identically to printf. + */ +void guacd_client_log_guac_error(guac_client* client, + guac_client_log_level level, const char* message); + +#endif + diff --git a/src/libguacd/socket-ssl.h b/src/libguacd/libguacd/socket-ssl.h similarity index 100% rename from src/libguacd/socket-ssl.h rename to src/libguacd/libguacd/socket-ssl.h diff --git a/src/libguacd/user.h b/src/libguacd/libguacd/user.h similarity index 98% rename from src/libguacd/user.h rename to src/libguacd/libguacd/user.h index 65eef704..a872f145 100644 --- a/src/libguacd/user.h +++ b/src/libguacd/libguacd/user.h @@ -18,8 +18,8 @@ */ -#ifndef _GUACD_USER_H -#define _GUACD_USER_H +#ifndef LIBGUACD_USER_H +#define LIBGUACD_USER_H #include "config.h" diff --git a/src/libguacd/log.c b/src/libguacd/log.c index 229d2f91..26b24e4c 100644 --- a/src/libguacd/log.c +++ b/src/libguacd/log.c @@ -18,7 +18,7 @@ */ #include "config.h" -#include "log.h" +#include "libguacd/log.h" #include #include @@ -28,102 +28,6 @@ #include #include -int guacd_log_level = GUAC_LOG_INFO; - -void vguacd_log(guac_client_log_level level, const char* format, - va_list args) { - - const char* priority_name; - int priority; - - char message[2048]; - - /* Don't bother if the log level is too high */ - if (level > guacd_log_level) - return; - - /* Copy log message into buffer */ - vsnprintf(message, sizeof(message), format, args); - - /* Convert log level to syslog priority */ - switch (level) { - - /* Error log level */ - case GUAC_LOG_ERROR: - priority = LOG_ERR; - priority_name = "ERROR"; - break; - - /* Warning log level */ - case GUAC_LOG_WARNING: - priority = LOG_WARNING; - priority_name = "WARNING"; - break; - - /* Informational log level */ - case GUAC_LOG_INFO: - priority = LOG_INFO; - priority_name = "INFO"; - break; - - /* Debug log level */ - case GUAC_LOG_DEBUG: - priority = LOG_DEBUG; - priority_name = "DEBUG"; - break; - - /* Any unknown/undefined log level */ - default: - priority = LOG_INFO; - priority_name = "UNKNOWN"; - break; - } - - /* Log to syslog */ - syslog(priority, "%s", message); - - /* Log to STDERR */ - fprintf(stderr, GUACD_LOG_NAME "[%i]: %s:\t%s\n", - getpid(), priority_name, message); - -} - -void guacd_log(guac_client_log_level level, const char* format, ...) { - va_list args; - va_start(args, format); - vguacd_log(level, format, args); - va_end(args); -} - -void guacd_client_log(guac_client* client, guac_client_log_level level, - const char* format, va_list args) { - vguacd_log(level, format, args); -} - -void guacd_log_guac_error(guac_client_log_level level, const char* message) { - - if (guac_error != GUAC_STATUS_SUCCESS) { - - /* If error message provided, include in log */ - if (guac_error_message != NULL) - guacd_log(level, "%s: %s", - message, - guac_error_message); - - /* Otherwise just log with standard status string */ - else - guacd_log(level, "%s: %s", - message, - guac_status_string(guac_error)); - - } - - /* Just log message if no status code */ - else - guacd_log(level, "%s", message); - -} - void guacd_client_log_guac_error(guac_client* client, guac_client_log_level level, const char* message) { @@ -149,20 +53,3 @@ void guacd_client_log_guac_error(guac_client* client, } -void guacd_log_handshake_failure() { - - if (guac_error == GUAC_STATUS_CLOSED) - guacd_log(GUAC_LOG_INFO, - "Guacamole connection closed during handshake"); - else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR) - guacd_log(GUAC_LOG_ERROR, - "Guacamole protocol violation. Perhaps the version of " - "guacamole-client is incompatible with this version of " - "guacd?"); - else - guacd_log(GUAC_LOG_WARNING, - "Guacamole handshake failed: %s", - guac_status_string(guac_error)); - -} - diff --git a/src/libguacd/socket-ssl.c b/src/libguacd/socket-ssl.c index 4f19442a..aa8664f3 100644 --- a/src/libguacd/socket-ssl.c +++ b/src/libguacd/socket-ssl.c @@ -19,7 +19,7 @@ #include "config.h" -#include "socket-ssl.h" +#include "libguacd/socket-ssl.h" #include #include diff --git a/src/libguacd/user.c b/src/libguacd/user.c index 0a371477..e9f73bef 100644 --- a/src/libguacd/user.c +++ b/src/libguacd/user.c @@ -19,8 +19,8 @@ #include "config.h" -#include "log.h" -#include "user.h" +#include "libguacd/log.h" +#include "libguacd/user.h" #include #include From 4c06d755f95bfacaa6f1b5f435b6a94ef2d8a608 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 11 Sep 2016 13:18:27 -0700 Subject: [PATCH 3/3] GUACAMOLE-175: Move guacd_handle_user() to libguacd. --- src/guacd/proc.c | 210 ----------------------------------- src/libguacd/libguacd/log.h | 6 + src/libguacd/libguacd/user.h | 15 +++ src/libguacd/log.c | 17 +++ src/libguacd/user.c | 208 ++++++++++++++++++++++++++++++++++ 5 files changed, 246 insertions(+), 210 deletions(-) diff --git a/src/guacd/proc.c b/src/guacd/proc.c index f4d7f2a4..74ba1465 100644 --- a/src/guacd/proc.c +++ b/src/guacd/proc.c @@ -40,216 +40,6 @@ #include #include -/** - * Copies the given array of mimetypes (strings) into a newly-allocated NULL- - * terminated array of strings. Both the array and the strings within the array - * are newly-allocated and must be later freed via guacd_free_mimetypes(). - * - * @param mimetypes - * The array of mimetypes to copy. - * - * @param count - * The number of mimetypes in the given array. - * - * @return - * A newly-allocated, NULL-terminated array containing newly-allocated - * copies of each of the mimetypes provided in the original mimetypes - * array. - */ -static char** guacd_copy_mimetypes(char** mimetypes, int count) { - - int i; - - /* Allocate sufficient space for NULL-terminated array of mimetypes */ - char** mimetypes_copy = malloc(sizeof(char*) * (count+1)); - - /* Copy each provided mimetype */ - for (i = 0; i < count; i++) - mimetypes_copy[i] = strdup(mimetypes[i]); - - /* Terminate with NULL */ - mimetypes_copy[count] = NULL; - - return mimetypes_copy; - -} - -/** - * Frees the given array of mimetypes, including the space allocated to each - * mimetype string within the array. The provided array of mimetypes MUST have - * been allocated with guacd_copy_mimetypes(). - * - * @param mimetypes - * The NULL-terminated array of mimetypes to free. This array MUST have - * been previously allocated with guacd_copy_mimetypes(). - */ -static void guacd_free_mimetypes(char** mimetypes) { - - char** current_mimetype = mimetypes; - - /* Free all strings within NULL-terminated mimetype array */ - while (*current_mimetype != NULL) { - free(*current_mimetype); - current_mimetype++; - } - - /* Free the array itself, now that its contents have been freed */ - free(mimetypes); - -} - -/** - * Handles the initial handshake of a user and all subsequent I/O. This - * function blocks until the user disconnects. - * - * @param user - * The user whose handshake and entire Guacamole protocol exchange should - * be handled. - * - * @return - * Zero if the user's Guacamole connection was successfully handled and - * the user has disconnected, or non-zero if an error prevented the user's - * connection from being handled properly. - */ -static int guacd_handle_user(guac_user* user) { - - guac_socket* socket = user->socket; - guac_client* client = user->client; - - /* Send args */ - if (guac_protocol_send_args(socket, client->args) - || guac_socket_flush(socket)) { - - /* Log error */ - guacd_log_handshake_failure(); - guacd_log_guac_error(GUAC_LOG_DEBUG, "Error sending \"args\" to new user"); - - return 1; - } - - guac_parser* parser = guac_parser_alloc(); - - /* Get optimal screen size */ - if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "size")) { - - /* Log error */ - guacd_log_handshake_failure(); - guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"size\""); - - guac_parser_free(parser); - return 1; - } - - /* Validate content of size instruction */ - if (parser->argc < 2) { - guacd_log(GUAC_LOG_ERROR, "Received \"size\" instruction lacked required arguments."); - guac_parser_free(parser); - return 1; - } - - /* Parse optimal screen dimensions from size instruction */ - user->info.optimal_width = atoi(parser->argv[0]); - user->info.optimal_height = atoi(parser->argv[1]); - - /* If DPI given, set the client resolution */ - if (parser->argc >= 3) - user->info.optimal_resolution = atoi(parser->argv[2]); - - /* Otherwise, use a safe default for rough backwards compatibility */ - else - user->info.optimal_resolution = 96; - - /* Get supported audio formats */ - if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "audio")) { - - /* Log error */ - guacd_log_handshake_failure(); - guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"audio\""); - - guac_parser_free(parser); - return 1; - } - - /* Store audio mimetypes */ - char** audio_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc); - user->info.audio_mimetypes = (const char**) audio_mimetypes; - - /* Get supported video formats */ - if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "video")) { - - /* Log error */ - guacd_log_handshake_failure(); - guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"video\""); - - guac_parser_free(parser); - return 1; - } - - /* Store video mimetypes */ - char** video_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc); - user->info.video_mimetypes = (const char**) video_mimetypes; - - /* Get supported image formats */ - if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "image")) { - - /* Log error */ - guacd_log_handshake_failure(); - guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"image\""); - - guac_parser_free(parser); - return 1; - } - - /* Store image mimetypes */ - char** image_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc); - user->info.image_mimetypes = (const char**) image_mimetypes; - - /* Get args from connect instruction */ - if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "connect")) { - - /* Log error */ - guacd_log_handshake_failure(); - guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"connect\""); - - guac_parser_free(parser); - return 1; - } - - /* Acknowledge connection availability */ - guac_protocol_send_ready(socket, client->connection_id); - guac_socket_flush(socket); - - /* Attempt join */ - if (guac_client_add_user(client, user, parser->argc, parser->argv)) - guacd_log(GUAC_LOG_ERROR, "User \"%s\" could NOT join connection \"%s\"", user->user_id, client->connection_id); - - /* Begin user connection if join successful */ - else { - - guacd_log(GUAC_LOG_INFO, "User \"%s\" joined connection \"%s\" (%i users now present)", - user->user_id, client->connection_id, client->connected_users); - - /* Handle user I/O, wait for connection to terminate */ - guacd_user_start(parser, user); - - /* Remove/free user */ - guac_client_remove_user(client, user); - guacd_log(GUAC_LOG_INFO, "User \"%s\" disconnected (%i users remain)", user->user_id, client->connected_users); - - } - - /* Free mimetype lists */ - guacd_free_mimetypes(audio_mimetypes); - guacd_free_mimetypes(video_mimetypes); - guacd_free_mimetypes(image_mimetypes); - - guac_parser_free(parser); - - /* Successful disconnect */ - return 0; - -} - /** * Parameters for the user thread. */ diff --git a/src/libguacd/libguacd/log.h b/src/libguacd/libguacd/log.h index 2e65f5a3..76509e32 100644 --- a/src/libguacd/libguacd/log.h +++ b/src/libguacd/libguacd/log.h @@ -32,5 +32,11 @@ void guacd_client_log_guac_error(guac_client* client, guac_client_log_level level, const char* message); +/** + * Logs a reasonable explanatory message regarding handshake failure based on + * the current value of guac_error. + */ +void guacd_client_log_handshake_failure(guac_client* client); + #endif diff --git a/src/libguacd/libguacd/user.h b/src/libguacd/libguacd/user.h index a872f145..cb2a8b3e 100644 --- a/src/libguacd/libguacd/user.h +++ b/src/libguacd/libguacd/user.h @@ -80,6 +80,21 @@ typedef struct guacd_user_input_thread_params { */ int guacd_user_start(guac_parser* parser, guac_user* user); +/** + * Handles the initial handshake of a user and all subsequent I/O. This + * function blocks until the user disconnects. + * + * @param user + * The user whose handshake and entire Guacamole protocol exchange should + * be handled. + * + * @return + * Zero if the user's Guacamole connection was successfully handled and + * the user has disconnected, or non-zero if an error prevented the user's + * connection from being handled properly. + */ +int guacd_handle_user(guac_user* user); + /** * The thread which handles all user input, calling event handlers for received * instructions. diff --git a/src/libguacd/log.c b/src/libguacd/log.c index 26b24e4c..e746373b 100644 --- a/src/libguacd/log.c +++ b/src/libguacd/log.c @@ -53,3 +53,20 @@ void guacd_client_log_guac_error(guac_client* client, } +void guacd_client_log_handshake_failure(guac_client* client) { + + if (guac_error == GUAC_STATUS_CLOSED) + guac_client_log(client, GUAC_LOG_INFO, + "Guacamole connection closed during handshake"); + else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR) + guac_client_log(client, GUAC_LOG_ERROR, + "Guacamole protocol violation. Perhaps the version of " + "guacamole-client is incompatible with this version of " + "guacd?"); + else + guac_client_log(client, GUAC_LOG_WARNING, + "Guacamole handshake failed: %s", + guac_status_string(guac_error)); + +} + diff --git a/src/libguacd/user.c b/src/libguacd/user.c index e9f73bef..db39fce7 100644 --- a/src/libguacd/user.c +++ b/src/libguacd/user.c @@ -31,6 +31,65 @@ #include #include +#include + +/** + * Copies the given array of mimetypes (strings) into a newly-allocated NULL- + * terminated array of strings. Both the array and the strings within the array + * are newly-allocated and must be later freed via guacd_free_mimetypes(). + * + * @param mimetypes + * The array of mimetypes to copy. + * + * @param count + * The number of mimetypes in the given array. + * + * @return + * A newly-allocated, NULL-terminated array containing newly-allocated + * copies of each of the mimetypes provided in the original mimetypes + * array. + */ +static char** guacd_copy_mimetypes(char** mimetypes, int count) { + + int i; + + /* Allocate sufficient space for NULL-terminated array of mimetypes */ + char** mimetypes_copy = malloc(sizeof(char*) * (count+1)); + + /* Copy each provided mimetype */ + for (i = 0; i < count; i++) + mimetypes_copy[i] = strdup(mimetypes[i]); + + /* Terminate with NULL */ + mimetypes_copy[count] = NULL; + + return mimetypes_copy; + +} + +/** + * Frees the given array of mimetypes, including the space allocated to each + * mimetype string within the array. The provided array of mimetypes MUST have + * been allocated with guacd_copy_mimetypes(). + * + * @param mimetypes + * The NULL-terminated array of mimetypes to free. This array MUST have + * been previously allocated with guacd_copy_mimetypes(). + */ +static void guacd_free_mimetypes(char** mimetypes) { + + char** current_mimetype = mimetypes; + + /* Free all strings within NULL-terminated mimetype array */ + while (*current_mimetype != NULL) { + free(*current_mimetype); + current_mimetype++; + } + + /* Free the array itself, now that its contents have been freed */ + free(mimetypes); + +} void* guacd_user_input_thread(void* data) { @@ -111,3 +170,152 @@ int guacd_user_start(guac_parser* parser, guac_user* user) { } +int guacd_handle_user(guac_user* user) { + + guac_socket* socket = user->socket; + guac_client* client = user->client; + + /* Send args */ + if (guac_protocol_send_args(socket, client->args) + || guac_socket_flush(socket)) { + + /* Log error */ + guacd_client_log_handshake_failure(client); + guacd_client_log_guac_error(client, GUAC_LOG_DEBUG, + "Error sending \"args\" to new user"); + + return 1; + } + + guac_parser* parser = guac_parser_alloc(); + + /* Get optimal screen size */ + if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "size")) { + + /* Log error */ + guacd_client_log_handshake_failure(client); + guacd_client_log_guac_error(client, GUAC_LOG_DEBUG, + "Error reading \"size\""); + + guac_parser_free(parser); + return 1; + } + + /* Validate content of size instruction */ + if (parser->argc < 2) { + guac_client_log(client, GUAC_LOG_ERROR, "Received \"size\" " + "instruction lacked required arguments."); + guac_parser_free(parser); + return 1; + } + + /* Parse optimal screen dimensions from size instruction */ + user->info.optimal_width = atoi(parser->argv[0]); + user->info.optimal_height = atoi(parser->argv[1]); + + /* If DPI given, set the client resolution */ + if (parser->argc >= 3) + user->info.optimal_resolution = atoi(parser->argv[2]); + + /* Otherwise, use a safe default for rough backwards compatibility */ + else + user->info.optimal_resolution = 96; + + /* Get supported audio formats */ + if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "audio")) { + + /* Log error */ + guacd_client_log_handshake_failure(client); + guacd_client_log_guac_error(client, GUAC_LOG_DEBUG, + "Error reading \"audio\""); + + guac_parser_free(parser); + return 1; + } + + /* Store audio mimetypes */ + char** audio_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc); + user->info.audio_mimetypes = (const char**) audio_mimetypes; + + /* Get supported video formats */ + if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "video")) { + + /* Log error */ + guacd_client_log_handshake_failure(client); + guacd_client_log_guac_error(client, GUAC_LOG_DEBUG, + "Error reading \"video\""); + + guac_parser_free(parser); + return 1; + } + + /* Store video mimetypes */ + char** video_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc); + user->info.video_mimetypes = (const char**) video_mimetypes; + + /* Get supported image formats */ + if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "image")) { + + /* Log error */ + guacd_client_log_handshake_failure(client); + guacd_client_log_guac_error(client, GUAC_LOG_DEBUG, + "Error reading \"image\""); + + guac_parser_free(parser); + return 1; + } + + /* Store image mimetypes */ + char** image_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc); + user->info.image_mimetypes = (const char**) image_mimetypes; + + /* Get args from connect instruction */ + if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "connect")) { + + /* Log error */ + guacd_client_log_handshake_failure(client); + guacd_client_log_guac_error(client, GUAC_LOG_DEBUG, + "Error reading \"connect\""); + + guac_parser_free(parser); + return 1; + } + + /* Acknowledge connection availability */ + guac_protocol_send_ready(socket, client->connection_id); + guac_socket_flush(socket); + + /* Attempt join */ + if (guac_client_add_user(client, user, parser->argc, parser->argv)) + guac_client_log(client, GUAC_LOG_ERROR, "User \"%s\" could NOT " + "join connection \"%s\"", user->user_id, client->connection_id); + + /* Begin user connection if join successful */ + else { + + guac_client_log(client, GUAC_LOG_INFO, "User \"%s\" joined connection " + "\"%s\" (%i users now present)", user->user_id, + client->connection_id, client->connected_users); + + /* Handle user I/O, wait for connection to terminate */ + guacd_user_start(parser, user); + + /* Remove/free user */ + guac_client_remove_user(client, user); + guac_client_log(client, GUAC_LOG_INFO, "User \"%s\" disconnected (%i " + "users remain)", user->user_id, client->connected_users); + + } + + /* Free mimetype lists */ + guacd_free_mimetypes(audio_mimetypes); + guacd_free_mimetypes(video_mimetypes); + guacd_free_mimetypes(image_mimetypes); + + guac_parser_free(parser); + + /* Successful disconnect */ + return 0; + +} +