Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions apps/wolfssh/wolfssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,14 +332,20 @@ static int FlushQueuedSend(WOLFSSH* ssh, wolfSSL_Mutex* lock)
if (lock != NULL) {
wc_UnLockMutex(lock);
}
} while (ret == WS_WANT_WRITE && WTIME(NULL) < deadline);

/* The queue is out. Whatever the worker made of the peer's end of the
* conversation is for the reader to sort out. A rekey started on the way
* through is the reader's as well, the send itself went out. */
if (ret == WS_WANT_READ || ret == WS_CHAN_RXD || ret == WS_EXTDATA
|| ret == WS_REKEYING || ret == WS_EOF) {
ret = WS_SUCCESS;

/* None of these is a failure for the flush. */
if (ret == WS_WANT_READ || ret == WS_CHAN_RXD || ret == WS_EXTDATA
|| ret == WS_REKEYING || ret == WS_EOF
|| ret == WS_WANT_WRITE) {
ret = WS_SUCCESS;
}
} while (ret == WS_SUCCESS
&& wolfSSH_get_error(ssh) == WS_WANT_WRITE
&& WTIME(NULL) < deadline);

/* The deadline can run out with the packet still queued. */
if (ret == WS_SUCCESS && wolfSSH_get_error(ssh) == WS_WANT_WRITE) {
ret = WS_WANT_WRITE;
}

return ret;
Expand Down
23 changes: 21 additions & 2 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2056,14 +2056,29 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
/* read in case a window-change packet might be queued */
{
int rc;
int selected = WS_SELECT_SEND_READY;
WS_SOCKET_T fd = wolfSSH_get_fd(ssh);
word32 lastChannel = 0;

do {
rc = wolfSSH_worker(ssh, &lastChannel);
if (rc < 0) {
rc = wolfSSH_get_error(ssh);
}
} while (rc == WS_WANT_WRITE);
if (rc == WS_WANT_WRITE) {
selected = tcp_select_write(fd, 1);
}
} while (rc == WS_WANT_WRITE
&& selected == WS_SELECT_SEND_READY);

