Files
ewm/scripts/systemd/ewm-one@.service
T
Stefan ArentzandClaude Fable 5 3c7fe06776 --tty-telnet: proactive echo negotiation (fix telnet double-echo)
The telnet echo suppression was reactive — the server only announced
WILL ECHO / WILL SGA after the client sent an IAC first. But a classic
telnet client sits in line-mode-with-local-echo and waits for the
server to negotiate, so the announcement never went out, the client
kept echoing locally, and every line appeared twice (its echo plus the
machine's own authentic echo).

A telnet server that wants remote echo has to offer it proactively on
connect. The new --tty-telnet flag (implies --tty) does exactly that:
it writes WILL ECHO + WILL SGA before the banner and marks the filter
active so the reactive path doesn't double-announce. Bare --tty stays
byte-clean for local terminals and nc (kickoff option B); the reactive
fallback still helps a plain --tty client that does negotiate first.
The systemd @.service switches its ExecStart to --tty-telnet.

The growing session-behavior params (throttle, banner, telnet) fold
into a TtyConfig struct. Tests: proactive announce leads the stream
(before the banner) and doesn't double-announce when the client then
sends its own IAC; the flag implies --tty and parses. Verified live:
`ewm one --tty-telnet | xxd` shows FF FB 01 FF FB 03 then the prompt.

Docs: scripts/systemd/README.md and notes/APPLE1.md explain proactive
--tty-telnet vs byte-clean --tty, with troubleshooting for the
double-echo and the nc negotiation bytes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:11:12 -04:00

33 lines
1.2 KiB
Desktop File

# One telnet connection = one Apple 1 (see ewm-one.socket). The
# emulator does no networking: systemd hands the accepted connection
# over as stdin/stdout and `ewm one --tty` speaks bytes — keyboard in,
# display out, Meta-R (or telnet's `send brk`) is the RESET button.
#
# The sandbox can be tight because the binary needs no filesystem at
# all: the machine configs and ROM images are embedded. Swap the
# --config for builtin:replica1 (or a config path, if you loosen the
# sandbox) to serve a different machine.
[Unit]
Description=Apple 1 for %i
[Service]
# Install banner.txt (next to these units) wherever you like — it is
# readable under ProtectSystem=strict from /usr or /etc.
# --tty-telnet (implies --tty) negotiates server-side echo on connect, so
# a telnet client stops echoing locally and each line appears once.
ExecStart=/usr/local/bin/ewm one --config builtin:apple1 --tty-telnet --tty-banner /usr/local/share/ewm/banner.txt
StandardInput=socket
StandardOutput=socket
StandardError=journal
DynamicUser=yes
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
RestrictAddressFamilies=AF_UNIX
MemoryMax=64M
# Abandoned sessions do not get to keep a 1 MHz loop forever.
RuntimeMaxSec=4h