Uh oh!
There was an error while loading. Please reload this page.
wolfssh client app: -E logging, CI coverage, two build/exit fixes - #1168
wolfssh client app: -E logging, CI coverage, two build/exit fixes#1168ejohnstown wants to merge 6 commits into
Conversation
- -E was parsed into config.logFile and printed by -G, never read. - Install a logging callback that writes to the named file, following what wolfsshd does for its own -E. - Turn logging on with wolfSSH_Debugging_ON(). Installing the callback is not enough on its own, the file came out empty in any build that wasn't --enable-debug, including the --enable-all builds where the library has all of its logging compiled in. wolfsshd turns logging on the same way. - Match DefaultLoggingCb()'s format, timestamp and level tag, so a log written to the file and one written to stderr are comparable. That function's GetLogStr() is private to the library, so the level names are repeated in the app. - Parse the command line and open the file in main(), before wolfSSH_Init(), so the start up messages land in the file. - Close the file after wolfSSH_Cleanup(). The callback cannot be uninstalled, so it ran with a closed stream and segfaulted on exit. It falls back to stderr. - Name the stream logFileStream, apart from struct config's logFile, which is the path it was opened from. - Drop the always true condition around the session threads.
- --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.
wolfSSH_shutdown() returns WS_WANT_WRITE when the channel EOF, exit and close messages are still queued on the non-blocking socket. Masking that to WS_SUCCESS reported a clean exit for a session whose close messages never reached the peer. Mask a want write from the drain worker only, where the close messages are already sent. The want read masking stays on both, wolfSSH_shutdown() runs a worker of its own and passes that want read back.
The client runs every session's I/O on threads, so it needs a threaded wolfSSL. configure probes for SINGLE_THREADED when the client app is enabled. Asking for the app with --enable-sshclient is an error, getting it from --enable-all drops the app instead, so --enable-all still configures against a single threaded wolfSSL. The compile time check stays for the builds that never run configure. That leaves the SINGLE_THREADED terms in the app's own guards unreachable, so drop them.
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
This PR wires up the wolfSSH client app’s -E logfile flag end-to-end, extends CI to build/test the client app, and fixes a shutdown drain behavior that could incorrectly affect exit status.
Changes:
- Implement
-Eby installing a logging callback that appends to a file and enables logging. - Add a new
scripts/sshclient.testand include it in distribution scripts formake checkcoverage. - Improve configure/CI behavior around
--enable-sshclientwith single-threaded wolfSSL and adjust multi-compiler CI to build the client.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/sshclient.test | Adds an end-to-end client test (remote command, terminal session, -E logging) against echoserver. |
| scripts/include.am | Ships the new client test script in the dist script list. |
| configure.ac | Rejects explicit --enable-sshclient with single-threaded wolfSSL; drops implied sshclient under --enable-all. |
| apps/wolfssh/wolfssh.c | Implements -E logging callback/file lifecycle, makes config parsing happen before init, and adjusts shutdown drain return handling. |
| apps/wolfssh/README.md | Documents threading requirement and clarifies -E behavior. |
| .github/workflows/sshd-test.yml | Renames workflow job to reflect it now covers multiple apps. |
| .github/workflows/multi-compiler.yml | Enables client app build in the multi-compiler workflow. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| while [ ! -s "$ready_file" ] && [ "$counter" -lt 100 ]; do | ||
| echo "waiting for ready file..." | ||
| sleep 0.1 | ||
| counter=$((counter + 1)) | ||
| done | ||
| if [ ! -s "$ready_file" ]; then | ||
| echo -e "\n\nNO ready file ending test..." |
| done | ||
| if [ ! -s "$ready_file" ]; then | ||
| echo -e "\n\nNO ready file ending test..." |
| } | ||
| fail() { | ||
| echo -e "\n\n$1" |
| count=0 | ||
| while [ "$count" -lt 300 ]; do | ||
| grep -q "$1" $client_out 2>/dev/null && return 0 | ||
| sleep 0.1 |
| kill -9 $server_pid 2>/dev/null | ||
| server_pid=$no_pid | ||
| fi | ||
| rm -rf $work_dir |
| #endif | ||
| fprintf(out, "%s[%s] %s\r\n", timeStr, ClientLogLevelStr(level), str); | ||
| /* flush so the log is complete when the client is interrupted */ | ||
| fflush(out); |
A send the socket wasn't ready for stays queued but still reports the data as taken, so the client waited on a reply to a message it never sent. Flush after a queued send, a terminal size change, and at shutdown. The shutdown drain reports its want read as WS_FATAL_ERROR, so read the status with wolfSSH_get_error(); an ordinary shutdown was exiting 1. Time out readPeer()'s select() so a flush can't strand the reader.
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.
Wire up the client's
-Elog file option-Ewas parsed and printed by-G, never read. Installs a callback that writes the log to the file inDefaultLoggingCb's format.Build and test the client app in CI
scripts/sshclient.test(sessions and-Eagainst the echoserver) tomake check. Exits 77 where the app is not built.--enable-sshclientto the multi-compiler matrix; the app never saw the warning flags.Keep a failed shutdown send out of the exit status
WS_WANT_READ/WS_WANT_WRITEfrom the shutdown drain overrode the remote command's status with exit code 1. The socket is non-blocking; nothing ready is not a failure.Don't build the client app against a single threaded wolfSSL
--enable-allenables the client, so bothsinglethread-checkcells failed to compile. configure now errors on explicit--enable-sshclientand drops the client when it is implied.#errorforuser_settings.hbuilds that skip configure.