/* A dead socket ends the session */
if (ret == WS_SUCCESS
&& (selected == WS_SELECT_ERROR_READY
|| selected == WS_SELECT_FAIL
|| rc == WS_SOCKET_ERROR_E
|| rc == WS_DISCONNECT)) {
ret = WS_FATAL_ERROR;
}
}
}
}
Expand Down Expand Up @@ -2263,6 +2278,10 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
cnt_r = wolfSSH_worker(ssh, &lastChannel);
if (cnt_r < 0) {
rc = wolfSSH_get_error(ssh);
if (cnt_r == WS_CHAN_RXD || cnt_r == WS_CHANNEL_CLOSED
|| cnt_r == WS_EOF) {
rc = cnt_r;
}
if (rc == WS_CHAN_RXD) {
if (lastChannel == shellChannelId) {
cnt_r = wolfSSH_ChannelIdRead(ssh,
Expand Down Expand Up @@ -2296,7 +2315,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
* peer. Both want fixing where they can be tested. */
continue;
}
else if (rc != WS_WANT_READ) {
else if (rc != WS_WANT_READ && rc != WS_WANT_WRITE) {
Comment thread
yosuke-wolfssl marked this conversation as resolved.
Comment thread
yosuke-wolfssl marked this conversation as resolved.
Comment thread
yosuke-wolfssl marked this conversation as resolved.
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
* is still owed, so the drain below is exactly what is wanted. */
if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E
&& wolfSSH_get_error(ssh) != WS_CHANNEL_CLOSED) {
if (ret != WS_SUCCESS) {
if (ret != WS_SUCCESS && ret != WS_WANT_WRITE) {
Comment thread
yosuke-wolfssl marked this conversation as resolved.
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
Expand Down
23 changes: 13 additions & 10 deletions examples/echoserver/echoserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1035,17 +1035,16 @@ static int ssh_worker(thread_ctx_t* threadCtx)
channel. The additional channel is only used with the
agent. */
cnt_r = wolfSSH_worker(ssh, &lastChannel);
/* Take the worker's status before the drain below: its
* reads and sends latch their own into ssh->error. */
rc = wolfSSH_get_error(ssh);
if (cnt_r == WS_CHAN_RXD || cnt_r == WS_REKEYING
|| cnt_r == WS_CHANNEL_CLOSED || cnt_r == WS_EOF) {
rc = cnt_r;
}

/* The peer is done sending: hand back the backlog and answer
* its EOF, or a client that half-closed waits on a server
* that never finishes -- the library no longer answers for
* us. Off the channel's own state, not the WS_EOF status: the
* flush inside wolfSSH_worker() can supersede that, and it is
* raised once. Echo mode only; a shell child on a pty is
* still producing, so its EOF waits for the child to exit. */
* its EOF, since the library no longer answers for us. Off
* the channel's own state, not the once-only WS_EOF status.
* Echo mode only; a shell child on a pty still produces. */
if (!eofAnswered && echoOnly) {
WOLFSSH_CHANNEL* eofChannel;

Expand Down Expand Up @@ -1243,7 +1242,7 @@ static int ssh_worker(thread_ctx_t* threadCtx)
* above, which has already run this pass. */
continue;
}
else if (rc != WS_WANT_READ) {
else if (rc != WS_WANT_READ && rc != WS_WANT_WRITE) {
Comment thread
yosuke-wolfssl marked this conversation as resolved.
Comment thread
yosuke-wolfssl marked this conversation as resolved.
Comment thread
yosuke-wolfssl marked this conversation as resolved.
#ifdef SHELL_DEBUG
printf("Break:read sshFd returns %d: errno =%x\n",
cnt_r, errno);
Expand Down Expand Up @@ -1533,8 +1532,12 @@ static int sftp_worker(thread_ctx_t* threadCtx)
ret = error = wolfSSH_get_error(ssh);

/* there is an edge case where the last SFTP handshake message sent got a
* WANT_WRITE case, keep trying to send it here. */
* WANT_WRITE case, keep trying to send it here. Waits for the socket to
* take bytes again rather than retrying into a full one. */
while (error == WS_WANT_WRITE) {
selected = tcp_select_write(s, TEST_SFTP_TIMEOUT);
if (selected != WS_SELECT_SEND_READY)
Comment thread
yosuke-wolfssl marked this conversation as resolved.
break;
ret = wolfSSH_worker(ssh, NULL);
error = wolfSSH_get_error(ssh);
}
Expand Down
11 changes: 6 additions & 5 deletions examples/portfwd/portfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,10 +832,9 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args)

/* Relay the half-close so a local reader waiting on end-of-input
* returns; nothing else relays it. Driven off the latched channel
* state, not the WS_EOF status: the flush inside wolfSSH_worker()
* can supersede that, and it is raised only once. Only the channel
* appFd is wired to, since half-closing the wrong socket truncates
* a live transfer. */
* state, not the once-only WS_EOF status. Only the channel appFd
* is wired to: half-closing the wrong socket truncates a live
* transfer. */
if (appFdSet && fwdChannel != NULL && !appFdHalfClosed
&& wolfSSH_ChannelGetEof(fwdChannel)) {
int drained;
Expand Down Expand Up @@ -935,7 +934,9 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args)
}

ret = wolfSSH_shutdown(ssh);
if (ret != WS_SUCCESS)
/* The socket closes next, so a queued write and a retired channel are
* both done as far as this teardown is concerned. */
if (ret != WS_SUCCESS && ret != WS_WANT_WRITE && ret != WS_CHANNEL_CLOSED)
err_sys("Closing port forward stream failed.");

WCLOSESOCKET(sshFd);
Expand Down
4 changes: 2 additions & 2 deletions examples/scpclient/scpclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args)
if (ret != WS_CHANNEL_CLOSED && ret != WS_SOCKET_ERROR_E &&
wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E &&
wolfSSH_get_error(ssh) != WS_CHANNEL_CLOSED) {
if (ret != WS_SUCCESS) {
if (ret != WS_SUCCESS && ret != WS_WANT_WRITE) {
WLOG(WS_LOG_DEBUG, "Sending the shutdown messages failed.");
}
else {
Expand Down Expand Up @@ -351,7 +351,7 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args)
#endif

if ((ret != WS_SUCCESS) && (ret != WS_CHANNEL_CLOSED)
&& (ret != WS_EOF))
&& (ret != WS_EOF) && (ret != WS_WANT_WRITE))
Comment thread
yosuke-wolfssl marked this conversation as resolved.
((func_args*)args)->return_code = 1;
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -995,17 +995,16 @@ static int ssh_worker(thread_ctx_t* threadCtx)
channel. The additional channel is only used with the
agent. */
cnt_r = wolfSSH_worker(ssh, &lastChannel);
/* Take the worker's status before the drain below: its
* reads and sends latch their own into ssh->error. */
rc = wolfSSH_get_error(ssh);
if (cnt_r == WS_CHAN_RXD || cnt_r == WS_REKEYING
|| cnt_r == WS_CHANNEL_CLOSED || cnt_r == WS_EOF) {
rc = cnt_r;
}

/* The peer is done sending: hand back the backlog and answer
* its EOF, or a client that half-closed waits on a server
* that never finishes -- the library no longer answers for
* us. Off the channel's own state, not the WS_EOF status: the
* flush inside wolfSSH_worker() can supersede that, and it is
* raised once. Echo mode only; a shell child on a pty is
* still producing, so its EOF waits for the child to exit. */
* its EOF, since the library no longer answers for us. Off
* the channel's own state, not the once-only WS_EOF status.
* Echo mode only; a shell child on a pty still produces. */
if (!eofAnswered && echoOnly) {
WOLFSSH_CHANNEL* eofChannel;

Expand Down Expand Up @@ -1170,7 +1169,7 @@ static int ssh_worker(thread_ctx_t* threadCtx)
* above, which has already run this pass. */
continue;
}
else if (rc != WS_WANT_READ) {
else if (rc != WS_WANT_READ && rc != WS_WANT_WRITE) {
Comment thread
yosuke-wolfssl marked this conversation as resolved.
#ifdef SHELL_DEBUG
printf("Break:read sshFd returns %d: errno =%x\n",
cnt_r, errno);
Expand Down
12 changes: 11 additions & 1 deletion src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -5474,6 +5474,7 @@ static int SendPacketFlush(WOLFSSH* ssh)

if (ssh->ctx->ioSendCb == NULL) {
WLOG(WS_LOG_DEBUG, "Your IO Send callback is null, please set");
ssh->error = WS_SOCKET_ERROR_E;
return WS_SOCKET_ERROR_E;
}

Expand All @@ -5484,6 +5485,7 @@ static int SendPacketFlush(WOLFSSH* ssh)
if (ssh->outputBuffer.length > ssh->outputBuffer.bufferSz ||
ssh->outputBuffer.length < ssh->outputBuffer.idx) {
WLOG(WS_LOG_ERROR, "Bad buffer state");
ssh->error = WS_BUFFER_E;
return WS_BUFFER_E;
}

Expand Down Expand Up @@ -5522,11 +5524,13 @@ static int SendPacketFlush(WOLFSSH* ssh)
ssh->outputBuffer.plainSz = 0;
ShrinkBuffer(&ssh->outputBuffer, 1);
}
ssh->error = WS_SOCKET_ERROR_E;
return WS_SOCKET_ERROR_E;
}

if ((word32)sent > ssh->outputBuffer.length) {
WLOG(WS_LOG_DEBUG, "wolfSSH_SendPacket() out of bounds read");
ssh->error = WS_SEND_OOB_READ_E;
return WS_SEND_OOB_READ_E;
}

Expand All @@ -5551,7 +5555,9 @@ static int SendPacketFlush(WOLFSSH* ssh)
}


/* returns WS_SUCCESS on success */
/* returns WS_SUCCESS on success. Transport failures record their code in
* ssh->error, so a later write to that field on the same pass has to be
* conditional on this having succeeded, or it hides the dead transport. */
int wolfSSH_SendPacket(WOLFSSH* ssh)
{
int ret;
Expand Down Expand Up @@ -14805,6 +14811,10 @@ static int BundlePacket(WOLFSSH* ssh)
}
else {
WLOG(WS_LOG_DEBUG, "BP: failed to encrypt buffer");
if (ssh != NULL) {
/* Drop the aborted packet */
ssh->outputBuffer.length = ssh->packetStartIdx;
}
}

return ret;
Expand Down
Loading
Loading