You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2017/01/25 00:39:40 UTC

[1/4] incubator-guacamole-server git commit: GUACAMOLE-175: Move common core of guacd into libguacd utility library.

Repository: incubator-guacamole-server
Updated Branches:
  refs/heads/master 396eaa21f -> 5d2c9676f


GUACAMOLE-175: Move common core of guacd into libguacd utility library.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/d7a604c8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/d7a604c8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/d7a604c8

Branch: refs/heads/master
Commit: d7a604c8b29574be21002ad5c90ff27d76301824
Parents: a1886f5
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Sep 9 10:44:16 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Jan 24 15:44:51 2017 -0800

----------------------------------------------------------------------
 Makefile.am               |   8 +-
 configure.ac              |   5 ++
 src/guacd/Makefile.am     |  20 ++---
 src/guacd/log.c           | 168 -----------------------------------------
 src/guacd/log.h           |  80 --------------------
 src/guacd/socket-ssl.c    | 153 -------------------------------------
 src/guacd/socket-ssl.h    |  71 -----------------
 src/guacd/user.c          | 113 ---------------------------
 src/guacd/user.h          |  98 ------------------------
 src/libguacd/Makefile.am  |  50 ++++++++++++
 src/libguacd/log.c        | 168 +++++++++++++++++++++++++++++++++++++++++
 src/libguacd/log.h        |  80 ++++++++++++++++++++
 src/libguacd/socket-ssl.c | 153 +++++++++++++++++++++++++++++++++++++
 src/libguacd/socket-ssl.h |  71 +++++++++++++++++
 src/libguacd/user.c       | 113 +++++++++++++++++++++++++++
 src/libguacd/user.h       |  98 ++++++++++++++++++++++++
 16 files changed, 749 insertions(+), 700 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index 54899e9..78f76e1 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

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 4c43359..a763d6a 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

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/Makefile.am
----------------------------------------------------------------------
diff --git a/src/guacd/Makefile.am b/src/guacd/Makefile.am
index 51e5f87..e25a101 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@

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/log.c
----------------------------------------------------------------------
diff --git a/src/guacd/log.c b/src/guacd/log.c
deleted file mode 100644
index 229d2f9..0000000
--- a/src/guacd/log.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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 <guacamole/client.h>
-#include <guacamole/error.h>
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <unistd.h>
-
-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) {
-
-    if (guac_error != GUAC_STATUS_SUCCESS) {
-
-        /* If error message provided, include in log */
-        if (guac_error_message != NULL)
-            guac_client_log(client, level, "%s: %s",
-                    message,
-                    guac_error_message);
-
-        /* Otherwise just log with standard status string */
-        else
-            guac_client_log(client, level, "%s: %s",
-                    message,
-                    guac_status_string(guac_error));
-
-    }
-
-    /* Just log message if no status code */
-    else
-        guac_client_log(client, 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));
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/log.h
----------------------------------------------------------------------
diff --git a/src/guacd/log.h b/src/guacd/log.h
deleted file mode 100644
index 09fe152..0000000
--- a/src/guacd/log.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 __GUACD_LOG_H
-#define __GUACD_LOG_H
-
-#include "config.h"
-
-#include <guacamole/client.h>
-
-/**
- * The maximum level at which to log messages. All other messages will be
- * dropped.
- */
-extern int guacd_log_level;
-
-/**
- * The string to prepend to all log messages.
- */
-#define GUACD_LOG_NAME "guacd"
-
-/**
- * Writes a message to guacd's logs. This function takes a format and va_list,
- * similar to vprintf.
- */
-void vguacd_log(guac_client_log_level level, const char* format, va_list args);
-
-/**
- * Writes a message to guacd's logs. This function accepts parameters
- * identically to printf.
- */
-void guacd_log(guac_client_log_level level, const char* format, ...);
-
-/**
- * Writes a message using the logging facilities of the given client. This
- * function accepts parameters identically to printf.
- */
-void guacd_client_log(guac_client* client, guac_client_log_level level,
-        const char* format, va_list args);
-
-/**
- * Prints an error message to guacd's logs, automatically including any
- * information present in guac_error. This function accepts parameters
- * identically to printf.
- */
-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.
- */
-void guacd_log_handshake_failure();
-
-#endif
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/socket-ssl.c
----------------------------------------------------------------------
diff --git a/src/guacd/socket-ssl.c b/src/guacd/socket-ssl.c
deleted file mode 100644
index 4f19442..0000000
--- a/src/guacd/socket-ssl.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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 "socket-ssl.h"
-
-#include <poll.h>
-#include <stdlib.h>
-
-#include <guacamole/error.h>
-#include <guacamole/socket.h>
-#include <openssl/ssl.h>
-
-static ssize_t __guac_socket_ssl_read_handler(guac_socket* socket,
-        void* buf, size_t count) {
-
-    /* Read from socket */
-    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
-    int retval;
-
-    retval = SSL_read(data->ssl, buf, count);
-
-    /* Record errors in guac_error */
-    if (retval <= 0) {
-        guac_error = GUAC_STATUS_SEE_ERRNO;
-        guac_error_message = "Error reading data from secure socket";
-    }
-
-    return retval;
-
-}
-
-static ssize_t __guac_socket_ssl_write_handler(guac_socket* socket,
-        const void* buf, size_t count) {
-
-    /* Write data to socket */
-    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
-    int retval;
-
-    retval = SSL_write(data->ssl, buf, count);
-
-    /* Record errors in guac_error */
-    if (retval <= 0) {
-        guac_error = GUAC_STATUS_SEE_ERRNO;
-        guac_error_message = "Error writing data to secure socket";
-    }
-
-    return retval;
-
-}
-
-static int __guac_socket_ssl_select_handler(guac_socket* socket, int usec_timeout) {
-
-    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
-
-    int retval;
-
-    /* Initialize with single underlying file descriptor */
-    struct pollfd fds[1] = {{
-        .fd      = data->fd,
-        .events  = POLLIN,
-        .revents = 0,
-    }};
-
-    /* No timeout if usec_timeout is negative */
-    if (usec_timeout < 0)
-        retval = poll(fds, 1, -1);
-
-    /* Handle timeout if specified, rounding up to poll()'s granularity */
-    else
-        retval = poll(fds, 1, (usec_timeout + 999) / 1000);
-
-    /* Properly set guac_error */
-    if (retval <  0) {
-        guac_error = GUAC_STATUS_SEE_ERRNO;
-        guac_error_message = "Error while waiting for data on secure socket";
-    }
-
-    if (retval == 0) {
-        guac_error = GUAC_STATUS_TIMEOUT;
-        guac_error_message = "Timeout while waiting for data on secure socket";
-    }
-
-    return retval;
-
-}
-
-static int __guac_socket_ssl_free_handler(guac_socket* socket) {
-
-    /* Shutdown SSL */
-    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
-    SSL_shutdown(data->ssl);
-
-    /* Close file descriptor */
-    close(data->fd);
-
-    free(data);
-    return 0;
-}
-
-guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) {
-
-    /* Allocate socket and associated data */
-    guac_socket* socket = guac_socket_alloc();
-    guac_socket_ssl_data* data = malloc(sizeof(guac_socket_ssl_data));
-
-    /* Init SSL */
-    data->context = context;
-    data->ssl = SSL_new(context);
-    SSL_set_fd(data->ssl, fd);
-
-    /* Accept SSL connection, handle errors */
-    if (SSL_accept(data->ssl) <= 0) {
-
-        guac_error = GUAC_STATUS_INTERNAL_ERROR;
-        guac_error_message = "SSL accept failed";
-
-        free(data);
-        guac_socket_free(socket);
-        return NULL;
-    }
-
-    /* Store file descriptor as socket data */
-    data->fd = fd;
-    socket->data = data;
-
-    /* Set read/write handlers */
-    socket->read_handler   = __guac_socket_ssl_read_handler;
-    socket->write_handler  = __guac_socket_ssl_write_handler;
-    socket->select_handler = __guac_socket_ssl_select_handler;
-    socket->free_handler   = __guac_socket_ssl_free_handler;
-
-    return socket;
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/socket-ssl.h
----------------------------------------------------------------------
diff --git a/src/guacd/socket-ssl.h b/src/guacd/socket-ssl.h
deleted file mode 100644
index e1a341e..0000000
--- a/src/guacd/socket-ssl.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 __GUACD_SOCKET_SSL_H
-#define __GUACD_SOCKET_SSL_H
-
-#include "config.h"
-
-#include <guacamole/socket.h>
-#include <openssl/ssl.h>
-
-/**
- * SSL socket-specific data.
- */
-typedef struct guac_socket_ssl_data {
-
-    /**
-     * The file descriptor that SSL communication will take place
-     * over.
-     */
-    int fd;
-
-    /**
-     * The current SSL context.
-     */
-    SSL_CTX* context;
-
-    /**
-     * The SSL connection, created automatically via
-     * guac_socket_open_secure().
-     */
-    SSL* ssl;
-
-} guac_socket_ssl_data;
-
-/**
- * Creates a new guac_socket which will use SSL for all communication. Freeing
- * this guac_socket will automatically close the associated file descriptor.
- *
- * @param context
- *     The SSL_CTX structure describing the desired SSL configuration.
- *
- * @param fd
- *     The file descriptor to use for the SSL connection underlying the
- *     created guac_socket.
- *
- * @return
- *     A newly-allocated guac_socket which will transparently use SSL for
- *     all communication.
- */
-guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd);
-
-#endif
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/user.c
----------------------------------------------------------------------
diff --git a/src/guacd/user.c b/src/guacd/user.c
deleted file mode 100644
index 0a37147..0000000
--- a/src/guacd/user.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 "user.h"
-
-#include <guacamole/client.h>
-#include <guacamole/error.h>
-#include <guacamole/parser.h>
-#include <guacamole/protocol.h>
-#include <guacamole/socket.h>
-#include <guacamole/user.h>
-
-#include <pthread.h>
-#include <stdlib.h>
-
-void* guacd_user_input_thread(void* data) {
-
-    guacd_user_input_thread_params* params = (guacd_user_input_thread_params*) data;
-    guac_user* user = params->user;
-    guac_parser* parser = params->parser;
-    guac_client* client = user->client;
-    guac_socket* socket = user->socket;
-
-    /* Guacamole user input loop */
-    while (client->state == GUAC_CLIENT_RUNNING && user->active) {
-
-        /* Read instruction, stop on error */
-        if (guac_parser_read(parser, socket, GUACD_USEC_TIMEOUT)) {
-
-            if (guac_error == GUAC_STATUS_TIMEOUT)
-                guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding.");
-
-            else {
-                if (guac_error != GUAC_STATUS_CLOSED)
-                    guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
-                            "Guacamole connection failure");
-                guac_user_stop(user);
-            }
-
-            return NULL;
-        }
-
-        /* Reset guac_error and guac_error_message (user/client handlers are not
-         * guaranteed to set these) */
-        guac_error = GUAC_STATUS_SUCCESS;
-        guac_error_message = NULL;
-
-        /* Call handler, stop on error */
-        if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) {
-
-            /* Log error */
-            guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
-                    "User connection aborted");
-
-            /* Log handler details */
-            guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode);
-
-            guac_user_stop(user);
-            return NULL;
-        }
-
-    }
-
-    return NULL;
-
-}
-
-int guacd_user_start(guac_parser* parser, guac_user* user) {
-
-    guacd_user_input_thread_params params = {
-        .parser = parser,
-        .user = user
-    };
-
-    pthread_t input_thread;
-
-    if (pthread_create(&input_thread, NULL, guacd_user_input_thread, (void*) &params)) {
-        guac_user_log(user, GUAC_LOG_ERROR, "Unable to start input thread");
-        guac_user_stop(user);
-        return -1;
-    }
-
-    /* Wait for I/O threads */
-    pthread_join(input_thread, NULL);
-
-    /* Explicitly signal disconnect */
-    guac_protocol_send_disconnect(user->socket);
-    guac_socket_flush(user->socket);
-
-    /* Done */
-    return 0;
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/guacd/user.h
----------------------------------------------------------------------
diff --git a/src/guacd/user.h b/src/guacd/user.h
deleted file mode 100644
index 65eef70..0000000
--- a/src/guacd/user.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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 _GUACD_USER_H
-#define _GUACD_USER_H
-
-#include "config.h"
-
-#include <guacamole/parser.h>
-#include <guacamole/socket.h>
-#include <guacamole/user.h>
-
-/**
- * The number of milliseconds to wait for messages in any phase before
- * timing out and closing the connection with an error.
- */
-#define GUACD_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 GUACD_TIMEOUT * 1000.
- */
-#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000)
-
-/**
- * The maximum number of concurrent connections to a single instance
- * of guacd.
- */
-#define GUACD_CLIENT_MAX_CONNECTIONS 65536
-
-/**
- * Parameters required by the user input thread.
- */
-typedef struct guacd_user_input_thread_params {
-
-    /**
-     * The parser which will be used throughout the user's session.
-     */
-    guac_parser* parser;
-
-    /**
-     * A reference to the connected user.
-     */
-    guac_user* user;
-
-} guacd_user_input_thread_params;
-
-/**
- * Starts the input/output threads of a new user. This function will block
- * until the user disconnects. If an error prevents the input/output threads
- * from starting, guac_user_stop() will be invoked on the given user.
- *
- * @param parser
- *     The guac_parser to use to handle all input from the given user.
- *
- * @param user
- *     The user whose associated I/O transfer threads should be started.
- *
- * @return
- *     Zero if the I/O threads started successfully and user has disconnected,
- *     or non-zero if the I/O threads could not be started.
- */
-int guacd_user_start(guac_parser* parser, guac_user* user);
-
-/**
- * The thread which handles all user input, calling event handlers for received
- * instructions.
- *
- * @param data
- *     A pointer to a guacd_user_input_thread_params structure describing the
- *     user whose input is being handled and the guac_parser with which to
- *     handle it.
- *
- * @return
- *     Always NULL.
- */
-void* guacd_user_input_thread(void* data);
-
-#endif
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/Makefile.am
----------------------------------------------------------------------
diff --git a/src/libguacd/Makefile.am b/src/libguacd/Makefile.am
new file mode 100644
index 0000000..9e20cec
--- /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
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/log.c
----------------------------------------------------------------------
diff --git a/src/libguacd/log.c b/src/libguacd/log.c
new file mode 100644
index 0000000..229d2f9
--- /dev/null
+++ b/src/libguacd/log.c
@@ -0,0 +1,168 @@
+/*
+ * 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 <guacamole/client.h>
+#include <guacamole/error.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+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) {
+
+    if (guac_error != GUAC_STATUS_SUCCESS) {
+
+        /* If error message provided, include in log */
+        if (guac_error_message != NULL)
+            guac_client_log(client, level, "%s: %s",
+                    message,
+                    guac_error_message);
+
+        /* Otherwise just log with standard status string */
+        else
+            guac_client_log(client, level, "%s: %s",
+                    message,
+                    guac_status_string(guac_error));
+
+    }
+
+    /* Just log message if no status code */
+    else
+        guac_client_log(client, 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));
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/log.h
----------------------------------------------------------------------
diff --git a/src/libguacd/log.h b/src/libguacd/log.h
new file mode 100644
index 0000000..09fe152
--- /dev/null
+++ b/src/libguacd/log.h
@@ -0,0 +1,80 @@
+/*
+ * 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 __GUACD_LOG_H
+#define __GUACD_LOG_H
+
+#include "config.h"
+
+#include <guacamole/client.h>
+
+/**
+ * The maximum level at which to log messages. All other messages will be
+ * dropped.
+ */
+extern int guacd_log_level;
+
+/**
+ * The string to prepend to all log messages.
+ */
+#define GUACD_LOG_NAME "guacd"
+
+/**
+ * Writes a message to guacd's logs. This function takes a format and va_list,
+ * similar to vprintf.
+ */
+void vguacd_log(guac_client_log_level level, const char* format, va_list args);
+
+/**
+ * Writes a message to guacd's logs. This function accepts parameters
+ * identically to printf.
+ */
+void guacd_log(guac_client_log_level level, const char* format, ...);
+
+/**
+ * Writes a message using the logging facilities of the given client. This
+ * function accepts parameters identically to printf.
+ */
+void guacd_client_log(guac_client* client, guac_client_log_level level,
+        const char* format, va_list args);
+
+/**
+ * Prints an error message to guacd's logs, automatically including any
+ * information present in guac_error. This function accepts parameters
+ * identically to printf.
+ */
+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.
+ */
+void guacd_log_handshake_failure();
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/socket-ssl.c
----------------------------------------------------------------------
diff --git a/src/libguacd/socket-ssl.c b/src/libguacd/socket-ssl.c
new file mode 100644
index 0000000..4f19442
--- /dev/null
+++ b/src/libguacd/socket-ssl.c
@@ -0,0 +1,153 @@
+/*
+ * 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 "socket-ssl.h"
+
+#include <poll.h>
+#include <stdlib.h>
+
+#include <guacamole/error.h>
+#include <guacamole/socket.h>
+#include <openssl/ssl.h>
+
+static ssize_t __guac_socket_ssl_read_handler(guac_socket* socket,
+        void* buf, size_t count) {
+
+    /* Read from socket */
+    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
+    int retval;
+
+    retval = SSL_read(data->ssl, buf, count);
+
+    /* Record errors in guac_error */
+    if (retval <= 0) {
+        guac_error = GUAC_STATUS_SEE_ERRNO;
+        guac_error_message = "Error reading data from secure socket";
+    }
+
+    return retval;
+
+}
+
+static ssize_t __guac_socket_ssl_write_handler(guac_socket* socket,
+        const void* buf, size_t count) {
+
+    /* Write data to socket */
+    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
+    int retval;
+
+    retval = SSL_write(data->ssl, buf, count);
+
+    /* Record errors in guac_error */
+    if (retval <= 0) {
+        guac_error = GUAC_STATUS_SEE_ERRNO;
+        guac_error_message = "Error writing data to secure socket";
+    }
+
+    return retval;
+
+}
+
+static int __guac_socket_ssl_select_handler(guac_socket* socket, int usec_timeout) {
+
+    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
+
+    int retval;
+
+    /* Initialize with single underlying file descriptor */
+    struct pollfd fds[1] = {{
+        .fd      = data->fd,
+        .events  = POLLIN,
+        .revents = 0,
+    }};
+
+    /* No timeout if usec_timeout is negative */
+    if (usec_timeout < 0)
+        retval = poll(fds, 1, -1);
+
+    /* Handle timeout if specified, rounding up to poll()'s granularity */
+    else
+        retval = poll(fds, 1, (usec_timeout + 999) / 1000);
+
+    /* Properly set guac_error */
+    if (retval <  0) {
+        guac_error = GUAC_STATUS_SEE_ERRNO;
+        guac_error_message = "Error while waiting for data on secure socket";
+    }
+
+    if (retval == 0) {
+        guac_error = GUAC_STATUS_TIMEOUT;
+        guac_error_message = "Timeout while waiting for data on secure socket";
+    }
+
+    return retval;
+
+}
+
+static int __guac_socket_ssl_free_handler(guac_socket* socket) {
+
+    /* Shutdown SSL */
+    guac_socket_ssl_data* data = (guac_socket_ssl_data*) socket->data;
+    SSL_shutdown(data->ssl);
+
+    /* Close file descriptor */
+    close(data->fd);
+
+    free(data);
+    return 0;
+}
+
+guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd) {
+
+    /* Allocate socket and associated data */
+    guac_socket* socket = guac_socket_alloc();
+    guac_socket_ssl_data* data = malloc(sizeof(guac_socket_ssl_data));
+
+    /* Init SSL */
+    data->context = context;
+    data->ssl = SSL_new(context);
+    SSL_set_fd(data->ssl, fd);
+
+    /* Accept SSL connection, handle errors */
+    if (SSL_accept(data->ssl) <= 0) {
+
+        guac_error = GUAC_STATUS_INTERNAL_ERROR;
+        guac_error_message = "SSL accept failed";
+
+        free(data);
+        guac_socket_free(socket);
+        return NULL;
+    }
+
+    /* Store file descriptor as socket data */
+    data->fd = fd;
+    socket->data = data;
+
+    /* Set read/write handlers */
+    socket->read_handler   = __guac_socket_ssl_read_handler;
+    socket->write_handler  = __guac_socket_ssl_write_handler;
+    socket->select_handler = __guac_socket_ssl_select_handler;
+    socket->free_handler   = __guac_socket_ssl_free_handler;
+
+    return socket;
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/socket-ssl.h
----------------------------------------------------------------------
diff --git a/src/libguacd/socket-ssl.h b/src/libguacd/socket-ssl.h
new file mode 100644
index 0000000..e1a341e
--- /dev/null
+++ b/src/libguacd/socket-ssl.h
@@ -0,0 +1,71 @@
+/*
+ * 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 __GUACD_SOCKET_SSL_H
+#define __GUACD_SOCKET_SSL_H
+
+#include "config.h"
+
+#include <guacamole/socket.h>
+#include <openssl/ssl.h>
+
+/**
+ * SSL socket-specific data.
+ */
+typedef struct guac_socket_ssl_data {
+
+    /**
+     * The file descriptor that SSL communication will take place
+     * over.
+     */
+    int fd;
+
+    /**
+     * The current SSL context.
+     */
+    SSL_CTX* context;
+
+    /**
+     * The SSL connection, created automatically via
+     * guac_socket_open_secure().
+     */
+    SSL* ssl;
+
+} guac_socket_ssl_data;
+
+/**
+ * Creates a new guac_socket which will use SSL for all communication. Freeing
+ * this guac_socket will automatically close the associated file descriptor.
+ *
+ * @param context
+ *     The SSL_CTX structure describing the desired SSL configuration.
+ *
+ * @param fd
+ *     The file descriptor to use for the SSL connection underlying the
+ *     created guac_socket.
+ *
+ * @return
+ *     A newly-allocated guac_socket which will transparently use SSL for
+ *     all communication.
+ */
+guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/user.c
----------------------------------------------------------------------
diff --git a/src/libguacd/user.c b/src/libguacd/user.c
new file mode 100644
index 0000000..0a37147
--- /dev/null
+++ b/src/libguacd/user.c
@@ -0,0 +1,113 @@
+/*
+ * 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 "user.h"
+
+#include <guacamole/client.h>
+#include <guacamole/error.h>
+#include <guacamole/parser.h>
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+
+void* guacd_user_input_thread(void* data) {
+
+    guacd_user_input_thread_params* params = (guacd_user_input_thread_params*) data;
+    guac_user* user = params->user;
+    guac_parser* parser = params->parser;
+    guac_client* client = user->client;
+    guac_socket* socket = user->socket;
+
+    /* Guacamole user input loop */
+    while (client->state == GUAC_CLIENT_RUNNING && user->active) {
+
+        /* Read instruction, stop on error */
+        if (guac_parser_read(parser, socket, GUACD_USEC_TIMEOUT)) {
+
+            if (guac_error == GUAC_STATUS_TIMEOUT)
+                guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding.");
+
+            else {
+                if (guac_error != GUAC_STATUS_CLOSED)
+                    guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
+                            "Guacamole connection failure");
+                guac_user_stop(user);
+            }
+
+            return NULL;
+        }
+
+        /* Reset guac_error and guac_error_message (user/client handlers are not
+         * guaranteed to set these) */
+        guac_error = GUAC_STATUS_SUCCESS;
+        guac_error_message = NULL;
+
+        /* Call handler, stop on error */
+        if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) {
+
+            /* Log error */
+            guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
+                    "User connection aborted");
+
+            /* Log handler details */
+            guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode);
+
+            guac_user_stop(user);
+            return NULL;
+        }
+
+    }
+
+    return NULL;
+
+}
+
+int guacd_user_start(guac_parser* parser, guac_user* user) {
+
+    guacd_user_input_thread_params params = {
+        .parser = parser,
+        .user = user
+    };
+
+    pthread_t input_thread;
+
+    if (pthread_create(&input_thread, NULL, guacd_user_input_thread, (void*) &params)) {
+        guac_user_log(user, GUAC_LOG_ERROR, "Unable to start input thread");
+        guac_user_stop(user);
+        return -1;
+    }
+
+    /* Wait for I/O threads */
+    pthread_join(input_thread, NULL);
+
+    /* Explicitly signal disconnect */
+    guac_protocol_send_disconnect(user->socket);
+    guac_socket_flush(user->socket);
+
+    /* Done */
+    return 0;
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d7a604c8/src/libguacd/user.h
----------------------------------------------------------------------
diff --git a/src/libguacd/user.h b/src/libguacd/user.h
new file mode 100644
index 0000000..65eef70
--- /dev/null
+++ b/src/libguacd/user.h
@@ -0,0 +1,98 @@
+/*
+ * 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 _GUACD_USER_H
+#define _GUACD_USER_H
+
+#include "config.h"
+
+#include <guacamole/parser.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+/**
+ * The number of milliseconds to wait for messages in any phase before
+ * timing out and closing the connection with an error.
+ */
+#define GUACD_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 GUACD_TIMEOUT * 1000.
+ */
+#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000)
+
+/**
+ * The maximum number of concurrent connections to a single instance
+ * of guacd.
+ */
+#define GUACD_CLIENT_MAX_CONNECTIONS 65536
+
+/**
+ * Parameters required by the user input thread.
+ */
+typedef struct guacd_user_input_thread_params {
+
+    /**
+     * The parser which will be used throughout the user's session.
+     */
+    guac_parser* parser;
+
+    /**
+     * A reference to the connected user.
+     */
+    guac_user* user;
+
+} guacd_user_input_thread_params;
+
+/**
+ * Starts the input/output threads of a new user. This function will block
+ * until the user disconnects. If an error prevents the input/output threads
+ * from starting, guac_user_stop() will be invoked on the given user.
+ *
+ * @param parser
+ *     The guac_parser to use to handle all input from the given user.
+ *
+ * @param user
+ *     The user whose associated I/O transfer threads should be started.
+ *
+ * @return
+ *     Zero if the I/O threads started successfully and user has disconnected,
+ *     or non-zero if the I/O threads could not be started.
+ */
+int guacd_user_start(guac_parser* parser, guac_user* user);
+
+/**
+ * The thread which handles all user input, calling event handlers for received
+ * instructions.
+ *
+ * @param data
+ *     A pointer to a guacd_user_input_thread_params structure describing the
+ *     user whose input is being handled and the guac_parser with which to
+ *     handle it.
+ *
+ * @return
+ *     Always NULL.
+ */
+void* guacd_user_input_thread(void* data);
+
+#endif
+


[2/4] incubator-guacamole-server git commit: GUACAMOLE-175: Split logging between guacd and libguacd.

Posted by jm...@apache.org.
GUACAMOLE-175: Split logging between guacd and libguacd.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/45adc635
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/45adc635
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/45adc635

Branch: refs/heads/master
Commit: 45adc6359729d5f10636dd25488080c04b0463ea
Parents: d7a604c
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Sep 10 19:29:57 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Jan 24 15:44:55 2017 -0800

----------------------------------------------------------------------
 src/guacd/Makefile.am              |   2 +
 src/guacd/connection.c             |   4 +-
 src/guacd/daemon.c                 |   2 +-
 src/guacd/log.c                    | 143 ++++++++++++++++++++++++++++++++
 src/guacd/log.h                    |  72 ++++++++++++++++
 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 |  71 ++++++++++++++++
 src/libguacd/libguacd/user.h       |  98 ++++++++++++++++++++++
 src/libguacd/log.c                 | 115 +------------------------
 src/libguacd/log.h                 |  80 ------------------
 src/libguacd/socket-ssl.c          |   2 +-
 src/libguacd/socket-ssl.h          |  71 ----------------
 src/libguacd/user.c                |   4 +-
 src/libguacd/user.h                |  98 ----------------------
 18 files changed, 436 insertions(+), 376 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/Makefile.am
----------------------------------------------------------------------
diff --git a/src/guacd/Makefile.am b/src/guacd/Makefile.am
index e25a101..b9433e8 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

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/connection.c
----------------------------------------------------------------------
diff --git a/src/guacd/connection.c b/src/guacd/connection.c
index 3ad8eae..87efc5a 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 <guacamole/client.h>
 #include <guacamole/error.h>
@@ -36,7 +36,7 @@
 
 #ifdef ENABLE_SSL
 #include <openssl/ssl.h>
-#include "socket-ssl.h"
+#include "libguacd/socket-ssl.h"
 #endif
 
 #include <errno.h>

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/daemon.c
----------------------------------------------------------------------
diff --git a/src/guacd/daemon.c b/src/guacd/daemon.c
index 7d978aa..840c68f 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 <openssl/ssl.h>

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/log.c
----------------------------------------------------------------------
diff --git a/src/guacd/log.c b/src/guacd/log.c
new file mode 100644
index 0000000..121bb69
--- /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 <guacamole/client.h>
+#include <guacamole/error.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+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));
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/log.h
----------------------------------------------------------------------
diff --git a/src/guacd/log.h b/src/guacd/log.h
new file mode 100644
index 0000000..58a8752
--- /dev/null
+++ b/src/guacd/log.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __GUACD_LOG_H
+#define __GUACD_LOG_H
+
+#include "config.h"
+
+#include <guacamole/client.h>
+
+/**
+ * The maximum level at which to log messages. All other messages will be
+ * dropped.
+ */
+extern int guacd_log_level;
+
+/**
+ * The string to prepend to all log messages.
+ */
+#define GUACD_LOG_NAME "guacd"
+
+/**
+ * Writes a message to guacd's logs. This function takes a format and va_list,
+ * similar to vprintf.
+ */
+void vguacd_log(guac_client_log_level level, const char* format, va_list args);
+
+/**
+ * Writes a message to guacd's logs. This function accepts parameters
+ * identically to printf.
+ */
+void guacd_log(guac_client_log_level level, const char* format, ...);
+
+/**
+ * Writes a message using the logging facilities of the given client. This
+ * function accepts parameters identically to printf.
+ */
+void guacd_client_log(guac_client* client, guac_client_log_level level,
+        const char* format, va_list args);
+
+/**
+ * Prints an error message to guacd's logs, automatically including any
+ * information present in guac_error. This function accepts parameters
+ * identically to printf.
+ */
+void guacd_log_guac_error(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_log_handshake_failure();
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/proc-map.c
----------------------------------------------------------------------
diff --git a/src/guacd/proc-map.c b/src/guacd/proc-map.c
index c09c06a..bbe50b3 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 <guacamole/client.h>
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/proc-map.h
----------------------------------------------------------------------
diff --git a/src/guacd/proc-map.h b/src/guacd/proc-map.h
index 123449d..7313244 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 <guacamole/client.h>
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/guacd/proc.c
----------------------------------------------------------------------
diff --git a/src/guacd/proc.c b/src/guacd/proc.c
index 5bf1e5c..f4d7f2a 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 <guacamole/client.h>
 #include <guacamole/error.h>

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/Makefile.am
----------------------------------------------------------------------
diff --git a/src/libguacd/Makefile.am b/src/libguacd/Makefile.am
index 9e20cec..23cab3b 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
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/libguacd/log.h
----------------------------------------------------------------------
diff --git a/src/libguacd/libguacd/log.h b/src/libguacd/libguacd/log.h
new file mode 100644
index 0000000..2e65f5a
--- /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 <guacamole/client.h>
+
+/**
+ * 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
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/libguacd/socket-ssl.h
----------------------------------------------------------------------
diff --git a/src/libguacd/libguacd/socket-ssl.h b/src/libguacd/libguacd/socket-ssl.h
new file mode 100644
index 0000000..e1a341e
--- /dev/null
+++ b/src/libguacd/libguacd/socket-ssl.h
@@ -0,0 +1,71 @@
+/*
+ * 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 __GUACD_SOCKET_SSL_H
+#define __GUACD_SOCKET_SSL_H
+
+#include "config.h"
+
+#include <guacamole/socket.h>
+#include <openssl/ssl.h>
+
+/**
+ * SSL socket-specific data.
+ */
+typedef struct guac_socket_ssl_data {
+
+    /**
+     * The file descriptor that SSL communication will take place
+     * over.
+     */
+    int fd;
+
+    /**
+     * The current SSL context.
+     */
+    SSL_CTX* context;
+
+    /**
+     * The SSL connection, created automatically via
+     * guac_socket_open_secure().
+     */
+    SSL* ssl;
+
+} guac_socket_ssl_data;
+
+/**
+ * Creates a new guac_socket which will use SSL for all communication. Freeing
+ * this guac_socket will automatically close the associated file descriptor.
+ *
+ * @param context
+ *     The SSL_CTX structure describing the desired SSL configuration.
+ *
+ * @param fd
+ *     The file descriptor to use for the SSL connection underlying the
+ *     created guac_socket.
+ *
+ * @return
+ *     A newly-allocated guac_socket which will transparently use SSL for
+ *     all communication.
+ */
+guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/libguacd/user.h
----------------------------------------------------------------------
diff --git a/src/libguacd/libguacd/user.h b/src/libguacd/libguacd/user.h
new file mode 100644
index 0000000..a872f14
--- /dev/null
+++ b/src/libguacd/libguacd/user.h
@@ -0,0 +1,98 @@
+/*
+ * 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_USER_H
+#define LIBGUACD_USER_H
+
+#include "config.h"
+
+#include <guacamole/parser.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+/**
+ * The number of milliseconds to wait for messages in any phase before
+ * timing out and closing the connection with an error.
+ */
+#define GUACD_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 GUACD_TIMEOUT * 1000.
+ */
+#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000)
+
+/**
+ * The maximum number of concurrent connections to a single instance
+ * of guacd.
+ */
+#define GUACD_CLIENT_MAX_CONNECTIONS 65536
+
+/**
+ * Parameters required by the user input thread.
+ */
+typedef struct guacd_user_input_thread_params {
+
+    /**
+     * The parser which will be used throughout the user's session.
+     */
+    guac_parser* parser;
+
+    /**
+     * A reference to the connected user.
+     */
+    guac_user* user;
+
+} guacd_user_input_thread_params;
+
+/**
+ * Starts the input/output threads of a new user. This function will block
+ * until the user disconnects. If an error prevents the input/output threads
+ * from starting, guac_user_stop() will be invoked on the given user.
+ *
+ * @param parser
+ *     The guac_parser to use to handle all input from the given user.
+ *
+ * @param user
+ *     The user whose associated I/O transfer threads should be started.
+ *
+ * @return
+ *     Zero if the I/O threads started successfully and user has disconnected,
+ *     or non-zero if the I/O threads could not be started.
+ */
+int guacd_user_start(guac_parser* parser, guac_user* user);
+
+/**
+ * The thread which handles all user input, calling event handlers for received
+ * instructions.
+ *
+ * @param data
+ *     A pointer to a guacd_user_input_thread_params structure describing the
+ *     user whose input is being handled and the guac_parser with which to
+ *     handle it.
+ *
+ * @return
+ *     Always NULL.
+ */
+void* guacd_user_input_thread(void* data);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/log.c
----------------------------------------------------------------------
diff --git a/src/libguacd/log.c b/src/libguacd/log.c
index 229d2f9..26b24e4 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 <guacamole/client.h>
 #include <guacamole/error.h>
@@ -28,102 +28,6 @@
 #include <syslog.h>
 #include <unistd.h>
 
-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));
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/log.h
----------------------------------------------------------------------
diff --git a/src/libguacd/log.h b/src/libguacd/log.h
deleted file mode 100644
index 09fe152..0000000
--- a/src/libguacd/log.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 __GUACD_LOG_H
-#define __GUACD_LOG_H
-
-#include "config.h"
-
-#include <guacamole/client.h>
-
-/**
- * The maximum level at which to log messages. All other messages will be
- * dropped.
- */
-extern int guacd_log_level;
-
-/**
- * The string to prepend to all log messages.
- */
-#define GUACD_LOG_NAME "guacd"
-
-/**
- * Writes a message to guacd's logs. This function takes a format and va_list,
- * similar to vprintf.
- */
-void vguacd_log(guac_client_log_level level, const char* format, va_list args);
-
-/**
- * Writes a message to guacd's logs. This function accepts parameters
- * identically to printf.
- */
-void guacd_log(guac_client_log_level level, const char* format, ...);
-
-/**
- * Writes a message using the logging facilities of the given client. This
- * function accepts parameters identically to printf.
- */
-void guacd_client_log(guac_client* client, guac_client_log_level level,
-        const char* format, va_list args);
-
-/**
- * Prints an error message to guacd's logs, automatically including any
- * information present in guac_error. This function accepts parameters
- * identically to printf.
- */
-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.
- */
-void guacd_log_handshake_failure();
-
-#endif
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/socket-ssl.c
----------------------------------------------------------------------
diff --git a/src/libguacd/socket-ssl.c b/src/libguacd/socket-ssl.c
index 4f19442..aa8664f 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 <poll.h>
 #include <stdlib.h>

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/socket-ssl.h
----------------------------------------------------------------------
diff --git a/src/libguacd/socket-ssl.h b/src/libguacd/socket-ssl.h
deleted file mode 100644
index e1a341e..0000000
--- a/src/libguacd/socket-ssl.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 __GUACD_SOCKET_SSL_H
-#define __GUACD_SOCKET_SSL_H
-
-#include "config.h"
-
-#include <guacamole/socket.h>
-#include <openssl/ssl.h>
-
-/**
- * SSL socket-specific data.
- */
-typedef struct guac_socket_ssl_data {
-
-    /**
-     * The file descriptor that SSL communication will take place
-     * over.
-     */
-    int fd;
-
-    /**
-     * The current SSL context.
-     */
-    SSL_CTX* context;
-
-    /**
-     * The SSL connection, created automatically via
-     * guac_socket_open_secure().
-     */
-    SSL* ssl;
-
-} guac_socket_ssl_data;
-
-/**
- * Creates a new guac_socket which will use SSL for all communication. Freeing
- * this guac_socket will automatically close the associated file descriptor.
- *
- * @param context
- *     The SSL_CTX structure describing the desired SSL configuration.
- *
- * @param fd
- *     The file descriptor to use for the SSL connection underlying the
- *     created guac_socket.
- *
- * @return
- *     A newly-allocated guac_socket which will transparently use SSL for
- *     all communication.
- */
-guac_socket* guac_socket_open_secure(SSL_CTX* context, int fd);
-
-#endif
-

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/user.c
----------------------------------------------------------------------
diff --git a/src/libguacd/user.c b/src/libguacd/user.c
index 0a37147..e9f73be 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 <guacamole/client.h>
 #include <guacamole/error.h>

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/45adc635/src/libguacd/user.h
----------------------------------------------------------------------
diff --git a/src/libguacd/user.h b/src/libguacd/user.h
deleted file mode 100644
index 65eef70..0000000
--- a/src/libguacd/user.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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 _GUACD_USER_H
-#define _GUACD_USER_H
-
-#include "config.h"
-
-#include <guacamole/parser.h>
-#include <guacamole/socket.h>
-#include <guacamole/user.h>
-
-/**
- * The number of milliseconds to wait for messages in any phase before
- * timing out and closing the connection with an error.
- */
-#define GUACD_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 GUACD_TIMEOUT * 1000.
- */
-#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000)
-
-/**
- * The maximum number of concurrent connections to a single instance
- * of guacd.
- */
-#define GUACD_CLIENT_MAX_CONNECTIONS 65536
-
-/**
- * Parameters required by the user input thread.
- */
-typedef struct guacd_user_input_thread_params {
-
-    /**
-     * The parser which will be used throughout the user's session.
-     */
-    guac_parser* parser;
-
-    /**
-     * A reference to the connected user.
-     */
-    guac_user* user;
-
-} guacd_user_input_thread_params;
-
-/**
- * Starts the input/output threads of a new user. This function will block
- * until the user disconnects. If an error prevents the input/output threads
- * from starting, guac_user_stop() will be invoked on the given user.
- *
- * @param parser
- *     The guac_parser to use to handle all input from the given user.
- *
- * @param user
- *     The user whose associated I/O transfer threads should be started.
- *
- * @return
- *     Zero if the I/O threads started successfully and user has disconnected,
- *     or non-zero if the I/O threads could not be started.
- */
-int guacd_user_start(guac_parser* parser, guac_user* user);
-
-/**
- * The thread which handles all user input, calling event handlers for received
- * instructions.
- *
- * @param data
- *     A pointer to a guacd_user_input_thread_params structure describing the
- *     user whose input is being handled and the guac_parser with which to
- *     handle it.
- *
- * @return
- *     Always NULL.
- */
-void* guacd_user_input_thread(void* data);
-
-#endif
-


