diff --git a/src/ssh.c b/src/ssh.c index 1b4deec..cc0afd4 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1252,3 +1252,38 @@ WOLFSSH_CHANNEL* wolfSSH_ChannelNext(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) nextChannel == NULL ? "none" : "NEXT!"); return nextChannel; } + + +/* Protocols that have loops over wolfSSH_stream_send without doing any reads + * will run into the issue of not checking for a peer window adjustment packet. + * This function allows for checking for a peer window adjustment packet without + * requiring a read buffer and call to wolfSSH_stream_read. + * + * Data that is read and is not related to packet headers is stored in the + * WOLFSSH input buffer and can be gotten with a call to wolfSSH_stream_read. If + * more data is stored then MAX_PACKET_SZ then no more window adjustment packets + * are searched for. + */ +void wolfSSH_CheckPeerWindow(WOLFSSH* ssh) +{ + int bytes = 0; + Buffer* inputBuffer; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_CheckPeerWindow()"); + + if (ssh == NULL) + return; + + inputBuffer = &ssh->channelList->inputBuffer; + WIOCTL(wolfSSH_get_fd(ssh), FIONREAD, &bytes); + while (bytes > 0) { /* there is something to read off the wire */ + if (inputBuffer->length - inputBuffer->idx > MAX_PACKET_SZ) { + WLOG(WS_LOG_DEBUG, "Application data to be read"); + break; /* too much application data! */ + } + if (DoReceive(ssh) < 0) { + WLOG(WS_LOG_ERROR, "Error trying to read potential window adjust"); + } + WIOCTL(wolfSSH_get_fd(ssh), FIONREAD, &bytes); + } +} diff --git a/src/wolfscp.c b/src/wolfscp.c index 9b0b0b0..67d78e1 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -383,7 +383,8 @@ int DoScpSource(WOLFSSH* ssh) WOLFSSH_SCP_NEW_REQUEST, NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, NULL, 0, wolfSSH_GetScpSendCtx(ssh)); - if (ssh->scpConfirm == WS_SCP_ABORT) { + if (ssh->scpConfirm == WS_SCP_ABORT || + ssh->scpConfirm == WS_EOF) { ssh->scpState = SCP_RECEIVE_CONFIRMATION_WITH_RECEIPT; ssh->scpNextState = SCP_DONE; } else { @@ -456,7 +457,8 @@ int DoScpSource(WOLFSSH* ssh) ssh->scpFileName, ssh->scpFileNameSz, &(ssh->scpMTime), &(ssh->scpATime), &(ssh->scpFileMode), ssh->scpFileOffset, &(ssh->scpFileSz), - ssh->scpFileBuffer, ssh->scpFileBufferSz, + ssh->scpFileBuffer + ssh->scpBufferedSz, + ssh->scpFileBufferSz - ssh->scpBufferedSz, wolfSSH_GetScpSendCtx(ssh)); if (ssh->scpConfirm == WS_SCP_ENTER_DIR) { @@ -483,7 +485,7 @@ int DoScpSource(WOLFSSH* ssh) } else if (ssh->scpConfirm >= 0) { /* transfer buffered file data */ - ssh->scpBufferedSz = ssh->scpConfirm; + ssh->scpBufferedSz += ssh->scpConfirm; ssh->scpConfirm = WS_SCP_CONTINUE; /* only send timestamp and file header first time */ @@ -572,15 +574,20 @@ int DoScpSource(WOLFSSH* ssh) ret = wolfSSH_stream_send(ssh, ssh->scpFileBuffer, ssh->scpBufferedSz); + wolfSSH_CheckPeerWindow(ssh); /*check for adjust window packet*/ if (ret < 0) { WLOG(WS_LOG_ERROR, scpError, "failed to send file", ret); break; } ssh->scpFileOffset += ret; - ssh->scpBufferedSz = 0; + if (ret != (int)ssh->scpBufferedSz) { + /* case where not all of buffer was sent */ + WMEMMOVE(ssh->scpFileBuffer, ssh->scpFileBuffer + ret, + ssh->scpBufferedSz - ret); + } + ssh->scpBufferedSz -= ret; ret = WS_SUCCESS; - if (ssh->scpFileOffset < ssh->scpFileSz) { ssh->scpState = SCP_TRANSFER; ssh->scpRequestType = WOLFSSH_SCP_CONTINUE_FILE_TRANSFER; @@ -1352,7 +1359,6 @@ int SendScpConfirmation(WOLFSSH* ssh) /* skip first byte for accurate strlen, may be 0 */ msgSz = (int)XSTRLEN(msg + 1) + 1; ret = wolfSSH_stream_send(ssh, (byte*)msg, msgSz); - if (ret != msgSz || ssh->scpConfirm == WS_SCP_ABORT) { ret = WS_FATAL_ERROR; @@ -1646,6 +1652,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, if (bytes != bufSz) { WLOG(WS_LOG_ERROR, scpError, "scp receive callback unable " "to write requested size to file", bytes); + WFCLOSE(fp); ret = WS_SCP_ABORT; } break; @@ -2101,6 +2108,10 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, if (ret == WS_SUCCESS && sendCtx != NULL && sendCtx->fp != NULL) { ret = (word32)WFREAD(buf, 1, bufSz, sendCtx->fp); + if (ret == 0) { /* handle unexpected case */ + ret = WS_EOF; + } + } else { ret = WS_SCP_ABORT; } @@ -2246,6 +2257,10 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, } ret = (word32)WFREAD(buf, 1, bufSz, sendCtx->fp); + if (ret == 0) { /* handle case of EOF */ + ret = WS_EOF; + } + if ((ret <= 0) || (fileOffset + ret == *totalFileSz)) { WFCLOSE(sendCtx->fp); } diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 63e5b93..44f8eb4 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -2400,7 +2400,6 @@ int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, word32 maxSz) clean_path(name); if (SFTP_ParseAtributes_buffer(ssh, &atr, data + idx, maxSz - idx) != 0) { - printf("error parsing attributes\n"); wolfSSH_SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, "Unable to parse attributes error", "English"); return WS_BAD_FILE_E; @@ -2623,6 +2622,7 @@ int SendPacketType(WOLFSSH* ssh, byte type, byte* buf, word32 bufSz) * one time */ do { ret = wolfSSH_stream_send(ssh, data + sent, idx - sent); + wolfSSH_CheckPeerWindow(ssh); /* check for adjust window packet */ sent += (word32)ret; } while (ret > 0 && sent < idx); @@ -4258,6 +4258,7 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, statusCb(ssh, pOfst, from); } } + wolfSSH_CheckPeerWindow(ssh); /* check for adjust window packet */ } while (sz > 0 && ssh->sftpInt == 0); if (ssh->sftpInt) { wolfSSH_SFTP_SaveOfst(ssh, from, to, pOfst); diff --git a/wolfssh/port.h b/wolfssh/port.h index 4800eac..b22166d 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -482,6 +482,29 @@ extern "C" { #define FALL_THROUGH #endif +/* used for checking bytes on wire for window adjust packet read */ +#ifndef WIOCTL +#ifdef WOLFSSL_NUCLEUS + #include "nucleus.h" + #include "networking/nu_networking.h" + static inline void ws_Ioctl(int fd, int flag, int* ret) + { + SCK_IOCTL_OPTION op; + op.s_optval = (unsigned char*)&fd; + if (NU_Ioctl(flag, &op, sizeof(op)) != NU_SUCCESS) { + *ret = 0; + } + else { + *ret = op.s_ret.sck_bytes_pending; + } + } + #define WIOCTL ws_Ioctl +#else + #include + #define WIOCTL ioctl +#endif +#endif + #ifdef __cplusplus } diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 4857c86..329e5c7 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -181,6 +181,7 @@ typedef enum { WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_GetSessionCommand(const WOLFSSH*); WOLFSSH_API int wolfSSH_SetChannelType(WOLFSSH*, byte, byte*, word32); +WOLFSSH_API void wolfSSH_CheckPeerWindow(WOLFSSH* ssh); enum WS_HighwaterSide {