You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/09/26 12:44:22 UTC

[01/19] guacamole-server git commit: GUACAMOLE-623: Add missing documentation for URL character test.

Repository: guacamole-server
Updated Branches:
  refs/heads/master 54fda2136 -> 43db1965e


GUACAMOLE-623: Add missing documentation for URL character test.


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

Branch: refs/heads/master
Commit: 5e3aec6df2ec3578e47030665f7b12c3c3cadd51
Parents: 371eed1
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 21:08:19 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/url.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5e3aec6d/src/protocols/kubernetes/url.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/url.c b/src/protocols/kubernetes/url.c
index 434cc87..78c116e 100644
--- a/src/protocols/kubernetes/url.c
+++ b/src/protocols/kubernetes/url.c
@@ -23,6 +23,17 @@
 #include <stdlib.h>
 #include <string.h>
 
+/**
+ * Returns whether the given character is a character that need not be
+ * escaped when included as part of a component of a URL.
+ *
+ * @param c
+ *     The character to test.
+ *
+ * @return
+ *     Zero if the character does not need to be escaped when included as
+ *     part of a component of a URL, non-zero otherwise.
+ */
 static int guac_kubernetes_is_url_safe(char c) {
     return (c >= 'A' && c <= 'Z')
         || (c >= 'a' && c <= 'z')


[06/19] guacamole-server git commit: GUACAMOLE-623: Do not return -1 from libwebsockets callback. Doing so results in automatic cleanup of part of the context, resulting in a segfault when lws_context_destroy() is invoked.

Posted by vn...@apache.org.
GUACAMOLE-623: Do not return -1 from libwebsockets callback. Doing so results in automatic cleanup of part of the context, resulting in a segfault when lws_context_destroy() is invoked.


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

Branch: refs/heads/master
Commit: cbe593503f4cf819af32abc0b661662aa3fadc9e
Parents: f72877b
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 00:25:49 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/kubernetes.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/cbe59350/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index ae2a894..e38d5e3 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -109,7 +109,7 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
      * pointer passed by libwebsockets may be NULL for some events) */
     guac_client* client = (guac_client*) user;
     if (client != NULL && client->state != GUAC_CLIENT_RUNNING)
-        return -1;
+        return lws_callback_http_dummy(wsi, reason, user, in, length);
 
     switch (reason) {
 


[03/19] guacamole-server git commit: GUACAMOLE-623: Add warning when Kubernetes support will not be built. Fix summary output from configure.

Posted by vn...@apache.org.
GUACAMOLE-623: Add warning when Kubernetes support will not be built. Fix summary output from configure.


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

Branch: refs/heads/master
Commit: 77a866129b3b6592f122a5912c349a03f0c4b4e2
Parents: c5f67a3
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 20:09:36 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 configure.ac | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/77a86612/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 7c0bb73..df36eab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1190,7 +1190,12 @@ then
     AC_CHECK_LIB([websockets],
                  [lws_create_context],
                  [WEBSOCKETS_LIBS="$WEBSOCKETS_LIBS -lwebsockets"],
-                 [have_libwebsockets=no])
+                 [AC_MSG_WARN([
+  --------------------------------------------
+   Unable to find libwebsockets.
+   Support for Kubernetes will be disabled.
+  --------------------------------------------])
+                 have_libwebsockets=no])
 fi
 
 # Check for client-specific closed event, which must be used in favor of the
@@ -1339,7 +1344,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
      libVNCServer ........ ${have_libvncserver}
      libvorbis ........... ${have_vorbis}
      libpulse ............ ${have_pulse}
-     libwebsockets ....... ${have_websockets}
+     libwebsockets ....... ${have_libwebsockets}
      libwebp ............. ${have_webp}
      wsock32 ............. ${have_winsock}
 


[13/19] guacamole-server git commit: GUACAMOLE-623: Generate Kubernetes API endpoint dynamically.

Posted by vn...@apache.org.
GUACAMOLE-623: Generate Kubernetes API endpoint dynamically.


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

Branch: refs/heads/master
Commit: ed560938886e92dbe656d610966585b8178c2d73
Parents: 34f8f8b
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 18:39:06 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/Makefile.am  |   2 +
 src/protocols/kubernetes/kubernetes.c |  27 ++++++-
 src/protocols/kubernetes/settings.c   |  53 ++++++++++--
 src/protocols/kubernetes/settings.h   |  24 ++++++
 src/protocols/kubernetes/url.c        | 126 +++++++++++++++++++++++++++++
 src/protocols/kubernetes/url.h        |  87 ++++++++++++++++++++
 6 files changed, 311 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/ed560938/src/protocols/kubernetes/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/Makefile.am b/src/protocols/kubernetes/Makefile.am
index d864967..9e50feb 100644
--- a/src/protocols/kubernetes/Makefile.am
+++ b/src/protocols/kubernetes/Makefile.am
@@ -29,6 +29,7 @@ libguac_client_kubernetes_la_SOURCES = \
     pipe.c                             \
     settings.c                         \
     kubernetes.c                       \
+    url.c                              \
     user.c
 
 noinst_HEADERS = \
@@ -38,6 +39,7 @@ noinst_HEADERS = \
     pipe.h       \
     settings.h   \
     kubernetes.h \
+    url.h        \
     user.h
 
 libguac_client_kubernetes_la_CFLAGS = \

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/ed560938/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 53a8580..380d1d3 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -21,6 +21,7 @@
 #include "common/recording.h"
 #include "kubernetes.h"
 #include "terminal/terminal.h"
+#include "url.h"
 
 #include <guacamole/client.h>
 #include <guacamole/protocol.h>
@@ -345,6 +346,28 @@ void* guac_kubernetes_client_thread(void* data) {
     guac_kubernetes_settings* settings = kubernetes_client->settings;
 
     pthread_t input_thread;
+    char endpoint_path[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
+
+    /* Verify that the pod name was specified (it's always required) */
+    if (settings->kubernetes_pod == NULL) {
+        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                "The name of the Kubernetes pod is a required parameter.");
+        goto fail;
+    }
+
+    /* Generate endpoint for attachment URL */
+    if (guac_kubernetes_endpoint_attach(endpoint_path, sizeof(endpoint_path),
+                settings->kubernetes_namespace,
+                settings->kubernetes_pod,
+                settings->kubernetes_container)) {
+        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                "Unable to generate path for Kubernetes API endpoint: "
+                "Resulting path too long");
+        goto fail;
+    }
+
+    guac_client_log(client, GUAC_LOG_DEBUG, "The endpoint for attaching to "
+            "the requested Kubernetes pod is \"%s\".", endpoint_path);
 
     /* Set up screen recording, if requested */
     if (settings->recording_path != NULL) {
@@ -434,9 +457,9 @@ void* guac_kubernetes_client_thread(void* data) {
         goto fail;
     }
 
-    /* FIXME: Generate path dynamically */
+    /* Generate path dynamically */
     connection_info.context = kubernetes_client->context;
-    connection_info.path = "/api/v1/namespaces/default/pods/my-shell-68974bb7f7-rpjgr/attach?container=my-shell&stdin=true&stdout=true&tty=true";
+    connection_info.path = endpoint_path;
 
     /* Open WebSocket connection to Kubernetes */
     kubernetes_client->wsi = lws_client_connect_via_info(&connection_info);

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/ed560938/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 50daa6f..4f9f3f2 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -32,6 +32,9 @@
 const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
     "hostname",
     "port",
+    "namespace",
+    "pod",
+    "container",
     "use-ssl",
     "client-cert-file",
     "client-key-file",
@@ -68,6 +71,24 @@ enum KUBERNETES_ARGS_IDX {
     IDX_PORT,
 
     /**
+     * The name of the Kubernetes namespace of the pod containing the container
+     * being attached to. If omitted, the default namespace will be used.
+     */
+    IDX_NAMESPACE,
+
+    /**
+     * The name of the Kubernetes pod containing with the container being
+     * attached to. Required.
+     */
+    IDX_POD,
+
+    /**
+     * The name of the container to attach to. If omitted, the first container
+     * in the pod will be used.
+     */
+    IDX_CONTAINER,
+
+    /**
      * Whether SSL/TLS should be used. If omitted, SSL/TLS will not be used.
      */
     IDX_USE_SSL,
@@ -215,11 +236,31 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
     guac_kubernetes_settings* settings =
         calloc(1, sizeof(guac_kubernetes_settings));
 
-    /* Read parameters */
+    /* Read hostname */
     settings->hostname =
         guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                 IDX_HOSTNAME, "");
 
+    /* Read port */
+    settings->port =
+        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_PORT, GUAC_KUBERNETES_DEFAULT_PORT);
+
+    /* Read Kubernetes namespace */
+    settings->kubernetes_namespace =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_NAMESPACE, GUAC_KUBERNETES_DEFAULT_NAMESPACE);
+
+    /* Read name of Kubernetes pod (required) */
+    settings->kubernetes_pod =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_POD, NULL);
+
+    /* Read container of pod (optional) */
+    settings->kubernetes_container =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_CONTAINER, NULL);
+
     /* Parse whether SSL should be used */
     settings->use_ssl =
         guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
@@ -276,11 +317,6 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
     settings->height     = user->info.optimal_height;
     settings->resolution = user->info.optimal_resolution;
 
-    /* Read port */
-    settings->port =
-        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
-                IDX_PORT, GUAC_KUBERNETES_DEFAULT_PORT);
-
     /* Read typescript path */
     settings->typescript_path =
         guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
@@ -341,6 +377,11 @@ void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
     /* Free network connection information */
     free(settings->hostname);
 
+    /* Free Kubernetes pod/container details */
+    free(settings->kubernetes_namespace);
+    free(settings->kubernetes_pod);
+    free(settings->kubernetes_container);
+
     /* Free SSL/TLS details */
     free(settings->client_cert_file);
     free(settings->client_key_file);

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/ed560938/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index 8f42f8c..c2e479e 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -45,6 +45,12 @@
 #define GUAC_KUBERNETES_DEFAULT_PORT 8080
 
 /**
+ * The name of the Kubernetes namespace that should be used by default if no
+ * specific Kubernetes namespace is provided.
+ */
+#define GUAC_KUBERNETES_DEFAULT_NAMESPACE "default"
+
+/**
  * The filename to use for the typescript, if not specified.
  */
 #define GUAC_KUBERNETES_DEFAULT_TYPESCRIPT_NAME "typescript" 
