SCP: let the application start the transfer

An application that binds an "scp ..." command to a channel itself has no
way to run the transfer; wolfSSH_accept() did it through a WS_SCP_INIT
re-entry only that state machine can drive.

- add wolfSSH_SCP_accept(), a wrapper over DoScpRequest() reporting
  WS_SCP_COMPLETE for any non-negative result, as accept() does
- a receive-side want reaches the wrapper as a generic error with the
  want in ssh->error, so report the want itself and let the caller retry
- state that resume contract beside the prototype, and clear a stale want
  on entry the way the other re-entrant entry points do
pull/1245/head
John Safranek 2026-09-02 09:42:42 -07:00 committed by philljj
parent ba6bc667a9
commit 13b9e39f90
2 changed files with 45 additions and 0 deletions

View File

@ -883,6 +883,40 @@ int DoScpSource(WOLFSSH* ssh)
return ret;
}
/* Contract is in wolfssh/wolfscp.h. */
int wolfSSH_SCP_accept(WOLFSSH* ssh)
{
int ret;
if (ssh == NULL)
return WS_BAD_ARGUMENT;
/* Clear a want left by the previous call so the retry starts clean,
* the way the other re-entrant entry points do. */
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE)
ssh->error = WS_SUCCESS;
ret = DoScpRequest(ssh);
if (ret >= WS_SUCCESS) {
/* The tail of DoScpRequest() passes a read count through, so treat
* anything non-negative as done the way wolfSSH_accept() does. */
ret = WS_SCP_COMPLETE;
}
else {
/* A non-blocking want on a read path surfaces as a generic error
* with the want recorded in ssh->error (see GetInputData), so
* report it as the want the caller is told to retry on. */
int err = wolfSSH_get_error(ssh);
if (err == WS_WANT_READ || err == WS_WANT_WRITE)
ret = err;
}
return ret;
}
int DoScpRequest(WOLFSSH* ssh)
{
int ret = WS_SUCCESS;

View File

@ -158,6 +158,17 @@ WOLFSSH_API int wolfSSH_SCP_to(WOLFSSH* ssh, const char* src,
const char* dst);
WOLFSSH_API int wolfSSH_SCP_from(WOLFSSH* ssh, const char* src,
const char* dst);
/* Server side. Drives an SCP transfer on a channel whose "exec scp ..."
* command is already bound. This is the same work wolfSSH_accept() does
* through its WS_SCP_INIT re-entry, exposed so an application can start the
* transfer itself; use one or the other, not both. Call it once
* wolfSSH_accept() has returned and the exec channel-request callback has
* reported an SCP command, not from inside that callback.
*
* Returns WS_SCP_COMPLETE when the transfer is done. On a non-blocking
* socket it returns WS_WANT_READ or WS_WANT_WRITE with the transfer part
* done; call it again on the same session until it completes. */
WOLFSSH_API int wolfSSH_SCP_accept(WOLFSSH* ssh);
#ifdef __cplusplus