Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package neatvnc for openSUSE:Factory checked 
in at 2025-02-24 15:48:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/neatvnc (Old)
 and      /work/SRC/openSUSE:Factory/.neatvnc.new.1873 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "neatvnc"

Mon Feb 24 15:48:42 2025 rev:16 rq:1247934 version:0.9.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/neatvnc/neatvnc.changes  2025-01-07 
20:55:08.317179062 +0100
+++ /work/SRC/openSUSE:Factory/.neatvnc.new.1873/neatvnc.changes        
2025-02-24 15:48:58.403772366 +0100
@@ -1,0 +2,14 @@
+Sun Feb 23 18:23:21 UTC 2025 - Michael Vetter <[email protected]>
+
+- Update to 0.9.3:
+  * Fix some instances of use-after-free that can be reached before
+    authentication takes place. Those should be viewed as potential
+    vulnerabilities, so it would be prudent to upgrade ASAP if you're
+    running Neat VNC on the internet.
+  * Fix a few issues with WebSockets. One of those bugs will allow
+    an unauthenticated client to put the server into an endless
+    loop when parsing HTTP headers. There were also problems with
+    ping message handling and the way some legacy clients/browsers
+    were being dealt with that he fixed.
+
+-------------------------------------------------------------------

Old:
----
  neatvnc-0.9.2.tar.xz

New:
----
  neatvnc-0.9.3.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ neatvnc.spec ++++++
--- /var/tmp/diff_new_pack.sDwuBk/_old  2025-02-24 15:48:59.671825371 +0100
+++ /var/tmp/diff_new_pack.sDwuBk/_new  2025-02-24 15:48:59.671825371 +0100
@@ -19,7 +19,7 @@
 %define libsoname libneatvnc0
 
 Name:           neatvnc
-Version:        0.9.2
+Version:        0.9.3
 Release:        0
 Summary:        A VNC server library
 License:        ISC

++++++ _service ++++++
--- /var/tmp/diff_new_pack.sDwuBk/_old  2025-02-24 15:48:59.699826541 +0100
+++ /var/tmp/diff_new_pack.sDwuBk/_new  2025-02-24 15:48:59.699826541 +0100
@@ -3,8 +3,8 @@
   <service name="obs_scm" mode="manual">
     <param name="scm">git</param>
     <param name="url">https://github.com/any1/neatvnc.git</param>
-    <param name="revision">4c37ae9349f16a255cd3e95ed7931c71e6abf8fc</param>
-    <param name="versionformat">0.9.2</param>
+    <param name="revision">af5811b75e63f53d1d1f1f3f337387553a96786a</param>
+    <param name="versionformat">0.9.3</param>
   </service>
   <service name="tar" mode="manual"/>
   <service name="recompress" mode="manual">

