You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2017/01/24 20:59:46 UTC
[1/3] incubator-guacamole-server git commit: GUACAMOLE-171: Separate
broadcast socket from client. Ensure socket remains threadsafe even if no
users are connected.
Repository: incubator-guacamole-server
Updated Branches:
refs/heads/master 8cd98b529 -> a1886f51b
GUACAMOLE-171: Separate broadcast socket from client. Ensure socket remains threadsafe even if no users are connected.
Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/98b92f09
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/98b92f09
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/98b92f09
Branch: refs/heads/master
Commit: 98b92f0900cd579cab24c5640cf55d7b0fc5c5f8
Parents: 0ef87c4
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Dec 20 23:58:53 2016 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Jan 23 23:43:32 2017 -0800
----------------------------------------------------------------------
src/libguac/Makefile.am | 41 ++--
src/libguac/client.c | 273 +-------------------------
src/libguac/guacamole/socket.h | 27 +++
src/libguac/socket-broadcast.c | 377 ++++++++++++++++++++++++++++++++++++
4 files changed, 426 insertions(+), 292 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/98b92f09/src/libguac/Makefile.am
----------------------------------------------------------------------
diff --git a/src/libguac/Makefile.am b/src/libguac/Makefile.am
index 46d4e58..781f862 100644
--- a/src/libguac/Makefile.am
+++ b/src/libguac/Makefile.am
@@ -70,26 +70,27 @@ noinst_HEADERS = \
user-handlers.h \
raw_encoder.h
-libguac_la_SOURCES = \
- audio.c \
- client.c \
- encode-jpeg.c \
- encode-png.c \
- error.c \
- hash.c \
- id.c \
- palette.c \
- parser.c \
- pool.c \
- protocol.c \
- raw_encoder.c \
- socket.c \
- socket-fd.c \
- socket-nest.c \
- socket-tee.c \
- timestamp.c \
- unicode.c \
- user.c \
+libguac_la_SOURCES = \
+ audio.c \
+ client.c \
+ encode-jpeg.c \
+ encode-png.c \
+ error.c \
+ hash.c \
+ id.c \
+ palette.c \
+ parser.c \
+ pool.c \
+ protocol.c \
+ raw_encoder.c \
+ socket.c \
+ socket-broadcast.c \
+ socket-fd.c \
+ socket-nest.c \
+ socket-tee.c \
+ timestamp.c \
+ unicode.c \
+ user.c \
user-handlers.c
# Compile WebP support if available
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/98b92f09/src/libguac/client.c
----------------------------------------------------------------------
diff --git a/src/libguac/client.c b/src/libguac/client.c
index b9862a1..a3c3733 100644
--- a/src/libguac/client.c
+++ b/src/libguac/client.c
@@ -47,23 +47,6 @@ guac_layer __GUAC_DEFAULT_LAYER = {
const guac_layer* GUAC_DEFAULT_LAYER = &__GUAC_DEFAULT_LAYER;
-/**
- * Single chunk of data, to be broadcast to all users.
- */
-typedef struct __write_chunk {
-
- /**
- * The buffer to write.
- */
- const void* buffer;
-
- /**
- * The number of bytes in the buffer.
- */
- size_t length;
-
-} __write_chunk;
-
guac_layer* guac_client_alloc_layer(guac_client* client) {
/* Init new layer */
@@ -138,251 +121,6 @@ void guac_client_free_stream(guac_client* client, guac_stream* stream) {
}
-/**
- * Callback which handles read requests on the broadcast socket. This callback
- * always fails, as the broadcast socket is write-only; it cannot be read.
- *
- * @param socket
- * The broadcast socket to read from.
- *
- * @param buf
- * The buffer into which data should be read.
- *
- * @param count
- * The number of bytes to attempt to read.
- *
- * @return
- * The number of bytes read, or -1 if an error occurs. This implementation
- * always returns -1, as the broadcast socket is write-only and cannot be
- * read.
- */
-static ssize_t __guac_socket_broadcast_read_handler(guac_socket* socket,
- void* buf, size_t count) {
-
- /* Broadcast socket reads are not allowed */
- return -1;
-
-}
-
-/**
- * Callback invoked by guac_client_foreach_user() which write a given chunk of
- * data to that user's socket. If the write attempt fails, the user is
- * signalled to stop with guac_user_stop().
- *
- * @param user
- * The user that the chunk of data should be written to.
- *
- * @param data
- * A pointer to a __write_chunk which describes the data to be written.
- *
- * @return
- * Always NULL.
- */
-static void* __write_chunk_callback(guac_user* user, void* data) {
-
- __write_chunk* chunk = (__write_chunk*) data;
-
- /* Attempt write, disconnect on failure */
- if (guac_socket_write(user->socket, chunk->buffer, chunk->length))
- guac_user_stop(user);
-
- return NULL;
-
-}
-
-/**
- * Socket write handler which operates on each of the sockets of all connected
- * users. This write handler will always succeed, but any failing user-specific
- * writes will invoke guac_user_stop() on the failing user.
- *
- * @param socket
- * The socket to which the given data must be written.
- *
- * @param buf
- * The buffer containing the data to write.
- *
- * @param count
- * The number of bytes to attempt to write from the given buffer.
- *
- * @return
- * The number of bytes written, or -1 if an error occurs. This handler will
- * always succeed, and thus will always return the exact number of bytes
- * specified by count.
- */
-static ssize_t __guac_socket_broadcast_write_handler(guac_socket* socket,
- const void* buf, size_t count) {
-
- guac_client* client = (guac_client*) socket->data;
-
- /* Build chunk */
- __write_chunk chunk;
- chunk.buffer = buf;
- chunk.length = count;
-
- /* Broadcast chunk to all users */
- guac_client_foreach_user(client, __write_chunk_callback, &chunk);
-
- return count;
-
-}
-
-/**
- * Callback which is invoked by guac_client_foreach_user() to flush all
- * pending data on the given user's socket. If an error occurs while flushing
- * a user's socket, that user is signalled to stop with guac_user_stop().
- *
- * @param user
- * The user whose socket should be flushed.
- *
- * @param data
- * Arbitrary data passed to guac_client_foreach_user(). This is not needed
- * by this callback, and should be left as NULL.
- *
- * @return
- * Always NULL.
- */
-static void* __flush_callback(guac_user* user, void* data) {
-
- /* Attempt flush, disconnect on failure */
- if (guac_socket_flush(user->socket))
- guac_user_stop(user);
-
- return NULL;
-
-}
-
-/**
- * Socket flush handler which operates on each of the sockets of all connected
- * users. This flush handler will always succeed, but any failing user-specific
- * flush will invoke guac_user_stop() on the failing user.
- *
- * @param socket
- * The broadcast socket to flush.
- *
- * @return
- * Zero if the flush operation succeeds, non-zero if the operation fails.
- * This handler will always succeed, and thus will always return zero.
- */
-static ssize_t __guac_socket_broadcast_flush_handler(guac_socket* socket) {
-
- guac_client* client = (guac_client*) socket->data;
-
- /* Flush all users */
- guac_client_foreach_user(client, __flush_callback, NULL);
-
- return 0;
-
-}
-
-/**
- * Callback which is invoked by guac_client_foreach_user() to lock the given
- * user's socket in preparation for the beginning of a Guacamole protocol
- * instruction.
- *
- * @param user
- * The user whose socket should be locked.
- *
- * @param data
- * Arbitrary data passed to guac_client_foreach_user(). This is not needed
- * by this callback, and should be left as NULL.
- *
- * @return
- * Always NULL.
- */
-static void* __lock_callback(guac_user* user, void* data) {
-
- /* Lock socket */
- guac_socket_instruction_begin(user->socket);
-
- return NULL;
-
-}
-
-/**
- * Socket lock handler which acquires the socket locks of all connected users.
- * Socket-level locks are acquired in preparation for the beginning of a new
- * Guacamole instruction to ensure that parallel writes are only interleaved at
- * instruction boundaries.
- *
- * @param socket
- * The broadcast socket to lock.
- */
-static void __guac_socket_broadcast_lock_handler(guac_socket* socket) {
-
- guac_client* client = (guac_client*) socket->data;
-
- /* Lock sockets of all users */
- guac_client_foreach_user(client, __lock_callback, NULL);
-
-}
-
-/**
- * Callback which is invoked by guac_client_foreach_user() to unlock the given
- * user's socket at the end of a Guacamole protocol instruction.
- *
- * @param user
- * The user whose socket should be unlocked.
- *
- * @param data
- * Arbitrary data passed to guac_client_foreach_user(). This is not needed
- * by this callback, and should be left as NULL.
- *
- * @return
- * Always NULL.
- */
-static void* __unlock_callback(guac_user* user, void* data) {
-
- /* Unlock socket */
- guac_socket_instruction_end(user->socket);
-
- return NULL;
-
-}
-
-/**
- * Socket unlock handler which releases the socket locks of all connected users.
- * Socket-level locks are released after a Guacamole instruction has finished
- * being written.
- *
- * @param socket
- * The broadcast socket to unlock.
- */
-static void __guac_socket_broadcast_unlock_handler(guac_socket* socket) {
-
- guac_client* client = (guac_client*) socket->data;
-
- /* Unlock sockets of all users */
- guac_client_foreach_user(client, __unlock_callback, NULL);
-
-}
-
-/**
- * Callback which handles select operations on the broadcast socket, waiting
- * for data to become available such that the next read operation will not
- * block. This callback always fails, as the broadcast socket is write-only; it
- * cannot be read.
- *
- * @param socket
- * The broadcast socket to wait for.
- *
- * @param usec_timeout
- * The maximum amount of time to wait for data, in microseconds, or -1 to
- * potentially wait forever.
- *
- * @return
- * A positive value on success, zero if the timeout elapsed and no data is
- * available, or a negative value if an error occurs. This implementation
- * always returns -1, as the broadcast socket is write-only and cannot be
- * read.
- */
-static int __guac_socket_broadcast_select_handler(guac_socket* socket,
- int usec_timeout) {
-
- /* Selecting the broadcast socket is not possible */
- return -1;
-
-}
-
guac_client* guac_client_alloc() {
int i;
@@ -431,16 +169,7 @@ guac_client* guac_client_alloc() {
pthread_rwlock_init(&(client->__users_lock), &lock_attributes);
/* Set up socket to broadcast to all users */
- guac_socket* socket = guac_socket_alloc();
- client->socket = socket;
- socket->data = client;
-
- socket->read_handler = __guac_socket_broadcast_read_handler;
- socket->write_handler = __guac_socket_broadcast_write_handler;
- socket->select_handler = __guac_socket_broadcast_select_handler;
- socket->flush_handler = __guac_socket_broadcast_flush_handler;
- socket->lock_handler = __guac_socket_broadcast_lock_handler;
- socket->unlock_handler = __guac_socket_broadcast_unlock_handler;
+ client->socket = guac_socket_broadcast(client);
return client;
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/98b92f09/src/libguac/guacamole/socket.h
----------------------------------------------------------------------
diff --git a/src/libguac/guacamole/socket.h b/src/libguac/guacamole/socket.h
index 1290c34..e83a4eb 100644
--- a/src/libguac/guacamole/socket.h
+++ b/src/libguac/guacamole/socket.h
@@ -26,6 +26,7 @@
* @file socket.h
*/
+#include "client-types.h"
#include "socket-constants.h"
#include "socket-fntypes.h"
#include "socket-types.h"
@@ -221,6 +222,32 @@ guac_socket* guac_socket_nest(guac_socket* parent, int index);
guac_socket* guac_socket_tee(guac_socket* primary, guac_socket* secondary);
/**
+ * Allocates and initializes a new guac_socket which duplicates all
+ * instructions written across the sockets of each connected user of the given
+ * guac_client. The returned socket is a write-only socket. Attempts to read
+ * from the socket will fail. If a write occurs while no users are connected,
+ * that write will simply be dropped.
+ *
+ * Return values (error codes) from each user's socket will not affect the
+ * in-progress write, but each failing user will be forcibly stopped with
+ * guac_user_stop().
+ *
+ * If an error occurs while allocating the guac_socket object, NULL is returned,
+ * and guac_error is set appropriately.
+ *
+ * @param client
+ * The client associated with the group of connected users across which
+ * duplicates of all instructions should be written.
+ *
+ * @return
+ * A write-only guac_socket object which broadcasts copies of all
+ * instructions written across all connected users of the given
+ * guac_client, or NULL if an error occurs while allocating the guac_socket
+ * object.
+ */
+guac_socket* guac_socket_broadcast(guac_client* client);
+
+/**
* Writes the given unsigned int to the given guac_socket object. The data
* written may be buffered until the buffer is flushed automatically or
* manually.
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/98b92f09/src/libguac/socket-broadcast.c
----------------------------------------------------------------------
diff --git a/src/libguac/socket-broadcast.c b/src/libguac/socket-broadcast.c
new file mode 100644
index 0000000..a3f17fd
--- /dev/null
+++ b/src/libguac/socket-broadcast.c
@@ -0,0 +1,377 @@
+/*
+ * 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 "error.h"
+#include "socket.h"
+#include "user.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+/**
+ * Data associated with an open socket which writes to all connected users of
+ * a particular guac_client.
+ */
+typedef struct guac_socket_broadcast_data {
+
+ /**
+ * The guac_client whose connected users should receive all instructions
+ * written to this socket.
+ */
+ guac_client* client;
+
+ /**
+ * Lock which is acquired when an instruction is being written, and
+ * released when the instruction is finished being written.
+ */
+ pthread_mutex_t socket_lock;
+
+} guac_socket_broadcast_data;
+
+/**
+ * Single chunk of data, to be broadcast to all users.
+ */
+typedef struct __write_chunk {
+
+ /**
+ * The buffer to write.
+ */
+ const void* buffer;
+
+ /**
+ * The number of bytes in the buffer.
+ */
+ size_t length;
+
+} __write_chunk;
+
+/**
+ * Callback which handles read requests on the broadcast socket. This callback
+ * always fails, as the broadcast socket is write-only; it cannot be read.
+ *
+ * @param socket
+ * The broadcast socket to read from.
+ *
+ * @param buf
+ * The buffer into which data should be read.
+ *
+ * @param count
+ * The number of bytes to attempt to read.
+ *
+ * @return
+ * The number of bytes read, or -1 if an error occurs. This implementation
+ * always returns -1, as the broadcast socket is write-only and cannot be
+ * read.
+ */
+static ssize_t __guac_socket_broadcast_read_handler(guac_socket* socket,
+ void* buf, size_t count) {
+
+ /* Broadcast socket reads are not allowed */
+ return -1;
+
+}
+
+/**
+ * Callback invoked by guac_client_foreach_user() which write a given chunk of
+ * data to that user's socket. If the write attempt fails, the user is
+ * signalled to stop with guac_user_stop().
+ *
+ * @param user
+ * The user that the chunk of data should be written to.
+ *
+ * @param data
+ * A pointer to a __write_chunk which describes the data to be written.
+ *
+ * @return
+ * Always NULL.
+ */
+static void* __write_chunk_callback(guac_user* user, void* data) {
+
+ __write_chunk* chunk = (__write_chunk*) data;
+
+ /* Attempt write, disconnect on failure */
+ if (guac_socket_write(user->socket, chunk->buffer, chunk->length))
+ guac_user_stop(user);
+
+ return NULL;
+
+}
+
+/**
+ * Socket write handler which operates on each of the sockets of all connected
+ * users. This write handler will always succeed, but any failing user-specific
+ * writes will invoke guac_user_stop() on the failing user.
+ *
+ * @param socket
+ * The socket to which the given data must be written.
+ *
+ * @param buf
+ * The buffer containing the data to write.
+ *
+ * @param count
+ * The number of bytes to attempt to write from the given buffer.
+ *
+ * @return
+ * The number of bytes written, or -1 if an error occurs. This handler will
+ * always succeed, and thus will always return the exact number of bytes
+ * specified by count.
+ */
+static ssize_t __guac_socket_broadcast_write_handler(guac_socket* socket,
+ const void* buf, size_t count) {
+
+ guac_socket_broadcast_data* data =
+ (guac_socket_broadcast_data*) socket->data;
+
+ /* Build chunk */
+ __write_chunk chunk;
+ chunk.buffer = buf;
+ chunk.length = count;
+
+ /* Broadcast chunk to all users */
+ guac_client_foreach_user(data->client, __write_chunk_callback, &chunk);
+
+ return count;
+
+}
+
+/**
+ * Callback which is invoked by guac_client_foreach_user() to flush all
+ * pending data on the given user's socket. If an error occurs while flushing
+ * a user's socket, that user is signalled to stop with guac_user_stop().
+ *
+ * @param user
+ * The user whose socket should be flushed.
+ *
+ * @param data
+ * Arbitrary data passed to guac_client_foreach_user(). This is not needed
+ * by this callback, and should be left as NULL.
+ *
+ * @return
+ * Always NULL.
+ */
+static void* __flush_callback(guac_user* user, void* data) {
+
+ /* Attempt flush, disconnect on failure */
+ if (guac_socket_flush(user->socket))
+ guac_user_stop(user);
+
+ return NULL;
+
+}
+
+/**
+ * Socket flush handler which operates on each of the sockets of all connected
+ * users. This flush handler will always succeed, but any failing user-specific
+ * flush will invoke guac_user_stop() on the failing user.
+ *
+ * @param socket
+ * The broadcast socket to flush.
+ *
+ * @return
+ * Zero if the flush operation succeeds, non-zero if the operation fails.
+ * This handler will always succeed, and thus will always return zero.
+ */
+static ssize_t __guac_socket_broadcast_flush_handler(guac_socket* socket) {
+
+ guac_socket_broadcast_data* data =
+ (guac_socket_broadcast_data*) socket->data;
+
+ /* Flush all users */
+ guac_client_foreach_user(data->client, __flush_callback, NULL);
+
+ return 0;
+
+}
+
+/**
+ * Callback which is invoked by guac_client_foreach_user() to lock the given
+ * user's socket in preparation for the beginning of a Guacamole protocol
+ * instruction.
+ *
+ * @param user
+ * The user whose socket should be locked.
+ *
+ * @param data
+ * Arbitrary data passed to guac_client_foreach_user(). This is not needed
+ * by this callback, and should be left as NULL.
+ *
+ * @return
+ * Always NULL.
+ */
+static void* __lock_callback(guac_user* user, void* data) {
+
+ /* Lock socket */
+ guac_socket_instruction_begin(user->socket);
+
+ return NULL;
+
+}
+
+/**
+ * Socket lock handler which acquires the socket locks of all connected users.
+ * Socket-level locks are acquired in preparation for the beginning of a new
+ * Guacamole instruction to ensure that parallel writes are only interleaved at
+ * instruction boundaries.
+ *
+ * @param socket
+ * The broadcast socket to lock.
+ */
+static void __guac_socket_broadcast_lock_handler(guac_socket* socket) {
+
+ guac_socket_broadcast_data* data =
+ (guac_socket_broadcast_data*) socket->data;
+
+ /* Acquire exclusive access to socket */
+ pthread_mutex_lock(&(data->socket_lock));
+
+ /* Lock sockets of all users */
+ guac_client_foreach_user(data->client, __lock_callback, NULL);
+
+}
+
+/**
+ * Callback which is invoked by guac_client_foreach_user() to unlock the given
+ * user's socket at the end of a Guacamole protocol instruction.
+ *
+ * @param user
+ * The user whose socket should be unlocked.
+ *
+ * @param data
+ * Arbitrary data passed to guac_client_foreach_user(). This is not needed
+ * by this callback, and should be left as NULL.
+ *
+ * @return
+ * Always NULL.
+ */
+static void* __unlock_callback(guac_user* user, void* data) {
+
+ /* Unlock socket */
+ guac_socket_instruction_end(user->socket);
+
+ return NULL;
+
+}
+
+/**
+ * Socket unlock handler which releases the socket locks of all connected users.
+ * Socket-level locks are released after a Guacamole instruction has finished
+ * being written.
+ *
+ * @param socket
+ * The broadcast socket to unlock.
+ */
+static void __guac_socket_broadcast_unlock_handler(guac_socket* socket) {
+
+ guac_socket_broadcast_data* data =
+ (guac_socket_broadcast_data*) socket->data;
+
+ /* Unlock sockets of all users */
+ guac_client_foreach_user(data->client, __unlock_callback, NULL);
+
+ /* Relinquish exclusive access to socket */
+ pthread_mutex_unlock(&(data->socket_lock));
+
+}
+
+/**
+ * Callback which handles select operations on the broadcast socket, waiting
+ * for data to become available such that the next read operation will not
+ * block. This callback always fails, as the broadcast socket is write-only; it
+ * cannot be read.
+ *
+ * @param socket
+ * The broadcast socket to wait for.
+ *
+ * @param usec_timeout
+ * The maximum amount of time to wait for data, in microseconds, or -1 to
+ * potentially wait forever.
+ *
+ * @return
+ * A positive value on success, zero if the timeout elapsed and no data is
+ * available, or a negative value if an error occurs. This implementation
+ * always returns -1, as the broadcast socket is write-only and cannot be
+ * read.
+ */
+static int __guac_socket_broadcast_select_handler(guac_socket* socket,
+ int usec_timeout) {
+
+ /* Selecting the broadcast socket is not possible */
+ return -1;
+
+}
+
+/**
+ * Frees all implementation-specific data associated with the given socket, but
+ * not the socket object itself.
+ *
+ * @param socket
+ * The guac_socket whose associated data should be freed.
+ *
+ * @return
+ * Zero if the data was successfully freed, non-zero otherwise. This
+ * implementation always succeeds, and will always return zero.
+ */
+static int __guac_socket_broadcast_free_handler(guac_socket* socket) {
+
+ guac_socket_broadcast_data* data =
+ (guac_socket_broadcast_data*) socket->data;
+
+ /* Destroy locks */
+ pthread_mutex_destroy(&(data->socket_lock));
+
+ free(data);
+ return 0;
+
+}
+
+guac_socket* guac_socket_broadcast(guac_client* client) {
+
+ pthread_mutexattr_t lock_attributes;
+
+ /* Allocate socket and associated data */
+ guac_socket* socket = guac_socket_alloc();
+ guac_socket_broadcast_data* data =
+ malloc(sizeof(guac_socket_broadcast_data));
+
+ /* Store client as socket data */
+ data->client = client;
+ socket->data = data;
+
+ pthread_mutexattr_init(&lock_attributes);
+ pthread_mutexattr_setpshared(&lock_attributes, PTHREAD_PROCESS_SHARED);
+
+ /* Init lock */
+ pthread_mutex_init(&(data->socket_lock), &lock_attributes);
+
+ /* Set read/write handlers */
+ socket->read_handler = __guac_socket_broadcast_read_handler;
+ socket->write_handler = __guac_socket_broadcast_write_handler;
+ socket->select_handler = __guac_socket_broadcast_select_handler;
+ socket->flush_handler = __guac_socket_broadcast_flush_handler;
+ socket->lock_handler = __guac_socket_broadcast_lock_handler;
+ socket->unlock_handler = __guac_socket_broadcast_unlock_handler;
+ socket->free_handler = __guac_socket_broadcast_free_handler;
+
+ return socket;
+
+}
+
[2/3] incubator-guacamole-server git commit: GUACAMOLE-171: Do not
require knowledge of broadcast socket internals (do not acquire write lock
around join/leave handlers).
Posted by jm...@apache.org.
GUACAMOLE-171: Do not require knowledge of broadcast socket internals (do not acquire write lock around join/leave handlers).
Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/7a65a63a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/7a65a63a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/7a65a63a
Branch: refs/heads/master
Commit: 7a65a63aa9c7e6721652b5f2b6c449bcf840ccb1
Parents: 98b92f0
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Oct 7 13:09:59 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Jan 23 23:43:36 2017 -0800
----------------------------------------------------------------------
src/libguac/client.c | 16 ++++++++--------
src/libguac/guacamole/client.h | 18 ------------------
2 files changed, 8 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/7a65a63a/src/libguac/client.c
----------------------------------------------------------------------
diff --git a/src/libguac/client.c b/src/libguac/client.c
index a3c3733..824254f 100644
--- a/src/libguac/client.c
+++ b/src/libguac/client.c
@@ -273,12 +273,12 @@ int guac_client_add_user(guac_client* client, guac_user* user, int argc, char**
int retval = 0;
- pthread_rwlock_wrlock(&(client->__users_lock));
-
/* Call handler, if defined */
if (client->join_handler)
retval = client->join_handler(user, argc, argv);
+ pthread_rwlock_wrlock(&(client->__users_lock));
+
/* Add to list if join was successful */
if (retval == 0) {
@@ -307,12 +307,6 @@ void guac_client_remove_user(guac_client* client, guac_user* user) {
pthread_rwlock_wrlock(&(client->__users_lock));
- /* Call handler, if defined */
- if (user->leave_handler)
- user->leave_handler(user);
- else if (client->leave_handler)
- client->leave_handler(user);
-
/* Update prev / head */
if (user->__prev != NULL)
user->__prev->__next = user->__next;
@@ -331,6 +325,12 @@ void guac_client_remove_user(guac_client* client, guac_user* user) {
pthread_rwlock_unlock(&(client->__users_lock));
+ /* Call handler, if defined */
+ if (user->leave_handler)
+ user->leave_handler(user);
+ else if (client->leave_handler)
+ client->leave_handler(user);
+
}
void guac_client_foreach_user(guac_client* client, guac_user_callback* callback, void* data) {
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/7a65a63a/src/libguac/guacamole/client.h
----------------------------------------------------------------------
diff --git a/src/libguac/guacamole/client.h b/src/libguac/guacamole/client.h
index ccb49cf..2d01573 100644
--- a/src/libguac/guacamole/client.h
+++ b/src/libguac/guacamole/client.h
@@ -53,10 +53,6 @@ struct guac_client {
* provide their own mechanism of I/O for their protocol. The guac_socket
* structure is used only to communicate conveniently with the Guacamole
* web-client.
- *
- * Because this socket broadcasts to all connected users, this socket MUST
- * NOT be used within the same thread as a "leave" or "join" handler. Doing
- * so results in undefined behavior, including possible segfaults.
*/
guac_socket* socket;
@@ -437,10 +433,6 @@ void guac_client_remove_user(guac_client* client, guac_user* user);
* MAY invoke guac_client_foreach_user(), doing so should not be necessary, and
* may indicate poor design choices.
*
- * Because this function loops through all connected users, this function MUST
- * NOT be invoked within the same thread as a "leave" or "join" handler. Doing
- * so results in undefined behavior, including possible segfaults.
- *
* @param client
* The client whose users should be iterated.
*
@@ -465,11 +457,6 @@ void guac_client_foreach_user(guac_client* client,
* This function is reentrant, but the user list MUST NOT be manipulated
* within the same thread as a callback to this function.
*
- * Because this function depends on a consistent list of connected users, this
- * function MUST NOT be invoked within the same thread as a "leave" or "join"
- * handler. Doing so results in undefined behavior, including possible
- * segfaults.
- *
* @param client
* The client to retrieve the owner from.
*
@@ -498,11 +485,6 @@ void* guac_client_for_owner(guac_client* client, guac_user_callback* callback,
* This function is reentrant, but the user list MUST NOT be manipulated
* within the same thread as a callback to this function.
*
- * Because this function depends on a consistent list of connected users, this
- * function MUST NOT be invoked within the same thread as a "leave" or "join"
- * handler. Doing so results in undefined behavior, including possible
- * segfaults.
- *
* @param client
* The client that the given user is expected to be associated with.
*
[3/3] incubator-guacamole-server git commit: GUACAMOLE-171: Merge
move of broadcast socket to public API.
Posted by jm...@apache.org.
GUACAMOLE-171: Merge move of broadcast socket to public API.
Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/a1886f51
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/a1886f51
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/a1886f51
Branch: refs/heads/master
Commit: a1886f51bd82a327278faae04100f54fb6d972f1
Parents: 8cd98b5 7a65a63
Author: James Muehlner <ja...@guac-dev.org>
Authored: Tue Jan 24 11:49:29 2017 -0800
Committer: James Muehlner <ja...@guac-dev.org>
Committed: Tue Jan 24 11:49:29 2017 -0800
----------------------------------------------------------------------
src/libguac/Makefile.am | 41 ++--
src/libguac/client.c | 289 +--------------------------
src/libguac/guacamole/client.h | 18 --
src/libguac/guacamole/socket.h | 27 +++
src/libguac/socket-broadcast.c | 377 ++++++++++++++++++++++++++++++++++++
5 files changed, 434 insertions(+), 318 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/a1886f51/src/libguac/client.c
----------------------------------------------------------------------