https://gitlab.synchro.net/main/sbbs/-/commit/37de0f10359177f53b344452
Modified Files:
src/doors/syncconquer/CMakeLists.txt PROVENANCE.md src/doors/syncconquer/door/door_io.c src/doors/syncconquer/vanilla/common/utfargs.h src/doors/syncconquer/vanilla/redalert/startup.cpp
Log Message:
syncalert: fix four Windows-only defects that broke the door end to end
The door's first-ever Windows build surfaced four bugs, each invisible on
*nix. Two are in our code, two in the vendored engine's
Windows-without-SDL path -- which upstream never compiles, because its
Windows build always defines SDL_BUILD. All four date from f5578ea57f (foam-43-clip), where the door landed and was only ever built for *nix.
1. setvbuf(stderr, NULL, _IOLBF, 0) fast-failed the process before it
could log a thing: MSVC's CRT requires 2 <= size <= INT_MAX for
_IOLBF/_IOFBF, so size 0 is an invalid parameter and, with no handler
installed, __fastfail()s (c0000409, FAST_FAIL_INVALID_ARG, straight
through ucrtbase!_invoke_watson). glibc ignores the size. Launching
the door dumped the caller back to the BBS with a zero-byte node log.
Use _IONBF on Windows: valid with size 0, and it flushes every write
-- the crash-durability the comment promises, which _IOLBF would not
have delivered there anyway (that CRT silently treats it as _IOFBF).
syncduke fixed the identical fast-fail in 705a840fe9 (panel-11-mind);
syncconquer had copied the pre-fix idiom.
2. Winsock was only ever initialized from door_early_write(), which runs
on failure paths (the missing-assets splash). syncduke gets away with
the same placement because its constructor calls its splash
unconditionally. Here, a healthy launch never called WSAStartup() and
died on its first recv() with WSANOTINITIALISED (10093), which the
pump reads as a client hangup -- again dropping the user back to the
BBS. Hoist it into an idempotent door_wsa_ensure() called from the
pre-main constructor. xpdev's sockwrap does not self-init Winsock.
3. redalert/startup.cpp's `UtfArgs args(argc, argv)` replaces ArgV with a
fresh CommandLineToArgvU(GetCommandLineW()) parse, discarding the argv
door_sanitize_argv() rewrote in the constructor. So -NOMOVIES never
reached the engine (the intro and mission FMV played, with music but
no dialog audio -- vqaaudio_null.cpp stubs the VQA player's audio
hooks), and the door's own -s<fd>/-home tokens reached
Parse_Command_Line(), whose strstr() substring scan over every token
can mis-set an engine option from an unrelated path. utfargs.h now
honors SYNCALERT_KEEP_CRT_ARGV, defined for VanillaRA only.
UNICODE/_UNICODE stay on, so common/'s UTF-8 path handling is
untouched; only the argv re-derivation is skipped.
4. "Exit Game" hung forever. main() sets ReadyToQuit = 1, posts
WM_DESTROY to MainWindow, then spins on Keyboard->Check() until
winstub.cpp's window procedure advances it. The headless door has no
window (MainWindow is NULL) and no message pump, so nothing ever did:
the process stayed alive burning CPU in door_io_pump()'s recv(), the
terminal kept looping its music, and no frames were drawn.
Emergency_Exit()'s ReadyToQuit == 3 spin would hang the same way. Both
are now gated on !NEW_VIDEO_BUILD, which upstream sets for exactly the
backends (SDL1/SDL2) that have no legacy WndProc -- a no-op for every
upstream configuration.
Also close the door's own console window on Windows. Synchronet spawns a
native door with CREATE_NEW_CONSOLE, so a console pops up on the BBS
machine each session; the door draws to the client's terminal and logs to data/syncalert/syncalert_n<node>.log, so it is pure noise. Detach only
when we own the console exclusively (GetConsoleProcessList() == 1) -- a developer running the door from a shell shares that shell's console and
must not lose stdout -- and only with a door socket. FreeConsole()
invalidates all three std streams even when stderr already points at a
file, so it runs BEFORE the node log is opened and re-points every stream
at NUL (the engine still printf()s on some paths).
Vendored patches 10 and 11 recorded in PROVENANCE.md.
Verified on Windows (VS2022, Win32/Release) and by Rob against the live
BBS: the door launches, plays with audio, shows no movies, and exits
cleanly. The engine-argv fix confirmed under cdb (argv[1] "-s999" -> "-NOMOVIES"; bNoMovies 00 -> 01 across Parse_Command_Line); the console
detach confirmed against a CREATE_NEW_CONSOLE / CREATE_NO_WINDOW
launcher, with the node log intact in both. Not compiled by GCC/Clang.
Co-Authored-By: Claude Opus 4.8 (1M context) <
noreply@anthropic.com>
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net