diff --git a/apps/wolfssh/wolfssh.c b/apps/wolfssh/wolfssh.c index 409903e27..9951acf49 100644 --- a/apps/wolfssh/wolfssh.c +++ b/apps/wolfssh/wolfssh.c @@ -523,6 +523,7 @@ static THREAD_RET readInput(void* in) int ret = 0; int err = 0; int queued = 0; + int resend = 0; word32 sz = 0; #ifdef USE_WINDOWS_API HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE); @@ -549,16 +550,24 @@ static THREAD_RET readInput(void* in) ret = wolfSSH_stream_send(args->ssh, buf, sz); err = (ret == WS_FATAL_ERROR) ? wolfSSH_get_error(args->ssh) : ret; - /* A send the socket wasn't ready for still counts the data as - * taken, it is left queued in the session instead. */ + /* Data taken with a positive return can still be queued in the + * session, waiting on the socket. */ queued = (wolfSSH_get_error(args->ssh) == WS_WANT_WRITE); wc_UnLockMutex(&args->lock); + resend = 0; if (err == WS_REKEYING) { /* give readPeer() the lock to finish the rekey, then * send this buffer again */ PauseForSocket(); + resend = 1; } - } while (err == WS_REKEYING); + else if (ret <= 0 && err == WS_WANT_WRITE) { + /* None of buf was taken. Push out what is queued, then send + * buf again. */ + resend = (FlushQueuedSend(args->ssh, &args->lock) + == WS_SUCCESS); + } + } while (resend); if (ret <= 0) { fprintf(stderr, "Couldn't send data\n"); break; diff --git a/examples/client/client.c b/examples/client/client.c index 869ae54aa..951566795 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -346,6 +346,9 @@ static int windowMonitor(thread_args* args) #endif /* WOLFSSH_TERM */ +/* Seconds to keep resending stdin the socket was not ready to take. */ +#define SEND_RETRY_TIMEOUT 10 + static THREAD_RET readInput(void* in) { byte buf[256]; @@ -354,6 +357,7 @@ static THREAD_RET readInput(void* in) int ret = 0; int err = 0; word32 sz = 0; + time_t deadline = 0; #ifdef USE_WINDOWS_API HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE); #endif @@ -373,6 +377,7 @@ static THREAD_RET readInput(void* in) fprintf(stderr, "Error reading stdin\n"); break; } + deadline = 0; do { /* lock SSH structure access */ wc_LockMutex(&args->lock); @@ -380,16 +385,24 @@ static THREAD_RET readInput(void* in) err = (ret == WS_FATAL_ERROR) ? wolfSSH_get_error(args->ssh) : ret; wc_UnLockMutex(&args->lock); + /* A rekey restarts the wait on the socket. */ if (err == WS_REKEYING) { - /* give readPeer() the lock to finish the rekey, then - * send this buffer again */ + deadline = 0; + } + else if (err == WS_WANT_WRITE && deadline == 0) { + deadline = WTIME(NULL) + SEND_RETRY_TIMEOUT; + } + if (err == WS_REKEYING || err == WS_WANT_WRITE) { + /* give readPeer() the lock to finish the rekey, or let the + * socket drain, then send this buffer again */ #ifdef USE_WINDOWS_API Sleep(1); #else usleep(1000); #endif } - } while (err == WS_REKEYING); + } while (err == WS_REKEYING || + (err == WS_WANT_WRITE && WTIME(NULL) < deadline)); if (ret <= 0) { fprintf(stderr, "Couldn't send data\n"); break;