++++++ neatvnc-0.9.2.tar.xz -> neatvnc-0.9.3.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/include/common.h 
new/neatvnc-0.9.3/include/common.h
--- old/neatvnc-0.9.2/include/common.h  2024-12-07 21:42:23.000000000 +0100
+++ new/neatvnc-0.9.3/include/common.h  2025-02-23 10:52:50.000000000 +0100
@@ -43,7 +43,6 @@
 #define MAX_SECURITY_TYPES 32
 
 enum nvnc_client_state {
-       VNC_CLIENT_STATE_ERROR = -1,
        VNC_CLIENT_STATE_WAITING_FOR_VERSION = 0,
        VNC_CLIENT_STATE_WAITING_FOR_SECURITY,
 #ifdef ENABLE_TLS
@@ -82,7 +81,7 @@
        size_t length;
        size_t index;
        bool is_zlib;
-       bool is_provide;
+       bool is_text_provide;
 };
 
 struct nvnc_client {
@@ -134,6 +133,7 @@
        int32_t min_rtt;
        struct bwe* bwe;
        int32_t inflight_bytes;
+       struct aml_idle* close_task;
 
 #ifdef HAVE_CRYPTO
        struct crypto_key* apple_dh_secret;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/include/stream/stream.h 
new/neatvnc-0.9.3/include/stream/stream.h
--- old/neatvnc-0.9.2/include/stream/stream.h   2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/include/stream/stream.h   2025-02-23 10:52:50.000000000 
+0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 - 2023 Andri Yngvason
+ * Copyright (c) 2020 - 2025 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
@@ -78,6 +78,7 @@
 
 struct stream {
        struct stream_impl *impl;
+       int ref;
 
        enum stream_state state;
 
@@ -102,6 +103,8 @@
 #endif
 
 struct stream* stream_new(int fd, stream_event_fn on_event, void* userdata);
+void stream_init(struct stream* self);
+void stream_ref(struct stream* self);
 int stream_close(struct stream* self);
 void stream_destroy(struct stream* self);
 ssize_t stream_read(struct stream* self, void* dst, size_t size);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/meson.build 
new/neatvnc-0.9.3/meson.build
--- old/neatvnc-0.9.2/meson.build       2024-12-07 21:42:23.000000000 +0100
+++ new/neatvnc-0.9.3/meson.build       2025-02-23 10:52:50.000000000 +0100
@@ -1,7 +1,7 @@
 project(
        'neatvnc',
        'c',
-       version: '0.9.2',
+       version: '0.9.3',
        license: 'ISC',
        default_options: [
                'c_std=gnu11',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/auth/apple-dh.c 
new/neatvnc-0.9.3/src/auth/apple-dh.c
--- old/neatvnc-0.9.2/src/auth/apple-dh.c       2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/auth/apple-dh.c       2025-02-23 10:52:50.000000000 
+0100
@@ -98,13 +98,14 @@
 
        update_min_rtt(client);
 
-       if (server->auth_fn(username, password, server->auth_ud)) {
-               security_handshake_ok(client, username);
-               client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
-       } else {
+       if (!server->auth_fn(username, password, server->auth_ud)) {
                security_handshake_failed(client, username,
                                "Invalid username or password");
+               return -1;
        }
 
+       security_handshake_ok(client, username);
+       client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
+
        return sizeof(*msg) + key_len;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/auth/common.c 
new/neatvnc-0.9.3/src/auth/common.c
--- old/neatvnc-0.9.2/src/auth/common.c 2024-12-07 21:42:23.000000000 +0100
+++ new/neatvnc-0.9.3/src/auth/common.c 2025-02-23 10:52:50.000000000 +0100
@@ -32,8 +32,6 @@
 
        char buffer[256];
 
-       client->state = VNC_CLIENT_STATE_ERROR;
-
        uint32_t* result = (uint32_t*)buffer;
 
        struct rfb_error_reason* reason =
@@ -45,8 +43,11 @@
 
        size_t len = sizeof(*result) + sizeof(*reason) + strlen(reason_string);
        stream_write(client->net_stream, buffer, len, close_after_write,
-                       client);
+                       client->net_stream);
+
+       stream_ref(client->net_stream);
 
+       nvnc_client_close(client);
        return 0;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/auth/rsa-aes.c 
new/neatvnc-0.9.3/src/auth/rsa-aes.c
--- old/neatvnc-0.9.2/src/auth/rsa-aes.c        2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/auth/rsa-aes.c        2025-02-23 10:52:50.000000000 
+0100
@@ -134,9 +134,8 @@
                        client->rsa.challenge_len, msg->challenge, length);
        if (len < 0) {
                nvnc_log(NVNC_LOG_ERROR, "Failed to decrypt client's 
challenge");
-               client->state = VNC_CLIENT_STATE_ERROR;
                nvnc_client_close(client);
-               goto done;
+               return -1;
        }
 
        // ClientSessionKey = the first 16 bytes of SHA1(ServerRandom || 
ClientRandom)
@@ -202,7 +201,7 @@
                        client_rsa_aes_hash_len(client), NULL, NULL);
 
        client->state = VNC_CLIENT_STATE_WAITING_FOR_RSA_AES_CLIENT_HASH;
-done:
+
        return sizeof(*msg) + length;
 }
 
@@ -253,7 +252,7 @@
        if (memcmp(msg, client_hash, client_rsa_aes_hash_len(client)) != 0) {
                nvnc_log(NVNC_LOG_INFO, "Client hash mismatch");
                nvnc_client_close(client);
-               return 0;
+               return -1;
        }
 
        update_min_rtt(client);
@@ -294,14 +293,15 @@
 
        update_min_rtt(client);
 
-       if (server->auth_fn(username, password, server->auth_ud)) {
-               security_handshake_ok(client, username);
-               client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
-       } else {
+       if (!server->auth_fn(username, password, server->auth_ud)) {
                security_handshake_failed(client, username,
                                "Invalid username or password");
+               return -1;
        }
 
+       security_handshake_ok(client, username);
+       client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
+
        return 2 + username_len + password_len;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/auth/vencrypt.c 
new/neatvnc-0.9.3/src/auth/vencrypt.c
--- old/neatvnc-0.9.2/src/auth/vencrypt.c       2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/auth/vencrypt.c       2025-02-23 10:52:50.000000000 
+0100
@@ -28,8 +28,9 @@
 
 static int send_byte_and_close(struct nvnc_client* client, uint8_t value)
 {
+       stream_ref(client->net_stream);
        return stream_write(client->net_stream, &value, 1, close_after_write,
-                       client);
+                       client->net_stream);
 }
 
 int vencrypt_send_version(struct nvnc_client* client)
@@ -53,7 +54,7 @@
        if (msg->major != 0 || msg->minor != 2) {
                security_handshake_failed(client, NULL,
                                "Unsupported VeNCrypt version");
-               return sizeof(*msg);
+               return -1;
        }
 
        send_byte(client, 0);
@@ -80,7 +81,6 @@
        enum rfb_vencrypt_subtype subtype = ntohl(*msg);
 
        if (subtype != RFB_VENCRYPT_X509_PLAIN) {
-               client->state = VNC_CLIENT_STATE_ERROR;
                send_byte_and_close(client, 0);
                return sizeof(*msg);
        }
@@ -90,9 +90,8 @@
        send_byte(client, 1);
 
        if (stream_upgrade_to_tls(client->net_stream, 
client->server->tls_creds) < 0) {
-               client->state = VNC_CLIENT_STATE_ERROR;
                nvnc_client_close(client);
-               return sizeof(*msg);
+               return -1;
        }
 
        client->state = VNC_CLIENT_STATE_WAITING_FOR_VENCRYPT_PLAIN_AUTH;
@@ -127,14 +126,15 @@
 
        update_min_rtt(client);
 
-       if (server->auth_fn(username, password, server->auth_ud)) {
-               security_handshake_ok(client, username);
-               client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
-       } else {
+       if (!server->auth_fn(username, password, server->auth_ud)) {
                security_handshake_failed(client, username,
                                "Invalid username or password");
+               return -1;
        }
 
+       security_handshake_ok(client, username);
+       client->state = VNC_CLIENT_STATE_WAITING_FOR_INIT;
+
        return sizeof(*msg) + ulen + plen;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/enc/tight.c 
new/neatvnc-0.9.3/src/enc/tight.c
--- old/neatvnc-0.9.2/src/enc/tight.c   2024-12-07 21:42:23.000000000 +0100
+++ new/neatvnc-0.9.3/src/enc/tight.c   2025-02-23 10:52:50.000000000 +0100
@@ -374,7 +374,7 @@
        int32_t xoff = x * bpp;
        uint8_t* img = addr + xoff + y * byte_stride;
 
-       enum TJSAMP subsampling = (quality == 9) ? TJSAMP_444 : TJSAMP_420;
+       enum TJSAMP subsampling = (self->quality == 9) ? TJSAMP_444 : 
TJSAMP_420;
 
        int rc = -1;
        rc = tjCompress2(handle, img, width, byte_stride, height, tjfmt, 
&buffer,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/server.c 
new/neatvnc-0.9.3/src/server.c
--- old/neatvnc-0.9.2/src/server.c      2024-12-07 21:42:23.000000000 +0100
+++ new/neatvnc-0.9.3/src/server.c      2025-02-23 10:52:50.000000000 +0100
@@ -102,6 +102,7 @@
 #endif
 
 extern const unsigned short code_map_qnum_to_linux[];
+extern const unsigned int code_map_qnum_to_linux_len;
 
 static uint64_t nvnc__htonll(uint64_t x)
 {
@@ -163,6 +164,13 @@
 
 static void client_close(struct nvnc_client* client)
 {
+       if (client->close_task) {
+               struct aml_idle* task = client->close_task;
+               client->close_task = NULL;
+               aml_stop(aml_get_default(), task);
+               aml_unref(task);
+       }
+
        nvnc_log(NVNC_LOG_INFO, "Closing client connection %p", client);
 
        stream_close(client->net_stream);
@@ -204,7 +212,9 @@
 
 static void do_deferred_client_close(void *obj)
 {
-       client_close(obj);
+       struct nvnc_client* client = obj;
+       if (client->close_task)
+               client_close(client);
 }
 
 static void stop_self(void* obj)
@@ -214,31 +224,23 @@
 
 static void defer_client_close(struct nvnc_client* client)
 {
-       struct aml_idle* idle = aml_idle_new(stop_self, client,
+       if (client->close_task)
+               return;
+       client->close_task = aml_idle_new(stop_self, client,
                        do_deferred_client_close);
-       aml_start(aml_get_default(), idle);
-       aml_unref(idle);
+       aml_start(aml_get_default(), client->close_task);
 }
 
 void close_after_write(void* userdata, enum stream_req_status status)
 {
-       struct nvnc_client* client = userdata;
-       nvnc_log(NVNC_LOG_DEBUG, "close_after_write(%p)", client);
-       stream_close(client->net_stream);
-
-       /* This is a rather hacky way of making sure that the client object
-        * stays alive while the stream is processing its queue.
-        * TODO: Figure out some better resource management for clients
-        */
-       defer_client_close(client);
+       struct stream* stream = userdata;
+       stream_destroy(stream);
 }
 
 static int handle_unsupported_version(struct nvnc_client* client)
 {
        char buffer[256];
 
-       client->state = VNC_CLIENT_STATE_ERROR;
-
        struct rfb_error_reason* reason = (struct rfb_error_reason*)(buffer + 
1);
 
        static const char reason_string[] = "Unsupported version\n";
@@ -249,9 +251,13 @@
 
        size_t len = 1 + sizeof(*reason) + strlen(reason_string);
        stream_write(client->net_stream, buffer, len, close_after_write,
-                       client);
+                       client->net_stream);
 
-       return 0;
+       // Keep stream alive until the result has been sent to the client
+       stream_ref(client->net_stream);
+
+       client_close(client);
+       return -1;
 }
 
 static void init_security_types(struct nvnc* server)
@@ -417,7 +423,7 @@
 
 }
 
-static void send_server_init_message(struct nvnc_client* client)
+static int send_server_init_message(struct nvnc_client* client)
 {
        struct nvnc* server = client->server;
        struct nvnc_display* display = server->display;
@@ -471,10 +477,11 @@
 
        client->known_width = width;
        client->known_height = height;
-       return;
+       return 0;
 
 close:
        nvnc_client_close(client);
+       return -1;
 }
 
 static int on_init_message(struct nvnc_client* client)
@@ -488,7 +495,8 @@
 
        update_min_rtt(client);
 
-       send_server_init_message(client);
+       if (send_server_init_message(client) == -1)
+               return -1;
 
        nvnc_client_fn fn = client->server->new_client_fn;
        if (fn)
@@ -1043,7 +1051,14 @@
        int down_flag = msg->down_flag;
        uint32_t xt_keycode = ntohl(msg->keycode);
 
-       uint32_t evdev_keycode = code_map_qnum_to_linux[xt_keycode];
+
+       uint32_t evdev_keycode = 0;
+       if (xt_keycode < code_map_qnum_to_linux_len) {
+               evdev_keycode = code_map_qnum_to_linux[xt_keycode];
+       } else {
+               nvnc_log(NVNC_LOG_WARNING, "Received too large key code from 
client: %" PRIu32,
+                               xt_keycode);
+       }
        if (!evdev_keycode)
                evdev_keycode = xt_keycode;
 
@@ -1070,7 +1085,7 @@
        nvnc_log(NVNC_LOG_WARNING, "Got uninterpretable qemu message from 
client: %p",
                        client);
        nvnc_client_close(client);
-       return 0;
+       return -1;
 }
 
 static int on_client_pointer_event(struct nvnc_client* client)
@@ -1175,7 +1190,7 @@
                        continue;
                }
 
-               if ((in_len == 0) || (*(in + 1) != '\n'))
+               if ((in_len == 1) || (*(in + 1) != '\n'))
                        *out++ = '\n';
 
                in++;
@@ -1291,12 +1306,12 @@
                nvnc_log(NVNC_LOG_ERROR, "Extended clipboard payload length 
(%d) is greater than max supported length (%d)",
                                length, max_length);
                nvnc_client_close(client);
-               return 0;
+               return -1;
        }
 
        size_t msg_size = sizeof(*msg) + length;
 
-       /* this is expected to be a provide message. if not, tell
+       /* this is expected to be a text provide message. if not, tell
         * process_big_cut_text to ignore it, to avoid unnecessarily attempting
         * to inflate garbage */
        if (msg_size > left_to_process) {
@@ -1305,7 +1320,7 @@
                if (!client->cut_text.buffer) {
                        nvnc_log(NVNC_LOG_ERROR, "OOM: %m");
                        nvnc_client_close(client);
-                       return 0;
+                       return -1;
                }
 
                size_t partial_size = left_to_process - sizeof(*msg);
@@ -1316,7 +1331,8 @@
                client->cut_text.length = length;
                client->cut_text.index = partial_size;
 
-               client->cut_text.is_provide = (flags & 
RFB_EXT_CLIPBOARD_ACTION_PROVIDE &&
+               client->cut_text.is_text_provide = (flags & 
RFB_EXT_CLIPBOARD_ACTION_PROVIDE &&
+                               flags & RFB_EXT_CLIPBOARD_FORMAT_TEXT &&
                                !(flags & RFB_EXT_CLIPBOARD_CAPS));
 
                return left_to_process;
@@ -1366,7 +1382,7 @@
                nvnc_log(NVNC_LOG_ERROR, "Copied text length (%d) is greater 
than max supported length (%d)",
                                length, max_length);
                nvnc_client_close(client);
-               return 0;
+               return -1;
        }
 
        size_t msg_size = sizeof(*msg) + length;
@@ -1385,7 +1401,7 @@
        if (!client->cut_text.buffer) {
                nvnc_log(NVNC_LOG_ERROR, "OOM: %m");
                nvnc_client_close(client);
-               return 0;
+               return -1;
        }
 
        size_t partial_size = left_to_process - sizeof(*msg);
@@ -1393,7 +1409,7 @@
        memcpy(client->cut_text.buffer, msg->text, partial_size);
 
        client->cut_text.is_zlib = false;
-       client->cut_text.is_provide = false;
+       client->cut_text.is_text_provide = false;
        client->cut_text.length = length;
        client->cut_text.index = partial_size;
 
@@ -1479,7 +1495,7 @@
                return;
 
        if (client->cut_text.is_zlib) {
-               if (client->cut_text.is_provide)
+               if (client->cut_text.is_text_provide)
                        process_client_ext_clipboard_provide(client,
                                        (unsigned char*)client->cut_text.buffer,
                                        client->cut_text.length);
@@ -1522,6 +1538,7 @@
        server->ext_clipboard_provide_msg.buffer = malloc(length);
        if (!server->ext_clipboard_provide_msg.buffer) {
                nvnc_log(NVNC_LOG_ERROR, "OOM: %m");
+               free(provide_msg_buf);
                return;
        }
 
@@ -1846,7 +1863,7 @@
                nvnc_log(NVNC_LOG_WARNING,
                                "Client sent too long fence message. Closing.");
                nvnc_client_close(client);
-               return 0;
+               return -1;
        }
 
        enum rfb_fence_flags flags = ntohl(msg->flags);
@@ -1897,14 +1914,15 @@
        nvnc_log(NVNC_LOG_WARNING, "Got uninterpretable message from client: 
%p",
                        client);
        nvnc_client_close(client);
-       return 0;
+       return -1;
 }
 
 static int try_read_client_message(struct nvnc_client* client)
 {
+       if (client->net_stream->state == STREAM_STATE_CLOSED)
+               return -1;
+
        switch (client->state) {
-       case VNC_CLIENT_STATE_ERROR:
-               return client->buffer_len - client->buffer_index;
        case VNC_CLIENT_STATE_WAITING_FOR_VERSION:
                return on_version_message(client);
        case VNC_CLIENT_STATE_WAITING_FOR_SECURITY:
@@ -1981,6 +1999,9 @@
                if (rc == 0)
                        break;
 
+               if (rc == -1)
+                       return;
+
                client->buffer_index += rc;
        }
 
@@ -2097,6 +2118,8 @@
                nvnc_log(NVNC_LOG_DEBUG,
                                "Don't know how to convert sa_family %d to 
string",
                                addr->sa_family);
+               if (sz > 0)
+                       *dst = 0;
                break;
        }
 }