@@ -77,6 +83,24 @@ typedef struct guac_kubernetes_settings {
     int port;
 
     /**
+     * The name of the Kubernetes namespace of the pod containing the container
+     * being attached to.
+     */
+    char* kubernetes_namespace;
+
+    /**
+     * The name of the Kubernetes pod containing with the container being
+     * attached to.
+     */
+    char* kubernetes_pod;
+
+    /**
+     * The name of the container to attach to, or NULL to arbitrarily attach to
+     * the first container in the pod.
+     */
+    char* kubernetes_container;
+
+    /**
      * Whether SSL/TLS should be used.
      */
     bool use_ssl;

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/ed560938/src/protocols/kubernetes/url.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/url.c b/src/protocols/kubernetes/url.c
new file mode 100644
index 0000000..cfd6f74
--- /dev/null
+++ b/src/protocols/kubernetes/url.c
@@ -0,0 +1,126 @@
+/*
+ * 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 "url.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static int guac_kubernetes_is_url_safe(char c) {
+    return (c >= 'A' && c <= 'Z')
+        || (c >= 'a' && c <= 'z')
+        || (c >= '0' && c <= '9')
+        || strchr("-_.!~*'()", c) != NULL;
+}
+
+int guac_kubernetes_escape_url_component(char* output, int length,
+        const char* str) {
+
+    char* current = output;
+    while (*str != '\0') {
+
+        char c = *str;
+
+        /* Store alphanumeric characters verbatim */
+        if (guac_kubernetes_is_url_safe(c)) {
+
+            /* Verify space exists for single character */
+            if (length < 1)
+                return 1;
+
+            *(current++) = c;
+            length--;
+
+        }
+
+        /* Escape EVERYTHING else as hex */
+        else {
+
+            /* Verify space exists for hex-encoded character */
+            if (length < 4)
+                return 1;
+
+            snprintf(current, 4, "%%%02X", (int) c);
+
+            current += 3;
+            length -= 3;
+        }
+
+        /* Next character */
+        str++;
+
+    }
+
+    /* Verify space exists for null terminator */
+    if (length < 1)
+        return 1;
+
+    /* Append null terminator */
+    *current = '\0';
+    return 0;
+
+}
+
+int guac_kubernetes_endpoint_attach(char* buffer, int length,
+        const char* kubernetes_namespace, const char* kubernetes_pod,
+        const char* kubernetes_container) {
+
+    int written;
+
+    char escaped_namespace[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
+    char escaped_pod[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
+    char escaped_container[GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH];
+
+    /* Escape Kubernetes namespace */
+    if (guac_kubernetes_escape_url_component(escaped_namespace,
+                sizeof(escaped_namespace), kubernetes_namespace))
+        return 1;
+
+    /* Escape name of Kubernetes pod */
+    if (guac_kubernetes_escape_url_component(escaped_pod,
+                sizeof(escaped_pod), kubernetes_pod))
+        return 1;
+
+    /* Generate attachment endpoint URL */
+    if (kubernetes_container != NULL) {
+
+        /* Escape container name */
+        if (guac_kubernetes_escape_url_component(escaped_container,
+                    sizeof(escaped_container), kubernetes_container))
+            return 1;
+
+        written = snprintf(buffer, length,
+                "/api/v1/namespaces/%s/pods/%s/attach"
+                "?container=%s&stdin=true&stdout=true&tty=true",
+                escaped_namespace, escaped_pod, escaped_container);
+    }
+    else {
+        written = snprintf(buffer, length,
+                "/api/v1/namespaces/%s/pods/%s/attach"
+                "?stdin=true&stdout=true&tty=true",
+                escaped_namespace, escaped_pod);
+    }
+
+    /* Endpoint URL was successfully generated if it was written to the given
+     * buffer without truncation */
+    return !(written < length - 1);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/ed560938/src/protocols/kubernetes/url.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/url.h b/src/protocols/kubernetes/url.h
new file mode 100644
index 0000000..19084ee
--- /dev/null
+++ b/src/protocols/kubernetes/url.h
@@ -0,0 +1,87 @@
+/*
+ * 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 GUAC_KUBERNETES_URL_H
+#define GUAC_KUBERNETES_URL_H
+
+#include "config.h"
+
+/**
+ * The maximum number of characters allowed in the full path for any Kubernetes
+ * endpoint.
+ */
+#define GUAC_KUBERNETES_MAX_ENDPOINT_LENGTH 1024
+
+/**
+ * Escapes the given string such that it can be included safely within a URL.
+ * This function duplicates the behavior of JavaScript's encodeURIComponent(),
+ * escaping all but the following characters: A-Z a-z 0-9 - _ . ! ~ * ' ( )
+ *
+ * @param output
+ *     The buffer which should receive the escaped string. This buffer may be
+ *     touched even if escaping is unsuccessful.
+ *
+ * @param length
+ *     The number of bytes available in the given output buffer.
+ *
+ * @param str
+ *     The string to escape.
+ *
+ * @return
+ *     Zero if the string was successfully escaped and written into the
+ *     provided output buffer without being truncated, including null
+ *     terminator, non-zero otherwise.
+ */
+int guac_kubernetes_escape_url_component(char* output, int length,
+        const char* str);
+
+/**
+ * Generates the full path to the Kubernetes API endpoint which handles
+ * attaching to running containers within specific pods. Values within the path
+ * will be URL-escaped as necessary.
+ *
+ * @param buffer
+ *     The buffer which should receive the endpoint path. This buffer may be
+ *     touched even if the endpoint path could not be generated.
+ *
+ * @param length
+ *     The number of bytes available in the given buffer.
+ *
+ * @param kubernetes_namespace
+ *     The name of the Kubernetes namespace of the pod containing the container
+ *     being attached to.
+ *
+ * @param kubernetes_pod
+ *     The name of the Kubernetes pod containing with the container being
+ *     attached to.
+ *
+ * @param kubernetes_container
+ *     The name of the container to attach to, or NULL to arbitrarily attach
+ *     to the first container in the pod.
+ *
+ * @return
+ *     Zero if the endpoint path was successfully written to the provided
+ *     buffer, non-zero if insufficient space exists within the buffer.
+ */
+int guac_kubernetes_endpoint_attach(char* buffer, int length,
+        const char* kubernetes_namespace, const char* kubernetes_pod,
+        const char* kubernetes_container);
+
+#endif
+


[18/19] guacamole-server git commit: GUACAMOLE-623: Move I/O-related functions into separate files.

Posted by vn...@apache.org.
GUACAMOLE-623: Move I/O-related functions into separate files.


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

Branch: refs/heads/master
Commit: 2e50573531411a49c98dcb44a29fe2ad8a983609
Parents: 5e3aec6
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 22:55:02 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:52 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/Makefile.am  |   2 +
 src/protocols/kubernetes/io.c         | 143 +++++++++++++++++++++++++
 src/protocols/kubernetes/io.h         | 144 +++++++++++++++++++++++++
 src/protocols/kubernetes/kubernetes.c | 165 +----------------------------
 src/protocols/kubernetes/kubernetes.h |  59 +----------
 5 files changed, 292 insertions(+), 221 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/2e505735/src/protocols/kubernetes/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/Makefile.am b/src/protocols/kubernetes/Makefile.am
index 9e50feb..e818ff7 100644
--- a/src/protocols/kubernetes/Makefile.am
+++ b/src/protocols/kubernetes/Makefile.am
@@ -26,6 +26,7 @@ libguac_client_kubernetes_la_SOURCES = \
     client.c                           \
     clipboard.c                        \
     input.c                            \
+    io.c                               \
     pipe.c                             \
     settings.c                         \
     kubernetes.c                       \
@@ -36,6 +37,7 @@ noinst_HEADERS = \
     client.h     \
     clipboard.h  \
     input.h      \
+    io.h         \
     pipe.h       \
     settings.h   \
     kubernetes.h \

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/2e505735/src/protocols/kubernetes/io.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/io.c b/src/protocols/kubernetes/io.c
new file mode 100644
index 0000000..bfa37b1
--- /dev/null
+++ b/src/protocols/kubernetes/io.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 "kubernetes.h"
+#include "terminal/terminal.h"
+
+#include <guacamole/client.h>
+#include <libwebsockets.h>
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <string.h>
+
+void guac_kubernetes_receive_data(guac_client* client,
+        const char* buffer, size_t length) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Strip channel index from beginning of buffer */
+    int channel = *(buffer++);
+    length--;
+
+    switch (channel) {
+
+        /* Write STDOUT / STDERR directly to terminal as output */
+        case GUAC_KUBERNETES_CHANNEL_STDOUT:
+        case GUAC_KUBERNETES_CHANNEL_STDERR:
+            guac_terminal_write(kubernetes_client->term, buffer, length);
+            break;
+
+        /* Ignore data on other channels */
+        default:
+            guac_client_log(client, GUAC_LOG_DEBUG, "Received %i bytes along "
+                    "channel %i.", length, channel);
+
+    }
+
+}
+
+void guac_kubernetes_send_message(guac_client* client,
+        int channel, const char* data, int length) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    pthread_mutex_lock(&(kubernetes_client->outbound_message_lock));
+
+    /* Add message to buffer if space is available */
+    if (kubernetes_client->outbound_messages_waiting
+            < GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES) {
+
+        /* Calculate storage position of next message */
+        int index = (kubernetes_client->outbound_messages_top
+                  + kubernetes_client->outbound_messages_waiting)
+                  % GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES;
+
+        /* Obtain pointer to message slot at calculated position */
+        guac_kubernetes_message* message =
+            &(kubernetes_client->outbound_messages[index]);
+
+        /* Copy details of message into buffer */
+        message->channel = channel;
+        memcpy(message->data, data, length);
+        message->length = length;
+
+        /* One more message is now waiting */
+        kubernetes_client->outbound_messages_waiting++;
+
+        /* Notify libwebsockets that we need a callback to send pending
+         * messages */
+        lws_callback_on_writable(kubernetes_client->wsi);
+        lws_cancel_service(kubernetes_client->context);
+
+    }
+
+    /* Warn if data has to be dropped */
+    else
+        guac_client_log(client, GUAC_LOG_WARNING, "Send buffer could not be "
+                "flushed in time to handle additional data. Outbound "
+                "message dropped.");
+
+    pthread_mutex_unlock(&(kubernetes_client->outbound_message_lock));
+
+}
+
+bool guac_kubernetes_write_pending_message(guac_client* client) {
+
+    bool messages_remain;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    pthread_mutex_lock(&(kubernetes_client->outbound_message_lock));
+
+    /* Send one message from top of buffer */
+    if (kubernetes_client->outbound_messages_waiting > 0) {
+
+        /* Obtain pointer to message at top */
+        int top = kubernetes_client->outbound_messages_top;
+        guac_kubernetes_message* message =
+            &(kubernetes_client->outbound_messages[top]);
+
+        /* Write message including channel index */
+        lws_write(kubernetes_client->wsi,
+                ((unsigned char*) message) + LWS_PRE,
+                message->length + 1, LWS_WRITE_BINARY);
+
+        /* Advance top to next message */
+        kubernetes_client->outbound_messages_top++;
+        kubernetes_client->outbound_messages_top %=
+            GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES;
+
+        /* One less message is waiting */
+        kubernetes_client->outbound_messages_waiting--;
+
+    }
+
+    /* Record whether messages remained at time of completion */
+    messages_remain = (kubernetes_client->outbound_messages_waiting > 0);
+
+    pthread_mutex_unlock(&(kubernetes_client->outbound_message_lock));
+
+    return messages_remain;
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/2e505735/src/protocols/kubernetes/io.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/io.h b/src/protocols/kubernetes/io.h
new file mode 100644
index 0000000..40f2c69
--- /dev/null
+++ b/src/protocols/kubernetes/io.h
@@ -0,0 +1,144 @@
+/*
+ * 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 GUAC_KUBERNETES_IO_H
+#define GUAC_KUBERNETES_IO_H
+
+#include <guacamole/client.h>
+#include <libwebsockets.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * The maximum amount of data to include in any particular WebSocket message
+ * to Kubernetes. This excludes the storage space required for the channel
+ * index.
+ */
+#define GUAC_KUBERNETES_MAX_MESSAGE_SIZE 1024
+
+/**
+ * The index of the Kubernetes channel used for STDIN.
+ */
+#define GUAC_KUBERNETES_CHANNEL_STDIN 0
+
+/**
+ * The index of the Kubernetes channel used for STDOUT.
+ */
+#define GUAC_KUBERNETES_CHANNEL_STDOUT 1
+
+/**
+ * The index of the Kubernetes channel used for STDERR.
+ */
+#define GUAC_KUBERNETES_CHANNEL_STDERR 2
+
+/**
+ * The index of the Kubernetes channel used for terminal resize messages.
+ */
+#define GUAC_KUBERNETES_CHANNEL_RESIZE 4
+
+/**
+ * An outbound message to be received by Kubernetes over WebSocket.
+ */
+typedef struct guac_kubernetes_message {
+
+    /**
+     * lws_write() requires leading padding of LWS_PRE bytes to provide
+     * scratch space for WebSocket framing.
+     */
+    uint8_t _padding[LWS_PRE];
+
+    /**
+     * The index of the channel receiving the data, such as
+     * GUAC_KUBERNETES_CHANNEL_STDIN.
+     */
+    uint8_t channel;
+
+    /**
+     * The data that should be sent to Kubernetes (along with the channel
+     * index).
+     */
+    char data[GUAC_KUBERNETES_MAX_MESSAGE_SIZE];
+
+    /**
+     * The length of the data to be sent, excluding the channel index.
+     */
+    int length;
+
+} guac_kubernetes_message;
+
+
+/**
+ * Handles data received from Kubernetes over WebSocket, decoding the channel
+ * index of the received data and forwarding that data accordingly.
+ *
+ * @param client
+ *     The guac_client associated with the connection to Kubernetes.
+ *
+ * @param buffer
+ *     The data received from Kubernetes.
+ *
+ * @param length
+ *     The size of the data received from Kubernetes, in bytes.
+ */
+void guac_kubernetes_receive_data(guac_client* client,
+        const char* buffer, size_t length);
+
+/**
+ * Requests that the given data be sent along the given channel to the
+ * Kubernetes server when the WebSocket connection is next available for
+ * writing. If the WebSocket connection has not been available for writing for
+ * long enough that the outbound message buffer is full, the request to send
+ * this particular message will be dropped.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @param channel
+ *     The Kubernetes channel on which to send the message,
+ *     such as GUAC_KUBERNETES_CHANNEL_STDIN.
+ *
+ * @param data
+ *     A buffer containing the data to send.
+ *
+ * @param length
+ *     The number of bytes to send.
+ */
+void guac_kubernetes_send_message(guac_client* client,
+        int channel, const char* data, int length);
+
+/**
+ * Writes the oldest pending message within the outbound message queue,
+ * as scheduled with guac_kubernetes_send_message(), removing that message
+ * from the queue. This function MAY NOT be invoked outside the libwebsockets
+ * event callback and MUST only be invoked in the context of a
+ * LWS_CALLBACK_CLIENT_WRITEABLE event. If no messages are pending, this
+ * function has no effect.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @return
+ *     true if messages still remain to be written within the outbound message
+ *     queue, false otherwise.
+ */
+bool guac_kubernetes_write_pending_message(guac_client* client);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/2e505735/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 3644d6e..4e7928e 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -18,8 +18,9 @@
  */
 
 #include "config.h"
-#include "kubernetes.h"
 #include "common/recording.h"
+#include "io.h"
+#include "kubernetes.h"
 #include "terminal/terminal.h"
 #include "url.h"
 
@@ -30,168 +31,6 @@
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-
-/**
- * Handles data received from Kubernetes over WebSocket, decoding the channel
- * index of the received data and forwarding that data accordingly.
- *
- * @param client
- *     The guac_client associated with the connection to Kubernetes.
- *
- * @param buffer
- *     The data received from Kubernetes.
- *
- * @param length
- *     The size of the data received from Kubernetes, in bytes.
- */
-static void guac_kubernetes_receive_data(guac_client* client,
-        const char* buffer, size_t length) {
-
-    guac_kubernetes_client* kubernetes_client =
-        (guac_kubernetes_client*) client->data;
-
-    /* Strip channel index from beginning of buffer */
-    int channel = *(buffer++);
-    length--;
-
-    switch (channel) {
-
-        /* Write STDOUT / STDERR directly to terminal as output */
-        case GUAC_KUBERNETES_CHANNEL_STDOUT:
-        case GUAC_KUBERNETES_CHANNEL_STDERR:
-            guac_terminal_write(kubernetes_client->term, buffer, length);
-            break;
-
-        /* Ignore data on other channels */
-        default:
-            guac_client_log(client, GUAC_LOG_DEBUG, "Received %i bytes along "
-                    "channel %i.", length, channel);
-
-    }
-
-}
-
-/**
- * Requests that the given data be sent along the given channel to the
- * Kubernetes server when the WebSocket connection is next available for
- * writing. If the WebSocket connection has not been available for writing for
- * long enough that the outbound message buffer is full, the request to send
- * this particular message will be dropped.
- *
- * @param client
- *     The guac_client associated with the Kubernetes connection.
- *
- * @param channel
- *     The Kubernetes channel on which to send the message,
- *     such as GUAC_KUBERNETES_CHANNEL_STDIN.
- *
- * @param data
- *     A buffer containing the data to send.
- *
- * @param length
- *     The number of bytes to send.
- */
-static void guac_kubernetes_send_message(guac_client* client,
-        int channel, const char* data, int length) {
-
-    guac_kubernetes_client* kubernetes_client =
-        (guac_kubernetes_client*) client->data;
-
-    pthread_mutex_lock(&(kubernetes_client->outbound_message_lock));
-
-    /* Add message to buffer if space is available */
-    if (kubernetes_client->outbound_messages_waiting
-            < GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES) {
-
-        /* Calculate storage position of next message */
-        int index = (kubernetes_client->outbound_messages_top
-                  + kubernetes_client->outbound_messages_waiting)
-                  % GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES;
-
-        /* Obtain pointer to message slot at calculated position */
-        guac_kubernetes_message* message =
-            &(kubernetes_client->outbound_messages[index]);
-
-        /* Copy details of message into buffer */
-        message->channel = channel;
-        memcpy(message->data, data, length);
-        message->length = length;
-
-        /* One more message is now waiting */
-        kubernetes_client->outbound_messages_waiting++;
-
-        /* Notify libwebsockets that we need a callback to send pending
-         * messages */
-        lws_callback_on_writable(kubernetes_client->wsi);
-        lws_cancel_service(kubernetes_client->context);
-
-    }
-
-    /* Warn if data has to be dropped */
-    else
-        guac_client_log(client, GUAC_LOG_WARNING, "Send buffer could not be "
-                "flushed in time to handle additional data. Outbound "
-                "message dropped.");
-
-    pthread_mutex_unlock(&(kubernetes_client->outbound_message_lock));
-
-}
-
-/**
- * Writes the oldest pending message within the outbound message queue,
- * as scheduled with guac_kubernetes_send_message(), removing that message
- * from the queue. This function MAY NOT be invoked outside the libwebsockets
- * event callback and MUST only be invoked in the context of a
- * LWS_CALLBACK_CLIENT_WRITEABLE event. If no messages are pending, this
- * function has no effect.
- *
- * @param client
- *     The guac_client associated with the Kubernetes connection.
- *
- * @return
- *     true if messages still remain to be written within the outbound message
- *     queue, false otherwise.
- */
-static bool guac_kubernetes_write_pending_message(guac_client* client) {
-
-    bool messages_remain;
-    guac_kubernetes_client* kubernetes_client =
-        (guac_kubernetes_client*) client->data;
-
-    pthread_mutex_lock(&(kubernetes_client->outbound_message_lock));
-
-    /* Send one message from top of buffer */
-    if (kubernetes_client->outbound_messages_waiting > 0) {
-
-        /* Obtain pointer to message at top */
-        int top = kubernetes_client->outbound_messages_top;
-        guac_kubernetes_message* message =
-            &(kubernetes_client->outbound_messages[top]);
-
-        /* Write message including channel index */
-        lws_write(kubernetes_client->wsi,
-                ((unsigned char*) message) + LWS_PRE,
-                message->length + 1, LWS_WRITE_BINARY);
-
-        /* Advance top to next message */
-        kubernetes_client->outbound_messages_top++;
-        kubernetes_client->outbound_messages_top %=
-            GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES;
-
-        /* One less message is waiting */
-        kubernetes_client->outbound_messages_waiting--;
-
-    }
-
-    /* Record whether messages remained at time of completion */
-    messages_remain = (kubernetes_client->outbound_messages_waiting > 0);
-
-    pthread_mutex_unlock(&(kubernetes_client->outbound_message_lock));
-
-    return messages_remain;
-
-}
 
 /**
  * Callback invoked by libwebsockets for events related to a WebSocket being

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/2e505735/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index 8c9a25e..c37ca4c 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -22,6 +22,7 @@
 
 #include "common/clipboard.h"
 #include "common/recording.h"
+#include "io.h"
 #include "settings.h"
 #include "terminal/terminal.h"
 
@@ -29,7 +30,6 @@
 #include <libwebsockets.h>
 
 #include <pthread.h>
-#include <stdint.h>
 
 /**
  * The name of the WebSocket protocol specific to Kubernetes which should be
@@ -38,33 +38,6 @@
 #define GUAC_KUBERNETES_LWS_PROTOCOL "v4.channel.k8s.io"
 
 /**
- * The index of the Kubernetes channel used for STDIN.
- */
-#define GUAC_KUBERNETES_CHANNEL_STDIN 0
-
-/**
- * The index of the Kubernetes channel used for STDOUT.
- */
-#define GUAC_KUBERNETES_CHANNEL_STDOUT 1
-
-/**
- * The index of the Kubernetes channel used for STDERR.
- */
-#define GUAC_KUBERNETES_CHANNEL_STDERR 2
-
-/**
- * The index of the Kubernetes channel used for terminal resize messages.
- */
-#define GUAC_KUBERNETES_CHANNEL_RESIZE 4
-
-/**
- * The maximum amount of data to include in any particular WebSocket message
- * to Kubernetes. This excludes the storage space required for the channel
- * index.
- */
-#define GUAC_KUBERNETES_MAX_MESSAGE_SIZE 1024
-
-/**
  * The maximum number of messages to allow within the outbound message buffer.
  * If messages are sent despite the buffer being full, those messages will be
  * dropped.
@@ -78,36 +51,6 @@
 #define GUAC_KUBERNETES_SERVICE_INTERVAL 1000
 
 /**
- * An outbound message to be received by Kubernetes over WebSocket.
- */
-typedef struct guac_kubernetes_message {
-
-    /**
-     * lws_write() requires leading padding of LWS_PRE bytes to provide
-     * scratch space for WebSocket framing.
-     */
-    uint8_t _padding[LWS_PRE];
-
-    /**
-     * The index of the channel receiving the data, such as
-     * GUAC_KUBERNETES_CHANNEL_STDIN.
-     */
-    uint8_t channel;
-
-    /**
-     * The data that should be sent to Kubernetes (along with the channel
-     * index).
-     */
-    char data[GUAC_KUBERNETES_MAX_MESSAGE_SIZE];
-
-    /**
-     * The length of the data to be sent, excluding the channel index.
-     */
-    int length;
-
-} guac_kubernetes_message;
-
-/**
  * Kubernetes-specific client data.
  */
 typedef struct guac_kubernetes_client {


[15/19] guacamole-server git commit: GUACAMOLE-623: libwebsockets requires an integer port number.

Posted by vn...@apache.org.
GUACAMOLE-623: libwebsockets requires an integer port number.


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

Branch: refs/heads/master
Commit: 5bae422b29939c2e08aff13b33bdb8c2b9ab2ed9
Parents: b8bd0e4
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 9 21:49:58 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/settings.c | 3 +--
 src/protocols/kubernetes/settings.h | 4 ++--
 2 files changed, 3 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5bae422b/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 1f04b40..5ee6671 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -278,7 +278,7 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
 
     /* Read port */
     settings->port =
-        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
                 IDX_PORT, GUAC_KUBERNETES_DEFAULT_PORT);
 
     /* Read typescript path */
@@ -340,7 +340,6 @@ void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
 
     /* Free network connection information */
     free(settings->hostname);
-    free(settings->port);
 
     /* Free SSL/TLS details */
     free(settings->client_cert_file);

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/5bae422b/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index 3e89ce5..fea6cf1 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -42,7 +42,7 @@
  * The port to connect to when initiating any Kubernetes connection, if no
  * other port is specified.
  */
-#define GUAC_KUBERNETES_DEFAULT_PORT "8443"
+#define GUAC_KUBERNETES_DEFAULT_PORT 8443
 
 /**
  * The filename to use for the typescript, if not specified.
@@ -74,7 +74,7 @@ typedef struct guac_kubernetes_settings {
     /**
      * The port of the Kubernetes server to connect to.
      */
-    char* port;
+    int port;
 
     /**
      * Whether SSL/TLS should be used.


[07/19] guacamole-server git commit: GUACAMOLE-623: Default to unencrypted Kubernetes connections.

Posted by vn...@apache.org.
GUACAMOLE-623: Default to unencrypted Kubernetes connections.


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

Branch: refs/heads/master
Commit: 519c90a88760ae4db4ad4db8b0f4f02dcef599b4
Parents: 5bae422
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 9 22:54:50 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/settings.c | 4 ++--
 src/protocols/kubernetes/settings.h | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/519c90a8/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 5ee6671..50daa6f 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -68,7 +68,7 @@ enum KUBERNETES_ARGS_IDX {
     IDX_PORT,
 
     /**
-     * Whether SSL/TLS should be used. SSL is used by default.
+     * Whether SSL/TLS should be used. If omitted, SSL/TLS will not be used.
      */
     IDX_USE_SSL,
 
@@ -223,7 +223,7 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
     /* Parse whether SSL should be used */
     settings->use_ssl =
         guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
-                IDX_USE_SSL, true);
+                IDX_USE_SSL, false);
 
     /* Read SSL/TLS connection details only if enabled */
     if (settings->use_ssl) {

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/519c90a8/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index fea6cf1..8f42f8c 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -42,7 +42,7 @@
  * The port to connect to when initiating any Kubernetes connection, if no
  * other port is specified.
  */
-#define GUAC_KUBERNETES_DEFAULT_PORT 8443
+#define GUAC_KUBERNETES_DEFAULT_PORT 8080
 
 /**
  * The filename to use for the typescript, if not specified.


[02/19] guacamole-server git commit: GUACAMOLE-623: Add missin includes. Remove unnecessary includes.

Posted by vn...@apache.org.
GUACAMOLE-623: Add missin includes. Remove unnecessary includes.


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

Branch: refs/heads/master
Commit: 371eed1f93c353e0bf2159bcffd77cf6d8bd9716
Parents: 77a8661
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 21:05:23 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/client.c     |  9 ++++-----
 src/protocols/kubernetes/client.h     |  6 +-----
 src/protocols/kubernetes/clipboard.c  |  2 --
 src/protocols/kubernetes/clipboard.h  |  2 --
 src/protocols/kubernetes/input.c      |  5 +----
 src/protocols/kubernetes/input.h      |  2 --
 src/protocols/kubernetes/kubernetes.c | 10 ++--------
 src/protocols/kubernetes/kubernetes.h |  4 +++-
 src/protocols/kubernetes/pipe.c       |  5 +++--
 src/protocols/kubernetes/pipe.h       |  2 --
 src/protocols/kubernetes/settings.c   |  5 -----
 src/protocols/kubernetes/settings.h   |  3 ---
 src/protocols/kubernetes/url.c        |  2 +-
 src/protocols/kubernetes/url.h        |  2 --
 src/protocols/kubernetes/user.c       |  6 +++---
 src/protocols/kubernetes/user.h       |  2 --
 16 files changed, 18 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
index 450e1e8..58f4728 100644
--- a/src/protocols/kubernetes/client.c
+++ b/src/protocols/kubernetes/client.c
@@ -17,22 +17,21 @@
  * under the License.
  */
 
-#include "config.h"
 #include "client.h"
-#include "common/recording.h"
+#include "common/clipboard.h"
 #include "kubernetes.h"
 #include "settings.h"
-#include "terminal/terminal.h"
 #include "user.h"
 
+#include <guacamole/client.h>
+#include <libwebsockets.h>
+
 #include <langinfo.h>
 #include <locale.h>
 #include <pthread.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <guacamole/client.h>
-
 /**
  * Static reference to the guac_client associated with the active Kubernetes
  * connection. As guacd guarantees that each main client connection is

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/client.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.h b/src/protocols/kubernetes/client.h
index 2e96d10..0b847da 100644
--- a/src/protocols/kubernetes/client.h
+++ b/src/protocols/kubernetes/client.h
@@ -20,11 +20,7 @@
 #ifndef GUAC_KUBERNETES_CLIENT_H
 #define GUAC_KUBERNETES_CLIENT_H
 
-#include "config.h"
-#include "terminal/terminal.h"
-
-#include <pthread.h>
-#include <sys/types.h>
+#include <guacamole/client.h>
 
 /**
  * The maximum number of bytes to allow within the clipboard.

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/clipboard.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/clipboard.c b/src/protocols/kubernetes/clipboard.c
index 87a34b0..f168206 100644
--- a/src/protocols/kubernetes/clipboard.c
+++ b/src/protocols/kubernetes/clipboard.c
@@ -17,11 +17,9 @@
  * under the License.
  */
 
-#include "config.h"
 #include "clipboard.h"
 #include "common/clipboard.h"
 #include "kubernetes.h"
-#include "terminal/terminal.h"
 
 #include <guacamole/client.h>
 #include <guacamole/stream.h>

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/clipboard.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/clipboard.h b/src/protocols/kubernetes/clipboard.h
index 009219c..87a393c 100644
--- a/src/protocols/kubernetes/clipboard.h
+++ b/src/protocols/kubernetes/clipboard.h
@@ -20,8 +20,6 @@
 #ifndef GUAC_KUBERNETES_CLIPBOARD_H
 #define GUAC_KUBERNETES_CLIPBOARD_H
 
-#include "config.h"
-
 #include <guacamole/user.h>
 
 /**

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/input.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/input.c b/src/protocols/kubernetes/input.c
index e73772e..814578e 100644
--- a/src/protocols/kubernetes/input.c
+++ b/src/protocols/kubernetes/input.c
@@ -17,18 +17,15 @@
  * under the License.
  */
 
-#include "config.h"
 #include "common/recording.h"
-#include "kubernetes.h"
 #include "input.h"
+#include "kubernetes.h"
 #include "terminal/terminal.h"
 
 #include <guacamole/client.h>
 #include <guacamole/user.h>
 
 #include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 int guac_kubernetes_user_mouse_handler(guac_user* user,
         int x, int y, int mask) {

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/input.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/input.h b/src/protocols/kubernetes/input.h
index ac65835..6f24cf2 100644
--- a/src/protocols/kubernetes/input.h
+++ b/src/protocols/kubernetes/input.h
@@ -20,8 +20,6 @@
 #ifndef GUAC_KUBERNETES_INPUT_H
 #define GUAC_KUBERNETES_INPUT_H
 
-#include "config.h"
-
 #include <guacamole/user.h>
 
 /**

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 9850c6d..3644d6e 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -18,8 +18,8 @@
  */
 
 #include "config.h"
-#include "common/recording.h"
 #include "kubernetes.h"
+#include "common/recording.h"
 #include "terminal/terminal.h"
 #include "url.h"
 
@@ -27,16 +27,10 @@
 #include <guacamole/protocol.h>
 #include <libwebsockets.h>
 
-#include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <poll.h>
 #include <pthread.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <unistd.h>
 
 /**
  * Handles data received from Kubernetes over WebSocket, decoding the channel

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index fedf77a..8c9a25e 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -20,13 +20,15 @@
 #ifndef GUAC_KUBERNETES_H
 #define GUAC_KUBERNETES_H
 
-#include "config.h"
 #include "common/clipboard.h"
 #include "common/recording.h"
 #include "settings.h"
 #include "terminal/terminal.h"
 
+#include <guacamole/client.h>
 #include <libwebsockets.h>
+
+#include <pthread.h>
 #include <stdint.h>
 
 /**

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/pipe.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/pipe.c b/src/protocols/kubernetes/pipe.c
index 242105b..8f18530 100644
--- a/src/protocols/kubernetes/pipe.c
+++ b/src/protocols/kubernetes/pipe.c
@@ -17,12 +17,13 @@
  * under the License.
  */
 
-#include "config.h"
 #include "kubernetes.h"
-#include "pipe.h"
 #include "terminal/terminal.h"
+#include "pipe.h"
 
+#include <guacamole/client.h>
 #include <guacamole/protocol.h>
+#include <guacamole/stream-types.h>
 #include <guacamole/socket.h>
 #include <guacamole/user.h>
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/pipe.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/pipe.h b/src/protocols/kubernetes/pipe.h
index 7acae3c..47565bf 100644
--- a/src/protocols/kubernetes/pipe.h
+++ b/src/protocols/kubernetes/pipe.h
@@ -21,8 +21,6 @@
 #ifndef GUAC_KUBERNETES_PIPE_H
 #define GUAC_KUBERNETES_PIPE_H
 
-#include "config.h"
-
 #include <guacamole/user.h>
 
 /**

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 4f9f3f2..122a858 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -17,16 +17,11 @@
  * under the License.
  */
 
-#include "config.h"
-
 #include "settings.h"
 
 #include <guacamole/user.h>
 
-#include <sys/types.h>
 #include <stdlib.h>
-#include <string.h>
-#include <time.h>
 
 /* Client plugin arguments */
 const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index c2e479e..a86d14a 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -20,11 +20,8 @@
 #ifndef GUAC_KUBERNETES_SETTINGS_H
 #define GUAC_KUBERNETES_SETTINGS_H
 
-#include "config.h"
-
 #include <guacamole/user.h>
 
-#include <sys/types.h>
 #include <stdbool.h>
 
 /**

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/url.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/url.c b/src/protocols/kubernetes/url.c
index cfd6f74..434cc87 100644
--- a/src/protocols/kubernetes/url.c
+++ b/src/protocols/kubernetes/url.c
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-#include "config.h"
 #include "url.h"
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 static int guac_kubernetes_is_url_safe(char c) {

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/url.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/url.h b/src/protocols/kubernetes/url.h
index 19084ee..285baa2 100644
--- a/src/protocols/kubernetes/url.h
+++ b/src/protocols/kubernetes/url.h
@@ -20,8 +20,6 @@
 #ifndef GUAC_KUBERNETES_URL_H
 #define GUAC_KUBERNETES_URL_H
 
-#include "config.h"
-
 /**
  * The maximum number of characters allowed in the full path for any Kubernetes
  * endpoint.

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/user.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/user.c b/src/protocols/kubernetes/user.c
index 62666cb..f90260e 100644
--- a/src/protocols/kubernetes/user.c
+++ b/src/protocols/kubernetes/user.c
@@ -17,9 +17,8 @@
  * under the License.
  */
 
-#include "config.h"
-
 #include "clipboard.h"
+#include "common/cursor.h"
 #include "input.h"
 #include "kubernetes.h"
 #include "pipe.h"
@@ -28,11 +27,12 @@
 #include "user.h"
 
 #include <guacamole/client.h>
+#include <guacamole/protocol.h>
 #include <guacamole/socket.h>
 #include <guacamole/user.h>
 
 #include <pthread.h>
-#include <string.h>
+#include <stdlib.h>
 
 int guac_kubernetes_user_join_handler(guac_user* user, int argc, char** argv) {
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/371eed1f/src/protocols/kubernetes/user.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/user.h b/src/protocols/kubernetes/user.h
index d235b2b..55d49fd 100644
--- a/src/protocols/kubernetes/user.h
+++ b/src/protocols/kubernetes/user.h
@@ -20,8 +20,6 @@
 #ifndef GUAC_KUBERNETES_USER_H
 #define GUAC_KUBERNETES_USER_H
 
-#include "config.h"
-
 #include <guacamole/user.h>
 
 /**


[12/19] guacamole-server git commit: GUACAMOLE-623: Add support for terminal resize. Redraw Kubernetes container upon connect.

Posted by vn...@apache.org.
GUACAMOLE-623: Add support for terminal resize. Redraw Kubernetes container upon connect.


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

Branch: refs/heads/master
Commit: fe7edce5694a718ce233b4d4c85b386be4240262
Parents: b7c938c
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 02:50:15 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/input.c      |  4 ++-
 src/protocols/kubernetes/kubernetes.c | 55 +++++++++++++++++++++++++++++-
 src/protocols/kubernetes/kubernetes.h | 38 +++++++++++++++++++++
 3 files changed, 95 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/fe7edce5/src/protocols/kubernetes/input.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/input.c b/src/protocols/kubernetes/input.c
index 9bf5b71..e73772e 100644
--- a/src/protocols/kubernetes/input.c
+++ b/src/protocols/kubernetes/input.c
@@ -88,7 +88,9 @@ int guac_kubernetes_user_size_handler(guac_user* user, int width, int height) {
     /* Resize terminal */
     guac_terminal_resize(terminal, width, height);
 
-    /* TODO: Update Kubernetes terminal window size if connected */
+    /* Update Kubernetes terminal window size if connected */
+    guac_kubernetes_resize(client, terminal->term_height,
+            terminal->term_width);
 
     return 0;
 }

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/fe7edce5/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index aadb448..53a8580 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -246,6 +246,11 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
         case LWS_CALLBACK_CLIENT_ESTABLISHED:
             guac_client_log(client, GUAC_LOG_INFO,
                     "Kubernetes connection successful.");
+
+            /* Schedule check for pending messages in case messages were added
+             * to the outbound message buffer prior to the connection being
+             * fully established */
+            lws_callback_on_writable(wsi);
             break;
 
         /* Data received via WebSocket */
@@ -260,7 +265,6 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
              * yet more messages remain */
             if (guac_kubernetes_write_pending_message(client))
                 lws_callback_on_writable(wsi);
-
             break;
 
         /* TODO: Add configure test */
@@ -451,6 +455,11 @@ void* guac_kubernetes_client_thread(void* data) {
         goto fail;
     }
 
+    /* Force a redraw of the attached display (there will be no content
+     * otherwise, given the stream nature of attaching to a running
+     * container) */
+    guac_kubernetes_force_redraw(client);
+
     /* As long as client is connected, continue polling libwebsockets */
     while (client->state == GUAC_CLIENT_RUNNING) {
 
@@ -485,3 +494,47 @@ fail:
 
 }
 
+void guac_kubernetes_resize(guac_client* client, int rows, int columns) {
+
+    char buffer[64];
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Send request only if different from last request */
+    if (kubernetes_client->rows != rows ||
+            kubernetes_client->columns != columns) {
+
+        kubernetes_client->rows = rows;
+        kubernetes_client->columns = columns;
+
+        /* Construct terminal resize message for Kubernetes */
+        int length = snprintf(buffer, sizeof(buffer),
+                "{\"Width\":%i,\"Height\":%i}", columns, rows);
+
+        /* Schedule message for sending */
+        guac_kubernetes_send_message(client, GUAC_KUBERNETES_CHANNEL_RESIZE,
+                buffer, length);
+
+    }
+
+}
+
+void guac_kubernetes_force_redraw(guac_client* client) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Get current terminal dimensions */
+    guac_terminal* term = kubernetes_client->term;
+    int rows = term->term_height;
+    int columns = term->term_width;
+
+    /* Force a redraw by increasing the terminal size by one character in
+     * each dimension and then resizing it back to normal (the same technique
+     * used by kubectl */
+    guac_kubernetes_resize(client, rows + 1, columns + 1);
+    guac_kubernetes_resize(client, rows, columns);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/fe7edce5/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index 761a897..fedf77a 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -168,6 +168,18 @@ typedef struct guac_kubernetes_client {
     guac_terminal* term;
 
     /**
+     * The number of rows last sent to Kubernetes in a terminal resize
+     * request.
+     */
+    int rows;
+
+    /**
+     * The number of columns last sent to Kubernetes in a terminal resize
+     * request.
+     */
+    int columns;
+
+    /**
      * The in-progress session recording, or NULL if no recording is in
      * progress.
      */
@@ -181,5 +193,31 @@ typedef struct guac_kubernetes_client {
  */
 void* guac_kubernetes_client_thread(void* data);
 
+/**
+ * Sends a message to the Kubernetes server requesting that the terminal be
+ * resized to the given dimensions. This message may be queued until the
+ * underlying WebSocket connection is ready to send.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @param rows
+ *     The new terminal size in rows.
+ *
+ * @param columns
+ *     The new terminal size in columns.
+ */
+void guac_kubernetes_resize(guac_client* client, int rows, int columns);
+
+/**
+ * Sends messages to the Kubernetes server such that the terminal is forced
+ * to redraw. This function should be invoked at the beginning of each
+ * session in order to restore expected display state.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ */
+void guac_kubernetes_force_redraw(guac_client* client);
+
 #endif
 


[17/19] guacamole-server git commit: GUACAMOLE-623: Add support for SSL.

Posted by vn...@apache.org.
GUACAMOLE-623: Add support for SSL.


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

Branch: refs/heads/master
Commit: 83a531bc89a5c79371f42d1ec5142c484a08479a
Parents: 2e50573
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 11 03:03:17 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:52 2018 -0700

----------------------------------------------------------------------
 configure.ac                          |   1 +
 src/protocols/kubernetes/Makefile.am  |   3 +
 src/protocols/kubernetes/client.c     |  16 +--
 src/protocols/kubernetes/client.h     |   7 +
 src/protocols/kubernetes/kubernetes.c |  46 +++----
 src/protocols/kubernetes/settings.c   |  48 +++----
 src/protocols/kubernetes/settings.h   |  24 ++--
 src/protocols/kubernetes/ssl.c        | 210 +++++++++++++++++++++++++++++
 src/protocols/kubernetes/ssl.h        |  41 ++++++
 9 files changed, 326 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index df36eab..d26db39 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1225,6 +1225,7 @@ AC_ARG_ENABLE([kubernetes],
 
 AM_CONDITIONAL([ENABLE_KUBERNETES], [test "x${enable_kubernetes}"  = "xyes" \
                                        -a "x${have_libwebsockets}" = "xyes" \
+                                       -a "x${have_ssl}"           = "xyes" \
                                        -a "x${have_terminal}"      = "xyes"])
 
 #

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/Makefile.am b/src/protocols/kubernetes/Makefile.am
index e818ff7..56db4d6 100644
--- a/src/protocols/kubernetes/Makefile.am
+++ b/src/protocols/kubernetes/Makefile.am
@@ -29,6 +29,7 @@ libguac_client_kubernetes_la_SOURCES = \
     io.c                               \
     pipe.c                             \
     settings.c                         \
+    ssl.c                              \
     kubernetes.c                       \
     url.c                              \
     user.c
@@ -40,6 +41,7 @@ noinst_HEADERS = \
     io.h         \
     pipe.h       \
     settings.h   \
+    ssl.h        \
     kubernetes.h \
     url.h        \
     user.h
@@ -57,5 +59,6 @@ libguac_client_kubernetes_la_LIBADD = \
 libguac_client_kubernetes_la_LDFLAGS = \
     -version-info 0:0:0                \
     @PTHREAD_LIBS@                     \
+    @SSL_LIBS@                         \
     @WEBSOCKETS_LIBS@
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
index 58f4728..331e03d 100644
--- a/src/protocols/kubernetes/client.c
+++ b/src/protocols/kubernetes/client.c
@@ -32,12 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-/**
- * Static reference to the guac_client associated with the active Kubernetes
- * connection. As guacd guarantees that each main client connection is
- * isolated within its own process, this is safe.
- */
-static guac_client* guac_kubernetes_lws_log_client = NULL;
+guac_client* guac_kubernetes_lws_current_client = NULL;
 
 /**
  * Logging callback invoked by libwebsockets to log a single line of logging
@@ -53,15 +48,18 @@ static guac_client* guac_kubernetes_lws_log_client = NULL;
  *     The line of logging output to log.
  */
 static void guac_kubernetes_log(int level, const char* line) {
-    if (guac_kubernetes_lws_log_client != NULL)
-        guac_client_log(guac_kubernetes_lws_log_client, GUAC_LOG_DEBUG,
+    if (guac_kubernetes_lws_current_client != NULL)
+        guac_client_log(guac_kubernetes_lws_current_client, GUAC_LOG_DEBUG,
                 "libwebsockets: %s", line);
 }
 
 int guac_client_init(guac_client* client) {
 
+    /* Ensure reference to main guac_client remains available in all
+     * libwebsockets contexts */
+    guac_kubernetes_lws_current_client = client;
+
     /* Redirect libwebsockets logging */
-    guac_kubernetes_lws_log_client = client;
     lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO,
             guac_kubernetes_log);
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/client.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.h b/src/protocols/kubernetes/client.h
index 0b847da..ec4ba32 100644
--- a/src/protocols/kubernetes/client.h
+++ b/src/protocols/kubernetes/client.h
@@ -28,6 +28,13 @@
 #define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
 
 /**
+ * Static reference to the guac_client associated with the active Kubernetes
+ * connection. While libwebsockets provides some means of storing and
+ * retrieving custom data in some structures, this is not always available.
+ */
+extern guac_client* guac_kubernetes_lws_current_client;
+
+/**
  * Free handler. Required by libguac and called when the guac_client is
  * disconnected and must be cleaned up.
  */

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 4e7928e..f314c59 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -18,9 +18,11 @@
  */
 
 #include "config.h"
+#include "client.h"
 #include "common/recording.h"
 #include "io.h"
 #include "kubernetes.h"
+#include "ssl.h"
 #include "terminal/terminal.h"
 #include "url.h"
 
@@ -43,8 +45,9 @@
  *     The reason (event) that this callback was invoked.
  *
  * @param user
- *     Arbitrary data assocated with the WebSocket session. This will always
- *     be a pointer to the guac_client instance.
+ *     Arbitrary data assocated with the WebSocket session. In some cases,
+ *     this is actually event-specific data (such as the
+ *     LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERT event).
  *
  * @param in
  *     A pointer to arbitrary, reason-specific data.
@@ -60,14 +63,19 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
         enum lws_callback_reasons reason, void* user,
         void* in, size_t length) {
 
-    /* Request connection closure if client is stopped (note that the user
-     * pointer passed by libwebsockets may be NULL for some events) */
-    guac_client* client = (guac_client*) user;
-    if (client != NULL && client->state != GUAC_CLIENT_RUNNING)
+    guac_client* client = guac_kubernetes_lws_current_client;
+
+    /* Do not handle any further events if connection is closing */
+    if (client->state != GUAC_CLIENT_RUNNING)
         return lws_callback_http_dummy(wsi, reason, user, in, length);
 
     switch (reason) {
 
+        /* Complete initialization of SSL */
+        case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
+            guac_kubernetes_init_ssl(client, (SSL_CTX*) user);
+            break;
+
         /* Failed to connect */
         case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
             guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
@@ -256,29 +264,13 @@ void* guac_kubernetes_client_thread(void* data) {
     };
 
     /* If requested, use an SSL/TLS connection for communication with
-     * Kubernetes */
+     * Kubernetes. Note that we disable hostname checks here because we
+     * do our own validation - libwebsockets does not validate properly if
+     * IP addresses are used. */
     if (settings->use_ssl) {
-
-        /* Enable use of SSL/TLS */
         context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-        connection_info.ssl_connection = LCCSCF_USE_SSL;
-
-        /* Bypass certificate checks if requested */
-        if (settings->ignore_cert) {
-            connection_info.ssl_connection |=
-                  LCCSCF_ALLOW_SELFSIGNED
-                | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
-                | LCCSCF_ALLOW_EXPIRED;
-        }
-
-        /* Otherwise use the given CA certificate to validate (if any) */
-        else
-            context_info.client_ssl_ca_filepath = settings->ca_cert_file;
-
-        /* Certificate and key file for SSL/TLS client auth */
-        context_info.client_ssl_cert_filepath = settings->client_cert_file;
-        context_info.client_ssl_private_key_filepath = settings->client_key_file;
-
+        connection_info.ssl_connection = LCCSCF_USE_SSL
+            | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
     }
 
     /* Create libwebsockets context */

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 122a858..4f00a44 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -31,9 +31,9 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
     "pod",
     "container",
     "use-ssl",
-    "client-cert-file",
-    "client-key-file",
-    "ca-cert-file",
+    "client-cert",
+    "client-key",
+    "ca-cert",
     "ignore-cert",
     "font-name",
     "font-size",
@@ -89,24 +89,26 @@ enum KUBERNETES_ARGS_IDX {
     IDX_USE_SSL,
 
     /**
-     * The filename of the certificate to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed. 
+     * The certificate to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    IDX_CLIENT_CERT_FILE,
+    IDX_CLIENT_CERT,
 
     /**
-     * The filename of the key to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed. 
+     * The key to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    IDX_CLIENT_KEY_FILE,
+    IDX_CLIENT_KEY,
 
     /**
-     * The filename of the certificate of the certificate authority that signed
-     * the certificate of the Kubernetes server.
+     * The certificate of the certificate authority that signed the certificate
+     * of the Kubernetes server, in PEM format. If omitted. verification of
+     * the Kubernetes server certificate will use the systemwide certificate
+     * authorities.
      */
-    IDX_CA_CERT_FILE,
+    IDX_CA_CERT,
 
     /**
      * Whether the certificate used by the Kubernetes server for SSL/TLS should
@@ -264,17 +266,17 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
     /* Read SSL/TLS connection details only if enabled */
     if (settings->use_ssl) {
 
-        settings->client_cert_file =
+        settings->client_cert =
             guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
-                    argv, IDX_CLIENT_CERT_FILE, NULL);
+                    argv, IDX_CLIENT_CERT, NULL);
 
-        settings->client_key_file =
+        settings->client_key =
             guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
-                    argv, IDX_CLIENT_KEY_FILE, NULL);
+                    argv, IDX_CLIENT_KEY, NULL);
 
-        settings->ca_cert_file =
+        settings->ca_cert =
             guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
-                    argv, IDX_CA_CERT_FILE, NULL);
+                    argv, IDX_CA_CERT, NULL);
 
         settings->ignore_cert =
             guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
@@ -378,9 +380,9 @@ void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
     free(settings->kubernetes_container);
 
     /* Free SSL/TLS details */
-    free(settings->client_cert_file);
-    free(settings->client_key_file);
-    free(settings->ca_cert_file);
+    free(settings->client_cert);
+    free(settings->client_key);
+    free(settings->ca_cert);
 
     /* Free display preferences */
     free(settings->font_name);

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index a86d14a..6267a18 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -103,24 +103,26 @@ typedef struct guac_kubernetes_settings {
     bool use_ssl;
 
     /**
-     * The filename of the certificate to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed.
+     * The certificate to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    char* client_cert_file;
+    char* client_cert;
 
     /**
-     * The filename of the key to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed. 
+     * The key to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    char* client_key_file;
+    char* client_key;
 
     /**
-     * The filename of the certificate of the certificate authority that signed
-     * the certificate of the Kubernetes server.
+     * The certificate of the certificate authority that signed the certificate
+     * of the Kubernetes server, in PEM format. If omitted. verification of
+     * the Kubernetes server certificate will use the systemwide certificate
+     * authorities.
      */
-    char* ca_cert_file;
+    char* ca_cert;
 
     /**
      * Whether the certificate used by the Kubernetes server for SSL/TLS should

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/ssl.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/ssl.c b/src/protocols/kubernetes/ssl.c
new file mode 100644
index 0000000..6ebafc6
--- /dev/null
+++ b/src/protocols/kubernetes/ssl.c
@@ -0,0 +1,210 @@
+/*
+ * 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 "kubernetes.h"
+#include "settings.h"
+
+#include <guacamole/client.h>
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+
+/**
+ * Tests whether the given hostname is, in fact, an IP address.
+ *
+ * @param hostname
+ *     The hostname to test.
+ *
+ * @return
+ *     Non-zero if the given hostname is an IP address, zero otherwise.
+ */
+static int guac_kubernetes_is_address(const char* hostname) {
+
+    /* Attempt to interpret the hostname as an IP address */
+    ASN1_OCTET_STRING* ip = a2i_IPADDRESS(hostname);
+
+    /* If unsuccessful, the hostname is not an IP address */
+    if (ip == NULL)
+        return 0;
+
+    /* Converted hostname must be freed */
+    ASN1_OCTET_STRING_free(ip);
+    return 1;
+
+}
+
+/**
+ * Parses the given PEM certificate, returning a new OpenSSL X509 structure
+ * representing that certificate.
+ *
+ * @param pem
+ *     The PEM certificate.
+ *
+ * @return
+ *     An X509 structure representing the given certificate, or NULL if the
+ *     certificate was unreadable.
+ */
+static X509* guac_kubernetes_read_cert(char* pem) {
+
+    /* Prepare a BIO which provides access to the in-memory CA cert */
+    BIO* bio = BIO_new_mem_buf(pem, -1);
+    if (bio == NULL)
+        return NULL;
+
+    /* Read the CA cert as PEM */
+    X509* certificate = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+    if (certificate == NULL) {
+        BIO_free(bio);
+        return NULL;
+    }
+
+    return certificate;
+
+}
+
+/**
+ * Parses the given PEM private key, returning a new OpenSSL EVP_PKEY structure
+ * representing that key.
+ *
+ * @param pem
+ *     The PEM private key.
+ *
+ * @return
+ *     An EVP_KEY representing the given private key, or NULL if the private
+ *     key was unreadable.
+ */
+static EVP_PKEY* guac_kubernetes_read_key(char* pem) {
+
+    /* Prepare a BIO which provides access to the in-memory key */
+    BIO* bio = BIO_new_mem_buf(pem, -1);
+    if (bio == NULL)
+        return NULL;
+
+    /* Read the private key as PEM */
+    EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+    if (key == NULL) {
+        BIO_free(bio);
+        return NULL;
+    }
+
+    return key;
+
+}
+
+void guac_kubernetes_init_ssl(guac_client* client, SSL_CTX* context) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    guac_kubernetes_settings* settings = kubernetes_client->settings;
+
+    /* Bypass certificate checks if requested */
+    if (settings->ignore_cert)
+        SSL_CTX_set_verify(context, SSL_VERIFY_NONE, NULL);
+
+    /* Otherwise use the given CA certificate to validate (if any) */
+    else if (settings->ca_cert != NULL) {
+
+        /* Read CA certificate from configuration data */
+        X509* ca_cert = guac_kubernetes_read_cert(settings->ca_cert);
+        if (ca_cert == NULL) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Provided CA certificate is unreadable");
+            return;
+        }
+
+        /* Add certificate to CA store */
+        X509_STORE* ca_store = SSL_CTX_get_cert_store(context);
+        if (!X509_STORE_add_cert(ca_store, ca_cert)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Unable to add CA certificate to certificate store of "
+                    "SSL context");
+            return;
+        }
+
+    }
+
+    /* Certificate for SSL/TLS client auth */
+    if (settings->client_cert != NULL) {
+
+        /* Read client certificate from configuration data */
+        X509* client_cert = guac_kubernetes_read_cert(settings->client_cert);
+        if (client_cert == NULL) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Provided client certificate is unreadable");
+            return;
+        }
+
+        /* Use parsed certificate for authentication */
+        if (!SSL_CTX_use_certificate(context, client_cert)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Client certificate could not be used for SSL/TLS "
+                    "client authentication");
+            return;
+        }
+
+    }
+
+    /* Private key for SSL/TLS client auth */
+    if (settings->client_key != NULL) {
+
+        /* Read client private key from configuration data */
+        EVP_PKEY* client_key = guac_kubernetes_read_key(settings->client_key);
+        if (client_key == NULL) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Provided client private key is unreadable");
+            return;
+        }
+
+        /* Use parsed key for authentication */
+        if (!SSL_CTX_use_PrivateKey(context, client_key)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Client private key could not be used for SSL/TLS "
+                    "client authentication");
+            return;
+        }
+
+    }
+
+    /* Enable hostname checking */
+    X509_VERIFY_PARAM *param = SSL_CTX_get0_param(context);
+    X509_VERIFY_PARAM_set_hostflags(param,
+            X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+
+    /* Validate properly depending on whether hostname is an IP address */
+    if (guac_kubernetes_is_address(settings->hostname)) {
+        if (!X509_VERIFY_PARAM_set1_ip_asc(param, settings->hostname)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Server IP address validation could not be enabled");
+            return;
+        }
+    }
+    else {
+        if (!X509_VERIFY_PARAM_set1_host(param, settings->hostname, 0)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Server hostname validation could not be enabled");
+            return;
+        }
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/ssl.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/ssl.h b/src/protocols/kubernetes/ssl.h
new file mode 100644
index 0000000..cca02bd
--- /dev/null
+++ b/src/protocols/kubernetes/ssl.h
@@ -0,0 +1,41 @@
+/*
+ * 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 GUAC_KUBERNETES_SSL_H
+#define GUAC_KUBERNETES_SSL_H
+
+#include "settings.h"
+
+#include <openssl/ssl.h>
+
+/**
+ * Initializes the given SSL/TLS context using the configuration parameters
+ * associated with the given guac_client, setting up hostname/address
+ * validation and client authentication.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @param context
+ *     The SSL_CTX in use by libwebsockets.
+ */
+void guac_kubernetes_init_ssl(guac_client* client, SSL_CTX* context);
+
+#endif
+


[08/19] guacamole-server git commit: GUACAMOLE-623: Send typed data to Kubernetes via the STDIN channel.

Posted by vn...@apache.org.
GUACAMOLE-623: Send typed data to Kubernetes via the STDIN channel.


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

Branch: refs/heads/master
Commit: b7c938c239f0c61b6122c817c6ce44309d61bd1f
Parents: f35517b
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 02:16:36 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/kubernetes.c | 151 ++++++++++++++++++++++++++---
 src/protocols/kubernetes/kubernetes.h |  26 ++++-
 2 files changed, 164 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b7c938c2/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 62fb6ee..aadb448 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -78,6 +78,127 @@ static void guac_kubernetes_receive_data(guac_client* client,
 }
 
 /**
+ * Requests that the given data be sent along the given channel to the
+ * Kubernetes server when the WebSocket connection is next available for
+ * writing. If the WebSocket connection has not been available for writing for
+ * long enough that the outbound message buffer is full, the request to send
+ * this particular message will be dropped.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @param channel
+ *     The Kubernetes channel on which to send the message,
+ *     such as GUAC_KUBERNETES_CHANNEL_STDIN.
+ *
+ * @param data
+ *     A buffer containing the data to send.
+ *
+ * @param length
+ *     The number of bytes to send.
+ */
+static void guac_kubernetes_send_message(guac_client* client,
+        int channel, const char* data, int length) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    pthread_mutex_lock(&(kubernetes_client->outbound_message_lock));
+
+    /* Add message to buffer if space is available */
+    if (kubernetes_client->outbound_messages_waiting
+            < GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES) {
+
+        /* Calculate storage position of next message */
+        int index = (kubernetes_client->outbound_messages_top
+                  + kubernetes_client->outbound_messages_waiting)
+                  % GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES;
+
+        /* Obtain pointer to message slot at calculated position */
+        guac_kubernetes_message* message =
+            &(kubernetes_client->outbound_messages[index]);
+
+        /* Copy details of message into buffer */
+        message->channel = channel;
+        memcpy(message->data, data, length);
+        message->length = length;
+
+        /* One more message is now waiting */
+        kubernetes_client->outbound_messages_waiting++;
+
+        /* Notify libwebsockets that we need a callback to send pending
+         * messages */
+        lws_callback_on_writable(kubernetes_client->wsi);
+        lws_cancel_service(kubernetes_client->context);
+
+    }
+
+    /* Warn if data has to be dropped */
+    else
+        guac_client_log(client, GUAC_LOG_WARNING, "Send buffer could not be "
+                "flushed in time to handle additional data. Outbound "
+                "message dropped.");
+
+    pthread_mutex_unlock(&(kubernetes_client->outbound_message_lock));
+
+}
+
+/**
+ * Writes the oldest pending message within the outbound message queue,
+ * as scheduled with guac_kubernetes_send_message(), removing that message
+ * from the queue. This function MAY NOT be invoked outside the libwebsockets
+ * event callback and MUST only be invoked in the context of a
+ * LWS_CALLBACK_CLIENT_WRITEABLE event. If no messages are pending, this
+ * function has no effect.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @return
+ *     true if messages still remain to be written within the outbound message
+ *     queue, false otherwise.
+ */
+static bool guac_kubernetes_write_pending_message(guac_client* client) {
+
+    bool messages_remain;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    pthread_mutex_lock(&(kubernetes_client->outbound_message_lock));
+
+    /* Send one message from top of buffer */
+    if (kubernetes_client->outbound_messages_waiting > 0) {
+
+        /* Obtain pointer to message at top */
+        int top = kubernetes_client->outbound_messages_top;
+        guac_kubernetes_message* message =
+            &(kubernetes_client->outbound_messages[top]);
+
+        /* Write message including channel index */
+        lws_write(kubernetes_client->wsi,
+                ((unsigned char*) message) + LWS_PRE,
+                message->length + 1, LWS_WRITE_BINARY);
+
+        /* Advance top to next message */
+        kubernetes_client->outbound_messages_top++;
+        kubernetes_client->outbound_messages_top %=
+            GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES;
+
+        /* One less message is waiting */
+        kubernetes_client->outbound_messages_waiting--;
+
+    }
+
+    /* Record whether messages remained at time of completion */
+    messages_remain = (kubernetes_client->outbound_messages_waiting > 0);
+
+    pthread_mutex_unlock(&(kubernetes_client->outbound_message_lock));
+
+    return messages_remain;
+
+}
+
+/**
  * Callback invoked by libwebsockets for events related to a WebSocket being
  * used for communicating with an attached Kubernetes pod.
  *
@@ -132,8 +253,14 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
             guac_kubernetes_receive_data(client, (const char*) in, length);
             break;
 
-        /* TODO: Only send data here. Request callback for writing via lws_callback_on_writable(some struct lws*) */
+        /* WebSocket is ready for writing */
         case LWS_CALLBACK_CLIENT_WRITEABLE:
+
+            /* Send any pending messages, requesting another callback if
+             * yet more messages remain */
+            if (guac_kubernetes_write_pending_message(client))
+                lws_callback_on_writable(wsi);
+
             break;
 
         /* TODO: Add configure test */
@@ -189,14 +316,15 @@ static void* guac_kubernetes_input_thread(void* data) {
     guac_kubernetes_client* kubernetes_client =
         (guac_kubernetes_client*) client->data;
 
-    char buffer[8192];
+    char buffer[GUAC_KUBERNETES_MAX_MESSAGE_SIZE];
     int bytes_read;
 
     /* Write all data read */
     while ((bytes_read = guac_terminal_read_stdin(kubernetes_client->term, buffer, sizeof(buffer))) > 0) {
 
-        /* TODO: Send to Kubernetes */
-        guac_terminal_write(kubernetes_client->term, buffer, bytes_read);
+        /* Send received data to Kubernetes along STDIN channel */
+        guac_kubernetes_send_message(client, GUAC_KUBERNETES_CHANNEL_STDIN,
+                buffer, bytes_read);
 
     }
 
@@ -206,8 +334,6 @@ static void* guac_kubernetes_input_thread(void* data) {
 
 void* guac_kubernetes_client_thread(void* data) {
 
-    struct lws_context* context = NULL;
-
     guac_client* client = (guac_client*) data;
     guac_kubernetes_client* kubernetes_client =
         (guac_kubernetes_client*) client->data;
@@ -297,15 +423,15 @@ void* guac_kubernetes_client_thread(void* data) {
     }
 
     /* Create libwebsockets context */
-    context = lws_create_context(&context_info);
-    if (!context) {
+    kubernetes_client->context = lws_create_context(&context_info);
+    if (!kubernetes_client->context) {
         guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                 "Initialization of libwebsockets failed");
         goto fail;
     }
 
     /* FIXME: Generate path dynamically */
-    connection_info.context = context;
+    connection_info.context = kubernetes_client->context;
     connection_info.path = "/api/v1/namespaces/default/pods/my-shell-68974bb7f7-rpjgr/attach?container=my-shell&stdin=true&stdout=true&tty=true";
 
     /* Open WebSocket connection to Kubernetes */
@@ -329,7 +455,8 @@ void* guac_kubernetes_client_thread(void* data) {
     while (client->state == GUAC_CLIENT_RUNNING) {
 
         /* Cease polling libwebsockets if an error condition is signalled */
-        if (lws_service(context, 1000) < 0)
+        if (lws_service(kubernetes_client->context,
+                    GUAC_KUBERNETES_SERVICE_INTERVAL) < 0)
             break;
 
     }
@@ -350,8 +477,8 @@ fail:
         guac_common_recording_free(kubernetes_client->recording);
 
     /* Free WebSocket context if successfully allocated */
-    if (context != NULL)
-        lws_context_destroy(context);
+    if (kubernetes_client->context != NULL)
+        lws_context_destroy(kubernetes_client->context);
 
     guac_client_log(client, GUAC_LOG_INFO, "Kubernetes connection ended.");
     return NULL;

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b7c938c2/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index 8fb917d..761a897 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -56,6 +56,13 @@
 #define GUAC_KUBERNETES_CHANNEL_RESIZE 4
 
 /**
+ * The maximum amount of data to include in any particular WebSocket message
+ * to Kubernetes. This excludes the storage space required for the channel
+ * index.
+ */
+#define GUAC_KUBERNETES_MAX_MESSAGE_SIZE 1024
+
+/**
  * The maximum number of messages to allow within the outbound message buffer.
  * If messages are sent despite the buffer being full, those messages will be
  * dropped.
@@ -63,11 +70,23 @@
 #define GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES 8
 
 /**
+ * The maximum number of milliseconds to wait for a libwebsockets event to
+ * occur before entering another iteration of the libwebsockets event loop.
+ */
+#define GUAC_KUBERNETES_SERVICE_INTERVAL 1000
+
+/**
  * An outbound message to be received by Kubernetes over WebSocket.
  */
 typedef struct guac_kubernetes_message {
 
     /**
+     * lws_write() requires leading padding of LWS_PRE bytes to provide
+     * scratch space for WebSocket framing.
+     */
+    uint8_t _padding[LWS_PRE];
+
+    /**
      * The index of the channel receiving the data, such as
      * GUAC_KUBERNETES_CHANNEL_STDIN.
      */
@@ -77,7 +96,7 @@ typedef struct guac_kubernetes_message {
      * The data that should be sent to Kubernetes (along with the channel
      * index).
      */
-    char data[1024];
+    char data[GUAC_KUBERNETES_MAX_MESSAGE_SIZE];
 
     /**
      * The length of the data to be sent, excluding the channel index.
@@ -97,6 +116,11 @@ typedef struct guac_kubernetes_client {
     guac_kubernetes_settings* settings;
 
     /**
+     * The libwebsockets context associated with the connected WebSocket.
+     */
+    struct lws_context* context;
+
+    /**
      * The connected WebSocket.
      */
     struct lws* wsi;


[11/19] guacamole-server git commit: GUACAMOLE-623: Redirect libwebsockets logging to guacd's debug level log.

Posted by vn...@apache.org.
GUACAMOLE-623: Redirect libwebsockets logging to guacd's debug level log.


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

Branch: refs/heads/master
Commit: 34f8f8b30d84e7622005f2ba0ab704758cc88767
Parents: fe7edce
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 15:01:48 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/client.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/34f8f8b3/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
index 77aa647..450e1e8 100644
--- a/src/protocols/kubernetes/client.c
+++ b/src/protocols/kubernetes/client.c
@@ -33,8 +33,39 @@
 
 #include <guacamole/client.h>
 
+/**
+ * Static reference to the guac_client associated with the active Kubernetes
+ * connection. As guacd guarantees that each main client connection is
+ * isolated within its own process, this is safe.
+ */
+static guac_client* guac_kubernetes_lws_log_client = NULL;
+
+/**
+ * Logging callback invoked by libwebsockets to log a single line of logging
+ * output. As libwebsockets messages are all generally low-level, the log
+ * level provided by libwebsockets is ignored here, with all messages logged
+ * instead at guacd's debug level.
+ *
+ * @param level
+ *     The libwebsockets log level associated with the log message. This value
+ *     is ignored by this implementation of the logging callback.
+ *
+ * @param line
+ *     The line of logging output to log.
+ */
+static void guac_kubernetes_log(int level, const char* line) {
+    if (guac_kubernetes_lws_log_client != NULL)
+        guac_client_log(guac_kubernetes_lws_log_client, GUAC_LOG_DEBUG,
+                "libwebsockets: %s", line);
+}
+
 int guac_client_init(guac_client* client) {
 
+    /* Redirect libwebsockets logging */
+    guac_kubernetes_lws_log_client = client;
+    lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO,
+            guac_kubernetes_log);
+
     /* Set client args */
     client->args = GUAC_KUBERNETES_CLIENT_ARGS;
 


[09/19] guacamole-server git commit: GUACAMOLE-623: Add outbound message buffer.

Posted by vn...@apache.org.
GUACAMOLE-623: Add outbound message buffer.


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

Branch: refs/heads/master
Commit: f35517b3ff42f268e20f84282bc93130fa86e98d
Parents: cbe5935
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 01:26:13 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/client.c     | 13 ++-----
 src/protocols/kubernetes/kubernetes.c | 31 ++++++++++++----
 src/protocols/kubernetes/kubernetes.h | 58 ++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/f35517b3/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
index 1b5d175..77aa647 100644
--- a/src/protocols/kubernetes/client.c
+++ b/src/protocols/kubernetes/client.c
@@ -67,17 +67,8 @@ int guac_kubernetes_client_free_handler(guac_client* client) {
     guac_kubernetes_client* kubernetes_client =
         (guac_kubernetes_client*) client->data;
 
-    /* Clean up recording, if in progress */
-    if (kubernetes_client->recording != NULL)
-        guac_common_recording_free(kubernetes_client->recording);
-
-    /* Kill terminal */
-    guac_terminal_free(kubernetes_client->term);
-
-    /* TODO: Wait for and free WebSocket session, if connected */
-    /*if (kubernetes_client->websocket != NULL) {
-        pthread_join(kubernetes_client->client_thread, NULL);
-    }*/
+    /* Wait client thread to terminate */
+    pthread_join(kubernetes_client->client_thread, NULL);
 
     /* Free settings */
     if (kubernetes_client->settings != NULL)

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/f35517b3/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index e38d5e3..62fb6ee 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -206,6 +206,8 @@ static void* guac_kubernetes_input_thread(void* data) {
 
 void* guac_kubernetes_client_thread(void* data) {
 
+    struct lws_context* context = NULL;
+
     guac_client* client = (guac_client*) data;
     guac_kubernetes_client* kubernetes_client =
         (guac_kubernetes_client*) client->data;
@@ -236,7 +238,7 @@ void* guac_kubernetes_client_thread(void* data) {
     if (kubernetes_client->term == NULL) {
         guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                 "Terminal initialization failed");
-        return NULL;
+        goto fail;
     }
 
     /* Set up typescript, if requested */
@@ -295,11 +297,11 @@ void* guac_kubernetes_client_thread(void* data) {
     }
 
     /* Create libwebsockets context */
-    struct lws_context* context = lws_create_context(&context_info);
+    context = lws_create_context(&context_info);
     if (!context) {
         guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                 "Initialization of libwebsockets failed");
-        return NULL;
+        goto fail;
     }
 
     /* FIXME: Generate path dynamically */
@@ -311,13 +313,16 @@ void* guac_kubernetes_client_thread(void* data) {
     if (kubernetes_client->wsi == NULL) {
         guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                 "Connection via libwebsockets failed");
-        return NULL;
+        goto fail;
     }
 
+    /* Init outbound message buffer */
+    pthread_mutex_init(&(kubernetes_client->outbound_message_lock), NULL);
+
     /* Start input thread */
     if (pthread_create(&(input_thread), NULL, guac_kubernetes_input_thread, (void*) client)) {
         guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
-        return NULL;
+        goto fail;
     }
 
     /* As long as client is connected, continue polling libwebsockets */
@@ -330,11 +335,23 @@ void* guac_kubernetes_client_thread(void* data) {
     }
 
     /* Kill client and Wait for input thread to die */
+    guac_terminal_stop(kubernetes_client->term);
     guac_client_stop(client);
     pthread_join(input_thread, NULL);
 
-    /* All done with libwebsockets */
-    lws_context_destroy(context);
+fail:
+
+    /* Kill and free terminal, if allocated */
+    if (kubernetes_client->term != NULL)
+        guac_terminal_free(kubernetes_client->term);
+
+    /* Clean up recording, if in progress */
+    if (kubernetes_client->recording != NULL)
+        guac_common_recording_free(kubernetes_client->recording);
+
+    /* Free WebSocket context if successfully allocated */
+    if (context != NULL)
+        lws_context_destroy(context);
 
     guac_client_log(client, GUAC_LOG_INFO, "Kubernetes connection ended.");
     return NULL;

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/f35517b3/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index 89b6678..8fb917d 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -56,6 +56,37 @@
 #define GUAC_KUBERNETES_CHANNEL_RESIZE 4
 
 /**
+ * The maximum number of messages to allow within the outbound message buffer.
+ * If messages are sent despite the buffer being full, those messages will be
+ * dropped.
+ */
+#define GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES 8
+
+/**
+ * An outbound message to be received by Kubernetes over WebSocket.
+ */
+typedef struct guac_kubernetes_message {
+
+    /**
+     * The index of the channel receiving the data, such as
+     * GUAC_KUBERNETES_CHANNEL_STDIN.
+     */
+    uint8_t channel;
+
+    /**
+     * The data that should be sent to Kubernetes (along with the channel
+     * index).
+     */
+    char data[1024];
+
+    /**
+     * The length of the data to be sent, excluding the channel index.
+     */
+    int length;
+
+} guac_kubernetes_message;
+
+/**
  * Kubernetes-specific client data.
  */
 typedef struct guac_kubernetes_client {
@@ -71,6 +102,33 @@ typedef struct guac_kubernetes_client {
     struct lws* wsi;
 
     /**
+     * Outbound message ring buffer for outbound WebSocket messages. As
+     * libwebsockets uses an event loop for all operations, outbound messages
+     * may be sent only in context of a particular event received via a
+     * callback. Until that event is received, pending data must accumulate in
+     * a buffer.
+     */
+    guac_kubernetes_message outbound_messages[GUAC_KUBERNETES_MAX_OUTBOUND_MESSAGES];
+
+    /**
+     * The number of messages currently waiting in the outbound message
+     * buffer.
+     */
+    int outbound_messages_waiting;
+
+    /**
+     * The index of the oldest entry in the outbound message buffer. Newer
+     * messages follow this entry.
+     */
+    int outbound_messages_top;
+
+    /**
+     * Lock which is acquired when the outbound message buffer is being read
+     * or manipulated.
+     */
+    pthread_mutex_t outbound_message_lock;
+
+    /**
      * The Kubernetes client thread.
      */
     pthread_t client_thread;


[05/19] guacamole-server git commit: GUACAMOLE-623: Add base skeleton for Kubernetes protocol support.

Posted by vn...@apache.org.
GUACAMOLE-623: Add base skeleton for Kubernetes protocol support.


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

Branch: refs/heads/master
Commit: b8bd0e4c6a63995c18050fa4f88fa09b97f7a90c
Parents: 54fda21
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 9 20:03:40 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 Makefile.am                           |   4 +
 configure.ac                          |  60 ++++-
 src/protocols/kubernetes/Makefile.am  |  57 +++++
 src/protocols/kubernetes/client.c     |  91 +++++++
 src/protocols/kubernetes/client.h     |  41 ++++
 src/protocols/kubernetes/clipboard.c  |  67 ++++++
 src/protocols/kubernetes/clipboard.h  |  43 ++++
 src/protocols/kubernetes/input.c      |  95 ++++++++
 src/protocols/kubernetes/input.h      |  46 ++++
 src/protocols/kubernetes/kubernetes.c | 136 +++++++++++
 src/protocols/kubernetes/kubernetes.h |  71 ++++++
 src/protocols/kubernetes/pipe.c       |  51 ++++
 src/protocols/kubernetes/pipe.h       |  42 ++++
 src/protocols/kubernetes/settings.c   | 366 +++++++++++++++++++++++++++++
 src/protocols/kubernetes/settings.h   | 256 ++++++++++++++++++++
 src/protocols/kubernetes/user.c       | 116 +++++++++
 src/protocols/kubernetes/user.h       |  38 +++
 17 files changed, 1572 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
index e923376..91c8abe 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,6 +52,10 @@ if ENABLE_PULSE
 SUBDIRS += src/pulse
 endif
 
+if ENABLE_KUBERNETES
+SUBDIRS += src/protocols/kubernetes
+endif
+
 if ENABLE_RDP
 SUBDIRS += src/protocols/rdp
 endif

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 6b20c97..ae78324 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1173,6 +1173,46 @@ AM_CONDITIONAL([ENABLE_WEBP], [test "x${have_webp}" = "xyes"])
 AC_SUBST(WEBP_LIBS)
 
 #
+# libwebsockets
+#
+
+have_libwebsockets=disabled
+WEBSOCKETS_LIBS=
+AC_ARG_WITH([websockets],
+            [AS_HELP_STRING([--with-websockets],
+                            [support WebSockets @<:@default=check@:>@])],
+            [],
+            [with_websockets=check])
+
+if test "x$with_websockets" != "xno"
+then
+    have_libwebsockets=yes
+    AC_CHECK_LIB([websockets],
+                 [lws_create_context],
+                 [WEBSOCKETS_LIBS="$WEBSOCKETS_LIBS -lwebsockets"],
+                 [have_libwebsockets=no])
+fi
+
+AM_CONDITIONAL([ENABLE_WEBSOCKETS],
+               [test "x${have_libwebsockets}"  = "xyes"])
+
+AC_SUBST(WEBSOCKETS_LIBS)
+
+#
+# Kubernetes
+#
+
+AC_ARG_ENABLE([kubernetes],
+              [AS_HELP_STRING([--disable-kubernetes],
+                              [do not build support for attaching to Kubernetes pods])],
+              [],
+              [enable_kubernetes=yes])
+
+AM_CONDITIONAL([ENABLE_KUBERNETES], [test "x${enable_kubernetes}"  = "xyes" \
+                                       -a "x${have_libwebsockets}" = "xyes" \
+                                       -a "x${have_terminal}"      = "xyes"])
+
+#
 # guacd
 #
 
@@ -1230,6 +1270,7 @@ AC_CONFIG_FILES([Makefile
                  src/guaclog/Makefile
                  src/guaclog/man/guaclog.1
                  src/pulse/Makefile
+                 src/protocols/kubernetes/Makefile
                  src/protocols/rdp/Makefile
                  src/protocols/ssh/Makefile
                  src/protocols/telnet/Makefile
@@ -1240,10 +1281,11 @@ AC_OUTPUT
 # Protocol build status
 #
 
-AM_COND_IF([ENABLE_RDP],    [build_rdp=yes],    [build_rdp=no])
-AM_COND_IF([ENABLE_SSH],    [build_ssh=yes],    [build_ssh=no])
-AM_COND_IF([ENABLE_TELNET], [build_telnet=yes], [build_telnet=no])
-AM_COND_IF([ENABLE_VNC],    [build_vnc=yes],    [build_vnc=no])
+AM_COND_IF([ENABLE_KUBERNETES], [build_kubernetes=yes], [build_kubernetes=no])
+AM_COND_IF([ENABLE_RDP],        [build_rdp=yes],        [build_rdp=no])
+AM_COND_IF([ENABLE_SSH],        [build_ssh=yes],        [build_ssh=no])
+AM_COND_IF([ENABLE_TELNET],     [build_telnet=yes],     [build_telnet=no])
+AM_COND_IF([ENABLE_VNC],        [build_vnc=yes],        [build_vnc=no])
 
 #
 # Service / tool build status
@@ -1287,15 +1329,17 @@ $PACKAGE_NAME version $PACKAGE_VERSION
      libVNCServer ........ ${have_libvncserver}
      libvorbis ........... ${have_vorbis}
      libpulse ............ ${have_pulse}
+     libwebsockets ....... ${have_websockets}
      libwebp ............. ${have_webp}
      wsock32 ............. ${have_winsock}
 
    Protocol support:
 
-      RDP ....... ${build_rdp}
-      SSH ....... ${build_ssh}
-      Telnet .... ${build_telnet}
-      VNC ....... ${build_vnc}
+      Kubernetes .... ${build_kubernetes}
+      RDP ........... ${build_rdp}
+      SSH ........... ${build_ssh}
+      Telnet ........ ${build_telnet}
+      VNC ........... ${build_vnc}
 
    Services / tools:
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/Makefile.am b/src/protocols/kubernetes/Makefile.am
new file mode 100644
index 0000000..d864967
--- /dev/null
+++ b/src/protocols/kubernetes/Makefile.am
@@ -0,0 +1,57 @@
+#
+# 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
+ACLOCAL_AMFLAGS = -I m4
+
+lib_LTLIBRARIES = libguac-client-kubernetes.la
+
+libguac_client_kubernetes_la_SOURCES = \
+    client.c                           \
+    clipboard.c                        \
+    input.c                            \
+    pipe.c                             \
+    settings.c                         \
+    kubernetes.c                       \
+    user.c
+
+noinst_HEADERS = \
+    client.h     \
+    clipboard.h  \
+    input.h      \
+    pipe.h       \
+    settings.h   \
+    kubernetes.h \
+    user.h
+
+libguac_client_kubernetes_la_CFLAGS = \
+    -Werror -Wall -Iinclude           \
+    @LIBGUAC_INCLUDE@                 \
+    @TERMINAL_INCLUDE@
+
+libguac_client_kubernetes_la_LIBADD = \
+    @COMMON_LTLIB@                    \
+    @LIBGUAC_LTLIB@                   \
+    @TERMINAL_LTLIB@
+
+libguac_client_kubernetes_la_LDFLAGS = \
+    -version-info 0:0:0                \
+    @PTHREAD_LIBS@                     \
+    @WEBSOCKETS_LIBS@
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
new file mode 100644
index 0000000..1b5d175
--- /dev/null
+++ b/src/protocols/kubernetes/client.c
@@ -0,0 +1,91 @@
+/*
+ * 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 "client.h"
+#include "common/recording.h"
+#include "kubernetes.h"
+#include "settings.h"
+#include "terminal/terminal.h"
+#include "user.h"
+
+#include <langinfo.h>
+#include <locale.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <guacamole/client.h>
+
+int guac_client_init(guac_client* client) {
+
+    /* Set client args */
+    client->args = GUAC_KUBERNETES_CLIENT_ARGS;
+
+    /* Allocate client instance data */
+    guac_kubernetes_client* kubernetes_client = calloc(1, sizeof(guac_kubernetes_client));
+    client->data = kubernetes_client;
+
+    /* Init clipboard */
+    kubernetes_client->clipboard = guac_common_clipboard_alloc(GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH);
+
+    /* Set handlers */
+    client->join_handler = guac_kubernetes_user_join_handler;
+    client->free_handler = guac_kubernetes_client_free_handler;
+
+    /* Set locale and warn if not UTF-8 */
+    setlocale(LC_CTYPE, "");
+    if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) {
+        guac_client_log(client, GUAC_LOG_INFO,
+                "Current locale does not use UTF-8. Some characters may "
+                "not render correctly.");
+    }
+
+    /* Success */
+    return 0;
+
+}
+
+int guac_kubernetes_client_free_handler(guac_client* client) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Clean up recording, if in progress */
+    if (kubernetes_client->recording != NULL)
+        guac_common_recording_free(kubernetes_client->recording);
+
+    /* Kill terminal */
+    guac_terminal_free(kubernetes_client->term);
+
+    /* TODO: Wait for and free WebSocket session, if connected */
+    /*if (kubernetes_client->websocket != NULL) {
+        pthread_join(kubernetes_client->client_thread, NULL);
+    }*/
+
+    /* Free settings */
+    if (kubernetes_client->settings != NULL)
+        guac_kubernetes_settings_free(kubernetes_client->settings);
+
+    guac_common_clipboard_free(kubernetes_client->clipboard);
+    free(kubernetes_client);
+    return 0;
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/client.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.h b/src/protocols/kubernetes/client.h
new file mode 100644
index 0000000..2e96d10
--- /dev/null
+++ b/src/protocols/kubernetes/client.h
@@ -0,0 +1,41 @@
+/*
+ * 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 GUAC_KUBERNETES_CLIENT_H
+#define GUAC_KUBERNETES_CLIENT_H
+
+#include "config.h"
+#include "terminal/terminal.h"
+
+#include <pthread.h>
+#include <sys/types.h>
+
+/**
+ * The maximum number of bytes to allow within the clipboard.
+ */
+#define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
+
+/**
+ * Free handler. Required by libguac and called when the guac_client is
+ * disconnected and must be cleaned up.
+ */
+guac_client_free_handler guac_kubernetes_client_free_handler;
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/clipboard.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/clipboard.c b/src/protocols/kubernetes/clipboard.c
new file mode 100644
index 0000000..87a34b0
--- /dev/null
+++ b/src/protocols/kubernetes/clipboard.c
@@ -0,0 +1,67 @@
+/*
+ * 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 "clipboard.h"
+#include "common/clipboard.h"
+#include "kubernetes.h"
+#include "terminal/terminal.h"
+
+#include <guacamole/client.h>
+#include <guacamole/stream.h>
+#include <guacamole/user.h>
+
+int guac_kubernetes_clipboard_handler(guac_user* user, guac_stream* stream,
+        char* mimetype) {
+
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Clear clipboard and prepare for new data */
+    guac_common_clipboard_reset(kubernetes_client->clipboard, mimetype);
+
+    /* Set handlers for clipboard stream */
+    stream->blob_handler = guac_kubernetes_clipboard_blob_handler;
+    stream->end_handler = guac_kubernetes_clipboard_end_handler;
+
+    return 0;
+}
+
+int guac_kubernetes_clipboard_blob_handler(guac_user* user,
+        guac_stream* stream, void* data, int length) {
+
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Append new data */
+    guac_common_clipboard_append(kubernetes_client->clipboard, data, length);
+
+    return 0;
+}
+
+int guac_kubernetes_clipboard_end_handler(guac_user* user,
+        guac_stream* stream) {
+
+    /* Nothing to do - clipboard is implemented within client */
+
+    return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/clipboard.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/clipboard.h b/src/protocols/kubernetes/clipboard.h
new file mode 100644
index 0000000..009219c
--- /dev/null
+++ b/src/protocols/kubernetes/clipboard.h
@@ -0,0 +1,43 @@
+/*
+ * 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 GUAC_KUBERNETES_CLIPBOARD_H
+#define GUAC_KUBERNETES_CLIPBOARD_H
+
+#include "config.h"
+
+#include <guacamole/user.h>
+
+/**
+ * Handler for inbound clipboard streams.
+ */
+guac_user_clipboard_handler guac_kubernetes_clipboard_handler;
+
+/**
+ * Handler for data received along clipboard streams.
+ */
+guac_user_blob_handler guac_kubernetes_clipboard_blob_handler;
+
+/**
+ * Handler for end-of-stream related to clipboard.
+ */
+guac_user_end_handler guac_kubernetes_clipboard_end_handler;
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/input.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/input.c b/src/protocols/kubernetes/input.c
new file mode 100644
index 0000000..9bf5b71
--- /dev/null
+++ b/src/protocols/kubernetes/input.c
@@ -0,0 +1,95 @@
+/*
+ * 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 "common/recording.h"
+#include "kubernetes.h"
+#include "input.h"
+#include "terminal/terminal.h"
+
+#include <guacamole/client.h>
+#include <guacamole/user.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int guac_kubernetes_user_mouse_handler(guac_user* user,
+        int x, int y, int mask) {
+
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Skip if terminal not yet ready */
+    guac_terminal* term = kubernetes_client->term;
+    if (term == NULL)
+        return 0;
+
+    /* Report mouse position within recording */
+    if (kubernetes_client->recording != NULL)
+        guac_common_recording_report_mouse(kubernetes_client->recording, x, y,
+                mask);
+
+    guac_terminal_send_mouse(term, user, x, y, mask);
+    return 0;
+
+}
+
+int guac_kubernetes_user_key_handler(guac_user* user, int keysym, int pressed) {
+
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Report key state within recording */
+    if (kubernetes_client->recording != NULL)
+        guac_common_recording_report_key(kubernetes_client->recording,
+                keysym, pressed);
+
+    /* Skip if terminal not yet ready */
+    guac_terminal* term = kubernetes_client->term;
+    if (term == NULL)
+        return 0;
+
+    guac_terminal_send_key(term, keysym, pressed);
+    return 0;
+
+}
+
+int guac_kubernetes_user_size_handler(guac_user* user, int width, int height) {
+
+    /* Get terminal */
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Skip if terminal not yet ready */
+    guac_terminal* terminal = kubernetes_client->term;
+    if (terminal == NULL)
+        return 0;
+
+    /* Resize terminal */
+    guac_terminal_resize(terminal, width, height);
+
+    /* TODO: Update Kubernetes terminal window size if connected */
+
+    return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/input.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/input.h b/src/protocols/kubernetes/input.h
new file mode 100644
index 0000000..ac65835
--- /dev/null
+++ b/src/protocols/kubernetes/input.h
@@ -0,0 +1,46 @@
+/*
+ * 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 GUAC_KUBERNETES_INPUT_H
+#define GUAC_KUBERNETES_INPUT_H
+
+#include "config.h"
+
+#include <guacamole/user.h>
+
+/**
+ * Handler for key events. Required by libguac and called whenever key events
+ * are received.
+ */
+guac_user_key_handler guac_kubernetes_user_key_handler;
+
+/**
+ * Handler for mouse events. Required by libguac and called whenever mouse
+ * events are received.
+ */
+guac_user_mouse_handler guac_kubernetes_user_mouse_handler;
+
+/**
+ * Handler for size events. Required by libguac and called whenever the remote
+ * display (window) is resized.
+ */
+guac_user_size_handler guac_kubernetes_user_size_handler;
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
new file mode 100644
index 0000000..231d78d
--- /dev/null
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -0,0 +1,136 @@
+/*
+ * 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 "common/recording.h"
+#include "kubernetes.h"
+#include "terminal/terminal.h"
+
+#include <guacamole/client.h>
+#include <guacamole/protocol.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/**
+ * Input thread, started by the main Kubernetes client thread. This thread
+ * continuously reads from the terminal's STDIN and transfers all read
+ * data to the Kubernetes connection.
+ *
+ * @param data
+ *     The current guac_client instance.
+ *
+ * @return
+ *     Always NULL.
+ */
+static void* guac_kubernetes_input_thread(void* data) {
+
+    guac_client* client = (guac_client*) data;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    char buffer[8192];
+    int bytes_read;
+
+    /* Write all data read */
+    while ((bytes_read = guac_terminal_read_stdin(kubernetes_client->term, buffer, sizeof(buffer))) > 0) {
+
+        /* TODO: Send to Kubernetes */
+        guac_terminal_write(kubernetes_client->term, buffer, bytes_read);
+
+    }
+
+    return NULL;
+
+}
+
+void* guac_kubernetes_client_thread(void* data) {
+
+    guac_client* client = (guac_client*) data;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    guac_kubernetes_settings* settings = kubernetes_client->settings;
+
+    pthread_t input_thread;
+
+    /* Set up screen recording, if requested */
+    if (settings->recording_path != NULL) {
+        kubernetes_client->recording = guac_common_recording_create(client,
+                settings->recording_path,
+                settings->recording_name,
+                settings->create_recording_path,
+                !settings->recording_exclude_output,
+                !settings->recording_exclude_mouse,
+                settings->recording_include_keys);
+    }
+
+    /* Create terminal */
+    kubernetes_client->term = guac_terminal_create(client,
+            kubernetes_client->clipboard,
+            settings->max_scrollback, settings->font_name, settings->font_size,
+            settings->resolution, settings->width, settings->height,
+            settings->color_scheme, settings->backspace);
+
+    /* Fail if terminal init failed */
+    if (kubernetes_client->term == NULL) {
+        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                "Terminal initialization failed");
+        return NULL;
+    }
+
+    /* Set up typescript, if requested */
+    if (settings->typescript_path != NULL) {
+        guac_terminal_create_typescript(kubernetes_client->term,
+                settings->typescript_path,
+                settings->typescript_name,
+                settings->create_typescript_path);
+    }
+
+    /* TODO: Open WebSocket connection to Kubernetes */
+
+    /* Logged in */
+    guac_client_log(client, GUAC_LOG_INFO,
+            "Kubernetes connection successful.");
+
+    /* Start input thread */
+    if (pthread_create(&(input_thread), NULL, guac_kubernetes_input_thread, (void*) client)) {
+        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
+        return NULL;
+    }
+
+    /* TODO: While data available, write to terminal */
+
+    /* Kill client and Wait for input thread to die */
+    guac_client_stop(client);
+    pthread_join(input_thread, NULL);
+
+    guac_client_log(client, GUAC_LOG_INFO, "Kubernetes connection ended.");
+    return NULL;
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
new file mode 100644
index 0000000..f8035ae
--- /dev/null
+++ b/src/protocols/kubernetes/kubernetes.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 GUAC_KUBERNETES_H
+#define GUAC_KUBERNETES_H
+
+#include "config.h"
+#include "common/clipboard.h"
+#include "common/recording.h"
+#include "settings.h"
+#include "terminal/terminal.h"
+
+#include <stdint.h>
+
+/**
+ * Kubernetes-specific client data.
+ */
+typedef struct guac_kubernetes_client {
+
+    /**
+     * Kubernetes connection settings.
+     */
+    guac_kubernetes_settings* settings;
+
+    /**
+     * The Kubernetes client thread.
+     */
+    pthread_t client_thread;
+
+    /**
+     * The current clipboard contents.
+     */
+    guac_common_clipboard* clipboard;
+
+    /**
+     * The terminal which will render all output from the Kubernetes pod.
+     */
+    guac_terminal* term;
+
+    /**
+     * The in-progress session recording, or NULL if no recording is in
+     * progress.
+     */
+    guac_common_recording* recording;
+
+} guac_kubernetes_client;
+
+/**
+ * Main Kubernetes client thread, handling transfer of STDOUT/STDERR of an
+ * attached Kubernetes pod to STDOUT of the terminal.
+ */
+void* guac_kubernetes_client_thread(void* data);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/pipe.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/pipe.c b/src/protocols/kubernetes/pipe.c
new file mode 100644
index 0000000..242105b
--- /dev/null
+++ b/src/protocols/kubernetes/pipe.c
@@ -0,0 +1,51 @@
+/*
+ * 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 "kubernetes.h"
+#include "pipe.h"
+#include "terminal/terminal.h"
+
+#include <guacamole/protocol.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+#include <string.h>
+
+int guac_kubernetes_pipe_handler(guac_user* user, guac_stream* stream,
+        char* mimetype, char* name) {
+
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Redirect STDIN if pipe has required name */
+    if (strcmp(name, GUAC_KUBERNETES_STDIN_PIPE_NAME) == 0) {
+        guac_terminal_send_stream(kubernetes_client->term, user, stream);
+        return 0;
+    }
+
+    /* No other inbound pipe streams are supported */
+    guac_protocol_send_ack(user->socket, stream, "No such input stream.",
+            GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
+    guac_socket_flush(user->socket);
+    return 0;
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/pipe.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/pipe.h b/src/protocols/kubernetes/pipe.h
new file mode 100644
index 0000000..7acae3c
--- /dev/null
+++ b/src/protocols/kubernetes/pipe.h
@@ -0,0 +1,42 @@
+/*
+ * 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 GUAC_KUBERNETES_PIPE_H
+#define GUAC_KUBERNETES_PIPE_H
+
+#include "config.h"
+
+#include <guacamole/user.h>
+
+/**
+ * The name reserved for the inbound pipe stream which forces the terminal
+ * emulator's STDIN to be received from the pipe.
+ */
+#define GUAC_KUBERNETES_STDIN_PIPE_NAME "STDIN"
+
+/**
+ * Handles an incoming stream from a Guacamole "pipe" instruction. If the pipe
+ * is named "STDIN", the the contents of the pipe stream are redirected to
+ * STDIN of the terminal emulator for as long as the pipe is open.
+ */
+guac_user_pipe_handler guac_kubernetes_pipe_handler;
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
new file mode 100644
index 0000000..1f04b40
--- /dev/null
+++ b/src/protocols/kubernetes/settings.c
@@ -0,0 +1,366 @@
+/*
+ * 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 "settings.h"
+
+#include <guacamole/user.h>
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* Client plugin arguments */
+const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
+    "hostname",
+    "port",
+    "use-ssl",
+    "client-cert-file",
+    "client-key-file",
+    "ca-cert-file",
+    "ignore-cert",
+    "font-name",
+    "font-size",
+    "color-scheme",
+    "typescript-path",
+    "typescript-name",
+    "create-typescript-path",
+    "recording-path",
+    "recording-name",
+    "recording-exclude-output",
+    "recording-exclude-mouse",
+    "recording-include-keys",
+    "create-recording-path",
+    "read-only",
+    "backspace",
+    "scrollback",
+    NULL
+};
+
+enum KUBERNETES_ARGS_IDX {
+
+    /**
+     * The hostname to connect to. Required.
+     */
+    IDX_HOSTNAME,
+
+    /**
+     * The port to connect to. Optional.
+     */
+    IDX_PORT,
+
+    /**
+     * Whether SSL/TLS should be used. SSL is used by default.
+     */
+    IDX_USE_SSL,
+
+    /**
+     * The filename of the certificate to use if performing SSL/TLS client
+     * authentication to authenticate with the Kubernetes server. If omitted,
+     * SSL client authentication will not be performed. 
+     */
+    IDX_CLIENT_CERT_FILE,
+
+    /**
+     * The filename of the key to use if performing SSL/TLS client
+     * authentication to authenticate with the Kubernetes server. If omitted,
+     * SSL client authentication will not be performed. 
+     */
+    IDX_CLIENT_KEY_FILE,
+
+    /**
+     * The filename of the certificate of the certificate authority that signed
+     * the certificate of the Kubernetes server.
+     */
+    IDX_CA_CERT_FILE,
+
+    /**
+     * Whether the certificate used by the Kubernetes server for SSL/TLS should
+     * be ignored if it cannot be validated.
+     */
+    IDX_IGNORE_CERT,
+
+    /**
+     * The name of the font to use within the terminal.
+     */
+    IDX_FONT_NAME,
+
+    /**
+     * The size of the font to use within the terminal, in points.
+     */
+    IDX_FONT_SIZE,
+
+    /**
+     * The color scheme to use, as a series of semicolon-separated color-value
+     * pairs: "background: <color>", "foreground: <color>", or
+     * "color<n>: <color>", where <n> is a number from 0 to 255, and <color> is
+     * "color<n>" or an X11 color code (e.g. "aqua" or "rgb:12/34/56").
+     * The color scheme can also be one of the special values: "black-white",
+     * "white-black", "gray-black", or "green-black".
+     */
+    IDX_COLOR_SCHEME,
+
+    /**
+     * The full absolute path to the directory in which typescripts should be
+     * written.
+     */
+    IDX_TYPESCRIPT_PATH,
+
+    /**
+     * The name that should be given to typescripts which are written in the
+     * given path. Each typescript will consist of two files: "NAME" and
+     * "NAME.timing".
+     */
+    IDX_TYPESCRIPT_NAME,
+
+    /**
+     * Whether the specified typescript path should automatically be created
+     * if it does not yet exist.
+     */
+    IDX_CREATE_TYPESCRIPT_PATH,
+
+    /**
+     * The full absolute path to the directory in which screen recordings
+     * should be written.
+     */
+    IDX_RECORDING_PATH,
+
+    /**
+     * The name that should be given to screen recordings which are written in
+     * the given path.
+     */
+    IDX_RECORDING_NAME,
+
+    /**
+     * Whether output which is broadcast to each connected client (graphics,
+     * streams, etc.) should NOT be included in the session recording. Output
+     * is included by default, as it is necessary for any recording which must
+     * later be viewable as video.
+     */
+    IDX_RECORDING_EXCLUDE_OUTPUT,
+
+    /**
+     * Whether changes to mouse state, such as position and buttons pressed or
+     * released, should NOT be included in the session recording. Mouse state
+     * is included by default, as it is necessary for the mouse cursor to be
+     * rendered in any resulting video.
+     */
+    IDX_RECORDING_EXCLUDE_MOUSE,
+
+    /**
+     * Whether keys pressed and released should be included in the session
+     * recording. Key events are NOT included by default within the recording,
+     * as doing so has privacy and security implications.  Including key events
+     * may be necessary in certain auditing contexts, but should only be done
+     * with caution. Key events can easily contain sensitive information, such
+     * as passwords, credit card numbers, etc.
+     */
+    IDX_RECORDING_INCLUDE_KEYS,
+
+    /**
+     * Whether the specified screen recording path should automatically be
+     * created if it does not yet exist.
+     */
+    IDX_CREATE_RECORDING_PATH,
+
+    /**
+     * "true" if this connection should be read-only (user input should be
+     * dropped), "false" or blank otherwise.
+     */
+    IDX_READ_ONLY,
+
+    /**
+     * ASCII code, as an integer to use for the backspace key, or 127
+     * if not specified.
+     */
+    IDX_BACKSPACE,
+
+    /**
+     * The maximum size of the scrollback buffer in rows.
+     */
+    IDX_SCROLLBACK,
+
+    KUBERNETES_ARGS_COUNT
+};
+
+guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
+        int argc, const char** argv) {
+
+    /* Validate arg count */
+    if (argc != KUBERNETES_ARGS_COUNT) {
+        guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
+                "parameters provided: expected %i, got %i.",
+                KUBERNETES_ARGS_COUNT, argc);
+        return NULL;
+    }
+
+    guac_kubernetes_settings* settings =
+        calloc(1, sizeof(guac_kubernetes_settings));
+
+    /* Read parameters */
+    settings->hostname =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_HOSTNAME, "");
+
+    /* Parse whether SSL should be used */
+    settings->use_ssl =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_USE_SSL, true);
+
+    /* Read SSL/TLS connection details only if enabled */
+    if (settings->use_ssl) {
+
+        settings->client_cert_file =
+            guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
+                    argv, IDX_CLIENT_CERT_FILE, NULL);
+
+        settings->client_key_file =
+            guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
+                    argv, IDX_CLIENT_KEY_FILE, NULL);
+
+        settings->ca_cert_file =
+            guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
+                    argv, IDX_CA_CERT_FILE, NULL);
+
+        settings->ignore_cert =
+            guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
+                    argv, IDX_IGNORE_CERT, false);
+
+    }
+
+    /* Read-only mode */
+    settings->read_only =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_READ_ONLY, false);
+
+    /* Read maximum scrollback size */
+    settings->max_scrollback =
+        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_SCROLLBACK, GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK);
+
+    /* Read font name */
+    settings->font_name =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_FONT_NAME, GUAC_KUBERNETES_DEFAULT_FONT_NAME);
+
+    /* Read font size */
+    settings->font_size =
+        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_FONT_SIZE, GUAC_KUBERNETES_DEFAULT_FONT_SIZE);
+
+    /* Copy requested color scheme */
+    settings->color_scheme =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_COLOR_SCHEME, "");
+
+    /* Pull width/height/resolution directly from user */
+    settings->width      = user->info.optimal_width;
+    settings->height     = user->info.optimal_height;
+    settings->resolution = user->info.optimal_resolution;
+
+    /* Read port */
+    settings->port =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_PORT, GUAC_KUBERNETES_DEFAULT_PORT);
+
+    /* Read typescript path */
+    settings->typescript_path =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_TYPESCRIPT_PATH, NULL);
+
+    /* Read typescript name */
+    settings->typescript_name =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_TYPESCRIPT_NAME, GUAC_KUBERNETES_DEFAULT_TYPESCRIPT_NAME);
+
+    /* Parse path creation flag */
+    settings->create_typescript_path =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_CREATE_TYPESCRIPT_PATH, false);
+
+    /* Read recording path */
+    settings->recording_path =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_RECORDING_PATH, NULL);
+
+    /* Read recording name */
+    settings->recording_name =
+        guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_RECORDING_NAME, GUAC_KUBERNETES_DEFAULT_RECORDING_NAME);
+
+    /* Parse output exclusion flag */
+    settings->recording_exclude_output =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_RECORDING_EXCLUDE_OUTPUT, false);
+
+    /* Parse mouse exclusion flag */
+    settings->recording_exclude_mouse =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_RECORDING_EXCLUDE_MOUSE, false);
+
+    /* Parse key event inclusion flag */
+    settings->recording_include_keys =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_RECORDING_INCLUDE_KEYS, false);
+
+    /* Parse path creation flag */
+    settings->create_recording_path =
+        guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_CREATE_RECORDING_PATH, false);
+
+    /* Parse backspace key code */
+    settings->backspace =
+        guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
+                IDX_BACKSPACE, 127);
+
+    /* Parsing was successful */
+    return settings;
+
+}
+
+void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
+
+    /* Free network connection information */
+    free(settings->hostname);
+    free(settings->port);
+
+    /* Free SSL/TLS details */
+    free(settings->client_cert_file);
+    free(settings->client_key_file);
+    free(settings->ca_cert_file);
+
+    /* Free display preferences */
+    free(settings->font_name);
+    free(settings->color_scheme);
+
+    /* Free typescript settings */
+    free(settings->typescript_name);
+    free(settings->typescript_path);
+
+    /* Free screen recording settings */
+    free(settings->recording_name);
+    free(settings->recording_path);
+
+    /* Free overall structure */
+    free(settings);
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
new file mode 100644
index 0000000..3e89ce5
--- /dev/null
+++ b/src/protocols/kubernetes/settings.h
@@ -0,0 +1,256 @@
+/*
+ * 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 GUAC_KUBERNETES_SETTINGS_H
+#define GUAC_KUBERNETES_SETTINGS_H
+
+#include "config.h"
+
+#include <guacamole/user.h>
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+/**
+ * The name of the font to use for the terminal if no name is specified.
+ */
+#define GUAC_KUBERNETES_DEFAULT_FONT_NAME "monospace" 
+
+/**
+ * The size of the font to use for the terminal if no font size is specified,
+ * in points.
+ */
+#define GUAC_KUBERNETES_DEFAULT_FONT_SIZE 12
+
+/**
+ * The port to connect to when initiating any Kubernetes connection, if no
+ * other port is specified.
+ */
+#define GUAC_KUBERNETES_DEFAULT_PORT "8443"
+
+/**
+ * The filename to use for the typescript, if not specified.
+ */
+#define GUAC_KUBERNETES_DEFAULT_TYPESCRIPT_NAME "typescript" 
+
+/**
+ * The filename to use for the screen recording, if not specified.
+ */
+#define GUAC_KUBERNETES_DEFAULT_RECORDING_NAME "recording"
+
+/**
+ * The default maximum scrollback size in rows.
+ */
+#define GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK 1000
+
+/**
+ * Settings for the Kubernetes connection. The values for this structure are
+ * parsed from the arguments given during the Guacamole protocol handshake
+ * using the guac_kubernetes_parse_args() function.
+ */
+typedef struct guac_kubernetes_settings {
+
+    /**
+     * The hostname of the Kubernetes server to connect to.
+     */
+    char* hostname;
+
+    /**
+     * The port of the Kubernetes server to connect to.
+     */
+    char* port;
+
+    /**
+     * Whether SSL/TLS should be used.
+     */
+    bool use_ssl;
+
+    /**
+     * The filename of the certificate to use if performing SSL/TLS client
+     * authentication to authenticate with the Kubernetes server. If omitted,
+     * SSL client authentication will not be performed.
+     */
+    char* client_cert_file;
+
+    /**
+     * The filename of the key to use if performing SSL/TLS client
+     * authentication to authenticate with the Kubernetes server. If omitted,
+     * SSL client authentication will not be performed. 
+     */
+    char* client_key_file;
+
+    /**
+     * The filename of the certificate of the certificate authority that signed
+     * the certificate of the Kubernetes server.
+     */
+    char* ca_cert_file;
+
+    /**
+     * Whether the certificate used by the Kubernetes server for SSL/TLS should
+     * be ignored if it cannot be validated.
+     */
+    bool ignore_cert;
+
+    /**
+     * Whether this connection is read-only, and user input should be dropped.
+     */
+    bool read_only;
+
+    /**
+     * The maximum size of the scrollback buffer in rows.
+     */
+    int max_scrollback;
+
+    /**
+     * The name of the font to use for display rendering.
+     */
+    char* font_name;
+
+    /**
+     * The size of the font to use, in points.
+     */
+    int font_size;
+
+    /**
+     * The name of the color scheme to use.
+     */
+    char* color_scheme; 
+
+    /**
+     * The desired width of the terminal display, in pixels.
+     */
+    int width;
+
+    /**
+     * The desired height of the terminal display, in pixels.
+     */
+    int height;
+
+    /**
+     * The desired screen resolution, in DPI.
+     */
+    int resolution;
+
+    /**
+     * The path in which the typescript should be saved, if enabled. If no
+     * typescript should be saved, this will be NULL.
+     */
+    char* typescript_path;
+
+    /**
+     * The filename to use for the typescript, if enabled.
+     */
+    char* typescript_name;
+
+    /**
+     * Whether the typescript path should be automatically created if it does
+     * not already exist.
+     */
+    bool create_typescript_path;
+
+    /**
+     * The path in which the screen recording should be saved, if enabled. If
+     * no screen recording should be saved, this will be NULL.
+     */
+    char* recording_path;
+
+    /**
+     * The filename to use for the screen recording, if enabled.
+     */
+    char* recording_name;
+
+    /**
+     * Whether the screen recording path should be automatically created if it
+     * does not already exist.
+     */
+    bool create_recording_path;
+
+    /**
+     * Whether output which is broadcast to each connected client (graphics,
+     * streams, etc.) should NOT be included in the session recording. Output
+     * is included by default, as it is necessary for any recording which must
+     * later be viewable as video.
+     */
+    bool recording_exclude_output;
+
+    /**
+     * Whether changes to mouse state, such as position and buttons pressed or
+     * released, should NOT be included in the session recording. Mouse state
+     * is included by default, as it is necessary for the mouse cursor to be
+     * rendered in any resulting video.
+     */
+    bool recording_exclude_mouse;
+
+    /**
+     * Whether keys pressed and released should be included in the session
+     * recording. Key events are NOT included by default within the recording,
+     * as doing so has privacy and security implications.  Including key events
+     * may be necessary in certain auditing contexts, but should only be done
+     * with caution. Key events can easily contain sensitive information, such
+     * as passwords, credit card numbers, etc.
+     */
+    bool recording_include_keys;
+
+    /**
+     * The ASCII code, as an integer, that the Kubernetes client will use when
+     * the backspace key is pressed. By default, this is 127, ASCII delete, if
+     * not specified in the client settings.
+     */
+    int backspace;
+
+} guac_kubernetes_settings;
+
+/**
+ * Parses all given args, storing them in a newly-allocated settings object. If
+ * the args fail to parse, NULL is returned.
+ *
+ * @param user
+ *     The user who submitted the given arguments while joining the
+ *     connection.
+ *
+ * @param argc
+ *     The number of arguments within the argv array.
+ *
+ * @param argv
+ *     The values of all arguments provided by the user.
+ *
+ * @return
+ *     A newly-allocated settings object which must be freed with
+ *     guac_kubernetes_settings_free() when no longer needed. If the arguments
+ *     fail to parse, NULL is returned.
+ */
+guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
+        int argc, const char** argv);
+
+/**
+ * Frees the given guac_kubernetes_settings object, having been previously
+ * allocated via guac_kubernetes_parse_args().
+ *
+ * @param settings
+ *     The settings object to free.
+ */
+void guac_kubernetes_settings_free(guac_kubernetes_settings* settings);
+
+/**
+ * NULL-terminated array of accepted client args.
+ */
+extern const char* GUAC_KUBERNETES_CLIENT_ARGS[];
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/user.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/user.c b/src/protocols/kubernetes/user.c
new file mode 100644
index 0000000..62666cb
--- /dev/null
+++ b/src/protocols/kubernetes/user.c
@@ -0,0 +1,116 @@
+/*
+ * 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 "clipboard.h"
+#include "input.h"
+#include "kubernetes.h"
+#include "pipe.h"
+#include "settings.h"
+#include "terminal/terminal.h"
+#include "user.h"
+
+#include <guacamole/client.h>
+#include <guacamole/socket.h>
+#include <guacamole/user.h>
+
+#include <pthread.h>
+#include <string.h>
+
+int guac_kubernetes_user_join_handler(guac_user* user, int argc, char** argv) {
+
+    guac_client* client = user->client;
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Parse provided arguments */
+    guac_kubernetes_settings* settings = guac_kubernetes_parse_args(user,
+            argc, (const char**) argv);
+
+    /* Fail if settings cannot be parsed */
+    if (settings == NULL) {
+        guac_user_log(user, GUAC_LOG_INFO,
+                "Badly formatted client arguments.");
+        return 1;
+    }
+
+    /* Store settings at user level */
+    user->data = settings;
+
+    /* Connect to Kubernetes if owner */
+    if (user->owner) {
+
+        /* Store owner's settings at client level */
+        kubernetes_client->settings = settings;
+
+        /* Start client thread */
+        if (pthread_create(&(kubernetes_client->client_thread), NULL,
+                    guac_kubernetes_client_thread, (void*) client)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Unable to start Kubernetes client thread");
+            return 1;
+        }
+
+    }
+
+    /* If not owner, synchronize with current display */
+    else {
+        guac_terminal_dup(kubernetes_client->term, user, user->socket);
+        guac_socket_flush(user->socket);
+    }
+
+    /* Only handle events if not read-only */
+    if (!settings->read_only) {
+
+        /* General mouse/keyboard/clipboard events */
+        user->key_handler       = guac_kubernetes_user_key_handler;
+        user->mouse_handler     = guac_kubernetes_user_mouse_handler;
+        user->clipboard_handler = guac_kubernetes_clipboard_handler;
+
+        /* STDIN redirection */
+        user->pipe_handler = guac_kubernetes_pipe_handler;
+
+        /* Display size change events */
+        user->size_handler = guac_kubernetes_user_size_handler;
+
+    }
+
+    return 0;
+
+}
+
+int guac_kubernetes_user_leave_handler(guac_user* user) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) user->client->data;
+
+    /* Update shared cursor state */
+    guac_common_cursor_remove_user(kubernetes_client->term->cursor, user);
+
+    /* Free settings if not owner (owner settings will be freed with client) */
+    if (!user->owner) {
+        guac_kubernetes_settings* settings =
+            (guac_kubernetes_settings*) user->data;
+        guac_kubernetes_settings_free(settings);
+    }
+
+    return 0;
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/b8bd0e4c/src/protocols/kubernetes/user.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/user.h b/src/protocols/kubernetes/user.h
new file mode 100644
index 0000000..d235b2b
--- /dev/null
+++ b/src/protocols/kubernetes/user.h
@@ -0,0 +1,38 @@
+/*
+ * 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 GUAC_KUBERNETES_USER_H
+#define GUAC_KUBERNETES_USER_H
+
+#include "config.h"
+
+#include <guacamole/user.h>
+
+/**
+ * Handler for joining users.
+ */
+guac_user_join_handler guac_kubernetes_user_join_handler;
+
+/**
+ * Handler for leaving users.
+ */
+guac_user_leave_handler guac_kubernetes_user_leave_handler;
+
+#endif
+


