@@ -15449,6 +15449,130 @@ static int test_SftpClientRecvInitVersion(void)
1544915449
1545015450 return 0;
1545115451}
15452+
15453+ /* Builds an SFTP DATA reply in "out": the 9 byte header carrying the request
15454+ * id where a VERSION message carries the version, then the data string as the
15455+ * trailing bytes. Returns the size written, or 0 if it does not fit. */
15456+ static word32 SftpBuildData(byte* out, word32 outSz, word32 reqId,
15457+ word32 dataSz)
15458+ {
15459+ word32 msgSz;
15460+
15461+ msgSz = SftpBuildVersion(out, outSz,
15462+ MSG_ID_SZ + UINT32_SZ + UINT32_SZ + dataSz, WOLFSSH_FTP_DATA,
15463+ reqId, UINT32_SZ + dataSz);
15464+ if (msgSz > 0) {
15465+ /* the trailing bytes open with the data string length */
15466+ PutU32BE(out + WOLFSSH_SFTP_HEADER, dataSz);
15467+ }
15468+
15469+ return msgSz;
15470+ }
15471+
15472+
15473+ /* Drives wolfSSH_SFTP_SendReadPacket() over a DATA reply delivered in two
15474+ * pieces, split after "split" bytes, with RecvAlwaysWantRead standing in for a
15475+ * non-blocking socket. Returns 0, or a negative sentinel on a setup failure. */
15476+ static int SftpClientDriveReadSplit(word32 dataSz, word32 split,
15477+ int* firstRet, int* firstErr, int* stateKept, int* secondRet,
15478+ byte* out, word32 outSz)
15479+ {
15480+ WOLFSSH_CTX* ctx = NULL;
15481+ WOLFSSH* ssh = NULL;
15482+ byte msg[WOLFSSH_SFTP_HEADER + UINT32_SZ + 32];
15483+ byte handle[4];
15484+ word32 ofst[2];
15485+ word32 msgSz;
15486+ int result;
15487+
15488+ *firstRet = WS_SUCCESS;
15489+ *firstErr = WS_SUCCESS;
15490+ *stateKept = 0;
15491+ *secondRet = WS_SUCCESS;
15492+
15493+ WMEMSET(handle, 'h', sizeof(handle));
15494+ WMEMSET(out, 0, outSz);
15495+ ofst[0] = 0;
15496+ ofst[1] = 0;
15497+
15498+ result = SftpClientNewSession(&ctx, &ssh);
15499+ if (result == 0) {
15500+ msgSz = SftpBuildData(msg, (word32)sizeof(msg), ssh->reqId, dataSz);
15501+ if (msgSz == 0 || split >= msgSz) {
15502+ result = -1019;
15503+ }
15504+ }
15505+ if (result == 0) {
15506+ /* ChannelNew leaves the peer window at zero, which would fail the
15507+ * READ request before any reply is read */
15508+ ssh->channelList->peerWindowSz = 1024;
15509+ ssh->channelList->peerMaxPacketSz = 1024;
15510+
15511+ if (wolfSSH_TestChannelPutData(ssh->channelList, msg, split)
15512+ != WS_SUCCESS) {
15513+ result = -1020;
15514+ }
15515+ }
15516+ if (result == 0) {
15517+ *firstRet = wolfSSH_SFTP_SendReadPacket(ssh, handle,
15518+ (word32)sizeof(handle), ofst, out, outSz);
15519+ *firstErr = wolfSSH_get_error(ssh);
15520+ *stateKept = (ssh->sendReadState != NULL);
15521+
15522+ if (wolfSSH_TestChannelPutData(ssh->channelList, msg + split,
15523+ msgSz - split) != WS_SUCCESS) {
15524+ result = -1021;
15525+ }
15526+ }
15527+ if (result == 0) {
15528+ *secondRet = wolfSSH_SFTP_SendReadPacket(ssh, handle,
15529+ (word32)sizeof(handle), ofst, out, outSz);
15530+ }
15531+
15532+ wolfSSH_free(ssh);
15533+ wolfSSH_CTX_free(ctx);
15534+ return result;
15535+ }
15536+
15537+
15538+ /* Regression for the SFTP DATA reply losing bytes when its four byte string
15539+ * length arrives split: the read must report WS_WANT_READ, keep the send read
15540+ * state, then complete with the payload intact on the retry. */
15541+ static int test_SftpSendReadPacketSplit(void)
15542+ {
15543+ static const word32 splits[2] = { WOLFSSH_SFTP_HEADER + 1,
15544+ WOLFSSH_SFTP_HEADER + 2 };
15545+ byte out[16];
15546+ word32 dataSz = 8;
15547+ word32 i;
15548+ word32 j;
15549+ int rc;
15550+ int firstRet;
15551+ int firstErr;
15552+ int stateKept;
15553+ int secondRet;
15554+
15555+ for (i = 0; i < (word32)(sizeof(splits) / sizeof(splits[0])); i++) {
15556+ rc = SftpClientDriveReadSplit(dataSz, splits[i], &firstRet, &firstErr,
15557+ &stateKept, &secondRet, out, (word32)sizeof(out));
15558+ if (rc != 0)
15559+ return rc;
15560+ if (firstRet != WS_FATAL_ERROR)
15561+ return -981;
15562+ if (firstErr != WS_WANT_READ)
15563+ return -982;
15564+ if (!stateKept)
15565+ return -983;
15566+ if (secondRet != (int)dataSz)
15567+ return -984;
15568+ for (j = 0; j < dataSz; j++) {
15569+ if (out[j] != (byte)(UINT32_SZ + j))
15570+ return -985;
15571+ }
15572+ }
15573+
15574+ return 0;
15575+ }
1545215576#endif /* NO_WOLFSSH_CLIENT */
1545315577#endif /* WOLFSSH_SFTP */
1545415578
@@ -16567,6 +16691,11 @@ int wolfSSH_UnitTest(int argc, char** argv)
1656716691 printf("SftpClientRecvInitVersion: %s\n",
1656816692 (unitResult == 0 ? "SUCCESS" : "FAILED"));
1656916693 testResult = testResult || unitResult;
16694+
16695+ unitResult = test_SftpSendReadPacketSplit();
16696+ printf("SftpSendReadPacketSplit: %s\n",
16697+ (unitResult == 0 ? "SUCCESS" : "FAILED"));
16698+ testResult = testResult || unitResult;
1657016699#endif
1657116700#endif
1657216701
0 commit comments