The non-blocking app-driven case runs under WOLFSSH_TEST_BLOCK again,
reverting ba899603. It deadlocks there until ssh_worker() waits on the
write side for a send wolfSSH_worker() reported through ssh->error, so
this wants PR 1251 landed with the wantWrite arm kept.
- ssh_worker() in both echoservers maps a WS_FATAL_ERROR return from
wolfSSH_worker() to WS_WANT_READ or WS_WANT_WRITE at the call site,
off a new local err, and keeps the result in rc.
- The terminal arm tests rc in place of re-reading wolfSSH_get_error():
rc != WS_WANT_READ in examples/echoserver, and rc != WS_WANT_READ &&
rc != WS_WANT_WRITE in the Espressif copy, whose empty WS_WANT_WRITE
arm is removed.
- ssh_worker() in examples/echoserver sets wantWrite from
wolfSSH_OutputPending() before it builds writeFds.
- The comment above rc = cnt_r in both echoservers names cnt_r and
ssh->error as the values that are reused.
- scripts/sshclient.test and scripts/fwd-bulk.test name the client's
missing non-blocking mode in the skip message where they echoed the
macro name, and the comments above both skips are removed.
The sftp, scp and get-put scripts wait for the echoserver to publish its
port before connecting. Two seconds is not enough for a libtool re-exec,
the dynamic linker and the sample-key parse with a dozen sibling test
jobs on the machine, so a parallel make check failed them at their first
scenario. Ten seconds matches what sshclient.test already allows.
- raise the three wait loops from 20 to 100 iterations of 0.1 seconds
- test -s, not -e, after the loop in scp.test and get-put.test: the
ready file is created empty and the port written afterward, so -e can
take a file caught mid-write and yield an empty port
The non-blocking app-driven case runs in every other build. Under forced
blocking the two ends deadlock -- the server sits in DoReceive with
output it owes still queued, the client waits for that output -- which
is a defect of its own to fix rather than this case failing.
- blockBuild names the macro being set, which nonblockingOnly already
stood for on a different question
The -A cases in scp.test reach the exec callback and the scp handoff.
These drive the rest: the subsystem callback with the sftp accept, the
shell callback in echo mode, and both accepts on a blocking server.
- sftp.test connects to an -A server blocking and non-blocking
- sshclient.test runs a terminal session and a command session against
an -A server
- scp.test copies from a blocking -A server, where wolfSSH_SCP_accept()
completes in one call rather than through the retry loop
The echoserver's -A mode runs an accepted scp command through
wolfSSH_SCP_accept(). Reaching that call's want retry path takes a
non-blocking server, which -N supplies.
- copy to and from an app-driven server in scp.test
- check the entry point's null-session argument
scripts/fwd.test sends eight short lines, so nothing in the suite drives
a forwarding channel past its first window, and a forward that stalled
once the window needed crediting would go unnoticed.
- push a payload several windows long through a local direct-tcpip
forward and compare the bytes that arrive
- end a second transfer one window plus a short tail in, where the tail
is what portfwd still holds at end-of-input, and repeat it since the
window credit beating that tail is a race
- give the listening nc its stdin from a fifo a sleep holds open:
reading end-of-input makes nc close the connection, which truncates
the transfer and looks exactly like a stall
- bail out early once the byte count stops moving, so a real stall
reports in seconds
- dump the logs on failure, check the listening nc came up, and take
ports clear of the ones fwd.test.expect hardcodes, so a squatted or
shared port is not reported as a stall
external.test connected the client and SFTP client to a host named by
WOLFSSH_EXTERNAL_HOST. It only ran when WOLFSSH_EXTERNAL_TEST was set,
which nothing in the tree or in CI does, so it always exited 77.
- delete scripts/external.test
- drop it from scripts/include.am
The ready-file counter is shared by every create_port call and was never
reset, so the twenty iterations are a budget for the whole run rather
than per server start. A slow first start leaves later ones with no wait
at all, and the test fails with "NO ready file" instead of waiting. The
guard after the loop then disagreed with the loop as well: the wait is
for a non-empty file, but the guard only asked whether the file existed,
so a wait that ran out still went on to read an empty port.
- reset the counter in create_port, so each server start gets the full
wait and a new call site cannot forget it
- test the guard on -s, matching what the loop waited for
- drop "echo -e", undefined for POSIX sh and printed literally by shells
that do not take the flag; the escapes were only ever blank lines
- quote the expansions, use $(...) instead of backticks, and grep -q
- exit 1 rather than exit -1 from the trap handler
- drop the redundant PWD assignment before the set-directory test, and
the second copy of the wolfsftp executable check
Leaves shellcheck -s sh clean apart from SC2329 on the trap handler.
The wolfSSL dependency version came solely from
WOLFSSL_DIR/wolfssl/version.h. That header is generated by configure as
well as tracked, so `make distclean` in the wolfSSL tree removes it. With
it gone the --dep-version override was never passed and gen-sbom fell
back to `pkg-config --modversion wolfssl`, which reports the *installed*
wolfSSL. On a host whose installed build differs from WOLFSSL_DIR the
SBOM recorded that unrelated version (9.9.9 in the report) and still
exited 0, attesting a component wolfSSH was not built against.
Fall back to AC_INIT in WOLFSSL_DIR/configure.ac, which survives
distclean, and fail when neither source is readable rather than letting
an installed copy answer for the tree. SBOM_WOLFSSL_VERSION still
overrides both.
wolfSSL/wolfssl#10343 merged on 2026-07-27, but the SBOM workflow still
checked out wolfssl at refs/pull/10343/head. GitHub keeps PR refs alive
after merge, so CI stayed green while validating a pre-merge snapshot
rather than master. Point wolfssl_ref and its fallback at master.
Distinguish the two gen-sbom lookup failures. A set-but-wrong
WOLFSSL_DIR previously printed the "re-run with WOLFSSL_DIR=..." advice
to someone who had already set it; it now names the path that was
probed and states that WOLFSSL_DIR is a source tree, not an install
prefix.
Refresh the README and in-recipe notes that still told users to track
the #10343 branch until it merged.
Sync scripts/sbom.am with the unified canonical copy in wolfSSL
(scripts/sbom.am), which adds the SBOM_OPTIONS_H override so one
fragment supports both options.h- and config.h/AM_CFLAGS-based macro
capture. wolfssh uses the default config.h path and does not set
SBOM_OPTIONS_H, so behavior is unchanged. Keeps the vendored fragment
byte-identical to the canonical.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Re-sync scripts/sbom.am with the canonical wolfSSL copy ($(docdir)
sbomdir, [[:space:]] version parse, GNU-make and uninstall-sbom docs)
and widen the SBOM workflow pull_request filter to '**'.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Sync the vendored fragment with the canonical wolfSSL copy: add
$(AM_CFLAGS) $(CFLAGS) to the -dM -E build-options capture and make the
config header path overridable via SBOM_CONFIG_H (default config.h) so
the SBOM records the configured feature macros.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Guard the SBOM_GEN wolfSSL fallback with $(if $(WOLFSSL_DIR),...) so an
unset WOLFSSL_DIR leaves it empty (yielding the intended "set WOLFSSL_DIR"
error) instead of resolving to an absolute /scripts/gen-sbom that could run
an unrelated host script. Reword the fragment header to describe the actual
gen-sbom resolution (vendored copy if present, else WOLFSSL_DIR) rather than
claiming offline tarball builds that aren't wired up yet. Condition the
README's wolfSSL-dependency statement on a sufficiently new gen-sbom to
match the existing degradation note.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
Move the make sbom / install-sbom / uninstall-sbom recipe out of
Makefile.am into a reusable scripts/sbom.am fragment; Makefile.am now
just declares the product facts (name, LICENSING, wolfssl dependency,
GPL-3.0-only default) and includes it.
Add a GitHub Actions workflow covering both SBOM paths:
- autotools: build wolfSSL + wolfSSH, run make sbom, assert SPDX
validity, CycloneDX identity, reproducibility, and the wolfssl
dependency edge.
- embedded: run gen-sbom against user_settings.h (via pcpp) + the
wolfSSH source set, asserting the same identity/validity/reproducibility
plus that user_settings.h options and the wolfssl dependency are
captured.
Both gracefully skip on a gen-sbom that predates the wolfSSL SBOM
change.
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
The paths are built from pwd, so an unquoted use split on a build
directory with a space in it, and the cleanup's rm -rf then deleted
whatever the first word named.
- Quote work_dir and every path derived from it
- Pass the directory to rm after --
- Replace the two echo -e calls, dash prints a literal -e
The echoserver needs -N under WOLFSSH_TEST_BLOCK, and even with it leaves
a failed write queued while it waits on the peer, so a session stalls.
scp.test and get-put.test skip the build too.
- --enable-sshclient defaults to no, so the app was built only by the
configs that use --enable-all, and never under the multi-compiler
warning flags. Add it to the multi-compiler matrix.
- Add scripts/sshclient.test, run by make check. It covers the client's
sessions and the -E log file against the echoserver.
- The script is not gated on BUILD_SSHCLIENT. It exits 77 when the
client app or the echoserver isn't there, so every build runs it and
the ones without the app report it as a skip.
- Check the client and the echoserver by asking each for its usage
message, not by looking for the file. Both are libtool wrapper
scripts in the build tree, and a wrapper outlives a reconfigure that
drops the program it wraps, then runs only far enough to say so.
- The echoserver runs in echo mode and the client's stdin comes from a
fifo written a piece at a time, so the session carries data and ends
on its own. Each client run has a watchdog.
- Rename sshd-test.yml's job to cover both apps. That workflow builds
the client app along with wolfsshd.
- Check that the command reaches the server, now that the client sends
it rather than discarding it.
- Make the SINGLE_THREADED guard a preprocessor #error. The runtime
err_sys() only caught the misconfiguration in an autotools build that
got as far as running; the #error catches it at compile time for the
IDE and plain Makefile builds too.
- Treat WS_WANT_READ and WS_WANT_WRITE out of wolfSSH_worker() as a
clean shutdown. The socket is non-blocking, so the peer having
nothing ready is not a session failure.
The scripts now read the build options from the probe instead of grepping
usage text, config.log and daemon logs. Drops the usage lines only tests read.
- fwd.test only exercised portfwd's local forwarding mode
- Factor the setup and line exchange into procs, run once per phase
- Add a reverse phase, and a second one using -f 0, where the peer
picks the port and only the tcpip-forward reply names it
- Each phase uses its own forwarding ports, so it skips the previous
phase's TIME_WAIT wait
- Take the SSH port from echoserver -R, which is written once its
listener is bound, so the client cannot race ahead of the listen()
- Wait for a port in the ready files rather than their existence
- Verified the reverse phase fails without the echoserver listener fix
Issue: ZD-21867
Refactor of the echoserver example only; library is unchanged.
1. Collapse FwdStates and AGENT_STATE_* into a single WS_AppState
(INIT/LISTEN/CONNECT/CONNECTED). FWD_STATE_DIRECT becomes an
isDirect flag, cleared after connect.
2. Hoist the fields shared by the forwarding, agent, and shell paths
into a common WS_AppCtx (privateData, listenFd, appFd, channelId,
state, buffer). Shell only uses buffer.
3. Feature-specific remainder stays in WS_AgentCbActionCtx (name) and
WS_FwdCbActionCtx (host/origin name+port, isDirect). Drop the unused
pid field; inline getpid() at the call site.
4. wolfSSH_AGENT_DefaultActions and wolfSSH_FwdDefaultActions now take
a WS_AppCtx* and reach feature-specific state via
appCtx->privateData. echoserver_test() is updated to register the
WS_AppCtx (not the old CbCtx) with wolfSSH_set_agent_cb_ctx and
wolfSSH_SetFwdCbCtx.
5. Reindent ssh_worker()'s #ifdef blocks and add /* WOLFSSH_xxx */
markers.
6. fwd.test.expect: redirect echoserver and portfwd output to log files
and sync on portfwd's -R ready file instead of matching "sampled" in
the pty. Under --enable-debug the WLOG volume fills the pty and
stalls portfwd in select() before channel-open.
1. Add a test script and expect script for testing forwarding.
2. Update portfwd to have a ready file option.
3. Fix echoserver error string, needed NL.
Simulate netowrk latency using netem and use it to test the non-blocking
mode of SFTP. This helps find issues which would affect running an SFTP
server on a microcontroller. It helped find the bug fixed in #876.
The autogen script is doing too many things. The tests that are set up
in the git hooks are already tested by GitHub with actions on branch
push. Also they don't work if you install wolfSSL somewhere specific.
All one needs to do is run `autoreconf -ivf` to make the configure
script. This is all autogen does now, with the addition of warnings.
1. Update scp.test to delete the empty test file.
2. In wolfSSHd, when coverting an IP address to a printable
representation, the destination needs to be able to handle IPv6
addresses potentially.
1. Added some command line options to the wolfSFTP client to show how to
use a hardcoded automatic file transfer rather than using the command
shell. On top of that, added a script to get and put some sample files.
It was built into the wolfSFTP client to allow for using all forms of
authentication as well as using the command line password.
2. Update wolfSSH_SFTP_STAT() with clearing the error register if it is WANT_READ.
1. Add enable options for "all" and "distro". all enables all options.
distro enables all and turns on both shared and static library builds.
2. Updated the commit-tests script to perform a check on enable-all as well.
3. Made a few syntactical changes to commit-tests.