diff --git a/src/common/surface.c b/src/common/surface.c index e5d1ca9f33..48335e0161 100644 --- a/src/common/surface.c +++ b/src/common/surface.c @@ -33,6 +33,7 @@ #include #include #include +#include /** * The width of an update which should be considered negible and thus @@ -1805,24 +1806,34 @@ static void __guac_common_surface_flush_to_webp(guac_common_surface* surface, cairo_surface_t* rect; /* Use RGB24 if the image is fully opaque */ - if (opaque) + if (opaque) { + fprintf(stderr, "About to cairo_image_surface_create_for_data(CAIRO_FORMAT_RGB24)\n"); rect = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_RGB24, surface->dirty_rect.width, surface->dirty_rect.height, surface->stride); + fprintf(stderr, "Did cairo_image_surface_create_for_data(CAIRO_FORMAT_RGB24)\n"); + } /* Otherwise ARGB32 is needed */ - else + else { + fprintf(stderr, "About to cairo_image_surface_create_for_data(CAIRO_FORMAT_ARGB32)\n"); rect = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_ARGB32, surface->dirty_rect.width, surface->dirty_rect.height, surface->stride); + fprintf(stderr, "Did cairo_image_surface_create_for_data(CAIRO_FORMAT_ARGB32)\n"); + } /* Send WebP for rect */ + fprintf(stderr, "About to guac_client_stream_webp()\n"); guac_client_stream_webp(surface->client, socket, GUAC_COMP_OVER, layer, surface->dirty_rect.x, surface->dirty_rect.y, rect, guac_common_surface_suggest_quality(surface->client), surface->lossless ? 1 : 0); + fprintf(stderr, "Did guac_client_stream_webp()\n"); + fprintf(stderr, "About to cairo_surface_destroy()\n"); cairo_surface_destroy(rect); + fprintf(stderr, "Did cairo_surface_destroy()\n"); surface->realized = 1; /* Surface is no longer dirty */ @@ -1892,6 +1903,8 @@ static void __guac_common_surface_flush(guac_common_surface* surface) { /* Flush final dirty rectangle to queue. */ __guac_common_surface_flush_to_queue(surface); + fprintf(stderr, "__guac_common_surface_flush did __guac_common_surface_flush_to_queue(surface)\n"); + guac_common_surface_bitmap_rect* current = surface->bitmap_queue; int i, j; int original_queue_length; @@ -1903,6 +1916,8 @@ static void __guac_common_surface_flush(guac_common_surface* surface) { qsort(surface->bitmap_queue, surface->bitmap_queue_length, sizeof(guac_common_surface_bitmap_rect), __guac_common_surface_bitmap_rect_compare); + fprintf(stderr, "__guac_common_surface_flush did qsort()\n"); + /* Flush all rects in queue */ for (i=0; i < surface->bitmap_queue_length; i++) { @@ -1929,6 +1944,8 @@ static void __guac_common_surface_flush(guac_common_surface* surface) { combined++; } + fprintf(stderr, "__guac_common_surface_flush did __guac_common_bound_rect()\n"); + } candidate++; @@ -1937,9 +1954,13 @@ static void __guac_common_surface_flush(guac_common_surface* surface) { /* Re-add to queue if there's room and this update was modified or we expect others might be */ if ((combined > 1 || i < original_queue_length) - && surface->bitmap_queue_length < GUAC_COMMON_SURFACE_QUEUE_SIZE) + && surface->bitmap_queue_length < GUAC_COMMON_SURFACE_QUEUE_SIZE) { + __guac_common_surface_flush_to_queue(surface); + fprintf(stderr, "__guac_common_surface_flush did __guac_common_surface_flush_to_queue()\n"); + } + /* Flush as bitmap otherwise */ else if (surface->dirty) { @@ -1948,28 +1969,47 @@ static void __guac_common_surface_flush(guac_common_surface* surface) { int opaque = __guac_common_surface_is_opaque(surface, &surface->dirty_rect); + fprintf(stderr, "__guac_common_surface_flush did __guac_common_surface_is_opaque()\n"); + /* Prefer WebP when reasonable */ if (__guac_common_surface_should_use_webp(surface, - &surface->dirty_rect)) + &surface->dirty_rect)) { + + fprintf(stderr, "__guac_common_surface_flush about to __guac_common_surface_flush_to_webp()\n"); __guac_common_surface_flush_to_webp(surface, opaque); + fprintf(stderr, "__guac_common_surface_flush did __guac_common_surface_flush_to_webp()\n"); + } + /* If not WebP, JPEG is the next best (lossy) choice */ else if (opaque && __guac_common_surface_should_use_jpeg( - surface, &surface->dirty_rect)) + surface, &surface->dirty_rect)) { + fprintf(stderr, "__guac_common_surface_flush about to __guac_common_surface_flush_to_jpeg()\n"); __guac_common_surface_flush_to_jpeg(surface); + fprintf(stderr, "__guac_common_surface_flush did __guac_common_surface_flush_to_jpeg()\n"); + } + /* Use PNG if no lossy formats are appropriate */ - else + else { + fprintf(stderr, "__guac_common_surface_flush about to __guac_common_surface_flush_to_png()\n"); __guac_common_surface_flush_to_png(surface, opaque); + fprintf(stderr, "__guac_common_surface_flush did __guac_common_surface_flush_to_png()\n"); + } + } } current++; + fprintf(stderr, "__guac_common_surface_flush did current++ - %p\n", (void*) current); + } + fprintf(stderr, "__guac_common_surface_flush Flush complete\n"); + /* Flush complete */ surface->bitmap_queue_length = 0; @@ -1977,16 +2017,23 @@ static void __guac_common_surface_flush(guac_common_surface* surface) { void guac_common_surface_flush(guac_common_surface* surface) { + fprintf(stderr, "guac_common_surface_flush about to pthread_mutex_lock(&surface->_lock)\n"); pthread_mutex_lock(&surface->_lock); + fprintf(stderr, "guac_common_surface_flush got pthread_mutex_lock(&surface->_lock)\n"); /* Flush any applicable layer properties */ __guac_common_surface_flush_properties(surface); + fprintf(stderr, "guac_common_surface_flush did __guac_common_surface_flush_properties(surface)\n"); /* Flush surface contents */ __guac_common_surface_flush(surface); + fprintf(stderr, "guac_common_surface_flush did __guac_common_surface_flush(surface)\n"); pthread_mutex_unlock(&surface->_lock); + fprintf(stderr, "guac_common_surface_flush did pthread_mutex_unlock(&surface->_lock)\n"); + + } void guac_common_surface_dup(guac_common_surface* surface, diff --git a/src/guacd/proc.c b/src/guacd/proc.c index 6e85e9411f..f9babe96b2 100644 --- a/src/guacd/proc.c +++ b/src/guacd/proc.c @@ -167,7 +167,8 @@ static void guacd_proc_add_user(guacd_proc* proc, HANDLE handle, int owner) { /* Start user thread */ pthread_t user_thread; - pthread_create(&user_thread, NULL, guacd_user_thread, params); + int the_return = pthread_create(&user_thread, NULL, guacd_user_thread, params); + fprintf(stderr, "guacd_proc_add_user pthread_create(): %i, errno: %i\n", the_return, errno); pthread_detach(user_thread); } @@ -362,7 +363,7 @@ static int guacd_timed_client_free(guac_client* client, int timeout) { /* Free the client in a separate thread, so we can time the free operation */ int the_return = pthread_create(&client_free_thread, NULL, guacd_client_free_thread, &free_operation); - fprintf(stderr, "pthread_create(): %i, errno: %i\n", the_return, errno); + fprintf(stderr, "guacd_timed_client_free pthread_create(): %i, errno: %i\n", the_return, errno); if (!the_return) { diff --git a/src/libguac/client.c b/src/libguac/client.c index b904fb7e42..ddaca1045a 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -913,20 +913,28 @@ void guac_client_stream_webp(guac_client* client, guac_socket* socket, cairo_surface_t* surface, int quality, int lossless) { #ifdef ENABLE_WEBP + + fprintf(stderr, "guac_client_stream_webp about to guac_client_alloc_stream()\n"); /* Allocate new stream for image */ guac_stream* stream = guac_client_alloc_stream(client); + fprintf(stderr, "guac_client_stream_webp about did guac_client_alloc_stream()\n"); /* Declare stream as containing image data */ guac_protocol_send_img(socket, stream, mode, layer, "image/webp", x, y); + fprintf(stderr, "guac_client_stream_webp about did guac_protocol_send_img()\n"); /* Write WebP data */ guac_webp_write(socket, stream, surface, quality, lossless); + fprintf(stderr, "guac_client_stream_webp about did guac_webp_write()\n"); /* Terminate stream */ guac_protocol_send_end(socket, stream); + fprintf(stderr, "guac_client_stream_webp about did guac_protocol_send_end()\n"); + /* Free allocated stream */ guac_client_free_stream(client, stream); + fprintf(stderr, "guac_client_stream_webp about did guac_client_free_stream()\n"); #else /* Do nothing if WebP support is not built in */ #endif diff --git a/src/libguac/encode-webp.c b/src/libguac/encode-webp.c index 43c5a00c5d..122f75cb1c 100644 --- a/src/libguac/encode-webp.c +++ b/src/libguac/encode-webp.c @@ -171,11 +171,19 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream, int x, y; + fprintf(stderr, "guac_webp_write about to cairo_image_surface_get_width()\n"); + int width = cairo_image_surface_get_width(surface); + + fprintf(stderr, "guac_webp_write did cairo_image_surface_get_width()\n"); int height = cairo_image_surface_get_height(surface); + fprintf(stderr, "guac_webp_write did cairo_image_surface_get_height()\n"); int stride = cairo_image_surface_get_stride(surface); + fprintf(stderr, "guac_webp_write did cairo_image_surface_get_stride()\n"); cairo_format_t format = cairo_image_surface_get_format(surface); + fprintf(stderr, "guac_webp_write did cairo_image_surface_get_format()\n"); unsigned char* data = cairo_image_surface_get_data(surface); + fprintf(stderr, "guac_webp_write did cairo_image_surface_get_data()\n"); if (format != CAIRO_FORMAT_RGB24 && format != CAIRO_FORMAT_ARGB32) { guac_error = GUAC_STATUS_INTERNAL_ERROR; @@ -185,11 +193,18 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream, /* Flush pending operations to surface */ cairo_surface_flush(surface); + fprintf(stderr, "guac_webp_write did cairo_surface_flush()\n"); /* Configure WebP compression bits */ WebPConfig config; - if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality)) + if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality)) { + + fprintf(stderr, "not WebPConfigPreset()\n"); + return -1; + } + + fprintf(stderr, "guac_webp_write did WebPConfigPreset()\n"); /* Add additional tuning */ config.lossless = lossless; @@ -200,22 +215,32 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream, /* Validate configuration */ WebPValidateConfig(&config); + fprintf(stderr, "guac_webp_write did WebPValidateConfig()\n"); + /* Set up WebP picture */ WebPPictureInit(&picture); picture.use_argb = 1; picture.width = width; picture.height = height; + fprintf(stderr, "guac_webp_write did WebPPictureInit()\n"); + /* Allocate and init writer */ WebPPictureAlloc(&picture); + + fprintf(stderr, "guac_webp_write did WebPPictureAlloc()\n"); picture.writer = guac_webp_stream_write; picture.custom_ptr = &writer; guac_webp_stream_writer_init(&writer, socket, stream); + fprintf(stderr, "guac_webp_write did guac_webp_stream_writer_init()\n"); + /* Copy image data into WebP picture */ argb_output = picture.argb; for (y = 0; y < height; y++) { + fprintf(stderr, "webp y: %i\n", y); + /* Get pixels at start of each row */ uint32_t* src = (uint32_t*) data; uint32_t* dst = argb_output; @@ -223,6 +248,8 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream, /* For each pixel in row */ for (x = 0; x < width; x++) { + fprintf(stderr, "webp x: %i\n", x); + /* Pull pixel data, removing alpha channel if necessary */ uint32_t src_pixel = *src; if (format != CAIRO_FORMAT_ARGB32) @@ -246,12 +273,18 @@ int guac_webp_write(guac_socket* socket, guac_stream* stream, /* Encode image */ WebPEncode(&config, &picture); + fprintf(stderr, "guac_webp_write did WebPEncode()\n"); + /* Free picture */ WebPPictureFree(&picture); + fprintf(stderr, "guac_webp_write did WebPPictureFree()\n"); + /* Ensure all data is written */ guac_webp_flush_data(&writer); + fprintf(stderr, "guac_webp_write did guac_webp_flush_data()\n"); + return 0; } diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index 3b94d5e759..3ca325b956 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -262,7 +262,10 @@ static int guac_vnc_wait_for_messages(rfbClient* rfb_client, int timeout) { return 1; /* If no data on buffer, wait for data on socket */ - return WaitForMessage(rfb_client, timeout); + fprintf(stderr, "About to WaitForMessage(%p, %i)\n", (void*) rfb_client, timeout); + int the_value = WaitForMessage(rfb_client, timeout); + fprintf(stderr, "Succesfully got WaitForMessage() value: %i\n", the_value); + return the_value; } @@ -419,6 +422,8 @@ void* guac_vnc_client_thread(void* data) { /* Set remaining client data */ vnc_client->rfb_client = rfb_client; + fprintf(stderr, "Did vnc_client->rfb_client = rfb_client\n"); + /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { vnc_client->recording = guac_recording_create(client, @@ -431,14 +436,20 @@ void* guac_vnc_client_thread(void* data) { settings->recording_include_keys); } + fprintf(stderr, "Did guac_recording_create\n"); + /* Create display */ vnc_client->display = guac_common_display_alloc(client, rfb_client->width, rfb_client->height); + fprintf(stderr, "Did guac_common_display_alloc\n"); + /* Use lossless compression only if requested (otherwise, use default * heuristics) */ guac_common_display_set_lossless(vnc_client->display, settings->lossless); + fprintf(stderr, "Did guac_common_display_set_lossless\n"); + /* If not read-only, set an appropriate cursor */ if (settings->read_only == 0) { if (settings->remote_cursor) @@ -448,21 +459,35 @@ void* guac_vnc_client_thread(void* data) { } + fprintf(stderr, "Did guac_common_cursor_set_\n"); + guac_socket_flush(client->socket); + fprintf(stderr, "Did guac_socket_flush\n"); + guac_timestamp last_frame_end = guac_timestamp_current(); + fprintf(stderr, "last_frame_end: %lu\n", last_frame_end); + fprintf(stderr, "client->state: %i\n", client->state); + /* Handle messages from VNC server while client is running */ while (client->state == GUAC_CLIENT_RUNNING) { /* Wait for start of frame */ int wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_FRAME_START_TIMEOUT); + + fprintf(stderr, "guac_vnc_wait_for_messages result: %i\n", wait_result); + if (wait_result > 0) { int processing_lag = guac_client_get_processing_lag(client); + + fprintf(stderr, "processing_lag: %i\n", processing_lag); guac_timestamp frame_start = guac_timestamp_current(); + fprintf(stderr, "frame_start: %lu\n", frame_start); + /* Read server messages until frame is built */ do { @@ -482,21 +507,34 @@ void* guac_vnc_client_thread(void* data) { frame_remaining = frame_start + GUAC_VNC_FRAME_DURATION - frame_end; + fprintf(stderr, "frame_end: %lu\n", frame_end); + /* Calculate time that client needs to catch up */ int time_elapsed = frame_end - last_frame_end; int required_wait = processing_lag - time_elapsed; + fprintf(stderr, "required_wait: %i\n", required_wait); + /* Increase the duration of this frame if client is lagging */ - if (required_wait > GUAC_VNC_FRAME_TIMEOUT) + if (required_wait > GUAC_VNC_FRAME_TIMEOUT) { + + fprintf(stderr, "waiting for: %i\n", required_wait); wait_result = guac_vnc_wait_for_messages(rfb_client, required_wait*1000); + fprintf(stderr, "wait_result: %i\n", wait_result); + } /* Wait again if frame remaining */ - else if (frame_remaining > 0) + else if (frame_remaining > 0) { + fprintf(stderr, "frame_remaining: %i, waiting for: %i\n", frame_remaining, GUAC_VNC_FRAME_TIMEOUT); wait_result = guac_vnc_wait_for_messages(rfb_client, GUAC_VNC_FRAME_TIMEOUT*1000); - else + fprintf(stderr, "wait_result: %i\n", wait_result); + } + else { + fprintf(stderr, "breaking\n"); break; + } } while (wait_result > 0); @@ -505,21 +543,32 @@ void* guac_vnc_client_thread(void* data) { * two subsequent frames, and that this time should thus be * excluded from the required wait period of the next frame). */ last_frame_end = frame_start; + fprintf(stderr, "final last_frame_end: %lu\n", last_frame_end); } + fprintf(stderr, "final wait_result: %i\n", wait_result); + /* If an error occurs, log it and fail */ - if (wait_result < 0) + if (wait_result < 0) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Connection closed."); + } /* Flush frame */ + fprintf(stderr, "about to guac_common_surface_flush()\n"); guac_common_surface_flush(vnc_client->display->default_surface); + fprintf(stderr, "did guac_common_surface_flush()\n"); + guac_client_end_frame(client); + fprintf(stderr, "did guac_client_end_frame()\n"); + guac_socket_flush(client->socket); + fprintf(stderr, "did guac_socket_flush()\n"); } /* Kill client and finish connection */ + fprintf(stderr, "about to guac_client_stop()\n"); guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "Internal VNC client disconnected"); return NULL;