Skip to content

Commit

Permalink
GUACAMOLE-1846: Sync data to all pending users using broadcast socket.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmuehlner committed Aug 23, 2023
1 parent 6265817 commit 1f0dc9e
Show file tree
Hide file tree
Showing 32 changed files with 453 additions and 248 deletions.
6 changes: 3 additions & 3 deletions src/common/common/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,14 @@ void guac_common_cursor_free(guac_common_cursor* cursor);
* @param cursor
* The cursor to send.
*
* @param user
* @param client
* The user receiving the updated cursor.
*
* @param socket
* The socket over which the updated cursor should be sent.
*/
void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
guac_socket* socket);
void guac_common_cursor_dup(
guac_common_cursor* cursor, guac_client* client, guac_socket* socket);

/**
* Updates the current position and button state of the mouse cursor, marking
Expand Down
7 changes: 4 additions & 3 deletions src/common/common/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,14 @@ void guac_common_display_free(guac_common_display* display);
* @param display
* The display whose state should be sent along the given socket.
*
* @param user
* The user receiving the display state.
* @param client
* The client associated with the users receiving the display state.
*
* @param socket
* The socket over which the display state should be sent.
*/
void guac_common_display_dup(guac_common_display* display, guac_user* user,
void guac_common_display_dup(
guac_common_display* display, guac_client* client,
guac_socket* socket);

/**
Expand Down
8 changes: 4 additions & 4 deletions src/common/common/surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,14 +490,14 @@ void guac_common_surface_flush(guac_common_surface* surface);
* @param surface
* The surface to duplicate.
*
* @param user
* The user receiving the surface.
* @param client
* The client whos users are receiving the surface.
*
* @param socket
* The socket over which the surface contents should be sent.
*/
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
guac_socket* socket);
void guac_common_surface_dup(guac_common_surface* surface,
guac_client* client, guac_socket* socket);

