Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package neatvnc for openSUSE:Factory checked 
in at 2026-10-08 15:14:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/neatvnc (Old)
 and      /work/SRC/openSUSE:Factory/.neatvnc.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "neatvnc"

Thu Oct  8 15:14:03 2026 rev:23 rq:1383307 version:1.0.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/neatvnc/neatvnc.changes  2026-09-28 
10:49:29.865607483 +0200
+++ /work/SRC/openSUSE:Factory/.neatvnc.new.3698736/neatvnc.changes     
2026-10-08 15:14:43.575119096 +0200
@@ -1,0 +2,23 @@
+Thu Oct  8 12:25:49 UTC 2026 - Dominique Leuenberger <[email protected]>
+
+- Add 5b190f0.patch: backport from master: Use nettle & hogweed version 4;
+  Fixes build against libnettle 4.x.
+
+-------------------------------------------------------------------
+Thu Oct  8 11:59:41 UTC 2026 - Michael Vetter <[email protected]>
+
+- Update to 1.0.3:
+  * stream: Fix message ordering, stalls and leaks
+  * stream: Remove local send queue
+  * stream: Do callbacks last on close
+  * stream: Add weakref guard around stream_close in remote_closed
+  * stream: ws: Return early on read failure
+  * stream: rsa-aes: Return early on read failure
+  * stream: ws: Return early on header send failure
+  * stream: ws: Queue frame header with payload
+  * stream: ws: Wait for complete ping before replying
+  * stream: ws: Keep mask phase across payload chunks
+  * stream: ws: Handle control frames between fragments
+  * stream: ws: Keep reading after empty frame
+
+-------------------------------------------------------------------

Old:
----
  neatvnc-1.0.2.tar.xz

New:
----
  5b190f0.patch
  neatvnc-1.0.3.tar.xz

----------(New B)----------
  New:
- Add 5b190f0.patch: backport from master: Use nettle & hogweed version 4;
  Fixes build against libnettle 4.x.
----------(New E)----------

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

Other differences:
------------------
++++++ neatvnc.spec ++++++
--- /var/tmp/diff_new_pack.fAlHaB/_old  2026-10-08 15:14:44.937176164 +0200
+++ /var/tmp/diff_new_pack.fAlHaB/_new  2026-10-08 15:14:44.938176205 +0200
@@ -19,7 +19,7 @@
 %define libsoname libneatvnc1
 
 Name:           neatvnc
-Version:        1.0.2
+Version:        1.0.3
 Release:        0
 Summary:        A VNC server library
 License:        ISC
@@ -27,6 +27,8 @@
 URL:            https://github.com/any1/neatvnc
 Source0:        %{name}-%{version}.tar.xz
 Patch0:         fix-build-in-15.6.patch
+# PATCH-FIX-UPSTREAM -- Use nettle & hogweed version 4; backported from 
https://github.com/any1/neatvnc/commit/5b190f0.patch
+Patch1:         5b190f0.patch
 
 BuildRequires:  meson
 BuildRequires:  pkgconfig

++++++ 5b190f0.patch ++++++
>From 5b190f0fd9e6b0bfd32752a9115242f87ec36c59 Mon Sep 17 00:00:00 2001
From: Andri Yngvason <[email protected]>
Date: Sun, 17 May 2026 09:57:07 +0000
Subject: [PATCH] Use nettle & hogweed version 4

---
 meson.build                | 6 ++++--
 src/crypto/nettle/cipher.c | 8 ++++----
 src/crypto/nettle/hash.c   | 2 +-
 3 files changed, 9 insertions(+), 7 deletions(-)

