Skip to content

wolfssh client app: -E logging, CI coverage, two build/exit fixes - #1168

Open
ejohnstown wants to merge 6 commits into
wolfSSL:masterfrom
ejohnstown:client-app-fixes
Open

wolfssh client app: -E logging, CI coverage, two build/exit fixes#1168
ejohnstown wants to merge 6 commits into
wolfSSL:masterfrom
ejohnstown:client-app-fixes

Conversation

@ejohnstown

Copy link
Copy Markdown
Contributor

Wire up the client's -E log file option

  • -E was parsed and printed by -G, never read. Installs a callback that writes the log to the file in DefaultLoggingCb's format.
  • Turns logging on, and closes the stream after cleanup; the callback cannot be uninstalled.

Build and test the client app in CI

  • Adds scripts/sshclient.test (sessions and -E against the echoserver) to make check. Exits 77 where the app is not built.
  • Adds --enable-sshclient to 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_WRITE from 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-all enables the client, so both singlethread-check cells failed to compile. configure now errors on explicit --enable-sshclient and drops the client when it is implied.
  • Keeps an #error for user_settings.h builds that skip configure.

- -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.
@ejohnstown
ejohnstown requested review from JacobBarthelmeh and wolfSSL-Fenrir-bot and a lite review from CopilotAugust 13, 2026 20:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 -E by installing a logging callback that appends to a file and enables logging.
  • Add a new scripts/sshclient.test and include it in distribution scripts for make check coverage.
  • Improve configure/CI behavior around --enable-sshclient with 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
FileDescription
scripts/sshclient.testAdds an end-to-end client test (remote command, terminal session, -E logging) against echoserver.
scripts/include.amShips the new client test script in the dist script list.
configure.acRejects explicit --enable-sshclient with single-threaded wolfSSL; drops implied sshclient under --enable-all.
apps/wolfssh/wolfssh.cImplements -E logging callback/file lifecycle, makes config parsing happen before init, and adjusts shutdown drain return handling.
apps/wolfssh/README.mdDocuments threading requirement and clarifies -E behavior.
.github/workflows/sshd-test.ymlRenames workflow job to reflect it now covers multiple apps.
.github/workflows/multi-compiler.ymlEnables 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.

Comment on lines +94 to +101
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
Comment on lines +138 to +141
#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.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@ejohnstown