mirror of https://github.com/wolfSSL/wolfssh.git
Non-blocking SFTP
1. Move the non-blocking state types to wolfsftp.c. 2. Updated wolfSSH_SFTP_Open() to use the non-blocking state machine. 3. Updated wolfSSH_SFTP_Get() using the new state machine method.pull/134/head
parent
4dc799ebeb
commit
42f116bf1d
230
src/wolfsftp.c
230
src/wolfsftp.c
|
@ -37,6 +37,54 @@
|
|||
#include "src/misc.c"
|
||||
#endif
|
||||
|
||||
|
||||
enum WS_SFTP_LSTAT_STATE_ID {
|
||||
STATE_LSTAT_INIT
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_LSTAT_STATE {
|
||||
enum WS_SFTP_LSTAT_STATE_ID state;
|
||||
} WS_SFTP_LSTAT_STATE;
|
||||
|
||||
|
||||
enum WS_SFTP_OPEN_STATE_ID {
|
||||
STATE_OPEN_INIT,
|
||||
STATE_OPEN_SEND,
|
||||
STATE_OPEN_GETHANDLE,
|
||||
STATE_OPEN_CLEANUP
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_OPEN_STATE {
|
||||
enum WS_SFTP_OPEN_STATE_ID state;
|
||||
byte* data;
|
||||
int sz;
|
||||
word32 idx;
|
||||
} WS_SFTP_OPEN_STATE;
|
||||
|
||||
|
||||
enum WS_SFTP_GET_STATE_ID {
|
||||
STATE_GET_INIT,
|
||||
STATE_GET_LSTAT,
|
||||
STATE_GET_OPEN_REMOTE,
|
||||
STATE_GET_LOOKUP_OFFSET,
|
||||
STATE_GET_OPEN_LOCAL,
|
||||
STATE_GET_READ,
|
||||
STATE_GET_CLOSE_LOCAL,
|
||||
STATE_GET_CLOSE_REMOTE,
|
||||
STATE_GET_CLEANUP
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_GET_STATE {
|
||||
enum WS_SFTP_GET_STATE_ID state;
|
||||
WS_SFTP_FILEATRB attrib;
|
||||
byte handle[WOLFSSH_MAX_HANDLE];
|
||||
WFILE* fl;
|
||||
long gOfst;
|
||||
word32 handleSz;
|
||||
byte r[WOLFSSH_MAX_SFTP_RW];
|
||||
} WS_SFTP_GET_STATE;
|
||||
|
||||
|
||||
static int SendPacketType(WOLFSSH* ssh, byte type, byte* buf, word32 bufSz);
|
||||
static int SFTP_ParseAtributes(WOLFSSH* ssh, WS_SFTP_FILEATRB* atr);
|
||||
static int SFTP_ParseAtributes_buffer(WOLFSSH* ssh, WS_SFTP_FILEATRB* atr,
|
||||
|
@ -3572,47 +3620,100 @@ int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
|
|||
int wolfSSH_SFTP_Open(WOLFSSH* ssh, char* dir, word32 reason,
|
||||
WS_SFTP_FILEATRB* atr, byte* handle, word32* handleSz)
|
||||
{
|
||||
int sz;
|
||||
byte* data;
|
||||
word32 idx;
|
||||
WS_SFTP_OPEN_STATE* state = NULL;
|
||||
int ret = WS_SUCCESS;
|
||||
|
||||
WLOG(WS_LOG_SFTP, "Entering wolfSSH_SFTP_Open()");
|
||||
if (ssh == NULL || dir == NULL) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
sz = (int)WSTRLEN(dir);
|
||||
data = (byte*)WMALLOC(sz + WOLFSSH_SFTP_HEADER + UINT32_SZ * 3 ,
|
||||
ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
if (data == NULL) {
|
||||
return WS_MEMORY_E;
|
||||
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE)
|
||||
ssh->error = WS_SUCCESS;
|
||||
|
||||
if (ssh->openState == NULL) {
|
||||
state = (WS_SFTP_OPEN_STATE*)WMALLOC(sizeof(WS_SFTP_OPEN_STATE),
|
||||
ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||
if (state == NULL) {
|
||||
ssh->error = WS_MEMORY_E;
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WMEMSET(state, 0, sizeof(WS_SFTP_OPEN_STATE));
|
||||
ssh->openState = state;
|
||||
state->state = STATE_OPEN_INIT;
|
||||
}
|
||||
else
|
||||
state = ssh->openState;
|
||||
|
||||
if (SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_OPEN,
|
||||
sz + UINT32_SZ * 3, data) != WS_SUCCESS) {
|
||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
for (;;) {
|
||||
switch (state->state) {
|
||||
case STATE_OPEN_INIT:
|
||||
WLOG(WS_LOG_SFTP, "SFTP OPEN STATE: INIT");
|
||||
state->sz = (int)WSTRLEN(dir);
|
||||
state->data =
|
||||
(byte*)WMALLOC(
|
||||
state->sz + WOLFSSH_SFTP_HEADER + UINT32_SZ * 3,
|
||||
ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
if (state->data == NULL) {
|
||||
ssh->error = WS_MEMORY_E;
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
idx = WOLFSSH_SFTP_HEADER;
|
||||
c32toa(sz, data + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(data + idx, (byte*)dir, sz); idx += sz;
|
||||
c32toa(reason, data + idx); idx += UINT32_SZ;
|
||||
ret = SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_OPEN,
|
||||
state->sz + UINT32_SZ * 3, state->data);
|
||||
if (ret != WS_SUCCESS) {
|
||||
WFREE(state->data, NULL, DYNTYPE_BUFFER);
|
||||
state->data = NULL;
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* @TODO handle adding attributes here */
|
||||
(void)atr;
|
||||
c32toa(0x00000000, data + idx); idx += UINT32_SZ;
|
||||
state->idx = WOLFSSH_SFTP_HEADER;
|
||||
c32toa(state->sz, state->data + state->idx);
|
||||
state->idx += UINT32_SZ;
|
||||
WMEMCPY(state->data + state->idx, (byte*)dir, state->sz);
|
||||
state->idx += state->sz;
|
||||
c32toa(reason, state->data + state->idx);
|
||||
state->idx += UINT32_SZ;
|
||||
|
||||
/* send header and type specific data */
|
||||
if (wolfSSH_stream_send(ssh, data, idx) < 0) {
|
||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
||||
/* @TODO handle adding attributes here */
|
||||
(void)atr;
|
||||
c32toa(0x00000000, state->data + state->idx);
|
||||
state->idx += UINT32_SZ;
|
||||
|
||||
if (wolfSSH_SFTP_GetHandle(ssh, handle, handleSz) != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_SFTP, "Error getting handle");
|
||||
return WS_FATAL_ERROR;
|
||||
state->state = STATE_OPEN_SEND;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_OPEN_SEND:
|
||||
WLOG(WS_LOG_SFTP, "SFTP OPEN STATE: SEND");
|
||||
/* send header and type specific data */
|
||||
ret = wolfSSH_stream_send(ssh, state->data, state->idx);
|
||||
if (ret < 0) {
|
||||
if (ssh->error != WS_WANT_READ &&
|
||||
ssh->error != WS_WANT_WRITE) {
|
||||
|
||||
WFREE(state->data, NULL, DYNTYPE_BUFFER);
|
||||
state->data = NULL;
|
||||
}
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WFREE(state->data, NULL, DYNTYPE_BUFFER);
|
||||
state->data = NULL;
|
||||
state->state = STATE_OPEN_GETHANDLE;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_OPEN_GETHANDLE:
|
||||
WLOG(WS_LOG_SFTP, "SFTP OPEN STATE: GETHANDLE");
|
||||
ret = wolfSSH_SFTP_GetHandle(ssh, handle, handleSz);
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_SFTP, "Error getting handle");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
state->state = STATE_OPEN_CLEANUP;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_OPEN_CLEANUP:
|
||||
WLOG(WS_LOG_SFTP, "SFTP OPEN STATE: CLEANUP");
|
||||
}
|
||||
}
|
||||
|
||||
return WS_SUCCESS;
|
||||
|
@ -4317,84 +4418,83 @@ void wolfSSH_SFTP_Interrupt(WOLFSSH* ssh)
|
|||
int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
|
||||
char* to, byte resume, WS_STATUS_CB* statusCb)
|
||||
{
|
||||
WS_SFTP_GET_STATE* getState = NULL;
|
||||
WS_SFTP_GET_STATE* state = NULL;
|
||||
long sz;
|
||||
int ret = WS_SUCCESS;
|
||||
|
||||
|
||||
if (ssh == NULL || from == NULL || to == NULL) {
|
||||
WLOG(WS_LOG_SFTP, "Entering wolfSSH_SFTP_Get()");
|
||||
if (ssh == NULL || from == NULL || to == NULL)
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE)
|
||||
ssh->error = WS_SUCCESS;
|
||||
|
||||
if (ssh->getState == NULL) {
|
||||
getState = (WS_SFTP_GET_STATE*)WMALLOC(sizeof(WS_SFTP_GET_STATE),
|
||||
state = (WS_SFTP_GET_STATE*)WMALLOC(sizeof(WS_SFTP_GET_STATE),
|
||||
ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||
if (getState == NULL) {
|
||||
if (state == NULL) {
|
||||
ssh->error = WS_MEMORY_E;
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WMEMSET(getState, 0, sizeof(WS_SFTP_GET_STATE));
|
||||
ssh->getState = getState;
|
||||
getState->state = STATE_GET_INIT;
|
||||
WMEMSET(state, 0, sizeof(WS_SFTP_GET_STATE));
|
||||
ssh->getState = state;
|
||||
state->state = STATE_GET_INIT;
|
||||
}
|
||||
else
|
||||
getState = ssh->getState;
|
||||
state = ssh->getState;
|
||||
|
||||
for (;;) {
|
||||
switch (getState->state) {
|
||||
switch (state->state) {
|
||||
|
||||
case STATE_GET_INIT:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: Init");
|
||||
getState->state = STATE_GET_LSTAT;
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: INIT");
|
||||
state->state = STATE_GET_LSTAT;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_LSTAT:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: LSTAT");
|
||||
ret = wolfSSH_SFTP_LSTAT(ssh, from, &getState->attrib);
|
||||
ret = wolfSSH_SFTP_LSTAT(ssh, from, &state->attrib);
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_SFTP, "Error verifying file");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
getState->state = STATE_GET_OPEN_REMOTE;
|
||||
state->handleSz = WOLFSSH_MAX_HANDLE;
|
||||
state->state = STATE_GET_OPEN_REMOTE;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_OPEN_REMOTE:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: OPEN REMOTE");
|
||||
/* open file and get handle */
|
||||
getState->handleSz = WOLFSSH_MAX_HANDLE;
|
||||
ret = wolfSSH_SFTP_Open(ssh, from, WOLFSSH_FXF_READ, NULL,
|
||||
getState->handle, &getState->handleSz);
|
||||
state->handle, &state->handleSz);
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_SFTP, "Error getting handle");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
getState->state = STATE_GET_LOOKUP_OFFSET;
|
||||
state->state = STATE_GET_LOOKUP_OFFSET;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_LOOKUP_OFFSET:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: LOOKUP OFFSET");
|
||||
/* if resuming then check for saved offset */
|
||||
if (resume) {
|
||||
getState->gOfst = (long)wolfSSH_SFTP_GetOfst(ssh, from, to);
|
||||
state->gOfst = (long)wolfSSH_SFTP_GetOfst(ssh, from, to);
|
||||
}
|
||||
getState->state = STATE_GET_OPEN_LOCAL;
|
||||
state->state = STATE_GET_OPEN_LOCAL;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_OPEN_LOCAL:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: OPEN LOCAL");
|
||||
if (getState->gOfst > 0)
|
||||
ret = WFOPEN(&getState->fl, to, "ab");
|
||||
if (state->gOfst > 0)
|
||||
ret = WFOPEN(&state->fl, to, "ab");
|
||||
else
|
||||
ret = WFOPEN(&getState->fl, to, "wb");
|
||||
ret = WFOPEN(&state->fl, to, "wb");
|
||||
if (ret != 0) {
|
||||
WLOG(WS_LOG_SFTP, "Unable to open output file");
|
||||
ssh->error = WS_BAD_FILE_E;
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
getState->state = STATE_GET_READ;
|
||||
state->state = STATE_GET_READ;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_READ:
|
||||
|
@ -4402,45 +4502,45 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
|
|||
ret = WS_SUCCESS;
|
||||
do {
|
||||
sz = wolfSSH_SFTP_SendReadPacket(ssh,
|
||||
getState->handle, getState->handleSz,
|
||||
getState->gOfst, getState->r,
|
||||
state->handle, state->handleSz,
|
||||
state->gOfst, state->r,
|
||||
WOLFSSH_MAX_SFTP_RW);
|
||||
if (sz > 0) {
|
||||
if ((long)WFWRITE(getState->r, 1,
|
||||
sz, getState->fl) != sz) {
|
||||
if ((long)WFWRITE(state->r, 1,
|
||||
sz, state->fl) != sz) {
|
||||
WLOG(WS_LOG_SFTP, "Error writing to file");
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
getState->gOfst += sz;
|
||||
state->gOfst += sz;
|
||||
if (statusCb != NULL) {
|
||||
statusCb(ssh, getState->gOfst, from);
|
||||
statusCb(ssh, state->gOfst, from);
|
||||
}
|
||||
}
|
||||
} while (sz > 0 && ssh->sftpInt == 0);
|
||||
if (ssh->sftpInt) {
|
||||
WLOG(WS_LOG_SFTP, "Interrupted, trying to save offset");
|
||||
wolfSSH_SFTP_SaveOfst(ssh, from, to, getState->gOfst);
|
||||
wolfSSH_SFTP_SaveOfst(ssh, from, to, state->gOfst);
|
||||
}
|
||||
ssh->sftpInt = 0;
|
||||
getState->state = STATE_GET_CLOSE_LOCAL;
|
||||
state->state = STATE_GET_CLOSE_LOCAL;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_CLOSE_LOCAL:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: CLOSE LOCAL");
|
||||
WFCLOSE(getState->fl);
|
||||
getState->state = STATE_GET_CLOSE_REMOTE;
|
||||
WFCLOSE(state->fl);
|
||||
state->state = STATE_GET_CLOSE_REMOTE;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_CLOSE_REMOTE:
|
||||
WLOG(WS_LOG_SFTP, "SFTP GET STATE: CLOSE REMOTE");
|
||||
ret = wolfSSH_SFTP_Close(ssh,
|
||||
getState->handle, getState->handleSz);
|
||||
state->handle, state->handleSz);
|
||||
if (ret != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_SFTP, "Error closing handle");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
getState->state = STATE_GET_CLEANUP;
|
||||
state->state = STATE_GET_CLEANUP;
|
||||
FALL_THROUGH;
|
||||
|
||||
case STATE_GET_CLEANUP:
|
||||
|
|
|
@ -256,49 +256,10 @@ typedef struct SFTP_OFST {
|
|||
char to[WOLFSSH_MAX_FILENAME];
|
||||
} SFTP_OFST;
|
||||
|
||||
#if 0
|
||||
enum WS_SFTP_LSTAT_STATE_ID {
|
||||
STATE_LSTAT_INIT
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_LSTAT_STATE {
|
||||
WS_SFTP_LSTAT_STATE_ID state;
|
||||
} WS_SFTP_LSTAT_STATE;
|
||||
|
||||
enum WS_SFTP_OPEN_STATE_ID {
|
||||
STATE_OPEN_INIT
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_OPEN_STATE {
|
||||
enum WS_SFTP_OPEN_STATE_ID state;
|
||||
} WS_SFTP_OPEN_STATE;
|
||||
#endif
|
||||
|
||||
enum WS_SFTP_GET_STATE_ID {
|
||||
STATE_GET_INIT,
|
||||
STATE_GET_LSTAT,
|
||||
STATE_GET_OPEN_REMOTE,
|
||||
STATE_GET_LOOKUP_OFFSET,
|
||||
STATE_GET_OPEN_LOCAL,
|
||||
STATE_GET_READ,
|
||||
STATE_GET_CLOSE_LOCAL,
|
||||
STATE_GET_CLOSE_REMOTE,
|
||||
STATE_GET_CLEANUP
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_GET_STATE {
|
||||
enum WS_SFTP_GET_STATE_ID state;
|
||||
WS_SFTP_FILEATRB attrib;
|
||||
byte handle[WOLFSSH_MAX_HANDLE];
|
||||
WFILE* fl;
|
||||
long gOfst;
|
||||
word32 handleSz;
|
||||
byte r[WOLFSSH_MAX_SFTP_RW];
|
||||
#if 0
|
||||
WS_SFTP_LSTAT_STATE lstatState;
|
||||
WS_SFTP_OPEN_STATE openState;
|
||||
#endif
|
||||
} WS_SFTP_GET_STATE;
|
||||
struct WS_SFTP_GET_STATE;
|
||||
struct WS_SFTP_LSTAT_STATE;
|
||||
struct WS_SFTP_OPEN_STATE;
|
||||
|
||||
#endif /* WOLFSSH_SFTP */
|
||||
|
||||
|
@ -428,7 +389,9 @@ struct WOLFSSH {
|
|||
#ifdef WOLFSSH_STOREHANDLE
|
||||
WS_HANDLE_LIST* handleList;
|
||||
#endif
|
||||
WS_SFTP_GET_STATE* getState;
|
||||
struct WS_SFTP_GET_STATE* getState;
|
||||
struct WS_SFTP_LSTAT_STATE* lstatState;
|
||||
struct WS_SFTP_OPEN_STATE* openState;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue