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
51 changes: 14 additions & 37 deletions apps/wolfssh/wolfssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1389,50 +1389,27 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args)
if (ret == WS_FATAL_ERROR) {
ret = wolfSSH_get_error(ssh);
}
if (ret != WS_SUCCESS && ret != WS_WANT_WRITE && ret != WS_WANT_READ &&
ret != WS_CHANNEL_CLOSED && ret != WS_EOF &&
ret != WS_SOCKET_ERROR_E && ret != WS_DISCONNECT) {
WLOG(WS_LOG_DEBUG, "Sending the shutdown messages failed.");
}

/* do not continue on with shutdown process if peer already disconnected */
if (ret != WS_SOCKET_ERROR_E
&& wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) {
#ifndef WOLFSSL_NUCLEUS
if (ret == WS_WANT_WRITE) {
/* The close messages are queued and the threads are done, no
* one else is going to send them. */
ret = FlushQueuedSend(ssh, NULL);
if (ret == WS_WANT_WRITE) {
/* The peer stopped reading. The socket closes next, there is
* nothing left to push the messages out with. */
ret = WS_SUCCESS;
}
}
#endif

if (ret == WS_SUCCESS) {
ret = wolfSSH_worker(ssh, NULL);
if (ret == WS_FATAL_ERROR) {
ret = wolfSSH_get_error(ssh);
}
if (ret == WS_WANT_WRITE) {
/* The close messages are already out, whatever the drain
* still wants to send is a reply to the peer. */
ret = WS_SUCCESS;
}
}
else if (ret != WS_CHANNEL_CLOSED && ret != WS_WANT_READ
&& ret != WS_EOF) {
WLOG(WS_LOG_DEBUG, "Sending the shutdown messages failed.");
}

if (ret == WS_CHANNEL_CLOSED || ret == WS_WANT_READ
|| ret == WS_EOF) {
/* Shutting down. The channel closing or the peer's EOF isn't a
* fail, and neither is the peer having nothing ready on this
* non-blocking socket; either way there is nothing left to wait
* for. */
/* The close messages a short send left queued go out with the
* disconnect: the threads are done, no one else is going to send
* them. */
ret = SendDisconnectAndDrain(ssh, sockFd);
if (ret == WS_WANT_READ || ret == WS_WANT_WRITE) {
/* The socket closes next, so there is nothing left to push a
* queued disconnect out with, and a peer that never hung up is
* not a fail. */
ret = WS_SUCCESS;
}
else if (ret != WS_SUCCESS) {
WLOG(WS_LOG_DEBUG,
"Failed to listen for close messages from the peer.");
WLOG(WS_LOG_DEBUG, "Sending the disconnect failed.");
}
}
WCLOSESOCKET(sockFd);
Expand Down
58 changes: 11 additions & 47 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -4080,63 +4080,27 @@ static void* HandleConnection(void* arg)
if (error != WS_SOCKET_ERROR_E && error != WS_FATAL_ERROR) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Attempting to close down connection");
ret = wolfSSH_shutdown(ssh);
error = wolfSSH_get_error(ssh);

/* peer hung up, stop shutdown */
if (ret == WS_SOCKET_ERROR_E) {
if (ret == WS_SOCKET_ERROR_E || error == WS_SOCKET_ERROR_E) {
ret = 0;
}
}

error = wolfSSH_get_error(ssh);
if (conn != NULL) {
/* The close exchange ended the session, so the half close alone
* says the daemon is done: OpenSSH's client exits 255 on a
* disconnect that lands before it is finished. */
if (error != WS_SOCKET_ERROR_E &&
(error == WS_WANT_READ || error == WS_WANT_WRITE)) {
int maxAttempt = 10; /* make 10 attempts max before giving up */
int attempt;

for (attempt = 0; attempt < maxAttempt; attempt++) {
ret = wolfSSH_worker(ssh, NULL);
error = wolfSSH_get_error(ssh);

/* peer successfully closed down gracefully */
if (ret == WS_CHANNEL_CLOSED || ret == WS_EOF) {
ret = 0;
break;
}

/* peer hung up, stop shutdown */
if (ret == WS_SOCKET_ERROR_E) {
ret = 0;
break;
}

if (ret == WS_FATAL_ERROR &&
(error != WS_WANT_READ &&
error != WS_WANT_WRITE)) {
break;
}
#ifdef _WIN32
Sleep(1);
#else
usleep(100000);
#endif
}

if (attempt == maxAttempt) {
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Gave up on graceful shutdown, closing the socket");
}
HalfCloseAndDrain(ssh, conn->fd) == WS_WANT_READ) {
wolfSSH_Log(WS_LOG_INFO,
"[SSHD] Gave up waiting for the peer to hang up, "
"closing the socket");
}
}

/* check if there is a response to the shutdown */
wolfSSH_free(ssh);
if (conn != NULL) {
byte sc[1024];
shutdown(conn->fd, 1);
/* Spin until socket closes. */
do {
ret = (int)recv(conn->fd, (char*)sc, 1024, 0);
} while (ret > 0);

WCLOSESOCKET(conn->fd);
}
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Return from closing connection = %d", ret);
Expand Down
41 changes: 23 additions & 18 deletions examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
socklen_t clientAddrSz = sizeof(clientAddr);
char rxBuf[80];
int ret = 0;
int error = 0;
int ch;
int userEcc = 0;
word16 port = wolfSshPort;
Expand Down Expand Up @@ -1250,24 +1251,28 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
#endif
}
ret = wolfSSH_shutdown(ssh);
/* do not continue on with shutdown process if peer already disconnected.
* A peer EOF is not a disconnect: the channel is still open and its close
* 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 && ret != WS_WANT_WRITE) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Sending the shutdown messages failed.");
}
ret = wolfSSH_worker(ssh, NULL);
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E &&
ret != WS_CHANNEL_CLOSED && ret != WS_EOF) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Failed to listen for close messages from the peer.");
error = wolfSSH_get_error(ssh);
/* WS_FATAL_ERROR only says to go look, the session has the detail. The
* teardown sends are the point of the call, so an unexpected result is
* worth a line, but the drain below still runs: the peer's close is
* still owed. */
if (ret == WS_FATAL_ERROR)
ret = error;
if (ret != WS_SUCCESS && ret != WS_WANT_WRITE && ret != WS_WANT_READ &&
ret != WS_CHANNEL_CLOSED && ret != WS_EOF &&
ret != WS_SOCKET_ERROR_E && ret != WS_DISCONNECT)
printf("Sending the shutdown messages failed, error %d\n", ret);
ret = WS_SUCCESS;

