Hello community, here is the log from the commit of package neatvnc for openSUSE:Factory checked in at 2020-10-05 19:41:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/neatvnc (Old) and /work/SRC/openSUSE:Factory/.neatvnc.new.4249 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "neatvnc" Mon Oct 5 19:41:48 2020 rev:4 rq:839498 version:0.3.2 Changes: -------- --- /work/SRC/openSUSE:Factory/neatvnc/neatvnc.changes 2020-08-07 14:19:53.962381149 +0200 +++ /work/SRC/openSUSE:Factory/.neatvnc.new.4249/neatvnc.changes 2020-10-05 19:43:10.245789030 +0200 @@ -1,0 +2,8 @@ +Wed Sep 30 08:28:57 UTC 2020 - Dirk Mueller <[email protected]> + +- update to 0.3.2: + * This release fixes a crash due to incorrect handling of fragmented packets + and adds copy & paste support. + * This release fixes a bug with tight encoding reported by Jeroen Hofstee + +------------------------------------------------------------------- Old: ---- v0.2.0.tar.gz New: ---- v0.3.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ neatvnc.spec ++++++ --- /var/tmp/diff_new_pack.nGEFEm/_old 2020-10-05 19:43:10.885789656 +0200 +++ /var/tmp/diff_new_pack.nGEFEm/_new 2020-10-05 19:43:10.889789660 +0200 @@ -17,7 +17,7 @@ Name: neatvnc -Version: 0.2.0 +Version: 0.3.2 Release: 0 Summary: A VNC server library License: ISC ++++++ v0.2.0.tar.gz -> v0.3.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/include/common.h new/neatvnc-0.3.2/include/common.h --- old/neatvnc-0.2.0/include/common.h 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/include/common.h 2020-09-27 19:31:06.000000000 +0200 @@ -34,6 +34,7 @@ #define MAX_ENCODINGS 32 #define MAX_OUTGOING_FRAMES 4 #define MSG_BUFFER_SIZE 4096 +#define MAX_CUT_TEXT_SIZE 10000000 enum nvnc_client_state { VNC_CLIENT_STATE_ERROR = -1, @@ -58,6 +59,12 @@ void* userdata; }; +struct cut_text { + char* buffer; + size_t length; + size_t index; +}; + struct nvnc_client { struct nvnc_common common; int ref; @@ -80,6 +87,7 @@ uint8_t msg_buffer[MSG_BUFFER_SIZE]; uint32_t known_width; uint32_t known_height; + struct cut_text cut_text; }; LIST_HEAD(nvnc_client_list, nvnc_client); @@ -96,6 +104,7 @@ nvnc_pointer_fn pointer_fn; nvnc_fb_req_fn fb_req_fn; nvnc_client_fn new_client_fn; + nvnc_cut_text_fn cut_text_fn; struct nvnc_display* display; #ifdef ENABLE_TLS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/include/enc-util.h new/neatvnc-0.3.2/include/enc-util.h --- old/neatvnc-0.2.0/include/enc-util.h 1970-01-01 01:00:00.000000000 +0100 +++ new/neatvnc-0.3.2/include/enc-util.h 2020-09-27 19:31:06.000000000 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 - 2020 Andri Yngvason + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +#include "rfb-proto.h" + +#include <stdint.h> + +struct vec; + +int encode_rect_count(struct vec* dst, uint32_t count); +int encode_rect_head(struct vec* dst, enum rfb_encodings encoding, + uint32_t x, uint32_t y, uint32_t width, uint32_t height); +uint32_t calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/include/neatvnc.h new/neatvnc-0.3.2/include/neatvnc.h --- old/neatvnc-0.2.0/include/neatvnc.h 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/include/neatvnc.h 2020-09-27 19:31:06.000000000 +0200 @@ -49,6 +49,7 @@ typedef bool (*nvnc_auth_fn)(const char* username, const char* password, void* userdata); typedef void (*nvnc_render_fn)(struct nvnc_display*, struct nvnc_fb*); +typedef void (*nvnc_cut_text_fn)(struct nvnc*, const char* text, uint32_t len); extern const char nvnc_version[]; @@ -70,6 +71,7 @@ void nvnc_set_fb_req_fn(struct nvnc* self, nvnc_fb_req_fn); void nvnc_set_new_client_fn(struct nvnc* self, nvnc_client_fn); void nvnc_set_client_cleanup_fn(struct nvnc_client* self, nvnc_client_fn fn); +void nvnc_set_cut_text_receive_fn(struct nvnc* self, nvnc_cut_text_fn fn); bool nvnc_has_auth(void); int nvnc_enable_auth(struct nvnc* self, const char* privkey_path, @@ -111,3 +113,5 @@ int nvnc_check_damage(struct nvnc_fb* fb0, struct nvnc_fb* fb1, int x_hint, int y_hint, int width_hint, int height_hint, nvnc_damage_fn on_check_done, void* userdata); + +void nvnc_send_cut_text(struct nvnc*, const char* text, uint32_t len); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/include/rfb-proto.h new/neatvnc-0.3.2/include/rfb-proto.h --- old/neatvnc-0.2.0/include/rfb-proto.h 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/include/rfb-proto.h 2020-09-27 19:31:06.000000000 +0200 @@ -140,11 +140,11 @@ uint16_t y; } RFB_PACKED; -struct rfb_client_cut_text_msg { +struct rfb_cut_text_msg { uint8_t type; uint8_t padding[3]; uint32_t length; - char test[0]; + char text[0]; } RFB_PACKED; struct rfb_server_fb_rect { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/include/tight.h new/neatvnc-0.3.2/include/tight.h --- old/neatvnc-0.2.0/include/tight.h 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/include/tight.h 2020-09-27 19:31:06.000000000 +0200 @@ -16,6 +16,9 @@ #pragma once +#include "rfb-proto.h" +#include "vec.h" + #include <unistd.h> #include <stdint.h> #include <zlib.h> @@ -25,6 +28,8 @@ struct pixman_region16; struct aml_work; +typedef void (*tight_done_fn)(struct vec* frame, void*); + enum tight_quality { TIGHT_QUALITY_UNSPEC = 0, TIGHT_QUALITY_LOSSLESS, @@ -44,17 +49,17 @@ z_stream zs[4]; struct aml_work* zs_worker[4]; - const struct rfb_pixel_format* dfmt; - const struct rfb_pixel_format* sfmt; - const struct nvnc_fb* fb; + struct rfb_pixel_format dfmt; + struct rfb_pixel_format sfmt; + struct nvnc_fb* fb; uint32_t n_rects; uint32_t n_jobs; - struct vec* dst; + struct vec dst; - pthread_mutex_t wait_mutex; - pthread_cond_t wait_cond; + tight_done_fn on_frame_done; + void* userdata; }; int tight_encoder_init(struct tight_encoder* self, uint32_t width, @@ -64,9 +69,10 @@ int tight_encoder_resize(struct tight_encoder* self, uint32_t width, uint32_t height); -int tight_encode_frame(struct tight_encoder* self, struct vec* dst, +int tight_encode_frame(struct tight_encoder* self, const struct rfb_pixel_format* dfmt, - const struct nvnc_fb* src, + struct nvnc_fb* src, const struct rfb_pixel_format* sfmt, struct pixman_region16* damage, - enum tight_quality quality); + enum tight_quality quality, + tight_done_fn on_done, void* userdata); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/meson.build new/neatvnc-0.3.2/meson.build --- old/neatvnc-0.2.0/meson.build 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/meson.build 2020-09-27 19:31:06.000000000 +0200 @@ -1,7 +1,7 @@ project( 'neatvnc', 'c', - version: '0.2.0', + version: '0.3.2', license: 'ISC', default_options: [ 'c_std=gnu11', @@ -66,6 +66,7 @@ 'src/stream.c', 'src/display.c', 'src/tight.c', + 'src/enc-util.c', ] dependencies = [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/src/enc-util.c new/neatvnc-0.3.2/src/enc-util.c --- old/neatvnc-0.2.0/src/enc-util.c 1970-01-01 01:00:00.000000000 +0100 +++ new/neatvnc-0.3.2/src/enc-util.c 2020-09-27 19:31:06.000000000 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 - 2020 Andri Yngvason + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "enc-util.h" +#include "rfb-proto.h" +#include "vec.h" + +#include <arpa/inet.h> + +int encode_rect_count(struct vec* dst, uint32_t count) +{ + struct rfb_server_fb_update_msg msg = { + .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE, + .n_rects = htons(count), + }; + + return vec_append(dst, &msg, sizeof(msg)); +} + +int encode_rect_head(struct vec* dst, enum rfb_encodings encoding, + uint32_t x, uint32_t y, uint32_t width, uint32_t height) +{ + struct rfb_server_fb_rect head = { + .encoding = htonl(encoding), + .x = htons(x), + .y = htons(y), + .width = htons(width), + .height = htons(height), + }; + + return vec_append(dst, &head, sizeof(head)); +} + +uint32_t calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt) +{ + return fmt->bits_per_pixel == 32 ? fmt->depth / 8 + : fmt->bits_per_pixel / 8; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/src/raw-encoding.c new/neatvnc-0.3.2/src/raw-encoding.c --- old/neatvnc-0.2.0/src/raw-encoding.c 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/src/raw-encoding.c 2020-09-27 19:31:06.000000000 +0200 @@ -20,6 +20,7 @@ #include "fb.h" #include "pixels.h" #include "raw-encoding.h" +#include "enc-util.h" #include <pixman.h> @@ -31,15 +32,8 @@ { int rc = -1; - struct rfb_server_fb_rect rect = { - .encoding = htonl(RFB_ENCODING_RAW), - .x = htons(x_start), - .y = htons(y_start), - .width = htons(width), - .height = htons(height), - }; - - rc = vec_append(dst, &rect, sizeof(rect)); + rc = encode_rect_head(dst, RFB_ENCODING_RAW, x_start, y_start, width, + height); if (rc < 0) return -1; @@ -77,16 +71,11 @@ n_rects = 1; } - struct rfb_server_fb_update_msg head = { - .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE, - .n_rects = htons(n_rects), - }; - rc = vec_reserve(dst, src->width * src->height * 4); if (rc < 0) return -1; - rc = vec_append(dst, &head, sizeof(head)); + rc = encode_rect_count(dst, n_rects); if (rc < 0) return -1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/src/server.c new/neatvnc-0.3.2/src/server.c --- old/neatvnc-0.2.0/src/server.c 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/src/server.c 2020-09-27 19:31:06.000000000 +0200 @@ -69,7 +69,12 @@ struct nvnc_fb* fb; }; -int schedule_client_update_fb(struct nvnc_client* client); +int schedule_client_update_fb(struct nvnc_client* client, + struct pixman_region16* damage); +static int send_desktop_resize(struct nvnc_client* client, struct nvnc_fb* fb); +static enum rfb_encodings choose_frame_encoding(struct nvnc_client* client); +static enum tight_quality client_get_tight_quality(struct nvnc_client* client); +static void on_tight_encode_frame_done(struct vec* frame, void* userdata); #if defined(GIT_VERSION) EXPORT const char nvnc_version[] = GIT_VERSION; @@ -92,6 +97,7 @@ tight_encoder_destroy(&client->tight_encoder); deflateEnd(&client->z_stream); pixman_region_fini(&client->damage); + free(client->cut_text.buffer); free(client); } @@ -489,7 +495,9 @@ static void process_fb_update_requests(struct nvnc_client* client) { - if (!client->server->display || !client->server->display->buffer) + struct nvnc* server = client->server; + + if (!server->display || !server->display->buffer) return; if (client->net_stream->state == STREAM_STATE_CLOSED) @@ -501,8 +509,57 @@ if (client->is_updating || client->n_pending_requests == 0) return; + struct nvnc_fb* fb = client->server->display->buffer; + assert(fb); + + if (!client->has_pixfmt) { + rfb_pixfmt_from_fourcc(&client->pixfmt, fb->fourcc_format); + client->has_pixfmt = true; + } + + if (fb->width != client->known_width + || fb->height != client->known_height) + send_desktop_resize(client, fb); + + DTRACE_PROBE1(neatvnc, update_fb_start, client); + + /* The client's damage is exchanged for an empty one */ + struct pixman_region16 damage = client->damage; + pixman_region_init(&client->damage); + client->is_updating = true; - if (schedule_client_update_fb(client) < 0) + + int rc; + enum rfb_encodings encoding = choose_frame_encoding(client); + + // TODO: Check the return value + struct rfb_pixel_format server_fmt; + rfb_pixfmt_from_fourcc(&server_fmt, fb->fourcc_format); + + switch (encoding) { + case RFB_ENCODING_RAW: + case RFB_ENCODING_ZRLE: + rc = schedule_client_update_fb(client, &damage); + break; + case RFB_ENCODING_TIGHT: + client_ref(client); + + enum tight_quality quality = client_get_tight_quality(client); + rc = tight_encode_frame(&client->tight_encoder, &client->pixfmt, + fb, &server_fmt, &damage, quality, + on_tight_encode_frame_done, client); + + if (rc < 0) + client_unref(client); + + pixman_region_fini(&damage); + break; + default: + rc = -1; + break; + } + + if (rc < 0) client->is_updating = false; } @@ -584,20 +641,113 @@ return sizeof(*msg); } +EXPORT +void nvnc_send_cut_text(struct nvnc* server, const char* text, uint32_t len) +{ + struct rfb_cut_text_msg msg; + + msg.type = RFB_SERVER_TO_CLIENT_SERVER_CUT_TEXT; + msg.length = htonl(len); + + struct nvnc_client* client; + LIST_FOREACH (client, &server->clients, link) { + stream_write(client->net_stream, &msg, sizeof(msg), NULL, NULL); + stream_write(client->net_stream, text, len, NULL, NULL); + } +} + static int on_client_cut_text(struct nvnc_client* client) { - struct rfb_client_cut_text_msg* msg = - (struct rfb_client_cut_text_msg*)(client->msg_buffer + - client->buffer_index); + struct nvnc* server = client->server; + nvnc_cut_text_fn fn = server->cut_text_fn; + struct rfb_cut_text_msg* msg = + (struct rfb_cut_text_msg*)(client->msg_buffer + + client->buffer_index); - if (client->buffer_len - client->buffer_index < sizeof(*msg)) + size_t left_to_process = client->buffer_len - client->buffer_index; + + if (left_to_process < sizeof(*msg)) return 0; uint32_t length = ntohl(msg->length); + uint32_t max_length = MAX_CUT_TEXT_SIZE; + + /* Messages greater than this size are unsupported */ + if (length > max_length) { + log_error("Copied text length (%d) is greater than max supported length (%d)\n", + length, max_length); + stream_close(client->net_stream); + client_unref(client); + return 0; + } + + size_t msg_size = sizeof(*msg) + length; + + if (msg_size <= left_to_process) { + if (fn) + fn(server, msg->text, length); + + return msg_size; + } - // TODO + assert(!client->cut_text.buffer); - return sizeof(*msg) + length; + client->cut_text.buffer = malloc(length); + if (!client->cut_text.buffer) { + log_error("OOM: %m\n"); + stream_close(client->net_stream); + client_unref(client); + return 0; + } + + size_t partial_size = left_to_process - sizeof(*msg); + + memcpy(client->cut_text.buffer, msg->text, partial_size); + + client->cut_text.length = length; + client->cut_text.index = partial_size; + + return left_to_process; +} + +static void process_big_cut_text(struct nvnc_client* client) +{ + struct nvnc* server = client->server; + nvnc_cut_text_fn fn = server->cut_text_fn; + + assert(client->cut_text.length > client->cut_text.index); + + void* start = client->cut_text.buffer + client->cut_text.index; + size_t space = client->cut_text.length - client->cut_text.index; + + space = MIN(space, MSG_BUFFER_SIZE); + + ssize_t n_read = stream_read(client->net_stream, start, space); + + if (n_read == 0) + return; + + if (n_read < 0) { + if (errno != EAGAIN) { + log_debug("Client connection error: %p (ref %d)\n", + client, client->ref); + stream_close(client->net_stream); + client_unref(client); + } + + return; + } + + client->cut_text.index += n_read; + + if (client->cut_text.index != client->cut_text.length) + return; + + if (fn) + fn(server, client->cut_text.buffer, client->cut_text.length); + + free(client->cut_text.buffer); + client->cut_text.buffer = NULL; } static int on_client_message(struct nvnc_client* client) @@ -670,6 +820,11 @@ return; } + if (client->cut_text.buffer) { + process_big_cut_text(client); + return; + } + assert(client->buffer_index == 0); void* start = client->msg_buffer + client->buffer_len; @@ -703,9 +858,9 @@ assert(client->buffer_index <= client->buffer_len); - memmove(client->msg_buffer, client->msg_buffer + client->buffer_index, - client->buffer_index); client->buffer_len -= client->buffer_index; + memmove(client->msg_buffer, client->msg_buffer + client->buffer_index, + client->buffer_len); client->buffer_index = 0; } @@ -991,21 +1146,13 @@ enum rfb_encodings encoding = choose_frame_encoding(client); - if (!client->has_pixfmt) { - rfb_pixfmt_from_fourcc(&client->pixfmt, fb->fourcc_format); - client->has_pixfmt = true; - } - switch (encoding) { case RFB_ENCODING_RAW: raw_encode_frame(&update->frame, &client->pixfmt, fb, &update->server_fmt, &update->region); break; - case RFB_ENCODING_TIGHT:; - enum tight_quality quality = client_get_tight_quality(client); - tight_encode_frame(&client->tight_encoder, &update->frame, - &client->pixfmt, fb, &update->server_fmt, - &update->region, quality); + case RFB_ENCODING_TIGHT: + abort(); break; case RFB_ENCODING_ZRLE: zrle_encode_frame(&client->z_stream, &update->frame, @@ -1017,14 +1164,8 @@ } } -static void on_client_update_fb_done(void* work) +static void finish_fb_update(struct nvnc_client* client, struct vec* frame) { - struct fb_update_work* update = aml_get_userdata(work); - struct nvnc_client* client = update->client; - struct vec* frame = &update->frame; - - nvnc_fb_unref(update->fb); - client_ref(client); if (client->net_stream->state != STREAM_STATE_CLOSED) { @@ -1042,6 +1183,24 @@ client->n_pending_requests--; DTRACE_PROBE1(neatvnc, update_fb_done, client); +} + +static void on_tight_encode_frame_done(struct vec* frame, void* userdata) +{ + struct nvnc_client* client = userdata; + finish_fb_update(client, frame); + client_unref(client); +} + +static void on_client_update_fb_done(void* work) +{ + struct fb_update_work* update = aml_get_userdata(work); + struct nvnc_client* client = update->client; + struct vec* frame = &update->frame; + + nvnc_fb_unref(update->fb); + + finish_fb_update(client, frame); pixman_region_fini(&update->region); @@ -1081,13 +1240,12 @@ return 0; } -int schedule_client_update_fb(struct nvnc_client* client) +int schedule_client_update_fb(struct nvnc_client* client, + struct pixman_region16* damage) { struct nvnc_fb* fb = client->server->display->buffer; assert(fb); - DTRACE_PROBE1(neatvnc, update_fb_start, client); - struct fb_update_work* work = calloc(1, sizeof(*work)); if (!work) return -1; @@ -1097,15 +1255,7 @@ work->client = client; work->fb = fb; - - if (fb->width != client->known_width - || fb->height != client->known_height) - if (send_desktop_resize(client, fb) < 0) - goto resize_failure; - - /* The client's damage is exchanged for an empty one */ - work->region = client->damage; - pixman_region_init(&client->damage); + work->region = *damage; int rc = vec_init(&work->frame, fb->width * fb->height * 3 / 2); if (rc < 0) @@ -1138,7 +1288,6 @@ vec_destroy(&work->frame); vec_failure: pixfmt_failure: -resize_failure: free(work); return -1; } @@ -1198,6 +1347,12 @@ } EXPORT +void nvnc_set_cut_text_receive_fn(struct nvnc* self, nvnc_cut_text_fn fn) +{ + self->cut_text_fn = fn; +} + +EXPORT void nvnc_add_display(struct nvnc* self, struct nvnc_display* display) { if (self->display) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/src/tight.c new/neatvnc-0.3.2/src/tight.c --- old/neatvnc-0.2.0/src/tight.c 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/src/tight.c 2020-09-27 19:31:06.000000000 +0200 @@ -22,6 +22,7 @@ #include "logging.h" #include "tight.h" #include "config.h" +#include "enc-util.h" #include <stdlib.h> #include <unistd.h> @@ -72,6 +73,7 @@ static void do_tight_zs_work(void*); static void on_tight_zs_work_done(void*); +static int schedule_tight_finish(struct tight_encoder* self); static int tight_encoder_init_stream(z_stream* zs) { @@ -157,21 +159,13 @@ tight_init_zs_worker(self, 2); tight_init_zs_worker(self, 3); - pthread_mutex_init(&self->wait_mutex, NULL); - pthread_cond_init(&self->wait_cond, NULL); - - // One worker is blocked while other workers are encoding, so at least - // 2 are required. - aml_require_workers(aml_get_default(), 2); + aml_require_workers(aml_get_default(), 1); return 0; } void tight_encoder_destroy(struct tight_encoder* self) { - pthread_cond_destroy(&self->wait_cond); - pthread_mutex_destroy(&self->wait_mutex); - aml_unref(self->zs_worker[3]); aml_unref(self->zs_worker[2]); aml_unref(self->zs_worker[1]); @@ -223,12 +217,6 @@ vec_fast_append_8(dst, (size >> 14) & 0xff); } -static int calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt) -{ - return fmt->bits_per_pixel == 32 ? fmt->depth / 8 - : fmt->bits_per_pixel / 8; -} - static int tight_deflate(struct tight_tile* tile, void* src, size_t len, z_stream* zs, bool flush) { @@ -261,7 +249,7 @@ z_stream* zs = &self->zs[zs_index]; tile->type = TIGHT_BASIC | TIGHT_STREAM(zs_index); - int bytes_per_cpixel = calc_bytes_per_cpixel(self->dfmt); + int bytes_per_cpixel = calc_bytes_per_cpixel(&self->dfmt); assert(bytes_per_cpixel <= 4); uint8_t row[TSL * 4]; @@ -269,7 +257,7 @@ if (bytes_per_cpixel == 3) rfb_pixfmt_from_fourcc(&cfmt, DRM_FORMAT_XBGR8888); else - memcpy(&cfmt, self->dfmt, sizeof(cfmt)); + memcpy(&cfmt, &self->dfmt, sizeof(cfmt)); uint32_t* addr = nvnc_fb_get_addr(self->fb); uint32_t stride = nvnc_fb_get_width(self->fb); @@ -277,8 +265,8 @@ // TODO: Limit width and hight to the sides for (uint32_t y = y_start; y < y_start + height; ++y) { void* img = addr + x + y * stride; - pixel32_to_cpixel(row, &cfmt, img, self->sfmt, bytes_per_cpixel, - width); + pixel32_to_cpixel(row, &cfmt, img, &self->sfmt, + bytes_per_cpixel, width); // TODO What to do if the buffer fills up? if (tight_deflate(tile, row, bytes_per_cpixel * width, @@ -397,16 +385,6 @@ tile->state = TIGHT_TILE_ENCODED; } -static int tight_encode_rect_count(struct tight_encoder* self) -{ - struct rfb_server_fb_update_msg msg = { - .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE, - .n_rects = htons(self->n_rects), - }; - - return vec_append(self->dst, &msg, sizeof(msg)); -} - static void do_tight_zs_work(void* obj) { struct tight_zs_worker_ctx* ctx = aml_get_userdata(obj); @@ -424,10 +402,10 @@ struct tight_zs_worker_ctx* ctx = aml_get_userdata(obj); struct tight_encoder* self = ctx->encoder; - pthread_mutex_lock(&self->wait_mutex); - if (--self->n_jobs == 0) - pthread_cond_signal(&self->wait_cond); - pthread_mutex_unlock(&self->wait_mutex); + if (--self->n_jobs == 0) { + nvnc_fb_unref(self->fb); + schedule_tight_finish(self); + } } static int tight_schedule_zs_work(struct tight_encoder* self, int index) @@ -441,17 +419,11 @@ static int tight_schedule_encoding_jobs(struct tight_encoder* self) { - int rc = -1; - - pthread_mutex_lock(&self->wait_mutex); for (int i = 0; i < 4; ++i) if (tight_schedule_zs_work(self, i) < 0) - goto failure; + return -1; - rc = 0; -failure: - pthread_mutex_unlock(&self->wait_mutex); - return rc; + return 0; } static void tight_finish_tile(struct tight_encoder* self, @@ -465,18 +437,11 @@ uint32_t width = tight_tile_width(self, x); uint32_t height = tight_tile_height(self, y); - struct rfb_server_fb_rect rect = { - .encoding = htonl(RFB_ENCODING_TIGHT), - .x = htons(x), - .y = htons(y), - .width = htons(width), - .height = htons(height), - }; - - vec_append(self->dst, &rect, sizeof(rect)); - vec_append(self->dst, &tile->type, sizeof(tile->type)); - tight_encode_size(self->dst, tile->size); - vec_append(self->dst, tile->buffer, tile->size); + encode_rect_head(&self->dst, RFB_ENCODING_TIGHT, x, y, width, height); + + vec_append(&self->dst, &tile->type, sizeof(tile->type)); + tight_encode_size(&self->dst, tile->size); + vec_append(&self->dst, tile->buffer, tile->size); tile->state = TIGHT_TILE_READY; } @@ -489,36 +454,64 @@ tight_finish_tile(self, x, y); } -int tight_encode_frame(struct tight_encoder* self, struct vec* dst, +static void do_tight_finish(void* obj) +{ + // TODO: Make sure there's no use-after-free here + struct tight_encoder* self = aml_get_userdata(obj); + tight_finish(self); +} + +static void on_tight_finished(void* obj) +{ + struct tight_encoder* self = aml_get_userdata(obj); + self->on_frame_done(&self->dst, self->userdata); +} + +static int schedule_tight_finish(struct tight_encoder* self) +{ + struct aml_work* work = aml_work_new(do_tight_finish, on_tight_finished, + self, NULL); + if (!work) + return -1; + + int rc = aml_start(aml_get_default(), work); + aml_unref(work); + return rc; +} + +int tight_encode_frame(struct tight_encoder* self, const struct rfb_pixel_format* dfmt, - const struct nvnc_fb* src, + struct nvnc_fb* src, const struct rfb_pixel_format* sfmt, struct pixman_region16* damage, - enum tight_quality quality) + enum tight_quality quality, + tight_done_fn on_done, void* userdata) { - self->dfmt = dfmt; - self->sfmt = sfmt; + memcpy(&self->dfmt, dfmt, sizeof(self->dfmt)); + memcpy(&self->sfmt, sfmt, sizeof(self->sfmt)); self->fb = src; - self->dst = dst; self->quality = quality; + self->on_frame_done = on_done; + self->userdata = userdata; - vec_clear(dst); + uint32_t width = nvnc_fb_get_width(src); + uint32_t height = nvnc_fb_get_height(src); + int rc = vec_init(&self->dst, width * height * 4); + if (rc < 0) + return -1; self->n_rects = tight_apply_damage(self, damage); assert(self->n_rects > 0); - tight_encode_rect_count(self); + encode_rect_count(&self->dst, self->n_rects); - if (tight_schedule_encoding_jobs(self) < 0) - return -1; + nvnc_fb_ref(self->fb); - // TODO Change architecture so we don't have to wait here - pthread_mutex_lock(&self->wait_mutex); - while (self->n_jobs != 0) - pthread_cond_wait(&self->wait_cond, &self->wait_mutex); - pthread_mutex_unlock(&self->wait_mutex); - - tight_finish(self); + if (tight_schedule_encoding_jobs(self) < 0) { + nvnc_fb_unref(self->fb); + vec_destroy(&self->dst); + return -1; + } return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/neatvnc-0.2.0/src/zrle.c new/neatvnc-0.3.2/src/zrle.c --- old/neatvnc-0.2.0/src/zrle.c 2020-07-26 15:52:00.000000000 +0200 +++ new/neatvnc-0.3.2/src/zrle.c 2020-09-27 19:31:06.000000000 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Andri Yngvason + * Copyright (c) 2019 - 2020 Andri Yngvason * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include "neatvnc.h" #include "pixels.h" #include "fb.h" +#include "enc-util.h" #include <stdint.h> #include <unistd.h> @@ -43,12 +44,6 @@ return -1; } -static inline int calc_bytes_per_cpixel(const struct rfb_pixel_format* fmt) -{ - return fmt->bits_per_pixel == 32 ? fmt->depth / 8 - : fmt->bits_per_pixel / 8; -} - static int zrle_get_tile_palette(uint32_t* palette, const uint32_t* src, size_t length) { @@ -222,15 +217,7 @@ if (vec_init(&in, 1 + bytes_per_cpixel * TILE_LENGTH * TILE_LENGTH) < 0) goto failure; - struct rfb_server_fb_rect rect = { - .encoding = htonl(RFB_ENCODING_ZRLE), - .x = htons(x), - .y = htons(y), - .width = htons(width), - .height = htons(height), - }; - - r = vec_append(out, &rect, sizeof(rect)); + r = encode_rect_head(out, RFB_ENCODING_ZRLE, x, y, width, height); if (r < 0) goto failure; @@ -289,12 +276,7 @@ n_rects = 1; } - struct rfb_server_fb_update_msg head = { - .type = RFB_SERVER_TO_CLIENT_FRAMEBUFFER_UPDATE, - .n_rects = htons(n_rects), - }; - - rc = vec_append(dst, &head, sizeof(head)); + rc = encode_rect_count(dst, n_rects); if (rc < 0) return -1;