[4/4] incubator-guacamole-server git commit: GUACAMOLE-175: Merge move of guacd core into library.

Posted by jm...@apache.org.
GUACAMOLE-175: Merge move of guacd core into library.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/5d2c9676
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/5d2c9676
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/5d2c9676

Branch: refs/heads/master
Commit: 5d2c9676f4681e49a95149ecb43176aba8a56528
Parents: 396eaa2 4c06d75
Author: James Muehlner <ja...@guac-dev.org>
Authored: Tue Jan 24 16:38:50 2017 -0800
Committer: James Muehlner <ja...@guac-dev.org>
Committed: Tue Jan 24 16:38:50 2017 -0800

----------------------------------------------------------------------
 Makefile.am                        |   8 +-
 configure.ac                       |   5 +
 src/guacd/Makefile.am              |  18 +-
 src/guacd/connection.c             |   4 +-
 src/guacd/daemon.c                 |   2 +-
 src/guacd/log.c                    |  25 ---
 src/guacd/log.h                    |   8 -
 src/guacd/proc-map.c               |   2 +-
 src/guacd/proc-map.h               |   2 +-
 src/guacd/proc.c                   | 212 +--------------------
 src/guacd/socket-ssl.c             | 153 ---------------
 src/guacd/socket-ssl.h             |  71 -------
 src/guacd/user.c                   | 113 -----------
 src/guacd/user.h                   |  98 ----------
 src/libguacd/Makefile.am           |  50 +++++
 src/libguacd/libguacd/log.h        |  42 +++++
 src/libguacd/libguacd/socket-ssl.h |  71 +++++++
 src/libguacd/libguacd/user.h       | 113 +++++++++++
 src/libguacd/log.c                 |  72 +++++++
 src/libguacd/socket-ssl.c          | 153 +++++++++++++++
 src/libguacd/user.c                | 321 ++++++++++++++++++++++++++++++++
 21 files changed, 844 insertions(+), 699 deletions(-)
