apps, examples: join readInput() on Windows

The Windows path of apps/wolfssh and examples/client sets the volatile
quit with InterlockedOr8() once readPeer() returns, repeats
CancelSynchronousIo() on the readInput() thread until it has exited,
and only then closes the handles and frees the session. readInput()
checks quit around its console read and inside its send retries, and
returns quietly when it is set.

Issue: F-11662
pull/1321/head
John Safranek 2026-10-09 14:56:17 -07:00 committed by philljj
parent 00b79a4d12
commit dbcaa75f49
2 changed files with 43 additions and 11 deletions

View File

@ -268,7 +268,7 @@ typedef struct thread_args {
WOLFSSH* ssh;
wolfSSL_Mutex lock;
byte rawMode;
byte quit;
volatile byte quit; /* set by the main thread, read by the workers */
int readError;
} thread_args;
@ -538,7 +538,7 @@ static void readInputLoop(thread_args* args, byte* buf, int bufSz)
HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
#endif
while (ret >= 0) {
while (ret >= 0 && !args->quit) {
WMEMSET(buf, 0, bufSz);
#ifdef USE_WINDOWS_API
/* Using A version to avoid potential 2 byte chars */
@ -549,6 +549,11 @@ static void readInputLoop(thread_args* args, byte* buf, int bufSz)
ret = (int)read(STDIN_FILENO, buf, bufSz -1);
sz = (word32)ret;
#endif
if (args->quit) {
/* The session is over and the read was broken to end this
* thread. */
break;
}
if (ret <= 0) {
fprintf(stderr, "Error reading stdin\n");
break;
@ -590,9 +595,11 @@ static void readInputLoop(thread_args* args, byte* buf, int bufSz)
else {
break;
}
} while (off < sz);
} while (off < sz && !args->quit);
if (ret <= 0) {
fprintf(stderr, "Couldn't send data\n");
if (!args->quit) {
fprintf(stderr, "Couldn't send data\n");
}
break;
}
}
@ -1396,9 +1403,9 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
wc_InitMutex(&arg.lock);
arg.ssh = ssh;
arg.quit = 0;
arg.readError = 0;
#ifdef WOLFSSH_TERM
arg.quit = 0;
if (!wolfSSH_SEMAPHORE_Init(&windowSem, 0)) {
err_sys("Couldn't initialize window semaphore.");
}
@ -1421,9 +1428,9 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
pthread_create(&thread[1], NULL, readInput, (void*)&arg);
pthread_create(&thread[2], NULL, readPeer, (void*)&arg);
pthread_join(thread[2], NULL);
arg.quit = 1;
#ifdef WOLFSSH_TERM
/* Wake the windowMonitor thread so it can exit. */
arg.quit = 1;
signal(SIGWINCH, SIG_DFL);
wolfSSH_SEMAPHORE_Post(&windowSem);
pthread_join(thread[0], NULL);
@ -1440,6 +1447,7 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
arg.ssh = ssh;
arg.rawMode = rawMode;
arg.quit = 0;
arg.readError = 0;
wc_InitMutex(&arg.lock);
@ -1458,6 +1466,14 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
thread[0] = CreateThread(NULL, 0, readInput, (void*)&arg, 0, 0);
thread[1] = CreateThread(NULL, 0, readPeer, (void*)&arg, 0, 0);
WaitForSingleObject(thread[1], INFINITE);
/* readInput() is blocked in ReadConsoleA() and would use the session
* after it is freed. Break the read and wait for the thread to see
* quit. The cancel finds nothing while the read is not yet pending,
* so repeat it until the thread is gone. */
InterlockedOr8((volatile CHAR*)&arg.quit, 1);
do {
CancelSynchronousIo(thread[0]);
} while (WaitForSingleObject(thread[0], 100) == WAIT_TIMEOUT);
CloseHandle(thread[0]);
CloseHandle(thread[1]);
ioErr = arg.readError;

View File

@ -177,7 +177,7 @@ typedef struct thread_args {
WOLFSSH* ssh;
wolfSSL_Mutex lock;
byte rawMode;
byte quit;
volatile byte quit; /* set by the main thread, read by the workers */
} thread_args;
#ifdef _POSIX_THREADS
@ -372,7 +372,7 @@ static void readInputLoop(thread_args* args, byte* buf, int bufSz)
HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
#endif
while (ret >= 0) {
while (ret >= 0 && !args->quit) {
WMEMSET(buf, 0, bufSz);
#ifdef USE_WINDOWS_API
/* Using A version to avoid potential 2 byte chars */
@ -383,6 +383,11 @@ static void readInputLoop(thread_args* args, byte* buf, int bufSz)
ret = (int)read(STDIN_FILENO, buf, bufSz -1);
sz = (word32)ret;
#endif
if (args->quit) {
/* The session is over and the read was broken to end this
* thread. */
break;
}
if (ret <= 0) {
fprintf(stderr, "Error reading stdin\n");
break;
@ -424,10 +429,12 @@ static void readInputLoop(thread_args* args, byte* buf, int bufSz)
usleep(1000);
#endif
}
} while (off < sz &&
} while (off < sz && !args->quit &&
(err != WS_WANT_WRITE || WTIME(NULL) < deadline));
if (ret <= 0) {
fprintf(stderr, "Couldn't send data\n");
if (!args->quit) {
fprintf(stderr, "Couldn't send data\n");
}
break;
}
}
@ -1259,9 +1266,9 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
pthread_create(&thread[1], NULL, readInput, (void*)&arg);
pthread_create(&thread[2], NULL, readPeer, (void*)&arg);
pthread_join(thread[2], NULL);
arg.quit = 1;
#ifdef WOLFSSH_TERM
/* Wake the windowMonitor thread so it can exit. */
arg.quit = 1;
signal(SIGWINCH, SIG_DFL);
wolfSSH_SEMAPHORE_Post(&windowSem);
pthread_join(thread[0], NULL);
@ -1277,6 +1284,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
arg.ssh = ssh;
arg.rawMode = rawMode;
arg.quit = 0;
wc_InitMutex(&arg.lock);
if (cmd) {
@ -1293,6 +1301,14 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
thread[0] = CreateThread(NULL, 0, readInput, (void*)&arg, 0, 0);
thread[1] = CreateThread(NULL, 0, readPeer, (void*)&arg, 0, 0);
WaitForSingleObject(thread[1], INFINITE);
/* readInput() is blocked in ReadConsoleA() and would use the session
* after it is freed. Break the read and wait for the thread to see
* quit. The cancel finds nothing while the read is not yet pending,
* so repeat it until the thread is gone. */
InterlockedOr8((volatile CHAR*)&arg.quit, 1);
do {
CancelSynchronousIo(thread[0]);
} while (WaitForSingleObject(thread[0], 100) == WAIT_TIMEOUT);
CloseHandle(thread[0]);
CloseHandle(thread[1]);
#else