@@ -517,7 +517,7 @@ static int wolfSSH_SFTP_buffer_send(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer)
517517 int ret = WS_SUCCESS ;
518518 int err ;
519519
520- if (buffer == NULL ) {
520+ if (buffer == NULL || ssh == NULL ) {
521521 return WS_BAD_ARGUMENT ;
522522 }
523523
@@ -538,11 +538,25 @@ static int wolfSSH_SFTP_buffer_send(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer)
538538 }
539539 }
540540
541- /* Call wolfSSH worker if rekeying or adjusting window size */
541+ /* Best-effort: drive the worker while a rekey or full window blocks sending.
542+ * Also checks ssh->isKeying for a rekey triggered by a receive
543+ * (HighwaterCheck) where ssh->error holds a different code. If the window is
544+ * still full after this (e.g. worker returned WS_CHAN_RXD), stream_send
545+ * returns WS_WINDOW_FULL and the caller retries via NoticeError(). */
542546 err = wolfSSH_get_error (ssh );
543- if (err == WS_WINDOW_FULL || err == WS_REKEYING ) {
544- (void )wolfSSH_worker (ssh , NULL );
547+ while (ssh -> isKeying || err == WS_WINDOW_FULL || err == WS_REKEYING ) {
548+ ret = wolfSSH_worker (ssh , NULL );
549+ /* Only a rekey/window/channel-data status means "keep driving". Any
550+ * other negative status (fatal error, or WS_WANT_READ/WS_WANT_WRITE on
551+ * a non-blocking socket) is returned so a stalled or dead rekey cannot
552+ * spin forever. */
553+ if (ret < 0 && ret != WS_REKEYING && ret != WS_WINDOW_FULL
554+ && ret != WS_CHAN_RXD ) {
555+ return ret ;
556+ }
557+ err = wolfSSH_get_error (ssh );
545558 }
559+ ret = WS_SUCCESS ;
546560
547561 if (buffer -> idx < buffer -> sz ) {
548562 ret = wolfSSH_stream_send (ssh , buffer -> data + buffer -> idx ,
@@ -577,6 +591,7 @@ static int wolfSSH_SFTP_buffer_read(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer,
577591 int readSz )
578592{
579593 int ret ;
594+ int polled ;
580595 byte peekBuf [1 ];
581596
582597 if (buffer == NULL || ssh == NULL ) {
@@ -598,9 +613,11 @@ static int wolfSSH_SFTP_buffer_read(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer,
598613 }
599614
600615 do {
616+ polled = 0 ;
601617 if (!wolfSSH_stream_peek (ssh , peekBuf , 1 )) {
602618 /* poll more data off the wire */
603619 ret = wolfSSH_worker (ssh , NULL );
620+ polled = 1 ;
604621 }
605622 else {
606623 ret = WS_CHAN_RXD ; /* existing data found with peek */
@@ -611,6 +628,20 @@ static int wolfSSH_SFTP_buffer_read(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer,
611628 buffer -> sz - buffer -> idx );
612629 }
613630 if (ret < 0 ) {
631+ if (wolfSSH_get_error (ssh ) == WS_REKEYING ) {
632+ /* Drive the rekey forward only if the top of the loop did not
633+ * already poll this iteration. Keep looping while it is still
634+ * in progress; a genuine failure changes ssh->error and is
635+ * returned. */
636+ if (!polled ) {
637+ ret = wolfSSH_worker (ssh , NULL );
638+ if (ret < 0 && ret != WS_CHAN_RXD
639+ && wolfSSH_get_error (ssh ) != WS_REKEYING ) {
640+ return WS_FATAL_ERROR ;
641+ }
642+ }
643+ continue ;
644+ }
614645 return WS_FATAL_ERROR ;
615646 }
616647 buffer -> idx += (word32 )ret ;
0 commit comments