mirror of https://github.com/wolfSSL/wolfssh.git
scp, test.h, apps, examples: wait to write and route on the return
- tcp_select_write() joins tcp_select(), with WS_SELECT_SEND_READY at the end of the enum. tcp_select() passes NULL for writefds and cannot wait on the write side. - The Windows wolfsshd window-change drain and sftp_worker()'s handshake flush retry wait on it. The drain records a give-up in ret, and sftp_worker() breaks only on WS_SELECT_ERROR_READY. - The echoserver, Espressif and both wolfsshd shell loops, and ReceiveScpMessage(), take the event from wolfSSH_worker()'s return when it carries one, in place of reading ssh->error alone. The two echoservers cover WS_CHAN_RXD, WS_REKEYING, WS_CHANNEL_CLOSED and WS_EOF; the wolfsshd loops and ReceiveScpMessage() cover the ones they have arms for. - The POSIX wolfsshd loop takes an owed write into wantWrite before the event overwrites rc, and its WS_WANT_WRITE arm runs the channel drain below in place of skipping it. - FlushQueuedSend() folds the receive's own statuses into WS_SUCCESS inside its loop and keeps flushing while wolfSSH_get_error() reports WS_WANT_WRITE within the deadline, in place of looping on the worker's return. It reports WS_WANT_WRITE when the deadline leaves the packet queued.pull/1249/head
parent
586b697b18
commit
21deb724fe
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2056,6 +2056,8 @@ 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 {
|
||||
|
|
@ -2063,7 +2065,20 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
@ -2962,6 +2981,14 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
|||
cnt_r = wolfSSH_worker(ssh, NULL);
|
||||
if (cnt_r < 0) {
|
||||
rc = wolfSSH_get_error(ssh);
|
||||
/* Take the owed write before the event overwrites rc. */
|
||||
if (rc == WS_WANT_WRITE) {
|
||||
wantWrite = 1;
|
||||
}
|
||||
if (cnt_r == WS_CHAN_RXD || cnt_r == WS_CHANNEL_CLOSED
|
||||
|| cnt_r == WS_EOF) {
|
||||
rc = cnt_r;
|
||||
}
|
||||
if (rc == WS_CHAN_RXD) {
|
||||
/* Arrival only; the drain below owns the read. */
|
||||
}
|
||||
|
|
@ -2984,8 +3011,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
|||
/* Half-close, handled below. */
|
||||
}
|
||||
else if (rc == WS_WANT_WRITE) {
|
||||
wantWrite = 1;
|
||||
continue;
|
||||
/* Recorded above; the channel drain below still runs. */
|
||||
}
|
||||
else if (rc == WS_REKEYING) {
|
||||
wantWrite = 1;
|
||||
|
|
@ -3019,6 +3045,10 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
|||
if (cnt_r <= 0)
|
||||
break;
|
||||
|
||||
/* The credit that read issued may still be queued. */
|
||||
if (wolfSSH_get_error(ssh) == WS_WANT_WRITE)
|
||||
wantWrite = 1;
|
||||
|
||||
childInIdx = 0;
|
||||
childInSz = cnt_r;
|
||||
|
||||
|
|
|
|||
|
|
@ -1035,9 +1035,11 @@ 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, since the library no longer answers for us. Off
|
||||
|
|
@ -1530,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)
|
||||
break;
|
||||
ret = wolfSSH_worker(ssh, NULL);
|
||||
error = wolfSSH_get_error(ssh);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -995,9 +995,11 @@ 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, since the library no longer answers for us. Off
|
||||
|
|
|
|||
|
|
@ -1788,6 +1788,10 @@ int ReceiveScpMessage(WOLFSSH* ssh)
|
|||
int rc;
|
||||
|
||||
rc = wolfSSH_get_error(ssh);
|
||||
if (err == WS_CHAN_RXD || err == WS_EXTDATA
|
||||
|| err == WS_CHANNEL_CLOSED) {
|
||||
rc = err;
|
||||
}
|
||||
switch (rc) {
|
||||
case WS_CHAN_RXD:
|
||||
sz = wolfSSH_ChannelIdRead(ssh, lastChannel,
|
||||
|
|
|
|||
|
|
@ -714,7 +714,8 @@ enum {
|
|||
WS_SELECT_FAIL,
|
||||
WS_SELECT_TIMEOUT,
|
||||
WS_SELECT_RECV_READY,
|
||||
WS_SELECT_ERROR_READY
|
||||
WS_SELECT_ERROR_READY,
|
||||
WS_SELECT_SEND_READY
|
||||
};
|
||||
|
||||
#if (defined(WOLFSSH_TEST_SERVER) || defined(WOLFSSH_TEST_CLIENT)) && !defined(FREESCALE_MQX)
|
||||
|
|
@ -795,6 +796,35 @@ static INLINE int tcp_select(SOCKET_T socketfd, int to_sec)
|
|||
return WS_SELECT_FAIL;
|
||||
}
|
||||
|
||||
|
||||
/* tcp_select() waits on the read side. This is the write side, for a caller
|
||||
* holding output the socket would not take. */
|
||||
static INLINE int tcp_select_write(SOCKET_T socketfd, int to_sec)
|
||||
{
|
||||
WFD_SET_TYPE sendfds, errfds;
|
||||
int nfds = (int)socketfd + 1;
|
||||
struct timeval timeout = {(to_sec > 0) ? to_sec : 0, 100};
|
||||
int result;
|
||||
|
||||
WFD_ZERO(&sendfds);
|
||||
WFD_SET(socketfd, &sendfds);
|
||||
WFD_ZERO(&errfds);
|
||||
WFD_SET(socketfd, &errfds);
|
||||
|
||||
result = wSelect(nfds, NULL, &sendfds, &errfds, &timeout);
|
||||
|
||||
if (result == 0)
|
||||
return WS_SELECT_TIMEOUT;
|
||||
else if (result > 0) {
|
||||
if (WFD_ISSET(socketfd, &sendfds))
|
||||
return WS_SELECT_SEND_READY;
|
||||
else if (WFD_ISSET(socketfd, &errfds))
|
||||
return WS_SELECT_ERROR_READY;
|
||||
}
|
||||
|
||||
return WS_SELECT_FAIL;
|
||||
}
|
||||
|
||||
#endif /* WOLFSSH_TEST_SERVER || WOLFSSH_TEST_CLIENT */
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue