https://bugs.kde.org/show_bug.cgi?id=527202

[email protected] changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |[email protected]

--- Comment #1 from [email protected] ---
Independent reproduction on a second machine, plus the cause. Setup: CachyOS,
krdp 6.8.0, Plasma 6.8.0 (kwin, xdg-desktop-portal-kde, kpipewire 6.8.0),
FreeRDP 3.32.2, Qt 6.12.0, kernel 7.2.9, Wayland, NVIDIA RTX 2080 Ti
(580.178.04, no VA-API H.264 encode, so libx264). Server started as `krdpserver
--virtual-monitor 1800x1169@1 -u … -p …` (portal path). Client: Windows App
11.4.2 on macOS 27.0.1. Reconnects worked on krdp 6.7.5 with the same client.

== Symptom ==

First connection after krdpserver starts works. Every later connection
authenticates, the portal session starts, the encoder starts, and the client
drops the TCP connection about 6 ms after the first frame. Windows App shows
0x200d. Server side:

  transport_read_layer: BIO_read retries exceeded
  transport_read_layer: ERRCONNECT_CONNECT_TRANSPORT_FAILED [0x0002000D]
  rdpgfx_server_handle_messages: WTSVirtualChannelRead failed!
  rdpgfx_server_thread_func: rdpgfx_server_handle_messages failed with error
1359

Those are the effect of the client hanging up, not the cause: `org.kde.krdp`
debug logging shows no krdp warning before them, and the portal session reports
"Started Freedesktop Portal session" normally each time. Same result with
KRDP_DISABLE_H264=1 (progressive codec), so the codec is not involved. A second
connection from sdl-freerdp3 (FreeRDP 3.32.2 client, same server process)
works, so the client matters: FreeRDP tolerates what the server sends, Windows
App does not.

== Cause: uninitialised Surface in VideoStreamSurface ==

With WLOG_LEVEL=DEBUG, WLOG_FILTER=com.freerdp.channels.rdpgfx.server:TRACE on
the server, the GFX PDUs the server sends at the first frame differ between the
first and the second connection of the same process:

First connection (works):

  rdpgfx_send_caps_confirm_pdu
  rdpgfx_send_reset_graphics_pdu
  rdpgfx_send_create_surface_pdu
  rdpgfx_send_map_surface_to_output_pdu
  rdpgfx_send_start_frame_pdu / surface_command / end_frame_pdu
  ... FRAMEACKNOWLEDGE, session runs

Second connection (fails):

  rdpgfx_send_caps_confirm_pdu
  rdpgfx_send_delete_encoding_context_pdu   <-- for a surface that was never
created
  rdpgfx_send_delete_surface_pdu            <-- same
  rdpgfx_send_reset_graphics_pdu
  rdpgfx_send_create_surface_pdu
  rdpgfx_send_map_surface_to_output_pdu
  rdpgfx_send_start_frame_pdu / surface_command / end_frame_pdu
  (6 ms later) transport_read_pdu() -1, client gone

DeleteEncodingContext and DeleteSurface before any CreateSurface is exactly
what `VideoStream::destroySurface()` emits when `d->surface->surface.id != 0`
and `codecContextId != 0` at the top of the first `performReset()`. On a fresh
connection both must be 0. They are not, because they are never initialised:

src/VideoStreamSurface.h (Plasma/6.8 and master):

  struct Surface {
      uint16_t id;
      uint32_t codecContextId;
      QSize size;
  };
  ...
  class VideoStreamSurface : public QObject {
      ...
      Surface surface;        // no initialiser
      ...
  };

src/VideoStreamSurface.cpp:

  VideoStreamSurface::VideoStreamSurface(VideoStream *stream)
      : QObject(stream)
      , m_stream(stream)
  {
  }

`Surface` has no default member initialisers and the constructor does not
value-initialise `surface`, so `id` and `codecContextId` are indeterminate. The
first VideoStreamSurface of the process usually lands on fresh (zeroed) heap
pages, so it works. Later ones reuse freed memory and inherit garbage, so
`destroySurface()` sends DeleteEncodingContext/DeleteSurface for bogus ids
before ResetGraphics. Windows App treats a DeleteSurface for an unknown
surfaceId as a protocol error and disconnects; FreeRDP-based clients only warn.
That also explains why it looked like a portal-vs-plasma difference (different
heap layout) and why nothing in PortalSession or xdg-desktop-portal-kde logs an
error. The struct came in with 50120646 "Introduce a separate
VideoStreamSurface object" (2026-09-08), which is why 6.7.5 is fine. 6.8.1
(d6b12bf5, 6d453c86) only touches authentication settings and does not change
this.

Suggested fix (either line is enough):

  -    Surface surface;
  +    Surface surface{};

or give the struct defaults:

  struct Surface {
      uint16_t id = 0;
      uint32_t codecContextId = 0;
      QSize size;
  };

`VideoStream::destroySurface()` already resets with `surface = Surface{}` after
use, so only the initial state is wrong.

== Repro ==

1. `krdpserver --virtual-monitor 1800x1169@1 -u user -p pass` (plain portal
mode without --virtual-monitor fails the same way for the other reporter).
2. Connect with Windows App (macOS 11.4.2 here), wait, disconnect.
3. Connect again: 0x200d within a second. Every further attempt fails until
krdpserver restarts.
4. Optional: WLOG_LEVEL=DEBUG WLOG_APPENDER=JOURNALD
WLOG_FILTER=com.freerdp.channels.rdpgfx.server:TRACE shows the two delete PDUs
on connection 2. (Without the JOURNALD appender FreeRDP's console log is
block-buffered under systemd and the lines appear only on the next flush.)

== Workaround in use ==

A systemd --user unit that follows the krdpserver journal and restarts the
service 2 s after each session ends (match on "ERRINFO_LOGOFF_BY_USER [" or
"ERRCONNECT_CONNECT_TRANSPORT_FAILED"). --plasma is not an option with
--virtual-monitor on 6.8.0 because of the pointer offset problem (bug 526783).

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to