Index: neatvnc-1.0.3/meson.build
===================================================================
--- neatvnc-1.0.3.orig/meson.build
+++ neatvnc-1.0.3/meson.build
@@ -61,8 +61,10 @@ libm = cc.find_library('m', required: fa
 pixman = dependency('pixman-1')
 libturbojpeg = dependency('libturbojpeg', required: get_option('jpeg'))
 gnutls = dependency('gnutls', required: get_option('tls'))
-nettle = dependency('nettle', required: get_option('nettle'))
-hogweed = dependency('hogweed', required: get_option('nettle'))
+nettle = dependency('nettle', required: get_option('nettle'),
+                    version: ['>=4.0', '<5.0'])
+hogweed = dependency('hogweed', required: get_option('nettle'),
+                     version: ['>=4.0', '<5.0'])
 gmp = cc.find_library('gmp')
 zlib = dependency('zlib')
 gbm = dependency('gbm', required: get_option('gbm'))
Index: neatvnc-1.0.3/src/crypto/nettle/cipher.c
===================================================================
--- neatvnc-1.0.3.orig/src/crypto/nettle/cipher.c
+++ neatvnc-1.0.3/src/crypto/nettle/cipher.c
@@ -119,7 +119,7 @@ static bool crypto_cipher_aes_eax_encryp
                        (uint8_t*)dst->data + dst->len, src);
        dst->len += src_len;
 
-       nettle_eax_aes128_digest(&self->enc_ctx.aes_eax.ctx, 16, mac);
+       nettle_eax_aes128_digest(&self->enc_ctx.aes_eax.ctx, mac);
 
        return true;
 }
@@ -131,7 +131,7 @@ static ssize_t crypto_cipher_aes_eax_dec
        crypto_aes_eax_update_nonce(&self->dec_ctx.aes_eax);
        nettle_eax_aes128_update(&self->dec_ctx.aes_eax.ctx, ad_len, ad);
        nettle_eax_aes128_decrypt(&self->dec_ctx.aes_eax.ctx, len, dst, src);
-       nettle_eax_aes128_digest(&self->dec_ctx.aes_eax.ctx, 16, mac);
+       nettle_eax_aes128_digest(&self->dec_ctx.aes_eax.ctx, mac);
        return len;
 }
 
@@ -179,7 +179,7 @@ static bool crypto_cipher_aes256_eax_enc
                        (uint8_t*)dst->data + dst->len, src);
        dst->len += src_len;
 
-       EAX_DIGEST(&self->enc_ctx.aes256_eax.ctx, aes256_encrypt, 16, mac);
+       EAX_DIGEST(&self->enc_ctx.aes256_eax.ctx, aes256_encrypt, mac);
 
        return true;
 }
@@ -191,7 +191,7 @@ static ssize_t crypto_cipher_aes256_eax_
        crypto_aes256_eax_update_nonce(&self->dec_ctx.aes256_eax);
        EAX_UPDATE(&self->dec_ctx.aes256_eax.ctx, aes256_encrypt, ad_len, ad);
        EAX_DECRYPT(&self->dec_ctx.aes256_eax.ctx, aes256_encrypt, len, dst, 
src);
-       EAX_DIGEST(&self->dec_ctx.aes256_eax.ctx, aes256_encrypt, 16, mac);
+       EAX_DIGEST(&self->dec_ctx.aes256_eax.ctx, aes256_encrypt, mac);
        return len;
 }
 
Index: neatvnc-1.0.3/src/crypto/nettle/hash.c
===================================================================
--- neatvnc-1.0.3.orig/src/crypto/nettle/hash.c
+++ neatvnc-1.0.3/src/crypto/nettle/hash.c
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 #include <nettle/md5.h>
 #include <nettle/sha1.h>
-#include <nettle/sha.h>
+#include <nettle/sha2.h>
 
 struct crypto_hash {
        union {

++++++ _service ++++++
--- /var/tmp/diff_new_pack.fAlHaB/_old  2026-10-08 15:14:44.991178426 +0200
+++ /var/tmp/diff_new_pack.fAlHaB/_new  2026-10-08 15:14:44.998178719 +0200
@@ -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">4d6d09b544d84b836cf1906735354b4e694a0c1c</param>
-    <param name="versionformat">1.0.2</param>
+    <param name="revision">783437adc56c2d7ce2cac1ec584acad798594267</param>
+    <param name="versionformat">1.0.3</param>
   </service>
   <service name="tar" mode="manual"/>
   <service name="recompress" mode="manual">

++++++ neatvnc-1.0.2.tar.xz -> neatvnc-1.0.3.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/include/stream/stream.h 
new/neatvnc-1.0.3/include/stream/stream.h
--- old/neatvnc-1.0.2/include/stream/stream.h   2026-07-09 20:55:08.000000000 
+0200
+++ new/neatvnc-1.0.3/include/stream/stream.h   2026-10-03 18:25:04.000000000 
+0200
@@ -20,6 +20,7 @@
 #include "sys/queue.h"
 #include "rcbuf.h"
 #include "vec.h"
+#include "weakref.h"
 
 #ifdef HAVE_CRYPTO
 #include "crypto.h"
@@ -78,7 +79,7 @@
 
 struct stream {
        struct stream_impl *impl;
-       int ref;
+       struct weakref_subject weakref;
 
        enum stream_state state;
 
@@ -104,7 +105,6 @@
 
 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-1.0.2/meson.build 
new/neatvnc-1.0.3/meson.build
--- old/neatvnc-1.0.2/meson.build       2026-07-09 20:55:08.000000000 +0200
+++ new/neatvnc-1.0.3/meson.build       2026-10-03 18:25:04.000000000 +0200
@@ -1,7 +1,7 @@
 project(
        'neatvnc',
        'c',
-       version: '1.0.1',
+       version: '1.0.3',
        license: 'ISC',
        default_options: [
                'c_std=gnu11',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/src/server.c 
new/neatvnc-1.0.3/src/server.c
--- old/neatvnc-1.0.2/src/server.c      2026-07-09 20:55:08.000000000 +0200
+++ new/neatvnc-1.0.3/src/server.c      2026-10-03 18:25:04.000000000 +0200
@@ -1255,7 +1255,7 @@
        int height = ntohs(msg->height);
 
        if (incremental && client->continuous_updates_enabled)
-               return 0;
+               return sizeof(*msg);
 
        client->n_pending_requests++;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/src/stream/common.c 
new/neatvnc-1.0.3/src/stream/common.c
--- old/neatvnc-1.0.2/src/stream/common.c       2026-07-09 20:55:08.000000000 
+0200
+++ new/neatvnc-1.0.3/src/stream/common.c       2026-10-03 18:25:04.000000000 
+0200
@@ -21,7 +21,7 @@
 
 void stream_init(struct stream* self)
 {
-       self->ref = 1;
+       weakref_subject_init(&self->weakref);
 }
 
 void stream_req__finish(struct stream_req* req, enum stream_req_status status)
@@ -39,8 +39,13 @@
 
 void stream__remote_closed(struct stream* self)
 {
+       struct weakref_observer ref;
+       weakref_observer_init(&ref, &self->weakref);
+
        stream_close(self);
 
-       if (self->on_event)
+       if (ref.subject && self->on_event)
                self->on_event(self, STREAM_EVENT_REMOTE_CLOSED);
+
+       weakref_observer_deinit(&ref);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/src/stream/gnutls.c 
new/neatvnc-1.0.3/src/stream/gnutls.c
--- old/neatvnc-1.0.2/src/stream/gnutls.c       2026-07-09 20:55:08.000000000 
+0200
+++ new/neatvnc-1.0.3/src/stream/gnutls.c       2026-10-03 18:25:04.000000000 
+0200
@@ -54,14 +54,6 @@
 
        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);
-               stream_req__finish(req, STREAM_REQ_FAILED);
-       }
-
        if (self->session)
                gnutls_deinit(self->session);
        self->session = NULL;
@@ -70,8 +62,15 @@
        close(self->base.fd);
        self->base.fd = -1;
 
-       // unref
-       stream_destroy(&self->base);
+       struct stream_send_queue send_queue;
+       TAILQ_INIT(&send_queue);
+       TAILQ_CONCAT(&send_queue, &self->base.send_queue, link);
+
+       while (!TAILQ_EMPTY(&send_queue)) {
+               struct stream_req* req = TAILQ_FIRST(&send_queue);
+               TAILQ_REMOVE(&send_queue, req, link);
+               stream_req__finish(req, STREAM_REQ_FAILED);
+       }
 
        return 0;
 }
@@ -85,15 +84,20 @@
 
 static int stream_gnutls__flush(struct stream* base)
 {
+       if (base->cork)
+               return 0;
+
        struct stream_gnutls* self = (struct stream_gnutls*)base;
 
-       stream_ref(base);
+       struct weakref_observer ref;
+       weakref_observer_init(&ref, &base->weakref);
+
        int rc = -1;
 
-       while (!TAILQ_EMPTY(&self->base.send_queue)) {
-               assert(self->base.state != STREAM_STATE_CLOSED);
+       base->cork = true;
 
-               struct stream_req* req = TAILQ_FIRST(&self->base.send_queue);
+       while (!TAILQ_EMPTY(&base->send_queue)) {
+               struct stream_req* req = TAILQ_FIRST(&base->send_queue);
 
                /* GnuTLS returns an error when sending with 0 data_size */
                if (req->payload->size == 0)
@@ -129,17 +133,24 @@
                assert(remaining == 0);
 
 req_done:
-               TAILQ_REMOVE(&self->base.send_queue, req, link);
+               TAILQ_REMOVE(&base->send_queue, req, link);
                stream_req__finish(req, STREAM_REQ_DONE);
+               if (!ref.subject || base->state == STREAM_STATE_CLOSED)
+                       goto done;
        }
 
-       if (TAILQ_EMPTY(&base->send_queue) && base->state != 
STREAM_STATE_CLOSED)
-               stream__poll_r(base);
-
        rc = 1;
 done:
-       // unref
-       stream_destroy(base);
+       if (ref.subject && base->state != STREAM_STATE_CLOSED) {
+               base->cork = false;
+
+               if (TAILQ_EMPTY(&base->send_queue))
+                       stream__poll_r(base);
+               else
+                       stream__poll_rw(base);
+       }
+
+       weakref_observer_deinit(&ref);
        return rc;
 }
 
@@ -181,15 +192,16 @@
        struct stream* self = aml_get_userdata(handler);
        uint32_t events = aml_get_revents(handler);
 
-       stream_ref(self);
+       struct weakref_observer ref;
+       weakref_observer_init(&ref, &self->weakref);
 
        if (events & AML_EVENT_READ)
                stream_gnutls__on_readable(self);
 
-       if (events & AML_EVENT_WRITE)
+       if ((events & AML_EVENT_WRITE) && ref.subject)
                stream_gnutls__on_writable(self);
 
-       stream_destroy(self);
+       weakref_observer_deinit(&ref);
 }
 
 static int stream_gnutls_send(struct stream* self, struct rcbuf* payload,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/src/stream/interface.c 
new/neatvnc-1.0.3/src/stream/interface.c
--- old/neatvnc-1.0.2/src/stream/interface.c    2026-07-09 20:55:08.000000000 
+0200
+++ new/neatvnc-1.0.3/src/stream/interface.c    2026-10-03 18:25:04.000000000 
+0200
@@ -18,11 +18,6 @@
 
 #include <assert.h>
 
-void stream_ref(struct stream* self)
-{
-       self->ref++;
-}
-
 int stream_close(struct stream* self)
 {
        assert(self->impl && self->impl->close);
@@ -32,8 +27,8 @@
 void stream_destroy(struct stream* self)
 {
        assert(self->impl && self->impl->destroy);
-       if (--self->ref == 0)
-               return self->impl->destroy(self);
+       weakref_subject_deinit(&self->weakref);
+       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-1.0.2/src/stream/rsa-aes.c 
new/neatvnc-1.0.3/src/stream/rsa-aes.c
--- old/neatvnc-1.0.2/src/stream/rsa-aes.c      2026-07-09 20:55:08.000000000 
+0200
+++ new/neatvnc-1.0.3/src/stream/rsa-aes.c      2026-10-03 18:25:04.000000000 
+0200
@@ -52,13 +52,14 @@
        stream_tcp_destroy(base);
 }
 
-static void stream_rsa_aes_read_into_buffer(struct stream_rsa_aes* self)
+static ssize_t stream_rsa_aes_read_into_buffer(struct stream_rsa_aes* self)
 {
        ssize_t n_read = stream_tcp_read(&self->base,
                        self->read_buffer + self->read_index,
                        RSA_AES_BUFFER_SIZE - self->read_index);
        if (n_read > 0)
                self->read_index += n_read;
+       return n_read;
 }
 
 static ssize_t stream_rsa_aes_parse_header(struct stream_rsa_aes* self)
@@ -121,9 +122,9 @@
 {
        struct stream_rsa_aes* self = (struct stream_rsa_aes*)base;
 
-       stream_rsa_aes_read_into_buffer(self);
-       if (self->base.state == STREAM_STATE_CLOSED)
-               return 0;
+       ssize_t n_read = stream_rsa_aes_read_into_buffer(self);
+       if (n_read <= 0)
+               return n_read;
 
        size_t total_read = 0;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/src/stream/tcp.c 
new/neatvnc-1.0.3/src/stream/tcp.c
--- old/neatvnc-1.0.2/src/stream/tcp.c  2026-07-09 20:55:08.000000000 +0200
+++ new/neatvnc-1.0.3/src/stream/tcp.c  2026-10-03 18:25:04.000000000 +0200
@@ -45,20 +45,19 @@
        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);
-               stream_req__finish(req, STREAM_REQ_FAILED);
-       }
-
        aml_stop(aml_get_default(), self->handler);
        close(self->fd);
        self->fd = -1;
 
-       // unref
-       stream_destroy(self);
+       struct stream_send_queue send_queue;
+       TAILQ_INIT(&send_queue);
+       TAILQ_CONCAT(&send_queue, &self->send_queue, link);
+
+       while (!TAILQ_EMPTY(&send_queue)) {
+               struct stream_req* req = TAILQ_FIRST(&send_queue);
+               TAILQ_REMOVE(&send_queue, req, link);
+               stream_req__finish(req, STREAM_REQ_FAILED);
+       }
 
        return 0;
 }
@@ -125,7 +124,8 @@
        // Don't flush while flushing
        self->cork = true;
 
-       stream_ref(self);
+       struct weakref_observer ref;
+       weakref_observer_init(&ref, &self->weakref);
 
        struct stream_req* tmp;
        TAILQ_FOREACH_SAFE(req, &self->send_queue, link, tmp) {
@@ -134,6 +134,8 @@
                if (bytes_left >= 0) {
                        TAILQ_REMOVE(&self->send_queue, req, link);
                        stream_req__finish(req, STREAM_REQ_DONE);
+                       if (!ref.subject || self->state == STREAM_STATE_CLOSED)
+                               break;
                } else {
                        if (req->exec) {
                                free(req->userdata);
@@ -151,15 +153,18 @@
                        break;
        }
 
-       self->cork = false;
+       if (ref.subject && self->state != STREAM_STATE_CLOSED) {
+               self->cork = false;
 
-       if (bytes_left == 0 && self->state != STREAM_STATE_CLOSED)
-               stream__poll_r(self);
+               if (TAILQ_EMPTY(&self->send_queue))
+                       stream__poll_r(self);
+               else
+                       stream__poll_rw(self);
 
-       assert(bytes_left <= 0);
+               assert(bytes_left <= 0);
+       }
 
-       // unref
-       stream_destroy(self);
+       weakref_observer_deinit(&ref);
 
        return bytes_sent;
 }
@@ -198,16 +203,16 @@
 
        // We hold a reference here in case the stream gets destroyed inside
        // callback.
-       stream_ref(self);
+       struct weakref_observer ref;
+       weakref_observer_init(&ref, &self->weakref);
 
        if (events & AML_EVENT_READ)
                stream_tcp__on_readable(self);
 
-       if (events & AML_EVENT_WRITE)
+       if ((events & AML_EVENT_WRITE) && ref.subject)
                stream_tcp__on_writable(self);
 
-       // unref
-       stream_destroy(self);
+       weakref_observer_deinit(&ref);
 }
 
 ssize_t stream_tcp_read(struct stream* self, void* dst, size_t size)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/neatvnc-1.0.2/src/stream/ws/ws.c 
new/neatvnc-1.0.3/src/stream/ws/ws.c
--- old/neatvnc-1.0.2/src/stream/ws/ws.c        2026-07-09 20:55:08.000000000 
+0200
+++ new/neatvnc-1.0.3/src/stream/ws/ws.c        2026-10-03 18:25:04.000000000 
+0200
@@ -47,13 +47,14 @@
        uint8_t read_buffer[4096]; // TODO: Is this a reasonable size?
 };
 
-static void stream_ws_read_into_buffer(struct stream_ws* ws)
+static ssize_t stream_ws_read_into_buffer(struct stream_ws* ws)
 {
        ssize_t n_read = stream_tcp_read(&ws->base,
                        ws->read_buffer + ws->read_index,
                        sizeof(ws->read_buffer) - ws->read_index);
        if (n_read > 0)
                ws->read_index += n_read;
+       return n_read;
 }
 
 static void stream_ws_advance_read_buffer(struct stream_ws* ws, size_t size,
@@ -66,6 +67,11 @@
        memmove(ws->read_buffer, ws->read_buffer + offset + payload_len,
                        ws->read_index);
        ws->header.payload_length -= payload_len;
+
+       uint8_t key[4];
+       memcpy(key, ws->header.masking_key, sizeof(key));
+       for (int i = 0; i < 4; ++i)
+               ws->header.masking_key[i] = key[(i + payload_len) % 4];
 }
 
 static ssize_t stream_ws_copy_payload(struct stream_ws* ws, void* dst,
@@ -79,6 +85,15 @@
        return payload_len;
 }
 
+static int stream_ws_queue(struct stream_ws* ws, struct rcbuf* payload)
+{
+       bool cork = ws->base.cork;
+       ws->base.cork = true;
+       int rc = stream_tcp_send(&ws->base, payload, NULL, NULL);
+       ws->base.cork = cork;
+       return rc;
+}
+
 static ssize_t stream_ws_process_ping(struct stream_ws* ws, size_t offset)
 {
        if (offset > 0) {
@@ -91,8 +106,8 @@
 
                uint8_t buf[WS_HEADER_MIN_SIZE];
                int reply_len = ws_write_frame_header(buf, &reply);
-               stream_tcp_send(&ws->base, rcbuf_from_mem(buf, reply_len),
-                               NULL, NULL);
+               if (stream_ws_queue(ws, rcbuf_from_mem(buf, reply_len)) < 0)
+                       return -1;
        }
 
        int payload_len = MIN(ws->read_index - offset, 
ws->header.payload_length);
@@ -102,7 +117,8 @@
        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);
+       if (stream_tcp_send(&ws->base, rcbuf, NULL, NULL) < 0)
+               return -1;
 
        stream_ws_advance_read_buffer(ws, payload_len, offset);
        return 0;
@@ -111,7 +127,10 @@
 static ssize_t stream_ws_process_payload(struct stream_ws* ws, void* dst,
                size_t size, size_t offset)
 {
-       switch (ws->current_opcode) {
+       enum ws_opcode opcode = ws->header.opcode == WS_OPCODE_CONT ?
+               ws->current_opcode : ws->header.opcode;
+
+       switch (opcode) {
        case WS_OPCODE_CONT:
                // Remote end started with a continuation frame. This is
                // unexpected, so we'll just close.
@@ -152,7 +171,15 @@
                return 0;
        }
 
-       if (ws->header.opcode != WS_OPCODE_CONT) {
+       if (ws->header.opcode == WS_OPCODE_PING &&
+                       ws->read_index - ws->header.header_length <
+                       ws->header.payload_length) {
+               ws->header.payload_length = 0;
+               return 0;
+       }
+
+       if (ws->header.opcode == WS_OPCODE_TEXT ||
+                       ws->header.opcode == WS_OPCODE_BIN) {
                ws->current_opcode = ws->header.opcode;
        }
 
@@ -165,18 +192,28 @@
 static ssize_t stream_ws_read_ready(struct stream_ws* ws, void* dst,
                size_t size)
 {
-       size_t total_read = 0;
+       struct weakref_observer ref;
+       weakref_observer_init(&ref, &ws->base.weakref);
+
+       ssize_t total_read = 0;
 
        while (true) {
+               size_t read_index = ws->read_index;
                ssize_t n_read = stream_ws_read_frame(ws, dst, size);
-               if (n_read == 0)
+               if (!ref.subject)
                        break;
 
-               if (n_read < 0) {
-                       if (errno == EAGAIN) {
+               if (n_read == 0) {
+                       if (ws->base.state == STREAM_STATE_CLOSED ||
+                                       ws->read_index == read_index)
                                break;
-                       }
-                       return -1;
+                       continue;
+               }
+
+               if (n_read < 0) {
+                       if (errno != EAGAIN)
+                               total_read = -1;
+                       break;
                }
 
                total_read += n_read;
@@ -184,6 +221,7 @@
                size -= n_read;
        }
 
+       weakref_observer_deinit(&ref);
        return total_read;
 }
 
@@ -218,9 +256,9 @@
 {
        struct stream_ws* ws = (struct stream_ws*)self;
 
-       stream_ws_read_into_buffer(ws);
-       if (self->state == STREAM_STATE_CLOSED)
-               return 0;
+       ssize_t n_read = stream_ws_read_into_buffer(ws);
+       if (n_read <= 0)
+               return n_read;
 
        switch (ws->ws_state) {
        case STREAM_WS_STATE_HANDSHAKE:
@@ -246,8 +284,11 @@
        uint8_t raw_head[WS_HEADER_MIN_SIZE];
        int head_len = ws_write_frame_header(raw_head, &head);
 
-       stream_tcp_send(&ws->base, rcbuf_from_mem(&raw_head, head_len),
-                       NULL, NULL);
+       if (stream_ws_queue(ws, rcbuf_from_mem(&raw_head, head_len)) < 0) {
+               rcbuf_unref(payload);
+               return -1;
+       }
+
        return stream_tcp_send(&ws->base, payload, on_done, userdata);
 }
 

++++++ neatvnc.obsinfo ++++++
--- /var/tmp/diff_new_pack.fAlHaB/_old  2026-10-08 15:14:45.183186471 +0200
+++ /var/tmp/diff_new_pack.fAlHaB/_new  2026-10-08 15:14:45.190186764 +0200
@@ -1,5 +1,5 @@
 name: neatvnc
-version: 1.0.2
-mtime: 1783623308
-commit: 4d6d09b544d84b836cf1906735354b4e694a0c1c
+version: 1.0.3
+mtime: 1791044704
+commit: 783437adc56c2d7ce2cac1ec584acad798594267
 

Reply via email to