/* peer already hung up, just close. A peer EOF is not a hang up: the
* channel is still open and its close is still owed, so the drain is
* exactly what is wanted there. */
if (error != WS_SOCKET_ERROR_E) {
ret = SendDisconnectAndDrain(ssh, sockFd);
if (ret == WS_WANT_READ || ret == WS_WANT_WRITE) {
printf("Gave up on a graceful shutdown, "
"closing the socket\n");
ret = WS_SUCCESS;
}
}
WCLOSESOCKET(sockFd);
Expand Down
54 changes: 11 additions & 43 deletions examples/echoserver/echoserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -2352,55 +2352,23 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs)
}

if (error != WS_SOCKET_ERROR_E && error != WS_FATAL_ERROR) {
ret = wolfSSH_shutdown(threadCtx->ssh);
(void)wolfSSH_shutdown(threadCtx->ssh);
error = wolfSSH_get_error(threadCtx->ssh);

/* peer hung up, stop shutdown */
if (ret == WS_SOCKET_ERROR_E) {
if (error == WS_SOCKET_ERROR_E) {
ret = 0;
}

/* The peer's close already retired the channel: a completed
* shutdown, not a failure. Left non-zero it sets quit, taking the
* server down after one session. */
if (ret == WS_CHANNEL_CLOSED) {
else {
/* The close exchange ended the session, and OpenSSH's client
* exits 255 on a disconnect that lands before it is done, so
* the half close alone says we are finished. */
ret = HalfCloseAndDrain(threadCtx->ssh, threadCtx->fd);
if (ret == WS_WANT_READ)
printf("Gave up waiting for the peer to hang up, "
"closing the socket\n");
ret = 0;
}

error = wolfSSH_get_error(threadCtx->ssh);
if (error != WS_SOCKET_ERROR_E &&
(error == WS_WANT_READ || error == WS_WANT_WRITE)) {
int maxAttempt = 10; /* make 10 attempts max before giving up */
int attempt;

for (attempt = 0; attempt < maxAttempt; attempt++) {
ret = wolfSSH_worker(threadCtx->ssh, NULL);
error = wolfSSH_get_error(threadCtx->ssh);

/* peer successfully closed down gracefully */
if (ret == WS_CHANNEL_CLOSED || ret == WS_EOF) {
ret = 0;
break;
}

/* peer hung up, stop shutdown */
if (ret == WS_SOCKET_ERROR_E) {
ret = 0;
break;
}

if (error == WS_WANT_READ || error == WS_WANT_WRITE) {
/* Wanting read or wanting write. Clear ret. */
ret = 0;
}
else {
break;
}
}

if (attempt == maxAttempt) {
printf("Gave up on graceful shutdown, closing the socket\n");
}
}
}

if (threadCtx->fd != -1) {
Expand Down
15 changes: 13 additions & 2 deletions examples/portfwd/portfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -934,11 +934,22 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args)
}

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

/* peer already hung up, just close */
if (wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) {
ret = SendDisconnectAndDrain(ssh, sshFd);
if (ret == WS_WANT_READ || ret == WS_WANT_WRITE) {
printf("Gave up on a graceful shutdown, closing the socket\n");
ret = WS_SUCCESS;
}
else if (ret != WS_SUCCESS)
err_sys("Sending the disconnect failed.");
}

WCLOSESOCKET(sshFd);
if (listenFd != (SOCKET_T)-1)
WCLOSESOCKET(listenFd);
Expand Down
33 changes: 17 additions & 16 deletions examples/scpclient/scpclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,22 +317,23 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args)
}