[04/19] guacamole-server git commit: GUACAMOLE-623: Handle data received from Kubernetes.

Posted by vn...@apache.org.
GUACAMOLE-623: Handle data received from Kubernetes.


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

Branch: refs/heads/master
Commit: f72877bf0d7c68fc2c08eb442d749ce096dc8118
Parents: 7165fa9
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 9 23:50:30 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/kubernetes.c | 70 +++++++++++++++++++++++-------
 src/protocols/kubernetes/kubernetes.h | 26 +++++++++++
 2 files changed, 81 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/f72877bf/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 98e49ec..ae2a894 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -38,10 +38,44 @@
 #include <unistd.h>
 
 /**
- * The name of the WebSocket protocol specific to Kubernetes which should be
- * sent to the Kubernetes server when attaching to a pod.
+ * Handles data received from Kubernetes over WebSocket, decoding the channel
+ * index of the received data and forwarding that data accordingly.
+ *
+ * @param client
+ *     The guac_client associated with the connection to Kubernetes.
+ *
+ * @param buffer
+ *     The data received from Kubernetes.
+ *
+ * @param length
+ *     The size of the data received from Kubernetes, in bytes.
  */
-#define GUAC_KUBERNETES_LWS_PROTOCOL "v4.channel.k8s.io"
+static void guac_kubernetes_receive_data(guac_client* client,
+        const char* buffer, size_t length) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    /* Strip channel index from beginning of buffer */
+    int channel = *(buffer++);
+    length--;
+
+    switch (channel) {
+
+        /* Write STDOUT / STDERR directly to terminal as output */
+        case GUAC_KUBERNETES_CHANNEL_STDOUT:
+        case GUAC_KUBERNETES_CHANNEL_STDERR:
+            guac_terminal_write(kubernetes_client->term, buffer, length);
+            break;
+
+        /* Ignore data on other channels */
+        default:
+            guac_client_log(client, GUAC_LOG_DEBUG, "Received %i bytes along "
+                    "channel %i.", length, channel);
+
+    }
+
+}
 
 /**
  * Callback invoked by libwebsockets for events related to a WebSocket being
@@ -71,16 +105,15 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
         enum lws_callback_reasons reason, void* user,
         void* in, size_t length) {
 
+    /* Request connection closure if client is stopped (note that the user
+     * pointer passed by libwebsockets may be NULL for some events) */
     guac_client* client = (guac_client*) user;
