GUACAMOLE-175: Merge move of guacd core into library.
This commit is contained in:
commit
5d2c9676f4
@ -22,6 +22,7 @@ ACLOCAL_AMFLAGS = -I m4
|
|||||||
# Subprojects
|
# Subprojects
|
||||||
DIST_SUBDIRS = \
|
DIST_SUBDIRS = \
|
||||||
src/libguac \
|
src/libguac \
|
||||||
|
src/libguacd \
|
||||||
src/common \
|
src/common \
|
||||||
src/common-ssh \
|
src/common-ssh \
|
||||||
src/terminal \
|
src/terminal \
|
||||||
@ -36,6 +37,7 @@ DIST_SUBDIRS = \
|
|||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
src/libguac \
|
src/libguac \
|
||||||
src/common \
|
src/common \
|
||||||
|
src/libguacd \
|
||||||
tests
|
tests
|
||||||
|
|
||||||
if ENABLE_COMMON_SSH
|
if ENABLE_COMMON_SSH
|
||||||
|
@ -119,6 +119,10 @@ AC_SUBST([LIBGUAC_INCLUDE], '-I$(top_srcdir)/src/libguac')
|
|||||||
AC_SUBST([COMMON_LTLIB], '$(top_builddir)/src/common/libguac_common.la')
|
AC_SUBST([COMMON_LTLIB], '$(top_builddir)/src/common/libguac_common.la')
|
||||||
AC_SUBST([COMMON_INCLUDE], '-I$(top_srcdir)/src/common')
|
AC_SUBST([COMMON_INCLUDE], '-I$(top_srcdir)/src/common')
|
||||||
|
|
||||||
|
# Common utility library for guacd implementations
|
||||||
|
AC_SUBST([LIBGUACD_LTLIB], '$(top_builddir)/src/libguacd/libguacd.la')
|
||||||
|
AC_SUBST([LIBGUACD_INCLUDE], '-I$(top_srcdir)/src/libguacd')
|
||||||
|
|
||||||
# Common base SSH client
|
# Common base SSH client
|
||||||
AC_SUBST([COMMON_SSH_LTLIB], '$(top_builddir)/src/common-ssh/libguac_common_ssh.la')
|
AC_SUBST([COMMON_SSH_LTLIB], '$(top_builddir)/src/common-ssh/libguac_common_ssh.la')
|
||||||
AC_SUBST([COMMON_SSH_INCLUDE], '-I$(top_srcdir)/src/common-ssh')
|
AC_SUBST([COMMON_SSH_INCLUDE], '-I$(top_srcdir)/src/common-ssh')
|
||||||
@ -1101,6 +1105,7 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/common-ssh/Makefile
|
src/common-ssh/Makefile
|
||||||
src/terminal/Makefile
|
src/terminal/Makefile
|
||||||
src/libguac/Makefile
|
src/libguac/Makefile
|
||||||
|
src/libguacd/Makefile
|
||||||
src/guacd/Makefile
|
src/guacd/Makefile
|
||||||
src/guacenc/Makefile
|
src/guacenc/Makefile
|
||||||
src/protocols/rdp/Makefile
|
src/protocols/rdp/Makefile
|
||||||
|
@ -33,8 +33,7 @@ noinst_HEADERS = \
|
|||||||
log.h \
|
log.h \
|
||||||
move-fd.h \
|
move-fd.h \
|
||||||
proc.h \
|
proc.h \
|
||||||
proc-map.h \
|
proc-map.h
|
||||||
user.h
|
|
||||||
|
|
||||||
guacd_SOURCES = \
|
guacd_SOURCES = \
|
||||||
conf-args.c \
|
conf-args.c \
|
||||||
@ -45,16 +44,17 @@ guacd_SOURCES = \
|
|||||||
log.c \
|
log.c \
|
||||||
move-fd.c \
|
move-fd.c \
|
||||||
proc.c \
|
proc.c \
|
||||||
proc-map.c \
|
proc-map.c
|
||||||
user.c
|
|
||||||
|
|
||||||
guacd_CFLAGS = \
|
guacd_CFLAGS = \
|
||||||
-Werror -Wall -pedantic \
|
-Werror -Wall -pedantic \
|
||||||
@COMMON_INCLUDE@ \
|
@COMMON_INCLUDE@ \
|
||||||
|
@LIBGUACD_INCLUDE@ \
|
||||||
@LIBGUAC_INCLUDE@
|
@LIBGUAC_INCLUDE@
|
||||||
|
|
||||||
guacd_LDADD = \
|
guacd_LDADD = \
|
||||||
@COMMON_LTLIB@ \
|
@COMMON_LTLIB@ \
|
||||||
|
@LIBGUACD_LTLIB@ \
|
||||||
@LIBGUAC_LTLIB@
|
@LIBGUAC_LTLIB@
|
||||||
|
|
||||||
guacd_LDFLAGS = \
|
guacd_LDFLAGS = \
|
||||||
@ -68,12 +68,6 @@ EXTRA_DIST = \
|
|||||||
|
|
||||||
CLEANFILES = $(init_SCRIPTS)
|
CLEANFILES = $(init_SCRIPTS)
|
||||||
|
|
||||||
# SSL support
|
|
||||||
if ENABLE_SSL
|
|
||||||
noinst_HEADERS += socket-ssl.h
|
|
||||||
guacd_SOURCES += socket-ssl.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Init script
|
# Init script
|
||||||
if ENABLE_INIT
|
if ENABLE_INIT
|
||||||
initdir = @init_dir@
|
initdir = @init_dir@
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "move-fd.h"
|
#include "move-fd.h"
|
||||||
|
#include "libguacd/user.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "proc-map.h"
|
#include "proc-map.h"
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/error.h>
|
#include <guacamole/error.h>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#ifdef ENABLE_SSL
|
#ifdef ENABLE_SSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include "socket-ssl.h"
|
#include "libguacd/socket-ssl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "conf-args.h"
|
#include "conf-args.h"
|
||||||
#include "conf-file.h"
|
#include "conf-file.h"
|
||||||
|
#include "libguacd/user.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "proc-map.h"
|
#include "proc-map.h"
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
#ifdef ENABLE_SSL
|
#ifdef ENABLE_SSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
@ -124,31 +124,6 @@ void guacd_log_guac_error(guac_client_log_level level, const char* message) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guacd_client_log_guac_error(guac_client* client,
|
|
||||||
guac_client_log_level level, const char* message) {
|
|
||||||
|
|
||||||
if (guac_error != GUAC_STATUS_SUCCESS) {
|
|
||||||
|
|
||||||
/* If error message provided, include in log */
|
|
||||||
if (guac_error_message != NULL)
|
|
||||||
guac_client_log(client, level, "%s: %s",
|
|
||||||
message,
|
|
||||||
guac_error_message);
|
|
||||||
|
|
||||||
/* Otherwise just log with standard status string */
|
|
||||||
else
|
|
||||||
guac_client_log(client, level, "%s: %s",
|
|
||||||
message,
|
|
||||||
guac_status_string(guac_error));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Just log message if no status code */
|
|
||||||
else
|
|
||||||
guac_client_log(client, level, "%s", message);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void guacd_log_handshake_failure() {
|
void guacd_log_handshake_failure() {
|
||||||
|
|
||||||
if (guac_error == GUAC_STATUS_CLOSED)
|
if (guac_error == GUAC_STATUS_CLOSED)
|
||||||
|
@ -62,14 +62,6 @@ void guacd_client_log(guac_client* client, guac_client_log_level level,
|
|||||||
*/
|
*/
|
||||||
void guacd_log_guac_error(guac_client_log_level level, const char* message);
|
void guacd_log_guac_error(guac_client_log_level level, const char* message);
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints an error message using the logging facilities of the given client,
|
|
||||||
* automatically including any information present in guac_error. This function
|
|
||||||
* accepts parameters identically to printf.
|
|
||||||
*/
|
|
||||||
void guacd_client_log_guac_error(guac_client* client,
|
|
||||||
guac_client_log_level level, const char* message);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs a reasonable explanatory message regarding handshake failure based on
|
* Logs a reasonable explanatory message regarding handshake failure based on
|
||||||
* the current value of guac_error.
|
* the current value of guac_error.
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "common/list.h"
|
#include "common/list.h"
|
||||||
|
#include "libguacd/user.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "proc-map.h"
|
#include "proc-map.h"
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "common/list.h"
|
#include "common/list.h"
|
||||||
|
#include "libguacd/user.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
212
src/guacd/proc.c
212
src/guacd/proc.c
@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "libguacd/user.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "move-fd.h"
|
#include "move-fd.h"
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "proc-map.h"
|
#include "proc-map.h"
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
#include <guacamole/error.h>
|
#include <guacamole/error.h>
|
||||||
@ -40,216 +40,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies the given array of mimetypes (strings) into a newly-allocated NULL-
|
|
||||||
* terminated array of strings. Both the array and the strings within the array
|
|
||||||
* are newly-allocated and must be later freed via guacd_free_mimetypes().
|
|
||||||
*
|
|
||||||
* @param mimetypes
|
|
||||||
* The array of mimetypes to copy.
|
|
||||||
*
|
|
||||||
* @param count
|
|
||||||
* The number of mimetypes in the given array.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* A newly-allocated, NULL-terminated array containing newly-allocated
|
|
||||||
* copies of each of the mimetypes provided in the original mimetypes
|
|
||||||
* array.
|
|
||||||
*/
|
|
||||||
static char** guacd_copy_mimetypes(char** mimetypes, int count) {
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Allocate sufficient space for NULL-terminated array of mimetypes */
|
|
||||||
char** mimetypes_copy = malloc(sizeof(char*) * (count+1));
|
|
||||||
|
|
||||||
/* Copy each provided mimetype */
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
mimetypes_copy[i] = strdup(mimetypes[i]);
|
|
||||||
|
|
||||||
/* Terminate with NULL */
|
|
||||||
mimetypes_copy[count] = NULL;
|
|
||||||
|
|
||||||
return mimetypes_copy;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees the given array of mimetypes, including the space allocated to each
|
|
||||||
* mimetype string within the array. The provided array of mimetypes MUST have
|
|
||||||
* been allocated with guacd_copy_mimetypes().
|
|
||||||
*
|
|
||||||
* @param mimetypes
|
|
||||||
* The NULL-terminated array of mimetypes to free. This array MUST have
|
|
||||||
* been previously allocated with guacd_copy_mimetypes().
|
|
||||||
*/
|
|
||||||
static void guacd_free_mimetypes(char** mimetypes) {
|
|
||||||
|
|
||||||
char** current_mimetype = mimetypes;
|
|
||||||
|
|
||||||
/* Free all strings within NULL-terminated mimetype array */
|
|
||||||
while (*current_mimetype != NULL) {
|
|
||||||
free(*current_mimetype);
|
|
||||||
current_mimetype++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the array itself, now that its contents have been freed */
|
|
||||||
free(mimetypes);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the initial handshake of a user and all subsequent I/O. This
|
|
||||||
* function blocks until the user disconnects.
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
* The user whose handshake and entire Guacamole protocol exchange should
|
|
||||||
* be handled.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero if the user's Guacamole connection was successfully handled and
|
|
||||||
* the user has disconnected, or non-zero if an error prevented the user's
|
|
||||||
* connection from being handled properly.
|
|
||||||
*/
|
|
||||||
static int guacd_handle_user(guac_user* user) {
|
|
||||||
|
|
||||||
guac_socket* socket = user->socket;
|
|
||||||
guac_client* client = user->client;
|
|
||||||
|
|
||||||
/* Send args */
|
|
||||||
if (guac_protocol_send_args(socket, client->args)
|
|
||||||
|| guac_socket_flush(socket)) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_log_handshake_failure();
|
|
||||||
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error sending \"args\" to new user");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
guac_parser* parser = guac_parser_alloc();
|
|
||||||
|
|
||||||
/* Get optimal screen size */
|
|
||||||
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "size")) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_log_handshake_failure();
|
|
||||||
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"size\"");
|
|
||||||
|
|
||||||
guac_parser_free(parser);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate content of size instruction */
|
|
||||||
if (parser->argc < 2) {
|
|
||||||
guacd_log(GUAC_LOG_ERROR, "Received \"size\" instruction lacked required arguments.");
|
|
||||||
guac_parser_free(parser);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse optimal screen dimensions from size instruction */
|
|
||||||
user->info.optimal_width = atoi(parser->argv[0]);
|
|
||||||
user->info.optimal_height = atoi(parser->argv[1]);
|
|
||||||
|
|
||||||
/* If DPI given, set the client resolution */
|
|
||||||
if (parser->argc >= 3)
|
|
||||||
user->info.optimal_resolution = atoi(parser->argv[2]);
|
|
||||||
|
|
||||||
/* Otherwise, use a safe default for rough backwards compatibility */
|
|
||||||
else
|
|
||||||
user->info.optimal_resolution = 96;
|
|
||||||
|
|
||||||
/* Get supported audio formats */
|
|
||||||
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "audio")) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_log_handshake_failure();
|
|
||||||
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"audio\"");
|
|
||||||
|
|
||||||
guac_parser_free(parser);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store audio mimetypes */
|
|
||||||
char** audio_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc);
|
|
||||||
user->info.audio_mimetypes = (const char**) audio_mimetypes;
|
|
||||||
|
|
||||||
/* Get supported video formats */
|
|
||||||
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "video")) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_log_handshake_failure();
|
|
||||||
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"video\"");
|
|
||||||
|
|
||||||
guac_parser_free(parser);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store video mimetypes */
|
|
||||||
char** video_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc);
|
|
||||||
user->info.video_mimetypes = (const char**) video_mimetypes;
|
|
||||||
|
|
||||||
/* Get supported image formats */
|
|
||||||
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "image")) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_log_handshake_failure();
|
|
||||||
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"image\"");
|
|
||||||
|
|
||||||
guac_parser_free(parser);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store image mimetypes */
|
|
||||||
char** image_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc);
|
|
||||||
user->info.image_mimetypes = (const char**) image_mimetypes;
|
|
||||||
|
|
||||||
/* Get args from connect instruction */
|
|
||||||
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "connect")) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_log_handshake_failure();
|
|
||||||
guacd_log_guac_error(GUAC_LOG_DEBUG, "Error reading \"connect\"");
|
|
||||||
|
|
||||||
guac_parser_free(parser);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acknowledge connection availability */
|
|
||||||
guac_protocol_send_ready(socket, client->connection_id);
|
|
||||||
guac_socket_flush(socket);
|
|
||||||
|
|
||||||
/* Attempt join */
|
|
||||||
if (guac_client_add_user(client, user, parser->argc, parser->argv))
|
|
||||||
guacd_log(GUAC_LOG_ERROR, "User \"%s\" could NOT join connection \"%s\"", user->user_id, client->connection_id);
|
|
||||||
|
|
||||||
/* Begin user connection if join successful */
|
|
||||||
else {
|
|
||||||
|
|
||||||
guacd_log(GUAC_LOG_INFO, "User \"%s\" joined connection \"%s\" (%i users now present)",
|
|
||||||
user->user_id, client->connection_id, client->connected_users);
|
|
||||||
|
|
||||||
/* Handle user I/O, wait for connection to terminate */
|
|
||||||
guacd_user_start(parser, user);
|
|
||||||
|
|
||||||
/* Remove/free user */
|
|
||||||
guac_client_remove_user(client, user);
|
|
||||||
guacd_log(GUAC_LOG_INFO, "User \"%s\" disconnected (%i users remain)", user->user_id, client->connected_users);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free mimetype lists */
|
|
||||||
guacd_free_mimetypes(audio_mimetypes);
|
|
||||||
guacd_free_mimetypes(video_mimetypes);
|
|
||||||
guacd_free_mimetypes(image_mimetypes);
|
|
||||||
|
|
||||||
guac_parser_free(parser);
|
|
||||||
|
|
||||||
/* Successful disconnect */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters for the user thread.
|
* Parameters for the user thread.
|
||||||
*/
|
*/
|
||||||
|
113
src/guacd/user.c
113
src/guacd/user.c
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
#include <guacamole/client.h>
|
|
||||||
#include <guacamole/error.h>
|
|
||||||
#include <guacamole/parser.h>
|
|
||||||
#include <guacamole/protocol.h>
|
|
||||||
#include <guacamole/socket.h>
|
|
||||||
#include <guacamole/user.h>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
void* guacd_user_input_thread(void* data) {
|
|
||||||
|
|
||||||
guacd_user_input_thread_params* params = (guacd_user_input_thread_params*) data;
|
|
||||||
guac_user* user = params->user;
|
|
||||||
guac_parser* parser = params->parser;
|
|
||||||
guac_client* client = user->client;
|
|
||||||
guac_socket* socket = user->socket;
|
|
||||||
|
|
||||||
/* Guacamole user input loop */
|
|
||||||
while (client->state == GUAC_CLIENT_RUNNING && user->active) {
|
|
||||||
|
|
||||||
/* Read instruction, stop on error */
|
|
||||||
if (guac_parser_read(parser, socket, GUACD_USEC_TIMEOUT)) {
|
|
||||||
|
|
||||||
if (guac_error == GUAC_STATUS_TIMEOUT)
|
|
||||||
guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding.");
|
|
||||||
|
|
||||||
else {
|
|
||||||
if (guac_error != GUAC_STATUS_CLOSED)
|
|
||||||
guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
|
|
||||||
"Guacamole connection failure");
|
|
||||||
guac_user_stop(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset guac_error and guac_error_message (user/client handlers are not
|
|
||||||
* guaranteed to set these) */
|
|
||||||
guac_error = GUAC_STATUS_SUCCESS;
|
|
||||||
guac_error_message = NULL;
|
|
||||||
|
|
||||||
/* Call handler, stop on error */
|
|
||||||
if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) {
|
|
||||||
|
|
||||||
/* Log error */
|
|
||||||
guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
|
|
||||||
"User connection aborted");
|
|
||||||
|
|
||||||
/* Log handler details */
|
|
||||||
guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode);
|
|
||||||
|
|
||||||
guac_user_stop(user);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int guacd_user_start(guac_parser* parser, guac_user* user) {
|
|
||||||
|
|
||||||
guacd_user_input_thread_params params = {
|
|
||||||
.parser = parser,
|
|
||||||
.user = user
|
|
||||||
};
|
|
||||||
|
|
||||||
pthread_t input_thread;
|
|
||||||
|
|
||||||
if (pthread_create(&input_thread, NULL, guacd_user_input_thread, (void*) ¶ms)) {
|
|
||||||
guac_user_log(user, GUAC_LOG_ERROR, "Unable to start input thread");
|
|
||||||
guac_user_stop(user);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for I/O threads */
|
|
||||||
pthread_join(input_thread, NULL);
|
|
||||||
|
|
||||||
/* Explicitly signal disconnect */
|
|
||||||
guac_protocol_send_disconnect(user->socket);
|
|
||||||
guac_socket_flush(user->socket);
|
|
||||||
|
|
||||||
/* Done */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
50
src/libguacd/Makefile.am
Normal file
50
src/libguacd/Makefile.am
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = foreign
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libguacd.la
|
||||||
|
|
||||||
|
noinst_HEADERS = \
|
||||||
|
libguacd/log.h \
|
||||||
|
libguacd/user.h
|
||||||
|
|
||||||
|
libguacd_la_SOURCES = \
|
||||||
|
log.c \
|
||||||
|
user.c
|
||||||
|
|
||||||
|
libguacd_la_CFLAGS = \
|
||||||
|
-Werror -Wall -pedantic \
|
||||||
|
@COMMON_INCLUDE@ \
|
||||||
|
@LIBGUAC_INCLUDE@
|
||||||
|
|
||||||
|
libguacd_la_LIBADD = \
|
||||||
|
@COMMON_LTLIB@ \
|
||||||
|
@LIBGUAC_LTLIB@
|
||||||
|
|
||||||
|
libguacd_la_LDFLAGS = \
|
||||||
|
@PTHREAD_LIBS@ \
|
||||||
|
@SSL_LIBS@
|
||||||
|
|
||||||
|
# SSL support
|
||||||
|
if ENABLE_SSL
|
||||||
|
noinst_HEADERS += libguacd/socket-ssl.h
|
||||||
|
libguacd_la_SOURCES += socket-ssl.c
|
||||||
|
endif
|
||||||
|
|
42
src/libguacd/libguacd/log.h
Normal file
42
src/libguacd/libguacd/log.h
Normal file
@ -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 LIBGUACD_LOG_H
|
||||||
|
#define LIBGUACD_LOG_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints an error message using the logging facilities of the given client,
|
||||||
|
* automatically including any information present in guac_error. This function
|
||||||
|
* accepts parameters identically to printf.
|
||||||
|
*/
|
||||||
|
void guacd_client_log_guac_error(guac_client* client,
|
||||||
|
guac_client_log_level level, const char* message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a reasonable explanatory message regarding handshake failure based on
|
||||||
|
* the current value of guac_error.
|
||||||
|
*/
|
||||||
|
void guacd_client_log_handshake_failure(guac_client* client);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _GUACD_USER_H
|
#ifndef LIBGUACD_USER_H
|
||||||
#define _GUACD_USER_H
|
#define LIBGUACD_USER_H
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -80,6 +80,21 @@ typedef struct guacd_user_input_thread_params {
|
|||||||
*/
|
*/
|
||||||
int guacd_user_start(guac_parser* parser, guac_user* user);
|
int guacd_user_start(guac_parser* parser, guac_user* user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the initial handshake of a user and all subsequent I/O. This
|
||||||
|
* function blocks until the user disconnects.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user whose handshake and entire Guacamole protocol exchange should
|
||||||
|
* be handled.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the user's Guacamole connection was successfully handled and
|
||||||
|
* the user has disconnected, or non-zero if an error prevented the user's
|
||||||
|
* connection from being handled properly.
|
||||||
|
*/
|
||||||
|
int guacd_handle_user(guac_user* user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The thread which handles all user input, calling event handlers for received
|
* The thread which handles all user input, calling event handlers for received
|
||||||
* instructions.
|
* instructions.
|
72
src/libguacd/log.c
Normal file
72
src/libguacd/log.c
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "libguacd/log.h"
|
||||||
|
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/error.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void guacd_client_log_guac_error(guac_client* client,
|
||||||
|
guac_client_log_level level, const char* message) {
|
||||||
|
|
||||||
|
if (guac_error != GUAC_STATUS_SUCCESS) {
|
||||||
|
|
||||||
|
/* If error message provided, include in log */
|
||||||
|
if (guac_error_message != NULL)
|
||||||
|
guac_client_log(client, level, "%s: %s",
|
||||||
|
message,
|
||||||
|
guac_error_message);
|
||||||
|
|
||||||
|
/* Otherwise just log with standard status string */
|
||||||
|
else
|
||||||
|
guac_client_log(client, level, "%s: %s",
|
||||||
|
message,
|
||||||
|
guac_status_string(guac_error));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just log message if no status code */
|
||||||
|
else
|
||||||
|
guac_client_log(client, level, "%s", message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guacd_client_log_handshake_failure(guac_client* client) {
|
||||||
|
|
||||||
|
if (guac_error == GUAC_STATUS_CLOSED)
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO,
|
||||||
|
"Guacamole connection closed during handshake");
|
||||||
|
else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR)
|
||||||
|
guac_client_log(client, GUAC_LOG_ERROR,
|
||||||
|
"Guacamole protocol violation. Perhaps the version of "
|
||||||
|
"guacamole-client is incompatible with this version of "
|
||||||
|
"guacd?");
|
||||||
|
else
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
|
"Guacamole handshake failed: %s",
|
||||||
|
guac_status_string(guac_error));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "socket-ssl.h"
|
#include "libguacd/socket-ssl.h"
|
||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
321
src/libguacd/user.c
Normal file
321
src/libguacd/user.c
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* 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 "libguacd/log.h"
|
||||||
|
#include "libguacd/user.h"
|
||||||
|
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/error.h>
|
||||||
|
#include <guacamole/parser.h>
|
||||||
|
#include <guacamole/protocol.h>
|
||||||
|
#include <guacamole/socket.h>
|
||||||
|
#include <guacamole/user.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given array of mimetypes (strings) into a newly-allocated NULL-
|
||||||
|
* terminated array of strings. Both the array and the strings within the array
|
||||||
|
* are newly-allocated and must be later freed via guacd_free_mimetypes().
|
||||||
|
*
|
||||||
|
* @param mimetypes
|
||||||
|
* The array of mimetypes to copy.
|
||||||
|
*
|
||||||
|
* @param count
|
||||||
|
* The number of mimetypes in the given array.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A newly-allocated, NULL-terminated array containing newly-allocated
|
||||||
|
* copies of each of the mimetypes provided in the original mimetypes
|
||||||
|
* array.
|
||||||
|
*/
|
||||||
|
static char** guacd_copy_mimetypes(char** mimetypes, int count) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Allocate sufficient space for NULL-terminated array of mimetypes */
|
||||||
|
char** mimetypes_copy = malloc(sizeof(char*) * (count+1));
|
||||||
|
|
||||||
|
/* Copy each provided mimetype */
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
mimetypes_copy[i] = strdup(mimetypes[i]);
|
||||||
|
|
||||||
|
/* Terminate with NULL */
|
||||||
|
mimetypes_copy[count] = NULL;
|
||||||
|
|
||||||
|
return mimetypes_copy;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the given array of mimetypes, including the space allocated to each
|
||||||
|
* mimetype string within the array. The provided array of mimetypes MUST have
|
||||||
|
* been allocated with guacd_copy_mimetypes().
|
||||||
|
*
|
||||||
|
* @param mimetypes
|
||||||
|
* The NULL-terminated array of mimetypes to free. This array MUST have
|
||||||
|
* been previously allocated with guacd_copy_mimetypes().
|
||||||
|
*/
|
||||||
|
static void guacd_free_mimetypes(char** mimetypes) {
|
||||||
|
|
||||||
|
char** current_mimetype = mimetypes;
|
||||||
|
|
||||||
|
/* Free all strings within NULL-terminated mimetype array */
|
||||||
|
while (*current_mimetype != NULL) {
|
||||||
|
free(*current_mimetype);
|
||||||
|
current_mimetype++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the array itself, now that its contents have been freed */
|
||||||
|
free(mimetypes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void* guacd_user_input_thread(void* data) {
|
||||||
|
|
||||||
|
guacd_user_input_thread_params* params = (guacd_user_input_thread_params*) data;
|
||||||
|
guac_user* user = params->user;
|
||||||
|
guac_parser* parser = params->parser;
|
||||||
|
guac_client* client = user->client;
|
||||||
|
guac_socket* socket = user->socket;
|
||||||
|
|
||||||
|
/* Guacamole user input loop */
|
||||||
|
while (client->state == GUAC_CLIENT_RUNNING && user->active) {
|
||||||
|
|
||||||
|
/* Read instruction, stop on error */
|
||||||
|
if (guac_parser_read(parser, socket, GUACD_USEC_TIMEOUT)) {
|
||||||
|
|
||||||
|
if (guac_error == GUAC_STATUS_TIMEOUT)
|
||||||
|
guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding.");
|
||||||
|
|
||||||
|
else {
|
||||||
|
if (guac_error != GUAC_STATUS_CLOSED)
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
|
||||||
|
"Guacamole connection failure");
|
||||||
|
guac_user_stop(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset guac_error and guac_error_message (user/client handlers are not
|
||||||
|
* guaranteed to set these) */
|
||||||
|
guac_error = GUAC_STATUS_SUCCESS;
|
||||||
|
guac_error_message = NULL;
|
||||||
|
|
||||||
|
/* Call handler, stop on error */
|
||||||
|
if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_WARNING,
|
||||||
|
"User connection aborted");
|
||||||
|
|
||||||
|
/* Log handler details */
|
||||||
|
guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode);
|
||||||
|
|
||||||
|
guac_user_stop(user);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guacd_user_start(guac_parser* parser, guac_user* user) {
|
||||||
|
|
||||||
|
guacd_user_input_thread_params params = {
|
||||||
|
.parser = parser,
|
||||||
|
.user = user
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_t input_thread;
|
||||||
|
|
||||||
|
if (pthread_create(&input_thread, NULL, guacd_user_input_thread, (void*) ¶ms)) {
|
||||||
|
guac_user_log(user, GUAC_LOG_ERROR, "Unable to start input thread");
|
||||||
|
guac_user_stop(user);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for I/O threads */
|
||||||
|
pthread_join(input_thread, NULL);
|
||||||
|
|
||||||
|
/* Explicitly signal disconnect */
|
||||||
|
guac_protocol_send_disconnect(user->socket);
|
||||||
|
guac_socket_flush(user->socket);
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guacd_handle_user(guac_user* user) {
|
||||||
|
|
||||||
|
guac_socket* socket = user->socket;
|
||||||
|
guac_client* client = user->client;
|
||||||
|
|
||||||
|
/* Send args */
|
||||||
|
if (guac_protocol_send_args(socket, client->args)
|
||||||
|
|| guac_socket_flush(socket)) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_handshake_failure(client);
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error sending \"args\" to new user");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_parser* parser = guac_parser_alloc();
|
||||||
|
|
||||||
|
/* Get optimal screen size */
|
||||||
|
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "size")) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_handshake_failure(client);
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error reading \"size\"");
|
||||||
|
|
||||||
|
guac_parser_free(parser);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate content of size instruction */
|
||||||
|
if (parser->argc < 2) {
|
||||||
|
guac_client_log(client, GUAC_LOG_ERROR, "Received \"size\" "
|
||||||
|
"instruction lacked required arguments.");
|
||||||
|
guac_parser_free(parser);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse optimal screen dimensions from size instruction */
|
||||||
|
user->info.optimal_width = atoi(parser->argv[0]);
|
||||||
|
user->info.optimal_height = atoi(parser->argv[1]);
|
||||||
|
|
||||||
|
/* If DPI given, set the client resolution */
|
||||||
|
if (parser->argc >= 3)
|
||||||
|
user->info.optimal_resolution = atoi(parser->argv[2]);
|
||||||
|
|
||||||
|
/* Otherwise, use a safe default for rough backwards compatibility */
|
||||||
|
else
|
||||||
|
user->info.optimal_resolution = 96;
|
||||||
|
|
||||||
|
/* Get supported audio formats */
|
||||||
|
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "audio")) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_handshake_failure(client);
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error reading \"audio\"");
|
||||||
|
|
||||||
|
guac_parser_free(parser);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store audio mimetypes */
|
||||||
|
char** audio_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc);
|
||||||
|
user->info.audio_mimetypes = (const char**) audio_mimetypes;
|
||||||
|
|
||||||
|
/* Get supported video formats */
|
||||||
|
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "video")) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_handshake_failure(client);
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error reading \"video\"");
|
||||||
|
|
||||||
|
guac_parser_free(parser);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store video mimetypes */
|
||||||
|
char** video_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc);
|
||||||
|
user->info.video_mimetypes = (const char**) video_mimetypes;
|
||||||
|
|
||||||
|
/* Get supported image formats */
|
||||||
|
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "image")) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_handshake_failure(client);
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error reading \"image\"");
|
||||||
|
|
||||||
|
guac_parser_free(parser);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store image mimetypes */
|
||||||
|
char** image_mimetypes = guacd_copy_mimetypes(parser->argv, parser->argc);
|
||||||
|
user->info.image_mimetypes = (const char**) image_mimetypes;
|
||||||
|
|
||||||
|
/* Get args from connect instruction */
|
||||||
|
if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "connect")) {
|
||||||
|
|
||||||
|
/* Log error */
|
||||||
|
guacd_client_log_handshake_failure(client);
|
||||||
|
guacd_client_log_guac_error(client, GUAC_LOG_DEBUG,
|
||||||
|
"Error reading \"connect\"");
|
||||||
|
|
||||||
|
guac_parser_free(parser);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acknowledge connection availability */
|
||||||
|
guac_protocol_send_ready(socket, client->connection_id);
|
||||||
|
guac_socket_flush(socket);
|
||||||
|
|
||||||
|
/* Attempt join */
|
||||||
|
if (guac_client_add_user(client, user, parser->argc, parser->argv))
|
||||||
|
guac_client_log(client, GUAC_LOG_ERROR, "User \"%s\" could NOT "
|
||||||
|
"join connection \"%s\"", user->user_id, client->connection_id);
|
||||||
|
|
||||||
|
/* Begin user connection if join successful */
|
||||||
|
else {
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO, "User \"%s\" joined connection "
|
||||||
|
"\"%s\" (%i users now present)", user->user_id,
|
||||||
|
client->connection_id, client->connected_users);
|
||||||
|
|
||||||
|
/* Handle user I/O, wait for connection to terminate */
|
||||||
|
guacd_user_start(parser, user);
|
||||||
|
|
||||||
|
/* Remove/free user */
|
||||||
|
guac_client_remove_user(client, user);
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO, "User \"%s\" disconnected (%i "
|
||||||
|
"users remain)", user->user_id, client->connected_users);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free mimetype lists */
|
||||||
|
guacd_free_mimetypes(audio_mimetypes);
|
||||||
|
guacd_free_mimetypes(video_mimetypes);
|
||||||
|
guacd_free_mimetypes(image_mimetypes);
|
||||||
|
|
||||||
|
guac_parser_free(parser);
|
||||||
|
|
||||||
|
/* Successful disconnect */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user