/**
* Declares that the given surface should receive touch events. By default,
Expand Down
6 changes: 3 additions & 3 deletions src/common/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ void guac_common_cursor_free(guac_common_cursor* cursor) {

}

void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
guac_socket* socket) {
void guac_common_cursor_dup(
guac_common_cursor* cursor, guac_client* client, guac_socket* socket) {

/* Synchronize location */
guac_protocol_send_mouse(socket, cursor->x, cursor->y, cursor->button_mask,
Expand All @@ -111,7 +111,7 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
guac_protocol_send_size(socket, cursor->buffer,
cursor->width, cursor->height);

guac_user_stream_png(user, socket, GUAC_COMP_SRC,
guac_client_stream_png(client, socket, GUAC_COMP_SRC,
cursor->buffer, 0, 0, cursor->surface);

guac_protocol_send_cursor(socket,
Expand Down
21 changes: 10 additions & 11 deletions src/common/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@
* The head element of the linked list of layers to synchronize, which may
* be NULL if the list is currently empty.
*
* @param user
* The user receiving the layers.
* @param client
* The client associated with the users receiving the layers.
*
* @param socket
* The socket over which each layer should be sent.
*/
static void guac_common_display_dup_layers(guac_common_display_layer* layers,
guac_user* user, guac_socket* socket) {
guac_client* client, guac_socket* socket) {

guac_common_display_layer* current = layers;

/* Synchronize all surfaces in given list */
while (current != NULL) {
guac_common_surface_dup(current->surface, user, socket);
guac_common_surface_dup(current->surface, client, socket);
current = current->next;
}

Expand Down Expand Up @@ -163,22 +163,21 @@ void guac_common_display_free(guac_common_display* display) {

}

void guac_common_display_dup(guac_common_display* display, guac_user* user,
void guac_common_display_dup(
guac_common_display* display, guac_client* client,
guac_socket* socket) {

guac_client* client = user->client;

pthread_mutex_lock(&display->_lock);

/* Sunchronize shared cursor */
guac_common_cursor_dup(display->cursor, user, socket);
guac_common_cursor_dup(display->cursor, client, socket);

/* Synchronize default surface */
guac_common_surface_dup(display->default_surface, user, socket);
guac_common_surface_dup(display->default_surface, client, socket);

/* Synchronize all layers and buffers */
guac_common_display_dup_layers(display->layers, user, socket);
guac_common_display_dup_layers(display->buffers, user, socket);
guac_common_display_dup_layers(display->layers, client, socket);
guac_common_display_dup_layers(display->buffers, client, socket);

/* Sends a sync instruction to mark the boundary of the first frame */
guac_protocol_send_sync(socket, client->last_sent_timestamp, 1);
Expand Down
7 changes: 3 additions & 4 deletions src/common/surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1989,8 +1989,8 @@ void guac_common_surface_flush(guac_common_surface* surface) {

}

void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
guac_socket* socket) {
void guac_common_surface_dup(guac_common_surface* surface,
guac_client* client, guac_socket* socket) {

pthread_mutex_lock(&surface->_lock);

Expand Down Expand Up @@ -2028,7 +2028,7 @@ void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
surface->width, surface->height, surface->stride);

/* Send PNG for rect */
guac_user_stream_png(user, socket, GUAC_COMP_OVER, surface->layer,
guac_client_stream_png(client, socket, GUAC_COMP_OVER, surface->layer,
0, 0, rect);
cairo_surface_destroy(rect);

Expand All @@ -2038,4 +2038,3 @@ void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
pthread_mutex_unlock(&surface->_lock);

}

8 changes: 5 additions & 3 deletions src/libguac/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static void guac_client_promote_pending_users(union sigval data) {

guac_release_lock(&(client->__users_lock));

/* Release the lock (this is done AFTER updating the non-pending user list
/* Release the lock (this is done AFTER updating the connected user list
* to ensure that all users are always on exactly one of these lists) */
guac_release_lock(&(client->__pending_users_lock));

Expand Down Expand Up @@ -253,8 +253,9 @@ guac_client* guac_client_alloc() {
/* Ensure the timer is constructed only once */
pthread_mutex_init(&(client->__pending_users_timer_mutex), NULL);

/* Set up socket to broadcast to all users */
/* Set up broadcast sockets */
client->socket = guac_socket_broadcast(client);
client->pending_socket = guac_socket_broadcast_pending(client);

/* Set the timer event thread as initially inactive, since it hasn't run */
atomic_flag_clear(&(client->__pending_timer_event_active));
Expand All @@ -280,8 +281,9 @@ void guac_client_free(guac_client* client) {

}

/* Free socket */
/* Free sockets */
guac_socket_free(client->socket);
guac_socket_free(client->pending_socket);

/* Free layer pools */
guac_pool_free(client->__buffer_pool);
Expand Down
8 changes: 5 additions & 3 deletions src/libguac/guacamole/client-fntypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
#include "client-types.h"
#include "object-types.h"
#include "protocol-types.h"
#include "socket.h"
#include "stream-types.h"
#include "user-fntypes.h"
#include "user-types.h"

#include <stdarg.h>
Expand All @@ -49,9 +51,9 @@
typedef int guac_client_free_handler(guac_client* client);

/**
* Handler that will run before pending users are promoted to full users.
* Any required operations for pending users should be applied using
* guac_client_foreach_pending_user().
* Handler that will run before immediately before pending users are promoted
* to full users. The pending user socket should be used to communicate to the
* pending users.
*
* @param client
* The client whose handler was invoked.
Expand Down
26 changes: 17 additions & 9 deletions src/libguac/guacamole/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,24 @@
struct guac_client {

/**
* The guac_socket structure to be used to communicate with all connected
* web-clients (users). Unlike the user-level guac_socket, this guac_socket
* will broadcast instructions to all connected users simultaneously. It
* is expected that the implementor of any Guacamole proxy client will
* 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.
* The guac_socket structure to be used to communicate with all non-pending
* connected web-clients (users). Unlike the user-level guac_socket, this
* guac_socket will broadcast instructions to all non-pending connected users
* simultaneously. It is expected that the implementor of any Guacamole proxy
* client will 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.
*/
guac_socket* socket;

/**
* The guac_socket structure to be used to communicate with all pending
* connected web-clients (users). Aside from operating on a different
* subset of users, this socket has all the same behavior and semantics as
* the non-pending socket.
*/
guac_socket* pending_socket;

/**
* The current state of the client. When the client is first allocated,
* this will be initialized to GUAC_CLIENT_RUNNING. It will remain at
Expand Down Expand Up @@ -248,8 +256,8 @@ struct guac_client {

/**
* A handler that will be run prior to pending users being promoted to full
* users. Any required pending user operations should be applied
* guac_client_foreach_pending_user().
* users. Any required pending user operations should be performed using
* the client's pending user socket.
*
* Example:
* @code
Expand Down
36 changes: 31 additions & 5 deletions src/libguac/guacamole/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,10 @@ 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.
* 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
Expand All @@ -253,12 +253,38 @@ guac_socket* guac_socket_tee(guac_socket* primary, guac_socket* secondary);
*
* @return
* A write-only guac_socket object which broadcasts copies of all
* instructions written across all connected users of the given
* instructions written across all non-pending 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);

/**
* Allocates and initializes a new guac_socket which duplicates all
* instructions written across the sockets of each pending 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 pending 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 pending connected users of the given
* guac_client, or NULL if an error occurs while allocating the guac_socket
* object.
*/
guac_socket* guac_socket_broadcast_pending(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
Expand Down
Loading

0 comments on commit 1f0dc9e

Please sign in to comment.