ret = wolfSSH_shutdown(ssh);
/* do not continue on with shutdown process if peer already disconnected.
* A peer EOF is not a disconnect: the channel is still open and its close
* is still owed, so the drain below is exactly what is wanted. */
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 && ret != WS_WANT_WRITE) {
WLOG(WS_LOG_DEBUG, "Sending the shutdown messages failed.");
}
else {
ret = wolfSSH_worker(ssh, NULL);
if (ret != WS_SUCCESS && ret != WS_CHANNEL_CLOSED
&& ret != WS_EOF) {
WLOG(WS_LOG_DEBUG,
"Failed to listen for close messages from the peer.");
}
/* WS_FATAL_ERROR only says to go look, the session has the detail. */
if (ret == WS_FATAL_ERROR)
ret = wolfSSH_get_error(ssh);
if (ret != WS_SUCCESS && ret != WS_WANT_WRITE && ret != WS_WANT_READ &&
ret != WS_CHANNEL_CLOSED && ret != WS_EOF &&
ret != WS_SOCKET_ERROR_E && ret != WS_DISCONNECT) {
WLOG(WS_LOG_DEBUG, "Sending the shutdown messages failed.");
}
ret = WS_SUCCESS;

/* peer already hung up, just close */
if (wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) {
ret = SendDisconnectAndDrain(ssh, sockFd);
if (ret == WS_WANT_READ || ret == WS_WANT_WRITE) {
WLOG(WS_LOG_DEBUG,
"Gave up on a graceful shutdown, closing the socket");
ret = WS_SUCCESS;
}
}
WCLOSESOCKET(sockFd);
Expand Down
51 changes: 9 additions & 42 deletions examples/sftpclient/sftpclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -1940,51 +1940,18 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)

WFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ret == WS_SUCCESS) {
int err;
ret = wolfSSH_shutdown(ssh);

/* peer hung up or channel already closed, stop trying.
* wolfSSH_shutdown() folds a peer EOF into WS_SUCCESS itself, so
* there is no WS_EOF to test for here. */
if (ret == WS_SOCKET_ERROR_E || ret == WS_ERROR ||
ret == WS_CHANNEL_CLOSED) {
ret = 0;
}

err = wolfSSH_get_error(ssh);
if (err != WS_SOCKET_ERROR_E &&
(err == WS_WANT_READ || err == WS_WANT_WRITE)) {
int maxAttempt = 10; /* make 10 attempts max before giving up */
int attempt;

for (attempt = 0; attempt < maxAttempt; attempt++) {
ret = wolfSSH_worker(ssh, NULL);
err = wolfSSH_get_error(ssh);

/* peer successfully closed down gracefully */
if (ret == WS_CHANNEL_CLOSED || ret == WS_EOF) {
ret = 0;
break;
}
int error;

/* peer hung up, stop shutdown */
if (ret == WS_SOCKET_ERROR_E || ret == WS_ERROR) {
ret = 0;
break;
}

if (err == WS_WANT_READ || err == WS_WANT_WRITE) {
/* Wanting read or wanting write. Clear ret. */
ret = 0;
}
else {
break;
}
}
(void)wolfSSH_shutdown(ssh);
error = wolfSSH_get_error(ssh);

if (attempt == maxAttempt) {
printf("SFTP client gave up on graceful shutdown,"
/* peer already hung up, just close */
if (error != WS_SOCKET_ERROR_E) {
ret = SendDisconnectAndDrain(ssh, sockFd);
if (ret == WS_WANT_READ || ret == WS_WANT_WRITE) {
printf("SFTP client gave up on a graceful shutdown, "
"closing the socket\n");
ret = WS_SUCCESS;
}
}
}
Expand Down
Loading
Loading