diff --git a/src/internal.c b/src/internal.c index bb91258e..643168f0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -20492,7 +20492,10 @@ int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId) if (ret == WS_SUCCESS) { ret = wolfSSH_SendPacket(ssh); - channel->closeTxd = 1; + /* Same terms as SendChannelEof(). A closeTxd for a close that never + * left makes wolfSSH_shutdown() skip the teardown. */ + if (ret != WS_SOCKET_ERROR_E || wolfSSH_OutputPending(ssh)) + channel->closeTxd = 1; } WLOG(WS_LOG_DEBUG, "Leaving SendChannelClose(), ret = %d", ret); diff --git a/tests/unit.c b/tests/unit.c index 4bb3851c..32df343b 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -7327,6 +7327,12 @@ static int test_SendChannelEofSendFails(void) if (ch->eofTxd) { result = -1692; goto done; } if (ssh->outputBuffer.length != 0) { result = -1693; goto done; } + /* SendChannelClose() has the same shape, and a closeTxd claiming a close + * that never left makes wolfSSH_shutdown() skip the teardown. */ + ret = SendChannelClose(ssh, ch->peerChannel); + if (ret != WS_SOCKET_ERROR_E) { result = -1762; goto done; } + if (ch->closeTxd) { result = -1763; goto done; } + /* So the channel is not half-closed, and an EOF can still be built and * sent once the socket takes bytes again. */ wolfSSH_SetIOSend(ctx, DiscardIoSend);