-    /*guac_kubernetes_client* kubernetes_client =
-        (guac_kubernetes_client*) client->data;*/
-
-    /* Request connection closure if client is stopped */
-    if (client->state != GUAC_CLIENT_RUNNING)
+    if (client != NULL && client->state != GUAC_CLIENT_RUNNING)
         return -1;
 
     switch (reason) {
 
+        /* Failed to connect */
         case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
             guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
                     "Error connecting to Kubernetes server: %s",
@@ -88,23 +121,29 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
                     "available)");
             break;
 
-        /* Logged in */
+        /* Connected / logged in */
         case LWS_CALLBACK_CLIENT_ESTABLISHED:
             guac_client_log(client, GUAC_LOG_INFO,
                     "Kubernetes connection successful.");
             break;
 
+        /* Data received via WebSocket */
         case LWS_CALLBACK_CLIENT_RECEIVE:
-            guac_client_log(client, GUAC_LOG_DEBUG, "Received: %s",
-                    (const char*) in);
+            guac_kubernetes_receive_data(client, (const char*) in, length);
             break;
 
         /* TODO: Only send data here. Request callback for writing via lws_callback_on_writable(some struct lws*) */
         case LWS_CALLBACK_CLIENT_WRITEABLE:
             break;
 
+        /* TODO: Add configure test */
+#ifdef HAVE_LWS_CALLBACK_CLIENT_CLOSED
+        /* Connection closed (client-specific) */
+        case LWS_CALLBACK_CLIENT_CLOSED:
+#endif
+
+        /* Connection closed */
         case LWS_CALLBACK_CLOSED:
