@@ -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. */
60686070static 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