----------------------------------------------------------------------



[3/4] incubator-guacamole-server git commit: GUACAMOLE-175: Move guacd_handle_user() to libguacd.

Posted by jm...@apache.org.
GUACAMOLE-175: Move guacd_handle_user() to libguacd.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/4c06d755
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/4c06d755
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/4c06d755

Branch: refs/heads/master
Commit: 4c06d755f95bfacaa6f1b5f435b6a94ef2d8a608
Parents: 45adc63
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 11 13:18:27 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Jan 24 15:44:59 2017 -0800

----------------------------------------------------------------------
 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(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4c06d755/src/guacd/proc.c
----------------------------------------------------------------------
diff --git a/src/guacd/proc.c b/src/guacd/proc.c
index f4d7f2a..74ba146 100644
--- a/src/guacd/proc.c
+++ b/src/guacd/proc.c
@@ -41,216 +41,6 @@
 #include <sys/socket.h>
 
 /**
- * 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.
  */
 typedef struct guacd_user_thread_params {

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4c06d755/src/libguacd/libguacd/log.h
----------------------------------------------------------------------
diff --git a/src/libguacd/libguacd/log.h b/src/libguacd/libguacd/log.h
index 2e65f5a..76509e3 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
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4c06d755/src/libguacd/libguacd/user.h
----------------------------------------------------------------------
diff --git a/src/libguacd/libguacd/user.h b/src/libguacd/libguacd/user.h
index a872f14..cb2a8b3 100644
--- a/src/libguacd/libguacd/user.h
+++ b/src/libguacd/libguacd/user.h
@@ -81,6 +81,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.
  *

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4c06d755/src/libguacd/log.c
----------------------------------------------------------------------
diff --git a/src/libguacd/log.c b/src/libguacd/log.c
index 26b24e4..e746373 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));
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/4c06d755/src/libguacd/user.c
----------------------------------------------------------------------
diff --git a/src/libguacd/user.c b/src/libguacd/user.c
index e9f73be..db39fce 100644
--- a/src/libguacd/user.c
+++ b/src/libguacd/user.c
@@ -31,6 +31,65 @@
 
 #include <pthread.h>
 #include <stdlib.h>
+#include <string.h>
+
+/**
+ * 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;
+
+}
+