add function to check for window adjustment and fix SCP file buffer offset

close file on SCP write fail, and add ioctl for Nucleus

window adjustment check with SFTP and handle multiple adjustment packets

fix for setting return value with Nucleus ioctl
pull/103/head
Jacob Barthelmeh 2018-09-13 09:49:29 -06:00
parent ba4fae0054
commit 68e6d8308b
5 changed files with 82 additions and 7 deletions

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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 <sys/ioctl.h>
#define WIOCTL ioctl
#endif
#endif
#ifdef __cplusplus
}

View File

@ -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 {