-        /* TODO: case LWS_CALLBACK_CLIENT_CLOSED: <-- Needs test and #ifdef */
             guac_client_stop(client);
             guac_client_log(client, GUAC_LOG_DEBUG, "WebSocket connection to "
                     "Kubernetes server closed.");
@@ -112,8 +151,6 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
 
         /* No other event types are applicable */
         default:
-            guac_client_log(client, GUAC_LOG_DEBUG, "Unexpected libwebsockets "
-                    "reason: %i", reason);
             break;
 
     }
@@ -213,7 +250,10 @@ void* guac_kubernetes_client_thread(void* data) {
     /* Init libwebsockets context creation parameters */
     struct lws_context_creation_info context_info = {
         .port = CONTEXT_PORT_NO_LISTEN, /* We are not a WebSocket server */
-        .protocols = guac_kubernetes_lws_protocols
+        .uid = -1,
+        .gid = -1,
+        .protocols = guac_kubernetes_lws_protocols,
+        .user = client
     };
 
     /* Init WebSocket connection parameters which do not vary by Guacmaole

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/f72877bf/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index 89c172f..89b6678 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -30,6 +30,32 @@
 #include <stdint.h>
 
 /**
+ * The name of the WebSocket protocol specific to Kubernetes which should be
+ * sent to the Kubernetes server when attaching to a pod.
+ */
+#define GUAC_KUBERNETES_LWS_PROTOCOL "v4.channel.k8s.io"
+
+/**
+ * The index of the Kubernetes channel used for STDIN.
+ */
+#define GUAC_KUBERNETES_CHANNEL_STDIN 0
+
+/**
+ * The index of the Kubernetes channel used for STDOUT.
+ */
+#define GUAC_KUBERNETES_CHANNEL_STDOUT 1
+
+/**
+ * The index of the Kubernetes channel used for STDERR.
+ */
+#define GUAC_KUBERNETES_CHANNEL_STDERR 2
+
+/**
+ * The index of the Kubernetes channel used for terminal resize messages.
+ */
+#define GUAC_KUBERNETES_CHANNEL_RESIZE 4
+
+/**
  * Kubernetes-specific client data.
  */
 typedef struct guac_kubernetes_client {


[14/19] guacamole-server git commit: GUACAMOLE-623: Stub out implementation of WebSocket client for Kubernetes.

Posted by vn...@apache.org.
GUACAMOLE-623: Stub out implementation of WebSocket client for Kubernetes.


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

Branch: refs/heads/master
Commit: 7165fa949d21386d19cbda795fbc849e916461d0
Parents: 519c90a
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 9 22:55:38 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/kubernetes.c | 177 ++++++++++++++++++++++++++++-
 src/protocols/kubernetes/kubernetes.h |   6 +
 2 files changed, 178 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/7165fa94/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 231d78d..98e49ec 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -24,6 +24,7 @@
 
 #include <guacamole/client.h>
 #include <guacamole/protocol.h>
+#include <libwebsockets.h>
 
 #include <errno.h>
 #include <netdb.h>
@@ -37,6 +38,104 @@
 #include <unistd.h>
 
 /**
+ * The name of the WebSocket protocol specific to Kubernetes which should be
+ * sent to the Kubernetes server when attaching to a pod.
+ */
+#define GUAC_KUBERNETES_LWS_PROTOCOL "v4.channel.k8s.io"
+
+/**
+ * Callback invoked by libwebsockets for events related to a WebSocket being
+ * used for communicating with an attached Kubernetes pod.
+ *
+ * @param wsi
+ *     The libwebsockets handle for the WebSocket connection.
+ *
+ * @param reason
+ *     The reason (event) that this callback was invoked.
+ *
+ * @param user
+ *     Arbitrary data assocated with the WebSocket session. This will always
+ *     be a pointer to the guac_client instance.
+ *
+ * @param in
+ *     A pointer to arbitrary, reason-specific data.
+ *
+ * @param length
+ *     An arbitrary, reason-specific length value.
+ *
+ * @return
+ *     An undocumented integer value related the success of handling the
+ *     event, or -1 if the WebSocket connection should be closed.
+ */
+static int guac_kubernetes_lws_callback(struct lws* wsi,
+        enum lws_callback_reasons reason, void* user,
+        void* in, size_t length) {
+
+    guac_client* client = (guac_client*) user;
+    /*guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;*/
+
+    /* Request connection closure if client is stopped */
+    if (client->state != GUAC_CLIENT_RUNNING)
+        return -1;
+
+    switch (reason) {
+
+        case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
+                    "Error connecting to Kubernetes server: %s",
+                    in != NULL ? (char*) in : "(no error description "
+                    "available)");
+            break;
+
+        /* Logged in */
+        case LWS_CALLBACK_CLIENT_ESTABLISHED:
+            guac_client_log(client, GUAC_LOG_INFO,
+                    "Kubernetes connection successful.");
+            break;
+
+        case LWS_CALLBACK_CLIENT_RECEIVE:
+            guac_client_log(client, GUAC_LOG_DEBUG, "Received: %s",
+                    (const char*) in);
+            break;
+
+        /* TODO: Only send data here. Request callback for writing via lws_callback_on_writable(some struct lws*) */
+        case LWS_CALLBACK_CLIENT_WRITEABLE:
+            break;
+
+        case LWS_CALLBACK_CLOSED:
+        /* TODO: case LWS_CALLBACK_CLIENT_CLOSED: <-- Needs test and #ifdef */
+            guac_client_stop(client);
+            guac_client_log(client, GUAC_LOG_DEBUG, "WebSocket connection to "
+                    "Kubernetes server closed.");
+            break;
+
+        /* No other event types are applicable */
+        default:
+            guac_client_log(client, GUAC_LOG_DEBUG, "Unexpected libwebsockets "
+                    "reason: %i", reason);
+            break;
+
+    }
+
+    return lws_callback_http_dummy(wsi, reason, user, in, length);
+
+}
+
+/**
+ * List of all WebSocket protocols which should be declared as supported by
+ * libwebsockets during the initial WebSocket handshake, along with
+ * corresponding event-handling callbacks.
+ */
+struct lws_protocols guac_kubernetes_lws_protocols[] = {
+    {
+        .name = GUAC_KUBERNETES_LWS_PROTOCOL,
+        .callback = guac_kubernetes_lws_callback
+    },
+    { 0 }
+};
+
+/**
  * Input thread, started by the main Kubernetes client thread. This thread
  * continuously reads from the terminal's STDIN and transfers all read
  * data to the Kubernetes connection.
@@ -111,11 +210,69 @@ void* guac_kubernetes_client_thread(void* data) {
                 settings->create_typescript_path);
     }
 
-    /* TODO: Open WebSocket connection to Kubernetes */
+    /* Init libwebsockets context creation parameters */
+    struct lws_context_creation_info context_info = {
+        .port = CONTEXT_PORT_NO_LISTEN, /* We are not a WebSocket server */
+        .protocols = guac_kubernetes_lws_protocols
+    };
+
+    /* Init WebSocket connection parameters which do not vary by Guacmaole
+     * connection parameters or creation of future libwebsockets objects */
+    struct lws_client_connect_info connection_info = {
+        .host = settings->hostname,
+        .address = settings->hostname,
+        .origin = settings->hostname,
+        .port = settings->port,
+        .protocol = GUAC_KUBERNETES_LWS_PROTOCOL,
+        .pwsi = &kubernetes_client->wsi,
+        .userdata = client
+    };
+
+    /* If requested, use an SSL/TLS connection for communication with
+     * Kubernetes */
+    if (settings->use_ssl) {
 
-    /* Logged in */
-    guac_client_log(client, GUAC_LOG_INFO,
-            "Kubernetes connection successful.");
+        /* Enable use of SSL/TLS */
+        context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+        connection_info.ssl_connection = LCCSCF_USE_SSL;
+
+        /* Bypass certificate checks if requested */
+        if (settings->ignore_cert) {
+            connection_info.ssl_connection |=
+                  LCCSCF_ALLOW_SELFSIGNED
+                | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
+                | LCCSCF_ALLOW_EXPIRED;
+        }
+
+        /* Otherwise use the given CA certificate to validate (if any) */
+        else
+            context_info.client_ssl_ca_filepath = settings->ca_cert_file;
+
+        /* Certificate and key file for SSL/TLS client auth */
+        context_info.client_ssl_cert_filepath = settings->client_cert_file;
+        context_info.client_ssl_private_key_filepath = settings->client_key_file;
+
+    }
+
+    /* Create libwebsockets context */
+    struct lws_context* context = lws_create_context(&context_info);
+    if (!context) {
+        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                "Initialization of libwebsockets failed");
+        return NULL;
+    }
+
+    /* FIXME: Generate path dynamically */
+    connection_info.context = context;
+    connection_info.path = "/api/v1/namespaces/default/pods/my-shell-68974bb7f7-rpjgr/attach?container=my-shell&stdin=true&stdout=true&tty=true";
+
+    /* Open WebSocket connection to Kubernetes */
+    kubernetes_client->wsi = lws_client_connect_via_info(&connection_info);
+    if (kubernetes_client->wsi == NULL) {
+        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                "Connection via libwebsockets failed");
+        return NULL;
+    }
 
     /* Start input thread */
     if (pthread_create(&(input_thread), NULL, guac_kubernetes_input_thread, (void*) client)) {
@@ -123,12 +280,22 @@ void* guac_kubernetes_client_thread(void* data) {
         return NULL;
     }
 
-    /* TODO: While data available, write to terminal */
+    /* As long as client is connected, continue polling libwebsockets */
+    while (client->state == GUAC_CLIENT_RUNNING) {
+
+        /* Cease polling libwebsockets if an error condition is signalled */
+        if (lws_service(context, 1000) < 0)
+            break;
+
+    }
 
     /* Kill client and Wait for input thread to die */
     guac_client_stop(client);
     pthread_join(input_thread, NULL);
 
+    /* All done with libwebsockets */
+    lws_context_destroy(context);
+
     guac_client_log(client, GUAC_LOG_INFO, "Kubernetes connection ended.");
     return NULL;
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/7165fa94/src/protocols/kubernetes/kubernetes.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.h b/src/protocols/kubernetes/kubernetes.h
index f8035ae..89c172f 100644
--- a/src/protocols/kubernetes/kubernetes.h
+++ b/src/protocols/kubernetes/kubernetes.h
@@ -26,6 +26,7 @@
 #include "settings.h"
 #include "terminal/terminal.h"
 
+#include <libwebsockets.h>
 #include <stdint.h>
 
 /**
@@ -39,6 +40,11 @@ typedef struct guac_kubernetes_client {
     guac_kubernetes_settings* settings;
 
     /**
+     * The connected WebSocket.
+     */
+    struct lws* wsi;
+
+    /**
      * The Kubernetes client thread.
      */
     pthread_t client_thread;


[10/19] guacamole-server git commit: GUACAMOLE-623: Add configure test for LWS_CALLBACK_CLIENT_CLOSED (only defined in recent libwebsockets and required if present).

Posted by vn...@apache.org.
GUACAMOLE-623: Add configure test for LWS_CALLBACK_CLIENT_CLOSED (only defined in recent libwebsockets and required if present).


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

Branch: refs/heads/master
Commit: c5f67a31dc6c803da23f70662befc102a9187855
Parents: ed56093
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 10 20:00:44 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:51 2018 -0700

----------------------------------------------------------------------
 configure.ac                          | 10 ++++++++++
 src/protocols/kubernetes/kubernetes.c |  1 -
 2 files changed, 10 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/c5f67a31/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index ae78324..7c0bb73 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1193,6 +1193,16 @@ then
                  [have_libwebsockets=no])
 fi
 
