diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 52805707..bf9d9186 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1140,7 +1140,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, HeapFree(GetProcessHeap(), 0, ext.lpAttributeList); } - if (wolfSSH_SendExitStatus(ssh, processState) != + if (wolfSSH_SetExitStatus(ssh, processState) != WS_SUCCESS) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit " "status"); @@ -1464,7 +1464,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, { int waitStatus; waitpid(-1, &waitStatus, WNOHANG); - if (wolfSSH_SendExitStatus(ssh, (word32)WEXITSTATUS(waitStatus)) != + if (wolfSSH_SetExitStatus(ssh, (word32)WEXITSTATUS(waitStatus)) != WS_SUCCESS) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit " "status"); @@ -1722,9 +1722,12 @@ static void* HandleConnection(void* arg) break; } - if (error != WS_WANT_READ && error != WS_WANT_WRITE) { + if (ret == WS_FATAL_ERROR && + (error != WS_WANT_READ && + error != WS_WANT_WRITE)) { break; } + usleep(1); } if (attempt == maxAttempt) { @@ -1734,6 +1737,7 @@ static void* HandleConnection(void* arg) } } + /* check if there is a response to the shutdown */ wolfSSH_free(ssh); if (conn != NULL) { WCLOSESOCKET(conn->fd); diff --git a/examples/client/client.c b/examples/client/client.c index 25c3a5cd..6c15fcbe 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -982,7 +982,8 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) err_sys("Sending the shutdown messages failed."); } ret = wolfSSH_worker(ssh, NULL); - if (ret != WS_SUCCESS) { + if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E && + ret != WS_CHANNEL_CLOSED) { err_sys("Failed to listen for close messages from the peer."); } } @@ -994,8 +995,10 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); - if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E) + if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E && + ret != WS_CHANNEL_CLOSED) { err_sys("Closing client stream failed"); + } ClientFreeBuffers(pubKeyName, privKeyName); #if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) diff --git a/src/internal.c b/src/internal.c index ba11fc25..4e69277f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -14034,64 +14034,6 @@ int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success) } -/* Sends out the channel exit-status msg - * returns WS_SUCCESS on success */ -int SendChannelExitStatus(WOLFSSH* ssh, word32 channelId, word32 exitStatus) -{ - byte* output; - word32 idx; - int ret = WS_SUCCESS; - WOLFSSH_CHANNEL* channel = NULL; - const char cType[] = "exit-status"; - int typeSz; - - WLOG(WS_LOG_DEBUG, "Entering SendChannelExitStatus()"); - if (ssh == NULL) - ret = WS_BAD_ARGUMENT; - - if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); - if (channel == NULL) { - WLOG(WS_LOG_DEBUG, "Invalid channel"); - ret = WS_INVALID_CHANID; - } - } - - if (ret == WS_SUCCESS) { - typeSz = (word32)WSTRLEN(cType); - ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + - typeSz + BOOLEAN_SZ + UINT32_SZ); - } - - if (ret == WS_SUCCESS) { - output = ssh->outputBuffer.buffer; - idx = ssh->outputBuffer.length; - - output[idx++] = MSGID_CHANNEL_REQUEST; - c32toa(channel->peerChannel, output + idx); - idx += UINT32_SZ; - - c32toa(typeSz, output + idx); - idx += LENGTH_SZ; - WMEMCPY(output + idx, cType, typeSz); - idx += typeSz; - output[idx++] = 0; /* boolean of want reply is always false */ - c32toa(exitStatus, output + idx); - idx += UINT32_SZ; - - ssh->outputBuffer.length = idx; - - ret = BundlePacket(ssh); - } - - if (ret == WS_SUCCESS) - ret = wolfSSH_SendPacket(ssh); - - WLOG(WS_LOG_DEBUG, "Leaving SendChannelExitStatus(), ret = %d", ret); - return ret; -} - - #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ !defined(NO_WOLFSSH_SERVER) /* cleans up absolute path diff --git a/src/ssh.c b/src/ssh.c index a7e8e968..d5b53af0 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -954,24 +954,43 @@ int wolfSSH_connect(WOLFSSH* ssh) int wolfSSH_shutdown(WOLFSSH* ssh) { int ret = WS_SUCCESS; + WOLFSSH_CHANNEL* channel = NULL; WLOG(WS_LOG_DEBUG, "Entering wolfSSH_shutdown()"); if (ssh == NULL || ssh->channelList == NULL) ret = WS_BAD_ARGUMENT; - if (ret == WS_SUCCESS) - ret = SendChannelEof(ssh, ssh->channelList->peerChannel); + /* look up the channel if it still exists */ + if (ret == WS_SUCCESS) { + channel = ChannelFind(ssh, ssh->channelList->peerChannel, WS_CHANNEL_ID_SELF); + } - /* continue on success and in case where queing up send packets */ - if (ret == WS_SUCCESS || - (ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE)) - ret = SendChannelExit(ssh, ssh->channelList->peerChannel, 0); + /* if channel close was not already sent then send it */ + if (channel != NULL && !channel->closeTxd) { + if (ret == WS_SUCCESS) { + ret = SendChannelEof(ssh, ssh->channelList->peerChannel); + } - /* continue on success and in case where queing up send packets */ - if (ret == WS_SUCCESS || - (ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE)) - ret = SendChannelClose(ssh, ssh->channelList->peerChannel); + /* continue on success and in case where queing up send packets */ + if (ret == WS_SUCCESS || + (ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE)) { + ret = SendChannelExit(ssh, ssh->channelList->peerChannel, + ssh->exitStatus); + } + + /* continue on success and in case where queing up send packets */ + if (ret == WS_SUCCESS || + (ret != WS_BAD_ARGUMENT && ssh->error == WS_WANT_WRITE)) + ret = SendChannelClose(ssh, ssh->channelList->peerChannel); + } + + + /* if the channel was not yet removed then read to get + * response to SendChannelClose */ + if (channel != NULL && ret == WS_SUCCESS) { + ret = wolfSSH_worker(ssh, NULL); + } if (ssh != NULL && ssh->channelList == NULL) { WLOG(WS_LOG_DEBUG, "channel list was already removed"); @@ -1377,18 +1396,18 @@ int wolfSSH_GetExitStatus(WOLFSSH* ssh) } -/* Sends the commands exit status to the peer +/* Sets the exit status to send on shutdown * returns WS_SUCCESS on success */ -int wolfSSH_SendExitStatus(WOLFSSH* ssh, word32 exitStatus) +int wolfSSH_SetExitStatus(WOLFSSH* ssh, word32 exitStatus) { if (ssh == NULL) { - WLOG(WS_LOG_DEBUG, "wolfSSH_SendExitStatus WOLFSSH struct was NULL"); + WLOG(WS_LOG_DEBUG, "wolfSSH_SetExitStatus WOLFSSH struct was NULL"); return WS_BAD_ARGUMENT; } - WLOG(WS_LOG_DEBUG, "wolfSSH_SendExitStatus sending exit status %u", + WLOG(WS_LOG_DEBUG, "wolfSSH_SetExitStatus sending exit status %u", exitStatus); - - return SendChannelExitStatus(ssh, ssh->defaultPeerChannelId, exitStatus); + ssh->exitStatus = exitStatus; + return WS_SUCCESS; } #endif diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 63c16574..0e2d49f8 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -294,7 +294,7 @@ WOLFSSH_API void wolfSSH_SetTerminalResizeCb(WOLFSSH* ssh, WS_CallbackTerminalSize cb); WOLFSSH_API void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx); WOLFSSH_API int wolfSSH_GetExitStatus(WOLFSSH* ssh); -WOLFSSH_API int wolfSSH_SendExitStatus(WOLFSSH* ssh, word32 exitStatus); +WOLFSSH_API int wolfSSH_SetExitStatus(WOLFSSH* ssh, word32 exitStatus); enum WS_HighwaterSide {