[ 
https://issues.apache.org/jira/browse/GUACAMOLE-2307?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18099885#comment-18099885
 ] 

Ciro Iriarte commented on GUACAMOLE-2307:
-----------------------------------------

The coordinated pull requests for this feature are now open against apache/main:

* guacamole-server: https://github.com/apache/guacamole-server/pull/697
* guacamole-client (UI: protocol parameter + translations): 
https://github.com/apache/guacamole-client/pull/1234
* guacamole-manual (documentation): 
https://github.com/apache/guacamole-manual/pull/301

The guacamole-server PR contains only the upstream-relevant change (the 
redistributable patch artifact carried on the development fork is excluded), 
builds clean and passes make check on Debian 12 and openSUSE Leap 16, and 
merges cleanly onto current main.

> Add opt-in raw text-output mode for terminal protocols (SSH/telnet/Kubernetes)
> ------------------------------------------------------------------------------
>
>                 Key: GUACAMOLE-2307
>                 URL: https://issues.apache.org/jira/browse/GUACAMOLE-2307
>             Project: Guacamole
>          Issue Type: New Feature
>          Components: guacamole-server
>            Reporter: Ciro Iriarte
>            Priority: Minor
>
> h2. Summary
> Add an opt-in per-connection parameter, {{text-output}}, that makes guacd tee 
> the
> raw remote PTY byte stream (including ANSI/CSI/OSC sequences) to an outbound
> Guacamole {{pipe}} stream named {{STDOUT}}, for the SSH, telnet, and 
> Kubernetes
> protocols. This lets a non-graphical / native CLI client present a terminal 
> session
> as true in-terminal text instead of decoding rasterized glyphs. Default off; 
> no
> change to existing connections.
> h2. Motivation
> The browser terminal renders output graphically: guacd runs the emulator and 
> emits
> only drawing instructions, so no character codepoints reach the client. A 
> native or
> CLI client therefore cannot reconstruct the text of a session. This adds a 
> faithful
> raw byte channel in the output direction, complementing the inbound STDIN pipe
> (GUACAMOLE-574). It deliberately does *not* reuse the {{guacctl}} pipe 
> redirect
> (GUACAMOLE-17): that path runs through {{guac_terminal_echo()}}, which strips
> ESC/CSI/OSC sequences and so cannot carry a faithful raw stream.
> h2. Design
> * New connection parameter {{text-output}} (string enum):
> ** {{true}} — tee mode: raw bytes are teed to STDOUT *and* the graphical 
> display is
>    still rendered, so browser users are unaffected.
> ** {{raw}} — headless mode: the graphical terminal is not rendered at all; 
> bytes are
>    delivered only via STDOUT, eliminating the graphical instruction stream 
> and its
>    render cost.
> ** anything else, including {{false}} or omitted — disabled.
> * guacd opens an outbound {{pipe}} stream named {{STDOUT}}, mimetype
>   {{application/octet-stream}} (advisory; payload is raw bytes carried in 
> base64
>   {{blob}} instructions, so it is binary-safe and charset-agnostic — the 
> client
>   decodes the bytes itself).
> * The tee is taken *at the protocol source* — in each protocol's PTY read 
> path,
>   upstream of the terminal emulator — via a dedicated {{text_output_stream}} 
> on
>   {{guac_terminal}}, independent of the {{guacctl}} pipe machinery.
> * The stream is allocated on the connection *owner's* user socket
>   ({{guac_user_alloc_stream}}), not broadcast to every user, and uses an even
>   (ack-routable) stream index so client {{ack}} instructions return to the 
> stream.
> * New additive public API in {{terminal.h}}:
>   {{guac_terminal_text_output_open/write/flush/close}} (+ a {{should_open}} 
> helper).
>   No existing symbol is changed.
> * In {{raw}} mode the read loop skips {{guac_terminal_write()}} (the terminal 
> is kept
>   for input/size/stdin) and flushes per-read, since there is no graphical 
> frame cycle.
> h2. Flow control / backpressure
> This is the subtle part and is worth reviewer attention:
> * Clients must {{ack}} every {{blob}}, on receipt rather than after rendering.
> * guacd bounds the unacknowledged backlog by *bytes*: 256 KB
>   ({{GUAC_TERMINAL_TEXT_OUTPUT_MAX_INFLIGHT_BYTES}}), plus a 256-blob cap 
> purely to
>   bound a small size-tracking FIFO. The byte bound is the operative one, 
> because
>   {{raw}} mode emits one blob per PTY read and those blobs are often only a 
> few bytes.
> * On a stalled consumer the response differs by mode, deliberately:
> ** {{tee}}: buffered output is *dropped* and the session continues. The tee 
> shares the
>    protocol read loop with the graphical display, so blocking on a stalled 
> text
>    consumer would also stall any co-attached browser user.
> ** {{raw}}: the read loop is *throttled* — the writer waits (on a condition 
> variable)
>    for the window to drain, which propagates backpressure to the remote 
> program
>    through the PTY exactly as a slow local terminal would. Raw renders nothing
>    graphically, so pausing starves no one and the byte stream stays intact.
> * A consumer that stops acking entirely for 15 s
>   ({{GUAC_TERMINAL_TEXT_OUTPUT_STALL_TIMEOUT}}) is disconnected with 
> {{SERVER_ERROR}}.
>   The wait also short-circuits immediately once the connection is going away, 
> so an
>   abrupt disconnect does not delay teardown.
> h2. Security
> * {{text-output}} is effectively a copy/export channel, so it is gated behind
>   {{disable-copy}}: guacd refuses to open the pipe when copying from the 
> terminal is
>   disabled (and logs a warning).
> * Pipe contents are not logged or recorded by default (output may echo 
> secrets).
> * Intended trust model: the parameter is admin-provisioned on the connection 
> (not
>   client-requestable); guacd is reached only over the authenticated 
> tunnel/gateway.
>   No new port, no new protocol instruction (reuses 
> {{pipe}}/{{blob}}/{{end}}/{{ack}}),
>   no authentication change.
> h2. Backwards compatibility / ABI
> Additive and opt-in, default off. No new protocol instruction, no DB schema 
> change,
> and no web-app change is required — an unmodified guacamole-client already 
> passes the
> parameter through, since {{ConfiguredGuacamoleSocket}} builds the {{connect}}
> instruction from the argument list guacd announces in its handshake. No ABI 
> break:
> only additive public symbols are introduced.
> h2. Validation
> * CUnit unit tests for terminal text-output: disable-copy gating, 
> owner-stream + ack
>   routing, tee drop-on-stall, raw throttle-vs-abort, the byte bound, ACK 
> retiring the
>   oldest blob's byte count, surplus-ACK safety, disconnect short-circuit, and
>   closed-stream-unroutable. Full {{make check}} is green on Debian 12 and 
> openSUSE
>   Leap 16.
> * An end-to-end harness (direct-to-guacd, no web app) covers 
> SSH/telnet/Kubernetes
>   across 13 scenarios: positive tee, negative (default-off and disable-copy 
> -> no
>   pipe), a byte-bound flood with and without acks, small-unacked-not-dropped, 
> and
>   raw (text delivered, graphics suppressed). All pass.
> * Validated live through an unmodified guacamole-client gateway with a native 
> CLI
>   client, in both tee and raw modes, including a 20,000-line flood and the 15 
> s
>   give-up path (measured: 256 KB delivered, then a clean SERVER_ERROR abort).
> h2. Patch / branch
> Implemented on a fork branch, 23 commits atop apache/main (base 6719b20d). A
> redistributable {{git format-patch}} artifact is available and applies 
> cleanly onto
> that base. Happy to open a PR against apache/main. The client side is UI-only
> convenience (protocol JSON enum + i18n strings), and a matching manual section
> documents the parameter and the backpressure contract.
> h2. Related
> * GUACAMOLE-17 (resolved) — the original {{guacctl}} output-to-pipe redirect; 
> routes
>   through the escape-stripping echo path, so it is not usable for a faithful 
> raw
>   stream. This issue is the complement, taken at the source.
> * GUACAMOLE-574 — inbound STDIN pipe (the input direction).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to