Skip to content

Commit 8352ae7

Browse files
ssh.c: report the byte count from a channel read that defers its credit
- _ChannelRead() records a non-WS_SUCCESS _UpdateChannelWindow() result in channel->ssh->error and returns the bytes copied, logging anything other than WS_WANT_WRITE. - tests/unit.c gains test_ChannelIdRead_deferredWindowAdjust(), which seeds ssh->error, then reads a full window through wolfSSH_ChannelIdRead() with an IO send that reports WS_CBIO_ERR_WANT_WRITE, and checks the byte count, the payload, the recorded error, the local window credit and the drained input buffer.
1 parent 6cc7f9e commit 8352ae7

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

tests/unit.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6063,6 +6063,8 @@ static int test_SendChannelData_zeroPeerMaxPacket(void)
60636063
return result;
60646064
}
60656065

6066+
#ifndef NO_WOLFSSH_SERVER
6067+
60666068
/* wolfSSH_stream_read() counterpart of test_ChannelExtDataCreditWantWrite():
60676069
* a deferred credit must not cost the caller the bytes already consumed. */
60686070
static int test_stream_read_deferredWindowAdjust(void)
@@ -6126,6 +6128,76 @@ static int test_stream_read_deferredWindowAdjust(void)
61266128
return result;
61276129
}
61286130

6131+
/* wolfSSH_ChannelIdRead() counterpart of
6132+
* test_stream_read_deferredWindowAdjust(): the echoserver's shell, agent and
6133+
* forwarding paths all break out on a non-positive read. */
6134+
static int test_ChannelIdRead_deferredWindowAdjust(void)
6135+
{
6136+
WOLFSSH_CTX* ctx = NULL;
6137+
WOLFSSH* ssh = NULL;
6138+
WOLFSSH_CHANNEL* ch = NULL;
6139+
int result = 0;
6140+
int ret;
6141+
byte in[64];
6142+
byte out[64];
6143+
word32 i;
6144+
6145+
for (i = 0; i < (word32)sizeof(in); i++) {
6146+
in[i] = (byte)i;
6147+
}
6148+
6149+
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
6150+
if (ctx == NULL)
6151+
return -7010;
6152+
wolfSSH_SetIOSend(ctx, WantWriteIoSend);
6153+
6154+
ssh = wolfSSH_new(ctx);
6155+
if (ssh == NULL) { result = -7011; goto done; }
6156+
/* Allow MSGID_CHANNEL_WINDOW_ADJUST on this bare session. */
6157+
ssh->acceptState = ACCEPT_SERVER_USERAUTH_SENT;
6158+
6159+
/* A window the size of the payload, so draining it in one read leaves
6160+
* windowSz at zero and _UpdateChannelWindow() has to credit. */
6161+
ch = ChannelNew(ssh, ID_CHANTYPE_SESSION,
6162+
(word32)sizeof(in), DEFAULT_MAX_PACKET_SZ);
6163+
if (ch == NULL) { result = -7012; goto done; }
6164+
if (ChannelAppend(ssh, ch) != WS_SUCCESS) {
6165+
ChannelDelete(ch, ssh->ctx->heap);
6166+
result = -7013;
6167+
goto done;
6168+
}
6169+
ch->openConfirmed = 1;
6170+
6171+
if (wolfSSH_TestChannelPutData(ch, in, (word32)sizeof(in)) != WS_SUCCESS) {
6172+
result = -7014; goto done;
6173+
}
6174+
if (ch->windowSz != 0) { result = -7015; goto done; }
6175+
6176+
/* Unlike wolfSSH_stream_read(), this entry point does not clear the error,
6177+
* so seed it: the assert below has to prove the read recorded it. */
6178+
ssh->error = WS_SUCCESS;
6179+
6180+
/* Every byte is reported, and they are the bytes that were put. */
6181+
ret = wolfSSH_ChannelIdRead(ssh, ch->channel, out, (word32)sizeof(out));
6182+
if (ret != (int)sizeof(in)) { result = -7016; goto done; }
6183+
if (WMEMCMP(out, in, sizeof(in)) != 0) { result = -7017; goto done; }
6184+
6185+
/* The deferral is observable, the window is credited locally, and the
6186+
* bytes are consumed rather than left for a re-read. */
6187+
if (ssh->error != WS_WANT_WRITE) { result = -7018; goto done; }
6188+
if (ch->windowSz != (word32)sizeof(in)) { result = -7019; goto done; }
6189+
if (ch->inputBuffer.length - ch->inputBuffer.idx != 0) {
6190+
result = -7020; goto done;
6191+
}
6192+
6193+
done:
6194+
wolfSSH_free(ssh);
6195+
wolfSSH_CTX_free(ctx);
6196+
return result;
6197+
}
6198+
6199+
#endif /* NO_WOLFSSH_SERVER */
6200+
61296201
/* BuildNameList() returns a C string. On an empty id list it must still
61306202
* terminate the buffer: SendKexInit() measures the result with WSTRLEN
61316203
* through AlgoListSz() and copies that many bytes into the KEXINIT. */
@@ -16463,11 +16535,18 @@ int wolfSSH_UnitTest(int argc, char** argv)
1646316535
(unitResult == 0 ? "SUCCESS" : "FAILED"));
1646416536
testResult = testResult || unitResult;
1646516537

16538+
#ifndef NO_WOLFSSH_SERVER
1646616539
unitResult = test_stream_read_deferredWindowAdjust();
1646716540
printf("stream_read_deferredWindowAdjust: %s\n",
1646816541
(unitResult == 0 ? "SUCCESS" : "FAILED"));
1646916542
testResult = testResult || unitResult;
1647016543

16544+
unitResult = test_ChannelIdRead_deferredWindowAdjust();
16545+
printf("ChannelIdRead_deferredWindowAdjust: %s\n",
16546+
(unitResult == 0 ? "SUCCESS" : "FAILED"));
16547+
testResult = testResult || unitResult;
16548+
#endif /* NO_WOLFSSH_SERVER */
16549+
1647116550
unitResult = test_BuildNameList_emptySrc();
1647216551
printf("BuildNameList_emptySrc: %s\n",
1647316552
(unitResult == 0 ? "SUCCESS" : "FAILED"));

0 commit comments

Comments
 (0)