|
40 | 40 | #include <wolfssh/port.h> |
41 | 41 | #include <wolfssh/ssh.h> |
42 | 42 | #include <wolfssh/internal.h> |
| 43 | +#ifdef WOLFSSH_SFTP |
| 44 | + #include <wolfssh/wolfsftp.h> |
| 45 | +#endif |
43 | 46 | #include "apps/wolfssh/common.h" |
44 | 47 |
|
45 | 48 | #ifndef WOLFSSH_NO_ABORT |
@@ -482,6 +485,78 @@ static void TestWorkerReadsWhenSendWouldBlock(void) |
482 | 485 | #endif |
483 | 486 |
|
484 | 487 |
|
| 488 | +#ifdef WOLFSSH_SFTP |
| 489 | +/* Test that wolfSSH_SFTP_buffer_send() properly handles WS_WANT_WRITE when |
| 490 | + * SSH output buffer has pending data. This is a regression test for |
| 491 | + * the SFTP hang issue with non-blocking sockets. |
| 492 | + * |
| 493 | + * The fix checks for pending data in ssh->outputBuffer at the start of |
| 494 | + * wolfSSH_SFTP_buffer_send() and returns WS_WANT_WRITE if the flush fails. */ |
| 495 | +static int sftpWantWriteCallCount = 0; |
| 496 | + |
| 497 | +static int SftpWantWriteSendCb(WOLFSSH* ssh, void* buf, word32 sz, void* ctx) |
| 498 | +{ |
| 499 | + (void)ssh; (void)buf; (void)ctx; |
| 500 | + sftpWantWriteCallCount++; |
| 501 | + /* First call returns WANT_WRITE, subsequent calls succeed */ |
| 502 | + if (sftpWantWriteCallCount == 1) { |
| 503 | + return WS_CBIO_ERR_WANT_WRITE; |
| 504 | + } |
| 505 | + return (int)sz; |
| 506 | +} |
| 507 | + |
| 508 | +static int SftpDummyRecv(WOLFSSH* ssh, void* buf, word32 sz, void* ctx) |
| 509 | +{ |
| 510 | + (void)ssh; (void)buf; (void)sz; (void)ctx; |
| 511 | + return WS_CBIO_ERR_WANT_READ; |
| 512 | +} |
| 513 | + |
| 514 | +static void TestSftpBufferSendPendingOutput(void) |
| 515 | +{ |
| 516 | + WOLFSSH_CTX* ctx; |
| 517 | + WOLFSSH* ssh; |
| 518 | + byte testData[16]; |
| 519 | + int ret; |
| 520 | + |
| 521 | + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); |
| 522 | + AssertNotNull(ctx); |
| 523 | + |
| 524 | + wolfSSH_SetIOSend(ctx, SftpWantWriteSendCb); |
| 525 | + wolfSSH_SetIORecv(ctx, SftpDummyRecv); |
| 526 | + |
| 527 | + ssh = wolfSSH_new(ctx); |
| 528 | + AssertNotNull(ssh); |
| 529 | + |
| 530 | + WMEMSET(testData, 0x42, sizeof(testData)); |
| 531 | + |
| 532 | + /* Simulate pending data in SSH output buffer (as if previous send |
| 533 | + * returned WS_WANT_WRITE and data was buffered). |
| 534 | + * Note: outputBuffer is initialized by BufferInit() with bufferSz set |
| 535 | + * to at least STATIC_BUFFER_LEN (16 bytes), so we use a smaller value. */ |
| 536 | + ssh->outputBuffer.length = 8; /* 8 bytes pending */ |
| 537 | + ssh->outputBuffer.idx = 0; /* none sent yet */ |
| 538 | + |
| 539 | + sftpWantWriteCallCount = 0; |
| 540 | + |
| 541 | + /* Call wolfSSH_TestSftpBufferSend - should return WS_WANT_WRITE because |
| 542 | + * the fix detects pending data in outputBuffer and tries to flush it, |
| 543 | + * which fails with WS_WANT_WRITE from our callback. |
| 544 | + * |
| 545 | + * Before the fix, the function would ignore the pending SSH output buffer |
| 546 | + * data and proceed to send new SFTP data, leading to a hang because the |
| 547 | + * pending data was never flushed. */ |
| 548 | + ret = wolfSSH_TestSftpBufferSend(ssh, testData, sizeof(testData), 0); |
| 549 | + AssertIntEQ(ret, WS_WANT_WRITE); |
| 550 | + |
| 551 | + /* Verify the SSH output buffer still has pending data */ |
| 552 | + AssertTrue(ssh->outputBuffer.length > ssh->outputBuffer.idx); |
| 553 | + |
| 554 | + wolfSSH_free(ssh); |
| 555 | + wolfSSH_CTX_free(ctx); |
| 556 | +} |
| 557 | +#endif /* WOLFSSH_SFTP */ |
| 558 | + |
| 559 | + |
485 | 560 | int main(int argc, char** argv) |
486 | 561 | { |
487 | 562 | WOLFSSH_CTX* ctx; |
@@ -515,6 +590,10 @@ int main(int argc, char** argv) |
515 | 590 | TestWorkerReadsWhenSendWouldBlock(); |
516 | 591 | #endif |
517 | 592 |
|
| 593 | +#ifdef WOLFSSH_SFTP |
| 594 | + TestSftpBufferSendPendingOutput(); |
| 595 | +#endif |
| 596 | + |
518 | 597 | /* TODO: add app-level regressions that simulate stdin EOF/password |
519 | 598 | * prompts and mid-session socket closes once the test harness can |
520 | 599 | * drive the wolfssh client without real sockets/tty. */ |
|
0 commit comments