mirror of
https://github.com/fluffos/fluffos
synced 2026-08-12 18:26:06 -04:00
The lws output wedge addressed in the previous commit was incompletely understood: under genuine backpressure (peer slow or paused, kernel send buffer full) a connection still froze permanently. Root cause, established by tracing the writeable-request plumbing end to end: lws_send_pipe_choked() is true not only when lws holds a truncated send (lws re-arms the writeable callback itself then) but also when a zero-timeout poll(POLLOUT) reports the socket simply full -- and in that case every lws_write() has fully succeeded, lws has nothing pending, and nobody re-arms anything. Fix, per lws README.coding.md: whenever the drain loop exits with data still queued in pss->buffer, request the next writeable callback. Queued data always has a callback requested, so no exit path can strand output. Also: - LWS_CALLBACK_CLOSED frees the session evbuffer unconditionally: on driver-initiated closes (e.g. the mudlib destructing the interactive) close_user_websocket() nulls pss->user first, and the old early return leaked the buffer every time. - src/www/README.md + src/www/AGENTS.md: architecture doc and agent checklist for the web terminal pages (xterm.js/telnet.js layering, vendor policy, packaging, testing, the wedge mechanism). - tools/ws-smoke.js, wired into CI on the Clang Debug matrix entries (with and without sanitizers): a dependency-free node websocket client that boots the real driver and exercises the http mount, telnet + ascii subprotocols through the shared src/www/telnet.js, SGA char-mode switching, live TUI streaming, TLS, and -- the actual regression gate -- forced-backpressure bursts (paused socket, ~4.8MB) on the plain and TLS ports plus a destruct-while-choked teardown check. All three backpressure checks fail on the unfixed driver; neither GTest nor the LPC suite exercises any websocket client traffic. - Fix stale src/www/wasm/vendor/ path references left from the vendor directory move (src/wasm/README.md, docs/build-wasm.md, release.yml). Validated on the ASan Debug build: forced-backpressure repros recover the full burst on both subprotocols, destruct-while-choked clean under ASan, ws-smoke 17/17, GTest 312/312, LPC testsuite clean.
215 lines
8.2 KiB
YAML
215 lines
8.2 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [master]
|
|
paths-ignore: ['docs/**']
|
|
pull_request:
|
|
branches: [master]
|
|
paths-ignore: ['docs/**']
|
|
|
|
env:
|
|
CTEST_OUTPUT_ON_FAILURE: 1
|
|
VERBOSE: 1
|
|
|
|
jobs:
|
|
build-and-test:
|
|
name: ${{ matrix.platform }} (${{ matrix.compiler || 'default' }}${{ matrix.sanitizer && '+sanitizer' || '' }}, ${{ matrix.build }})
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# Ubuntu - GCC (also builds the optional dwlib package so it can't
|
|
# silently bit-rot again)
|
|
- platform: Ubuntu
|
|
os: ubuntu-24.04
|
|
compiler: gcc
|
|
cc: gcc
|
|
cxx: g++
|
|
build: Debug
|
|
cmake_flags: -DPACKAGE_DWLIB=ON
|
|
packages: build-essential autoconf automake bison flex expect libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtool libz-dev telnet libgtest-dev libjemalloc-dev pkg-config libffi-dev
|
|
- platform: Ubuntu
|
|
os: ubuntu-24.04
|
|
compiler: gcc
|
|
cc: gcc
|
|
cxx: g++
|
|
build: RelWithDebInfo
|
|
cmake_flags: -DPACKAGE_DWLIB=ON
|
|
packages: build-essential autoconf automake bison flex expect libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtool libz-dev telnet libgtest-dev libjemalloc-dev pkg-config libffi-dev
|
|
|
|
# Ubuntu - Clang
|
|
- platform: Ubuntu
|
|
os: ubuntu-24.04
|
|
compiler: clang
|
|
cc: clang
|
|
cxx: clang++
|
|
build: Debug
|
|
packages: build-essential autoconf automake bison flex expect libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtool libz-dev telnet libgtest-dev libjemalloc-dev pkg-config libffi-dev
|
|
- platform: Ubuntu
|
|
os: ubuntu-24.04
|
|
compiler: clang
|
|
cc: clang
|
|
cxx: clang++
|
|
build: RelWithDebInfo
|
|
packages: build-essential autoconf automake bison flex expect libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtool libz-dev telnet libgtest-dev libjemalloc-dev pkg-config libffi-dev
|
|
|
|
# Ubuntu - Clang with Sanitizer
|
|
- platform: Ubuntu
|
|
os: ubuntu-24.04
|
|
compiler: clang
|
|
cc: clang
|
|
cxx: clang++
|
|
build: Debug
|
|
sanitizer: true
|
|
cmake_flags: -DENABLE_SANITIZER=ON
|
|
packages: build-essential autoconf automake bison flex expect libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtool libz-dev telnet libgtest-dev libjemalloc-dev pkg-config libdw-dev libbz2-dev libffi-dev
|
|
- platform: Ubuntu
|
|
os: ubuntu-24.04
|
|
compiler: clang
|
|
cc: clang
|
|
cxx: clang++
|
|
build: RelWithDebInfo
|
|
sanitizer: true
|
|
cmake_flags: -DENABLE_SANITIZER=ON
|
|
packages: build-essential autoconf automake bison flex expect libmysqlclient-dev libpcre3-dev libpq-dev libsqlite3-dev libssl-dev libtool libz-dev telnet libgtest-dev libjemalloc-dev pkg-config libdw-dev libbz2-dev libffi-dev
|
|
|
|
# macOS
|
|
- platform: macOS
|
|
os: macos-14
|
|
build: Debug
|
|
packages: cmake pkg-config pcre libgcrypt openssl jemalloc icu4c mysql sqlite3 googletest flex bison libffi
|
|
openssl_root: /usr/local/opt/openssl
|
|
icu_root: /opt/homebrew/opt/icu4c
|
|
- platform: macOS
|
|
os: macos-14
|
|
build: RelWithDebInfo
|
|
packages: cmake pkg-config pcre libgcrypt openssl jemalloc icu4c mysql sqlite3 googletest flex bison libffi
|
|
openssl_root: /usr/local/opt/openssl
|
|
icu_root: /opt/homebrew/opt/icu4c
|
|
|
|
# Windows (MSYS2), the static Alpine build, and WASM are separate jobs
|
|
# below -- each wraps a composite action in .github/actions/ that the
|
|
# release workflow reuses, so a release-only build can't silently break.
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install Dependencies (Ubuntu)
|
|
if: matrix.platform == 'Ubuntu'
|
|
run: |
|
|
sudo apt update
|
|
sudo apt install -y ${{ matrix.packages }}
|
|
|
|
- name: Install Dependencies (macOS)
|
|
if: matrix.platform == 'macOS'
|
|
env:
|
|
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
|
run: |
|
|
brew install ${{ matrix.packages }}
|
|
# Homebrew flex/bison are keg-only (they'd shadow the too-old
|
|
# system copies); put their bin dirs on PATH so CMake's
|
|
# find_package(FLEX 2.6)/(BISON 3.8) picks them up and the
|
|
# scanner/parser are regenerated from lex.l/grammar.y instead of
|
|
# falling back to the checked-in pre-generated sources.
|
|
echo "$(brew --prefix flex)/bin" >> "$GITHUB_PATH"
|
|
echo "$(brew --prefix bison)/bin" >> "$GITHUB_PATH"
|
|
# bison also needs its lib dir for -ly at link time on some setups.
|
|
echo "LDFLAGS=-L$(brew --prefix bison)/lib" >> "$GITHUB_ENV"
|
|
# libffi is keg-only on macOS; expose its pkg-config so
|
|
# pkg_check_modules(libffi) in package_ffi resolves it.
|
|
echo "PKG_CONFIG_PATH=$(brew --prefix libffi)/lib/pkgconfig:$PKG_CONFIG_PATH" >> "$GITHUB_ENV"
|
|
|
|
- name: Configure
|
|
run: |
|
|
mkdir build && cd build
|
|
cmake -DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
|
${{ matrix.cmake_flags }} \
|
|
-DPACKAGE_DB_SQLITE=2 \
|
|
..
|
|
env:
|
|
CC: ${{ matrix.cc }}
|
|
CXX: ${{ matrix.cxx }}
|
|
OPENSSL_ROOT_DIR: ${{ matrix.openssl_root }}
|
|
ICU_ROOT: ${{ matrix.icu_root }}
|
|
|
|
- name: Build
|
|
run: cd build && make -j 2 install
|
|
env:
|
|
OPENSSL_ROOT_DIR: ${{ matrix.openssl_root }}
|
|
ICU_ROOT: ${{ matrix.icu_root }}
|
|
|
|
- name: Run Unit Tests
|
|
run: cd build && ctest --output-on-failure -LE testsuite
|
|
|
|
- name: Run LPC Testsuite
|
|
run: cd build && ctest --output-on-failure -L testsuite
|
|
|
|
# Only on Clang Debug (with and without the sanitizer) -- it's the
|
|
# only test that drives real websocket client traffic against the
|
|
# native driver (see src/www/AGENTS.md); the sanitizer variant also
|
|
# catches memory-safety bugs in the ws_telnet.cc/ws_ascii.cc nudge
|
|
# timer that ctest's unit/LPC suites can't reach.
|
|
- name: Websocket smoke test
|
|
if: matrix.platform == 'Ubuntu' && matrix.compiler == 'clang' && matrix.build == 'Debug'
|
|
run: node tools/ws-smoke.js build/src/driver testsuite
|
|
|
|
# Windows (MSYS2/MinGW64). Uses the same build-windows composite as the
|
|
# release workflow, so the release build can't break in a way CI misses.
|
|
windows:
|
|
name: Windows (${{ matrix.build }})
|
|
runs-on: windows-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
build: [Debug, RelWithDebInfo]
|
|
defaults:
|
|
run:
|
|
shell: msys2 {0}
|
|
steps:
|
|
- name: Setup MSYS2
|
|
uses: msys2/setup-msys2@v2
|
|
with:
|
|
update: true
|
|
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Build & test
|
|
uses: ./.github/actions/build-windows
|
|
with:
|
|
build-type: ${{ matrix.build }}
|
|
db-sqlite: '2'
|
|
# flex regenerates the lexer from lexer.l instead of using the
|
|
# checked-in pre-generated source.
|
|
extra-packages: flex
|
|
|
|
# Statically-linked Alpine build. Uses the same build-alpine-static
|
|
# composite the release workflow ships as
|
|
# fluffos-<version>-linux-x86_64-static.tar.gz, so a missing/renamed Alpine
|
|
# package is caught on every PR instead of at release time.
|
|
alpine-static:
|
|
name: Alpine (static)
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Build & test
|
|
uses: ./.github/actions/build-alpine-static
|
|
|
|
# WebAssembly build: cross-compile the driver with Emscripten and run the
|
|
# full LPC testsuite inside the wasm driver under node, via the same
|
|
# build-wasm composite the release workflow uses. See docs/build-wasm.md
|
|
# for the workflow and src/wasm/README.md for the architecture.
|
|
wasm:
|
|
name: WASM (Emscripten)
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Build & test
|
|
uses: ./.github/actions/build-wasm
|