Skip to content

Commit

Permalink
GUACAMOLE-377: Migrate VNC to default render loop.
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-jumper committed Sep 28, 2024
1 parent 349ce5e commit e47c7f8
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 54 deletions.
29 changes: 7 additions & 22 deletions src/protocols/vnc/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,14 @@
#include <guacamole/client.h>

/**
* The maximum duration of a frame in milliseconds. This ensures we at least
* meet a reasonable minimum framerate in the case that the VNC server provides
* no frame boundaries and streams data continuously enough that frame
* boundaries are not discernable through timing.
* The amount of time to wait for new messages from the VNC server before
* moving on to internal matters, in milliseconds. This value must be kept
* reasonably small such that a slow VNC server will not prevent external
* events from being handled (such as the stop signal from guac_client_stop()),
* but large enough that the message handling loop does not eat up CPU
* spinning.
*/
#define GUAC_VNC_MAX_FRAME_DURATION 33

/**
* The minimum duration of a frame in milliseconds. This ensures we don't start
* flushing a ton of tiny frames if an VNC server provides no frame boundaries
* and streams data inconsistently enough that timing would suggest frame
* boundaries in the middle of a frame.
*/
#define GUAC_VNC_MIN_FRAME_DURATION 10

/**
* The amount of time to wait for a new message from the VNC server when
* beginning a new frame, in milliseconds. This value must be kept reasonably
* small such that a slow VNC server will not prevent external events from
* being handled (such as the stop signal from guac_client_stop()), but large
* enough that the message handling loop does not eat up CPU spinning.
*/
#define GUAC_VNC_FRAME_START_TIMEOUT 1000
#define GUAC_VNC_MESSAGE_CHECK_INTERVAL 1000

/**
* The number of milliseconds to wait between connection attempts.
Expand Down
1 change: 1 addition & 0 deletions src/protocols/vnc/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int vnc_bpp)

/* Draw operation is now complete */
guac_display_layer_close_raw(cursor_layer, context);
guac_display_render_thread_notify_modified(vnc_client->render_thread);

/* libvncclient does not free rcMask as it does rcSource */
if (client->rcMask != NULL) {
Expand Down
2 changes: 2 additions & 0 deletions src/protocols/vnc/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) {
vnc_client->copy_rect_used = 0;
}

guac_display_render_thread_notify_modified(vnc_client->render_thread);

}

void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
Expand Down
46 changes: 14 additions & 32 deletions src/protocols/vnc/vnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,44 +596,22 @@ void* guac_vnc_client_thread(void* data) {

guac_display_end_frame(vnc_client->display);

vnc_client->render_thread = guac_display_render_thread_create(vnc_client->display);

/* Handle messages from VNC server while client is running */
while (client->state == GUAC_CLIENT_RUNNING) {

/* Wait for data and construct a reasonable frame */
int wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_FRAME_START_TIMEOUT);
int wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_MESSAGE_CHECK_INTERVAL);
if (wait_result > 0) {

/* Read server messages until frame is built */
guac_timestamp frame_start = guac_timestamp_current();
do {

/* Handle any message received */
if (!guac_vnc_handle_messages(vnc_client)) {
guac_client_abort(client,
GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
"Error handling message from VNC server.");
break;
}

int frame_duration = guac_timestamp_current() - frame_start;

/* Continue processing messages for up to a reasonable minimum
* framerate without an explicit frame boundary indicating that
* the frame is not yet complete */
if (frame_duration > GUAC_VNC_MAX_FRAME_DURATION)
break;

/* Do not exceed a reasonable maximum framerate without an
* explicit frame boundary terminating the frame early */
int allowed_wait = GUAC_VNC_MIN_FRAME_DURATION - frame_duration;
if (allowed_wait < 0)
allowed_wait = 0;

wait_result = guac_vnc_wait_for_messages(rfb_client, allowed_wait);

} while (wait_result > 0);

guac_display_end_frame(vnc_client->display);
/* Handle any message received */
if (!guac_vnc_handle_messages(vnc_client)) {
guac_client_abort(client,
GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
"Error handling message from VNC server.");
break;
}

}

Expand All @@ -643,6 +621,10 @@ void* guac_vnc_client_thread(void* data) {

}

/* Stop render loop */
guac_display_render_thread_destroy(vnc_client->render_thread);
vnc_client->render_thread = NULL;

/* Kill client and finish connection */
guac_client_stop(client);
guac_client_log(client, GUAC_LOG_INFO, "Internal VNC client disconnected");
Expand Down
6 changes: 6 additions & 0 deletions src/protocols/vnc/vnc.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ typedef struct guac_vnc_client {
*/
guac_display_layer_raw_context* current_context;

/**
* The current instance of the guac_display render thread. If the thread
* has not yet been started, this will be NULL.
*/
guac_display_render_thread* render_thread;

/**
* Internal clipboard.
*/
Expand Down

0 comments on commit e47c7f8

Please sign in to comment.