@@ -2431,6 +2454,7 @@
                if (!client_supports_resizing(client)) {
                        nvnc_log(NVNC_LOG_ERROR, "Display has been resized but 
client does not support resizing.  Closing.");
                        client_close(client);
+                       return;
                }
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/stream/common.c 
new/neatvnc-0.9.3/src/stream/common.c
--- old/neatvnc-0.9.2/src/stream/common.c       2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/stream/common.c       2025-02-23 10:52:50.000000000 
+0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 - 2023 Andri Yngvason
+ * Copyright (c) 2020 - 2025 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
@@ -19,6 +19,11 @@
 
 #include <stdlib.h>
 
+void stream_init(struct stream* self)
+{
+       self->ref = 1;
+}
+
 void stream_req__finish(struct stream_req* req, enum stream_req_status status)
 {
        if (req->on_done)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/stream/gnutls.c 
new/neatvnc-0.9.3/src/stream/gnutls.c
--- old/neatvnc-0.9.2/src/stream/gnutls.c       2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/stream/gnutls.c       2025-02-23 10:52:50.000000000 
+0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 - 2023 Andri Yngvason
+ * Copyright (c) 2020 - 2025 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
@@ -54,6 +54,8 @@
 
        self->base.state = STREAM_STATE_CLOSED;
 
+       stream_ref(&self->base);
+
        while (!TAILQ_EMPTY(&self->base.send_queue)) {
                struct stream_req* req = TAILQ_FIRST(&self->base.send_queue);
                TAILQ_REMOVE(&self->base.send_queue, req, link);
@@ -68,6 +70,9 @@
        close(self->base.fd);
        self->base.fd = -1;
 
+       // unref
+       stream_destroy(&self->base);
+
        return 0;
 }
 
@@ -81,26 +86,31 @@
 static int stream_gnutls__flush(struct stream* base)
 {
        struct stream_gnutls* self = (struct stream_gnutls*)base;
+
+       stream_ref(base);
+       int rc = -1;
+
        while (!TAILQ_EMPTY(&self->base.send_queue)) {
                assert(self->base.state != STREAM_STATE_CLOSED);
 
                struct stream_req* req = TAILQ_FIRST(&self->base.send_queue);
 
-               ssize_t rc = gnutls_record_send(self->session,
+               ssize_t n_sent = gnutls_record_send(self->session,
                                req->payload->payload, req->payload->size);
-               if (rc < 0) {
-                       if (gnutls_error_is_fatal(rc)) {
+               if (n_sent < 0) {
+                       if (gnutls_error_is_fatal(n_sent)) {
                                stream_close(base);
-                               return -1;
+                               goto done;
                        }
 
                        stream__poll_rw(base);
-                       return 0;
+                       rc = 0;
+                       goto done;
                }
 
-               self->base.bytes_sent += rc;
+               self->base.bytes_sent += n_sent;
 
-               ssize_t remaining = req->payload->size - rc;
+               ssize_t remaining = req->payload->size - n_sent;
 
                if (remaining > 0) {
                        char* p = req->payload->payload;
@@ -108,7 +118,8 @@
                        memmove(p, p + s - remaining, remaining);
                        req->payload->size = remaining;
                        stream__poll_rw(base);
-                       return 1;
+                       rc = 1;
+                       goto done;
                }
 
                assert(remaining == 0);
@@ -120,7 +131,11 @@
        if (TAILQ_EMPTY(&base->send_queue) && base->state != 
STREAM_STATE_CLOSED)
                stream__poll_r(base);
 
-       return 1;
+       rc = 1;
+done:
+       // unref
+       stream_destroy(base);
+       return rc;
 }
 
 static void stream_gnutls__on_readable(struct stream* self)
@@ -161,22 +176,26 @@
        struct stream* self = aml_get_userdata(obj);
        uint32_t events = aml_get_revents(obj);
 
+       stream_ref(self);
+
        if (events & AML_EVENT_READ)
                stream_gnutls__on_readable(self);
 
        if (events & AML_EVENT_WRITE)
                stream_gnutls__on_writable(self);
+
+       stream_destroy(self);
 }
 
 static int stream_gnutls_send(struct stream* self, struct rcbuf* payload,
                stream_req_fn on_done, void* userdata)
 {
        if (self->state == STREAM_STATE_CLOSED)
-               return -1;
+               goto failure;
 
        struct stream_req* req = calloc(1, sizeof(*req));
        if (!req)
-               return -1;
+               goto failure;
 
        req->payload = payload;
        req->on_done = on_done;
@@ -185,6 +204,10 @@
        TAILQ_INSERT_TAIL(&self->send_queue, req, link);
 
        return stream_gnutls__flush(self);
+
+failure:
+       rcbuf_unref(payload);
+       return -1;
 }
 
 static ssize_t stream_gnutls_read(struct stream* base, void* dst, size_t size)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/stream/interface.c 
new/neatvnc-0.9.3/src/stream/interface.c
--- old/neatvnc-0.9.2/src/stream/interface.c    2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/stream/interface.c    2025-02-23 10:52:50.000000000 
+0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Andri Yngvason
+ * Copyright (c) 2023 - 2025 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
@@ -18,6 +18,11 @@
 
 #include <assert.h>
 
+void stream_ref(struct stream* self)
+{
+       self->ref++;
+}
+
 int stream_close(struct stream* self)
 {
        assert(self->impl && self->impl->close);
@@ -27,7 +32,8 @@
 void stream_destroy(struct stream* self)
 {
        assert(self->impl && self->impl->destroy);
-       return self->impl->destroy(self);
+       if (--self->ref == 0)
+               return self->impl->destroy(self);
 }
 
 int stream_send(struct stream* self, struct rcbuf* payload,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/stream/tcp.c 
new/neatvnc-0.9.3/src/stream/tcp.c
--- old/neatvnc-0.9.2/src/stream/tcp.c  2024-12-07 21:42:23.000000000 +0100
+++ new/neatvnc-0.9.3/src/stream/tcp.c  2025-02-23 10:52:50.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 - 2023 Andri Yngvason
+ * Copyright (c) 2020 - 2025 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
@@ -45,6 +45,8 @@
        self->state = STREAM_STATE_CLOSED;
        self->cork = true;
 
+       stream_ref(self);
+
        while (!TAILQ_EMPTY(&self->send_queue)) {
                struct stream_req* req = TAILQ_FIRST(&self->send_queue);
                TAILQ_REMOVE(&self->send_queue, req, link);
@@ -55,6 +57,9 @@
        close(self->fd);
        self->fd = -1;
 
+       // unref
+       stream_destroy(self);
+
        return 0;
 }
 
@@ -120,6 +125,8 @@
        // Don't flush while flushing
        self->cork = true;
 
+       stream_ref(self);
+
        struct stream_req* tmp;
        TAILQ_FOREACH_SAFE(req, &self->send_queue, link, tmp) {
                bytes_left -= req->payload->size;
@@ -151,6 +158,9 @@
 
        assert(bytes_left <= 0);
 
+       // unref
+       stream_destroy(self);
+
        return bytes_sent;
 }
 
@@ -186,11 +196,18 @@
        struct stream* self = aml_get_userdata(obj);
        uint32_t events = aml_get_revents(obj);
 
+       // We hold a reference here in case the stream gets destroyed inside
+       // callback.
+       stream_ref(self);
+
        if (events & AML_EVENT_READ)
                stream_tcp__on_readable(self);
 
        if (events & AML_EVENT_WRITE)
                stream_tcp__on_writable(self);
+
+       // unref
+       stream_destroy(self);
 }
 
 ssize_t stream_tcp_read(struct stream* self, void* dst, size_t size)
@@ -218,11 +235,11 @@
                stream_req_fn on_done, void* userdata)
 {
        if (self->state == STREAM_STATE_CLOSED)
-               return -1;
+               goto failure;
 
        struct stream_req* req = calloc(1, sizeof(*req));
        if (!req)
-               return -1;
+               goto failure;
 
        req->payload = payload;
        req->on_done = on_done;
@@ -231,21 +248,29 @@
        TAILQ_INSERT_TAIL(&self->send_queue, req, link);
 
        return stream_tcp__flush(self);
+
+failure:
+       rcbuf_unref(payload);
+       return -1;
 }
 
 int stream_tcp_send_first(struct stream* self, struct rcbuf* payload)
 {
        if (self->state == STREAM_STATE_CLOSED)
-               return -1;
+               goto failure;
 
        struct stream_req* req = calloc(1, sizeof(*req));
        if (!req)
-               return -1;
+               goto failure;
 
        req->payload = payload;
        TAILQ_INSERT_HEAD(&self->send_queue, req, link);
 
        return stream_tcp__flush(self);
+
+failure:
+       rcbuf_unref(payload);
+       return -1;
 }
 
 void stream_tcp_exec_and_send(struct stream* self,
@@ -309,11 +334,12 @@
        if (!self)
                return NULL;
 
+       stream_init(self);
+
        if (stream_tcp_init(self, fd, on_event, userdata) < 0) {
                free(self);
                return NULL;
        }
 
        return self;
-
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/stream/ws/handshake.c 
new/neatvnc-0.9.3/src/stream/ws/handshake.c
--- old/neatvnc-0.9.2/src/stream/ws/handshake.c 2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/stream/ws/handshake.c 2025-02-23 10:52:50.000000000 
+0100
@@ -29,9 +29,11 @@
 
 static void tolower_and_remove_ws(char* dst, const char* src)
 {
-       while (*src)
+       while (*src) {
                if (!isspace(*src))
-                       *dst++ = tolower(*src++);
+                       *dst++ = tolower(*src);
+               src++;
+       }
        *dst = '\0';
 }
 
@@ -70,7 +72,7 @@
        bool have_protocols = strlen(protocols) != 1;
        bool have_versions = strlen(versions) != 1;
 
-       if (have_protocols && !strstr(protocols, ",chat,"))
+       if (have_protocols && !strstr(protocols, ",binary,"))
                goto failure;
 
        if (have_versions && !strstr(versions, ",13,"))
@@ -95,7 +97,7 @@
                        "%s%s"
                        "\r\n",
                        response,
-                       have_protocols ? "Sec-WebSocket-Protocol: char\r\n" : 
"",
+                       have_protocols ? "Sec-WebSocket-Protocol: binary\r\n" : 
"",
                        have_versions ? "Sec-WebSocket-Version: 13\r\n" : "");
 
        ssize_t header_len = req.header_length;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-0.9.2/src/stream/ws/ws.c 
new/neatvnc-0.9.3/src/stream/ws/ws.c
--- old/neatvnc-0.9.2/src/stream/ws/ws.c        2024-12-07 21:42:23.000000000 
+0100
+++ new/neatvnc-0.9.3/src/stream/ws/ws.c        2025-02-23 10:52:50.000000000 
+0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Andri Yngvason
+ * Copyright (c) 2023 - 2025 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
@@ -95,11 +95,14 @@
                                NULL, NULL);
        }
 
-       int payload_len = MIN(ws->read_index, ws->header.payload_length);
+       int payload_len = MIN(ws->read_index - offset, 
ws->header.payload_length);
 
-       // Feed back the payload:
-       stream_tcp_send(&ws->base, rcbuf_from_mem(ws->read_buffer + offset,
-                       payload_len), NULL, NULL);
+       // Feed back the (unmasked) payload:
+       struct rcbuf* rcbuf = rcbuf_new(malloc(payload_len), payload_len);
+       assert(rcbuf && rcbuf->payload);
+       ws_copy_payload(&ws->header, rcbuf->payload, ws->read_buffer + offset,
+                       payload_len);
+       stream_tcp_send(&ws->base, rcbuf, NULL, NULL);
 
        stream_ws_advance_read_buffer(ws, payload_len, offset);
        return 0;
@@ -304,6 +307,8 @@
        if (!self)
                return NULL;
 
+       stream_init(&self->base);
+
        stream_tcp_init(&self->base, fd, on_event, userdata);
        self->base.impl =  &impl;
 

++++++ neatvnc.obsinfo ++++++
--- /var/tmp/diff_new_pack.sDwuBk/_old  2025-02-24 15:48:59.879834066 +0100
+++ /var/tmp/diff_new_pack.sDwuBk/_new  2025-02-24 15:48:59.883834232 +0100
@@ -1,5 +1,5 @@
 name: neatvnc
-version: 0.9.2
-mtime: 1733604143
-commit: 4c37ae9349f16a255cd3e95ed7931c71e6abf8fc
+version: 0.9.3
+mtime: 1740304370
+commit: af5811b75e63f53d1d1f1f3f337387553a96786a
 

Reply via email to