+# Check for client-specific closed event, which must be used in favor of the
+# generic closed event if libwebsockets is recent enough to provide this
+if test "x$with_websockets" != "xno"
+then
+    AC_CHECK_DECL([LWS_CALLBACK_CLIENT_CLOSED],
+        [AC_DEFINE([HAVE_LWS_CALLBACK_CLIENT_CLOSED],,
+                   [Whether LWS_CALLBACK_CLIENT_CLOSED is defined])],,
+        [#include <libwebsockets.h>])
+fi
+
 AM_CONDITIONAL([ENABLE_WEBSOCKETS],
                [test "x${have_libwebsockets}"  = "xyes"])
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/c5f67a31/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 380d1d3..9850c6d 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -268,7 +268,6 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
                 lws_callback_on_writable(wsi);
             break;
 
-        /* TODO: Add configure test */
 #ifdef HAVE_LWS_CALLBACK_CLIENT_CLOSED
         /* Connection closed (client-specific) */
         case LWS_CALLBACK_CLIENT_CLOSED:


[16/19] guacamole-server git commit: GUACAMOLE-623: Clean up logging (libwebsockets adds newline characters).

Posted by vn...@apache.org.
GUACAMOLE-623: Clean up logging (libwebsockets adds newline characters).


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

Branch: refs/heads/master
Commit: 61df2956b322a01a777c8169cbbd2b2a2877d696
Parents: 83a531b
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 11 03:17:00 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:52 2018 -0700

----------------------------------------------------------------------
 src/protocols/kubernetes/client.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/61df2956/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
index 331e03d..1a1eb3a 100644
--- a/src/protocols/kubernetes/client.c
+++ b/src/protocols/kubernetes/client.c
@@ -48,9 +48,32 @@ guac_client* guac_kubernetes_lws_current_client = NULL;
  *     The line of logging output to log.
  */
 static void guac_kubernetes_log(int level, const char* line) {
-    if (guac_kubernetes_lws_current_client != NULL)
-        guac_client_log(guac_kubernetes_lws_current_client, GUAC_LOG_DEBUG,
-                "libwebsockets: %s", line);
+
+    char buffer[1024];
+
+    /* Drop log message if there's nowhere to log yet */
+    if (guac_kubernetes_lws_current_client == NULL)
+        return;
+
+    /* Trim length of line to fit buffer (plus null terminator) */
+    int length = strlen(line);
+    if (length > sizeof(buffer) - 1)
+        length = sizeof(buffer) - 1;
+
+    /* Copy as much of the received line as will fit in the buffer */
+    memcpy(buffer, line, length);
+
+    /* If the line ends with a newline character, trim the character */
+    if (length > 0 && buffer[length - 1] == '\n')
+        length--;
+
+    /* Null-terminate the trimmed string */
+    buffer[length] = '\0';
+
+    /* Log using guacd's own log facilities */
+    guac_client_log(guac_kubernetes_lws_current_client, GUAC_LOG_DEBUG,
+            "libwebsockets: %s", buffer);
+
 }
 
 int guac_client_init(guac_client* client) {


[19/19] guacamole-server git commit: GUACAMOLE-623: Merge support for terminals of containers in Kubernetes pods.

Posted by vn...@apache.org.
GUACAMOLE-623: Merge support for terminals of containers in Kubernetes pods.


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

Branch: refs/heads/master
Commit: 43db1965efdf73717900e86778750996bd49395e
Parents: 54fda21 61df295
Author: Nick Couchman <vn...@apache.org>
Authored: Wed Sep 26 08:43:30 2018 -0400
Committer: Nick Couchman <vn...@apache.org>
Committed: Wed Sep 26 08:43:30 2018 -0400

----------------------------------------------------------------------
 Makefile.am                           |   4 +
 configure.ac                          |  76 +++++-
 src/protocols/kubernetes/Makefile.am  |  64 +++++
 src/protocols/kubernetes/client.c     | 133 ++++++++++
 src/protocols/kubernetes/client.h     |  44 ++++
 src/protocols/kubernetes/clipboard.c  |  65 +++++
 src/protocols/kubernetes/clipboard.h  |  41 +++
 src/protocols/kubernetes/input.c      |  94 +++++++
 src/protocols/kubernetes/input.h      |  44 ++++
 src/protocols/kubernetes/io.c         | 143 ++++++++++
 src/protocols/kubernetes/io.h         | 144 +++++++++++
 src/protocols/kubernetes/kubernetes.c | 387 +++++++++++++++++++++++++++
 src/protocols/kubernetes/kubernetes.h | 168 ++++++++++++
 src/protocols/kubernetes/pipe.c       |  52 ++++
 src/protocols/kubernetes/pipe.h       |  40 +++
 src/protocols/kubernetes/settings.c   | 403 +++++++++++++++++++++++++++++
 src/protocols/kubernetes/settings.h   | 279 ++++++++++++++++++++
 src/protocols/kubernetes/ssl.c        | 210 +++++++++++++++
 src/protocols/kubernetes/ssl.h        |  41 +++
 src/protocols/kubernetes/url.c        | 137 ++++++++++
 src/protocols/kubernetes/url.h        |  85 ++++++
 src/protocols/kubernetes/user.c       | 116 +++++++++
 src/protocols/kubernetes/user.h       |  36 +++
 23 files changed, 2798 insertions(+), 8 deletions(-)
----------------------------------------------------------------------