gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnurl] 24/282: wolfSSH: new SSH backend


From: gnunet
Subject: [gnurl] 24/282: wolfSSH: new SSH backend
Date: Wed, 01 Apr 2020 14:28:09 +0200

This is an automated email from the git hooks/post-receive script.

ng0 pushed a commit to branch master
in repository gnurl.

commit 6773c7ca65cf2183295e56603f9b86a5ce816a06
Author: Daniel Stenberg <address@hidden>
AuthorDate: Sun Jan 5 10:51:39 2020 +0100

    wolfSSH: new SSH backend
    
    Adds support for SFTP (not SCP) using WolfSSH.
    
    Closes #4231
---
 configure.ac       |   40 +-
 lib/Makefile.inc   |    2 +-
 lib/easy.c         |   13 +-
 lib/url.c          |    4 +-
 lib/version.c      |    6 +-
 lib/vssh/ssh.h     |   22 +-
 lib/vssh/wolfssh.c | 1150 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/vssh/wolfssh.h |   27 ++
 8 files changed, 1247 insertions(+), 17 deletions(-)

diff --git a/configure.ac b/configure.ac
index dd149b7e3..5d8215c59 100755
--- a/configure.ac
+++ b/configure.ac
@@ -2795,17 +2795,23 @@ dnl 
**********************************************************************
 dnl Default to compiler & linker defaults for LIBSSH2 files & libraries.
 OPT_LIBSSH2=off
 AC_ARG_WITH(libssh2,dnl
-AC_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points 
to the LIBSSH2 installation; when possible, set the PKG_CONFIG_PATH environment 
variable instead of using this option])
-AC_HELP_STRING([--with-libssh2], [enable LIBSSH2]),
+AC_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points 
to the libssh2 installation; when possible, set the PKG_CONFIG_PATH environment 
variable instead of using this option])
+AC_HELP_STRING([--with-libssh2], [enable libssh2]),
   OPT_LIBSSH2=$withval, OPT_LIBSSH2=no)
 
 
 OPT_LIBSSH=off
 AC_ARG_WITH(libssh,dnl
-AC_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to 
the LIBSSH installation; when possible, set the PKG_CONFIG_PATH environment 
variable instead of using this option])
-AC_HELP_STRING([--with-libssh], [enable LIBSSH]),
+AC_HELP_STRING([--with-libssh=PATH],[Where to look for libssh, PATH points to 
the libssh installation; when possible, set the PKG_CONFIG_PATH environment 
variable instead of using this option])
+AC_HELP_STRING([--with-libssh], [enable libssh]),
   OPT_LIBSSH=$withval, OPT_LIBSSH=no)
 
+OPT_WOLFSSH=off
+AC_ARG_WITH(wolfssh,dnl
+AC_HELP_STRING([--with-wolfssh=PATH],[Where to look for wolfssh, PATH points 
to the wolfSSH installation; when possible, set the PKG_CONFIG_PATH environment 
variable instead of using this option])
+AC_HELP_STRING([--with-wolfssh], [enable wolfssh]),
+  OPT_WOLFSSH=$withval, OPT_WOLFSSH=no)
+
 if test X"$OPT_LIBSSH2" != Xno; then
   dnl backup the pre-libssh2 variables
   CLEANLDFLAGS="$LDFLAGS"
@@ -2952,6 +2958,28 @@ elif test X"$OPT_LIBSSH" != Xno; then
     CPPFLAGS=$CLEANCPPFLAGS
     LIBS=$CLEANLIBS
   fi
+elif test X"$OPT_WOLFSSH" != Xno; then
+  dnl backup the pre-wolfssh variables
+  CLEANLDFLAGS="$LDFLAGS"
+  CLEANCPPFLAGS="$CPPFLAGS"
+  CLEANLIBS="$LIBS"
+
+
+  if test "$OPT_WOLFSSH" != yes; then
+     WOLFCONFIG="$OPT_WOLFSSH/bin/wolfssh-config"
+     LDFLAGS="$LDFLAGS `$WOLFCONFIG --libs`"
+     CPPFLAGS="$CPPFLAGS `$WOLFCONFIG --cflags`"
+  fi
+
+  AC_CHECK_LIB(wolfssh, wolfSSH_Init)
+
+  AC_CHECK_HEADERS(wolfssh/ssh.h,
+    curl_ssh_msg="enabled (wolfSSH)"
+    WOLFSSH_ENABLED=1
+    AC_DEFINE(USE_WOLFSSH, 1, [if wolfSSH is in use])
+    AC_SUBST(USE_WOLFSSH, [1])
+  )
+
 fi
 
 dnl **********************************************************************
@@ -4761,6 +4789,10 @@ if test "x$USE_LIBSSH" = "x1"; then
   SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
   SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
 fi
+if test "x$USE_WOLFSSH" = "x1"; then
+  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
+  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
+fi
 if test "x$CURL_DISABLE_RTSP" != "x1"; then
   SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP"
 fi
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 6c90c2675..4e19ea90c 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -42,7 +42,7 @@ LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c
 
 LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h
 
-LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c
+LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c
 
 LIB_VSSH_HFILES = vssh/ssh.h
 
diff --git a/lib/easy.c b/lib/easy.c
index 6382cee3d..9211bc219 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -193,6 +193,13 @@ static CURLcode global_init(long flags, bool memoryfuncs)
   }
 #endif
 
+#ifdef USE_WOLFSSH
+  if(WS_SUCCESS != wolfSSH_Init()) {
+    DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
+#endif
+
   if(flags & CURL_GLOBAL_ACK_EINTR)
     Curl_ack_eintr = 1;
 
@@ -272,6 +279,10 @@ void curl_global_cleanup(void)
 
   Curl_ssh_cleanup();
 
+#ifdef USE_WOLFSSH
+  (void)wolfSSH_Cleanup();
+#endif
+
   init_flags  = 0;
 }
 
diff --git a/lib/url.c b/lib/url.c
index 56fb73636..4797b5182 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -187,7 +187,7 @@ static const struct Curl_handler * const protocols[] = {
   &Curl_handler_tftp,
 #endif
 
-#if defined(USE_SSH)
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
   &Curl_handler_scp,
 #endif
 
diff --git a/lib/version.c b/lib/version.c
index 6405d369d..77aca7cbe 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -265,8 +265,10 @@ static const char * const protocols[] = {
 #ifndef CURL_DISABLE_RTSP
   "rtsp",
 #endif
-#if defined(USE_SSH)
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
   "scp",
+#endif
+#ifdef USE_SSH
   "sftp",
 #endif
 #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h
index 3213c5a52..0d4ee521d 100644
--- a/lib/vssh/ssh.h
+++ b/lib/vssh/ssh.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -30,7 +30,10 @@
 #elif defined(HAVE_LIBSSH_LIBSSH_H)
 #include <libssh/libssh.h>
 #include <libssh/sftp.h>
-#endif /* HAVE_LIBSSH2_H */
+#elif defined(USE_WOLFSSH)
+#include <wolfssh/ssh.h>
+#include <wolfssh/wolfsftp.h>
+#endif
 
 /****************************************************************************
  * SSH unique setup
@@ -188,6 +191,12 @@ struct ssh_conn {
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
   LIBSSH2_KNOWNHOSTS *kh;
 #endif
+#elif defined(USE_WOLFSSH)
+  WOLFSSH *ssh_session;
+  WOLFSSH_CTX *ctx;
+  word32 handleSz;
+  byte handle[WOLFSSH_MAX_HANDLE];
+  curl_off_t offset;
 #endif /* USE_LIBSSH */
 };
 
@@ -195,9 +204,6 @@ struct ssh_conn {
 
 #define CURL_LIBSSH_VERSION ssh_version(0)
 
-extern const struct Curl_handler Curl_handler_scp;
-extern const struct Curl_handler Curl_handler_sftp;
-
 #elif defined(USE_LIBSSH2)
 
 /* Feature detection based on version numbers to better work with
@@ -237,11 +243,13 @@ extern const struct Curl_handler Curl_handler_sftp;
 #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
 #endif
 
-extern const struct Curl_handler Curl_handler_scp;
-extern const struct Curl_handler Curl_handler_sftp;
 #endif /* USE_LIBSSH2 */
 
 #ifdef USE_SSH
+
+extern const struct Curl_handler Curl_handler_scp;
+extern const struct Curl_handler Curl_handler_sftp;
+
 /* generic SSH backend functions */
 CURLcode Curl_ssh_init(void);
 void Curl_ssh_cleanup(void);
diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c
new file mode 100644
index 000000000..e2daf0c0a
--- /dev/null
+++ b/lib/vssh/wolfssh.c
@@ -0,0 +1,1150 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2019 - 2020, Daniel Stenberg, <address@hidden>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WOLFSSH
+
+#include <limits.h>
+
+#include <wolfssh/ssh.h>
+#include <wolfssh/wolfsftp.h>
+#include "urldata.h"
+#include "connect.h"
+#include "sendf.h"
+#include "progress.h"
+#include "curl_path.h"
+#include "strtoofft.h"
+#include "transfer.h"
+#include "speedcheck.h"
+#include "select.h"
+#include "multiif.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static CURLcode wssh_connect(struct connectdata *conn, bool *done);
+static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode wssh_do(struct connectdata *conn, bool *done);
+#if 0
+static CURLcode wscp_done(struct connectdata *conn,
+                          CURLcode, bool premature);
+static CURLcode wscp_doing(struct connectdata *conn,
+                           bool *dophase_done);
+static CURLcode wscp_disconnect(struct connectdata *conn,
+                                bool dead_connection);
+#endif
+static CURLcode wsftp_done(struct connectdata *conn,
+                           CURLcode, bool premature);
+static CURLcode wsftp_doing(struct connectdata *conn,
+                            bool *dophase_done);
+static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead);
+static int wssh_getsock(struct connectdata *conn,
+                        curl_socket_t *sock);
+static int wssh_perform_getsock(const struct connectdata *conn,
+                                curl_socket_t *sock);
+static CURLcode wssh_setup_connection(struct connectdata *conn);
+
+#if 0
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+  "SCP",                                /* scheme */
+  wssh_setup_connection,                /* setup_connection */
+  wssh_do,                              /* do_it */
+  wscp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  wssh_connect,                         /* connect_it */
+  wssh_multi_statemach,                 /* connecting */
+  wscp_doing,                           /* doing */
+  wssh_getsock,                         /* proto_getsock */
+  wssh_getsock,                         /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  wssh_perform_getsock,                 /* perform_getsock */
+  wscp_disconnect,                      /* disconnect */
+  ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SCP,                        /* protocol */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+#endif
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+  "SFTP",                               /* scheme */
+  wssh_setup_connection,                /* setup_connection */
+  wssh_do,                              /* do_it */
+  wsftp_done,                           /* done */
+  ZERO_NULL,                            /* do_more */
+  wssh_connect,                         /* connect_it */
+  wssh_multi_statemach,                 /* connecting */
+  wsftp_doing,                          /* doing */
+  wssh_getsock,                         /* proto_getsock */
+  wssh_getsock,                         /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  wssh_perform_getsock,                 /* perform_getsock */
+  wsftp_disconnect,                     /* disconnect */
+  ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
+  PORT_SSH,                             /* defport */
+  CURLPROTO_SFTP,                       /* protocol */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
+};
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void state(struct connectdata *conn, sshstate nowstate)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "SSH_STOP",
+    "SSH_INIT",
+    "SSH_S_STARTUP",
+    "SSH_HOSTKEY",
+    "SSH_AUTHLIST",
+    "SSH_AUTH_PKEY_INIT",
+    "SSH_AUTH_PKEY",
+    "SSH_AUTH_PASS_INIT",
+    "SSH_AUTH_PASS",
+    "SSH_AUTH_AGENT_INIT",
+    "SSH_AUTH_AGENT_LIST",
+    "SSH_AUTH_AGENT",
+    "SSH_AUTH_HOST_INIT",
+    "SSH_AUTH_HOST",
+    "SSH_AUTH_KEY_INIT",
+    "SSH_AUTH_KEY",
+    "SSH_AUTH_GSSAPI",
+    "SSH_AUTH_DONE",
+    "SSH_SFTP_INIT",
+    "SSH_SFTP_REALPATH",
+    "SSH_SFTP_QUOTE_INIT",
+    "SSH_SFTP_POSTQUOTE_INIT",
+    "SSH_SFTP_QUOTE",
+    "SSH_SFTP_NEXT_QUOTE",
+    "SSH_SFTP_QUOTE_STAT",
+    "SSH_SFTP_QUOTE_SETSTAT",
+    "SSH_SFTP_QUOTE_SYMLINK",
+    "SSH_SFTP_QUOTE_MKDIR",
+    "SSH_SFTP_QUOTE_RENAME",
+    "SSH_SFTP_QUOTE_RMDIR",
+    "SSH_SFTP_QUOTE_UNLINK",
+    "SSH_SFTP_QUOTE_STATVFS",
+    "SSH_SFTP_GETINFO",
+    "SSH_SFTP_FILETIME",
+    "SSH_SFTP_TRANS_INIT",
+    "SSH_SFTP_UPLOAD_INIT",
+    "SSH_SFTP_CREATE_DIRS_INIT",
+    "SSH_SFTP_CREATE_DIRS",
+    "SSH_SFTP_CREATE_DIRS_MKDIR",
+    "SSH_SFTP_READDIR_INIT",
+    "SSH_SFTP_READDIR",
+    "SSH_SFTP_READDIR_LINK",
+    "SSH_SFTP_READDIR_BOTTOM",
+    "SSH_SFTP_READDIR_DONE",
+    "SSH_SFTP_DOWNLOAD_INIT",
+    "SSH_SFTP_DOWNLOAD_STAT",
+    "SSH_SFTP_CLOSE",
+    "SSH_SFTP_SHUTDOWN",
+    "SSH_SCP_TRANS_INIT",
+    "SSH_SCP_UPLOAD_INIT",
+    "SSH_SCP_DOWNLOAD_INIT",
+    "SSH_SCP_DOWNLOAD",
+    "SSH_SCP_DONE",
+    "SSH_SCP_SEND_EOF",
+    "SSH_SCP_WAIT_EOF",
+    "SSH_SCP_WAIT_CLOSE",
+    "SSH_SCP_CHANNEL_FREE",
+    "SSH_SESSION_DISCONNECT",
+    "SSH_SESSION_FREE",
+    "QUIT"
+  };
+
+  /* a precaution to make sure the lists are in sync */
+  DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
+
+  if(sshc->state != nowstate) {
+    infof(conn->data, "wolfssh %p state change from %s to %s\n",
+          (void *)sshc, names[sshc->state], names[nowstate]);
+  }
+#endif
+
+  sshc->state = nowstate;
+}
+
+static ssize_t wscp_send(struct connectdata *conn, int sockindex,
+                         const void *mem, size_t len, CURLcode *err)
+{
+  ssize_t nwrite = 0;
+  (void)conn;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+  (void)mem;
+  (void)len;
+  (void)err;
+
+  return nwrite;
+}
+
+static ssize_t wscp_recv(struct connectdata *conn, int sockindex,
+                         char *mem, size_t len, CURLcode *err)
+{
+  ssize_t nread = 0;
+  (void)conn;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+  (void)mem;
+  (void)len;
+  (void)err;
+
+  return nread;
+}
+
+/* return number of sent bytes */
+static ssize_t wsftp_send(struct connectdata *conn, int sockindex,
+                          const void *mem, size_t len, CURLcode *err)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  word32 offset[2];
+  int rc;
+  (void)sockindex;
+
+  offset[0] =  (word32)sshc->offset&0xFFFFFFFF;
+  offset[1] =  (word32)(sshc->offset>>32)&0xFFFFFFFF;
+
+  rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle,
+                                    sshc->handleSz,
+                                    &offset[0],
+                                    (byte *)mem, (word32)len);
+
+  if(rc == WS_FATAL_ERROR)
+    rc = wolfSSH_get_error(sshc->ssh_session);
+  if(rc == WS_WANT_READ) {
+    conn->waitfor = KEEP_RECV;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  else if(rc == WS_WANT_WRITE) {
+    conn->waitfor = KEEP_SEND;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  if(rc < 0) {
+    failf(conn->data, "wolfSSH_SFTP_SendWritePacket returned %d\n", rc);
+    return -1;
+  }
+  DEBUGASSERT(rc == (int)len);
+  infof(conn->data, "sent %zd bytes SFTP from offset %zd\n",
+        len, sshc->offset);
+  sshc->offset += len;
+  return (ssize_t)rc;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ * or <0 on error
+ */
+static ssize_t wsftp_recv(struct connectdata *conn, int sockindex,
+                          char *mem, size_t len, CURLcode *err)
+{
+  int rc;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  word32 offset[2];
+  (void)sockindex;
+
+  offset[0] =  (word32)sshc->offset&0xFFFFFFFF;
+  offset[1] =  (word32)(sshc->offset>>32)&0xFFFFFFFF;
+
+  rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle,
+                                   sshc->handleSz,
+                                   &offset[0],
+                                   (byte *)mem, (word32)len);
+  if(rc == WS_FATAL_ERROR)
+    rc = wolfSSH_get_error(sshc->ssh_session);
+  if(rc == WS_WANT_READ) {
+    conn->waitfor = KEEP_RECV;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+  else if(rc == WS_WANT_WRITE) {
+    conn->waitfor = KEEP_SEND;
+    *err = CURLE_AGAIN;
+    return -1;
+  }
+
+  DEBUGASSERT(rc <= (int)len);
+
+  if(rc < 0) {
+    failf(conn->data, "wolfSSH_SFTP_SendReadPacket returned %d\n", rc);
+    return -1;
+  }
+  sshc->offset += len;
+
+  return (ssize_t)rc;
+}
+
+/*
+ * SSH setup and connection
+ */
+static CURLcode wssh_setup_connection(struct connectdata *conn)
+{
+  struct SSHPROTO *ssh;
+
+  conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
+  if(!ssh)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static Curl_recv wscp_recv, wsftp_recv;
+static Curl_send wscp_send, wsftp_send;
+
+static int userauth(byte authtype,
+                    WS_UserAuthData* authdata,
+                    void *ctx)
+{
+  struct connectdata *conn = ctx;
+  word32 plen = (word32) strlen(conn->passwd);
+  fprintf(stderr, "wolfssh callback: %s type %s\n", __func__,
+          authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" :
+          "PUBLICCKEY");
+  authdata->sf.password.password = (byte *)conn->user;
+  authdata->sf.password.passwordSz = plen;
+
+  return 0;
+}
+
+static CURLcode wssh_connect(struct connectdata *conn, bool *done)
+{
+  struct Curl_easy *data = conn->data;
+  struct ssh_conn *sshc;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc;
+
+  /* initialize per-handle data if not already */
+  if(!data->req.protop)
+    wssh_setup_connection(conn);
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the re-use checks properly be able to check this bit. */
+  connkeep(conn, "SSH default");
+
+  if(conn->handler->protocol & CURLPROTO_SCP) {
+    conn->recv[FIRSTSOCKET] = wscp_recv;
+    conn->send[FIRSTSOCKET] = wscp_send;
+  }
+  else {
+    conn->recv[FIRSTSOCKET] = wsftp_recv;
+    conn->send[FIRSTSOCKET] = wsftp_send;
+  }
+  sshc = &conn->proto.sshc;
+  sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
+  if(!sshc->ctx) {
+    failf(data, "No wolfSSH context");
+    goto error;
+  }
+
+  sshc->ssh_session = wolfSSH_new(sshc->ctx);
+  if(sshc->ssh_session == NULL) {
+    failf(data, "No wolfSSH session");
+    goto error;
+  }
+
+  rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user);
+  if(rc != WS_SUCCESS) {
+    failf(data, "wolfSSH failed to set user name");
+    goto error;
+  }
+
+  /* set callback for authentication */
+  wolfSSH_SetUserAuth(sshc->ctx, userauth);
+  wolfSSH_SetUserAuthCtx(sshc->ssh_session, conn);
+
+  rc = wolfSSH_set_fd(sshc->ssh_session, (int)sock);
+  if(rc) {
+    failf(data, "wolfSSH failed to set socket");
+    goto error;
+  }
+
+#if 0
+  wolfSSH_Debugging_ON();
+#endif
+
+  *done = TRUE;
+  if(conn->handler->protocol & CURLPROTO_SCP)
+    state(conn, SSH_INIT);
+  else
+    state(conn, SSH_SFTP_INIT);
+
+  return wssh_multi_statemach(conn, done);
+  error:
+  wolfSSH_free(sshc->ssh_session);
+  wolfSSH_CTX_free(sshc->ctx);
+  return CURLE_FAILED_INIT;
+}
+
+/*
+ * wssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end.  The data the pointer 'block' points
+ * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it
+ * wants to be called again when the socket is ready
+ */
+
+static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block)
+{
+  CURLcode result = CURLE_OK;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  struct Curl_easy *data = conn->data;
+  struct SSHPROTO *sftp_scp = data->req.protop;
+  WS_SFTPNAME *name;
+  int rc = 0;
+  *block = FALSE; /* we're not blocking by default */
+
+  do {
+    switch(sshc->state) {
+    case SSH_INIT:
+      state(conn, SSH_S_STARTUP);
+      /* FALLTHROUGH */
+    case SSH_S_STARTUP:
+      rc = wolfSSH_connect(sshc->ssh_session);
+      if(rc != WS_SUCCESS)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc != WS_SUCCESS) {
+        state(conn, SSH_STOP);
+        return CURLE_SSH;
+      }
+      infof(data, "wolfssh connected!\n");
+      state(conn, SSH_STOP);
+      break;
+    case SSH_STOP:
+      break;
+
+    case SSH_SFTP_INIT:
+      rc = wolfSSH_SFTP_connect(sshc->ssh_session);
+      if(rc != WS_SUCCESS)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh SFTP connected!\n");
+        state(conn, SSH_SFTP_REALPATH);
+      }
+      else {
+        failf(data, "wolfssh SFTP connect error %d", rc);
+        return CURLE_SSH;
+      }
+      break;
+    case SSH_SFTP_REALPATH:
+      name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)".");
+      rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(name && (rc == WS_SUCCESS)) {
+        sshc->homedir = malloc(name->fSz + 1);
+        if(!sshc->homedir) {
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        }
+        else {
+          memcpy(sshc->homedir, name->fName, name->fSz);
+          sshc->homedir[name->fSz] = 0;
+          infof(data, "wolfssh SFTP realpath succeeded!\n");
+        }
+        wolfSSH_SFTPNAME_list_free(name);
+        state(conn, SSH_STOP);
+        return CURLE_OK;
+      }
+      failf(data, "wolfssh SFTP realpath %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_QUOTE_INIT:
+      result = Curl_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(conn, SSH_STOP);
+        break;
+      }
+
+      if(data->set.quote) {
+        infof(data, "Sending quote commands\n");
+        sshc->quote_item = data->set.quote;
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(conn, SSH_SFTP_GETINFO);
+      }
+      break;
+    case SSH_SFTP_GETINFO:
+      if(data->set.get_filetime) {
+        state(conn, SSH_SFTP_FILETIME);
+      }
+      else {
+        state(conn, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+    case SSH_SFTP_TRANS_INIT:
+      if(data->set.upload)
+        state(conn, SSH_SFTP_UPLOAD_INIT);
+      else {
+        if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+          state(conn, SSH_SFTP_READDIR_INIT);
+        else
+          state(conn, SSH_SFTP_DOWNLOAD_INIT);
+      }
+      break;
+    case SSH_SFTP_UPLOAD_INIT: {
+      word32 flags;
+      WS_SFTP_FILEATRB createattrs;
+      if(data->state.resume_from) {
+        WS_SFTP_FILEATRB attrs;
+        if(data->state.resume_from < 0) {
+          rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path,
+                                 &attrs);
+          if(rc != WS_SUCCESS)
+            break;
+
+          if(rc) {
+            data->state.resume_from = 0;
+          }
+          else {
+            curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0];
+            if(size < 0) {
+              failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+              return CURLE_BAD_DOWNLOAD_RESUME;
+            }
+            data->state.resume_from = size;
+          }
+        }
+      }
+
+      if(data->set.ftp_append)
+        /* Try to open for append, but create if nonexisting */
+        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND;
+      else if(data->state.resume_from > 0)
+        /* If we have restart position then open for append */
+        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND;
+      else
+        /* Clear file before writing (normal behaviour) */
+        flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC;
+
+      memset(&createattrs, 0, sizeof(createattrs));
+      createattrs.per = (word32)data->set.new_file_perms;
+      sshc->handleSz = sizeof(sshc->handle);
+      rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path,
+                             flags, &createattrs,
+                             sshc->handle, &sshc->handleSz);
+      if(rc == WS_FATAL_ERROR)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh SFTP open succeeded!\n");
+      }
+      else {
+        failf(data, "wolfssh SFTP upload open failed: %d", rc);
+        return CURLE_SSH;
+      }
+      state(conn, SSH_SFTP_DOWNLOAD_STAT);
+
+      /* If we have a restart point then we need to seek to the correct
+         position. */
+      if(data->state.resume_from > 0) {
+        /* Let's read off the proper amount of bytes from the input. */
+        int seekerr = CURL_SEEKFUNC_OK;
+        if(conn->seek_func) {
+          Curl_set_in_callback(data, true);
+          seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+                                    SEEK_SET);
+          Curl_set_in_callback(data, false);
+        }
+
+        if(seekerr != CURL_SEEKFUNC_OK) {
+          curl_off_t passed = 0;
+
+          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+            failf(data, "Could not seek stream");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+          do {
+            size_t readthisamountnow =
+              (data->state.resume_from - passed > data->set.buffer_size) ?
+              (size_t)data->set.buffer_size :
+              curlx_sotouz(data->state.resume_from - passed);
+
+            size_t actuallyread;
+            Curl_set_in_callback(data, true);
+            actuallyread = data->state.fread_func(data->state.buffer, 1,
+                                                  readthisamountnow,
+                                                  data->state.in);
+            Curl_set_in_callback(data, false);
+
+            passed += actuallyread;
+            if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+              /* this checks for greater-than only to make sure that the
+                 CURL_READFUNC_ABORT return code still aborts */
+              failf(data, "Failed to read data");
+              return CURLE_FTP_COULDNT_USE_REST;
+            }
+          } while(passed < data->state.resume_from);
+        }
+
+        /* now, decrease the size of the read */
+        if(data->state.infilesize > 0) {
+          data->state.infilesize -= data->state.resume_from;
+          data->req.size = data->state.infilesize;
+          Curl_pgrsSetUploadSize(data, data->state.infilesize);
+        }
+
+        sshc->offset += data->state.resume_from;
+      }
+      if(data->state.infilesize > 0) {
+        data->req.size = data->state.infilesize;
+        Curl_pgrsSetUploadSize(data, data->state.infilesize);
+      }
+      /* upload data */
+      Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
+
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      if(result) {
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        /* store this original bitmask setup to use later on if we can't
+           figure out a "real" bitmask */
+        sshc->orig_waitfor = data->req.keepon;
+
+        /* we want to use the _sending_ function even when the socket turns
+           out readable as the underlying libssh2 sftp send function will deal
+           with both accordingly */
+        conn->cselect_bits = CURL_CSELECT_OUT;
+
+        /* since we don't really wait for anything at this point, we want the
+           state machine to move on as soon as possible so we set a very short
+           timeout here */
+        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+        state(conn, SSH_STOP);
+      }
+      break;
+    }
+    case SSH_SFTP_DOWNLOAD_INIT:
+      sshc->handleSz = sizeof(sshc->handle);
+      rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path,
+                             WOLFSSH_FXF_READ, NULL,
+                             sshc->handle, &sshc->handleSz);
+      if(rc == WS_FATAL_ERROR)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh SFTP open succeeded!\n");
+        state(conn, SSH_SFTP_DOWNLOAD_STAT);
+        return CURLE_OK;
+      }
+
+      failf(data, "wolfssh SFTP open failed: %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_DOWNLOAD_STAT: {
+      WS_SFTP_FILEATRB attrs;
+      curl_off_t size;
+
+      rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, &attrs);
+      if(rc == WS_FATAL_ERROR)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        infof(data, "wolfssh STAT succeeded!\n");
+      }
+      else {
+        failf(data, "wolfssh SFTP open failed: %d", rc);
+        data->req.size = -1;
+        data->req.maxdownload = -1;
+        Curl_pgrsSetDownloadSize(data, -1);
+        return CURLE_SSH;
+      }
+
+      size = ((curl_off_t)attrs.sz[1] <<32) | attrs.sz[0];
+
+      data->req.size = size;
+      data->req.maxdownload = size;
+      Curl_pgrsSetDownloadSize(data, size);
+
+      infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes\n", size);
+
+      /* We cannot seek with wolfSSH so resuming and range requests are not
+         possible */
+      if(conn->data->state.use_range || data->state.resume_from) {
+        infof(data, "wolfSSH cannot do range/seek on SFTP\n");
+        return CURLE_BAD_DOWNLOAD_RESUME;
+      }
+
+      /* Setup the actual download */
+      if(data->req.size == 0) {
+        /* no data to transfer */
+        Curl_setup_transfer(data, -1, -1, FALSE, -1);
+        infof(data, "File already completely downloaded\n");
+        state(conn, SSH_STOP);
+        break;
+      }
+      Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
+
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
+
+      /* we want to use the _receiving_ function even when the socket turns
+         out writableable as the underlying libssh2 recv function will deal
+         with both accordingly */
+      conn->cselect_bits = CURL_CSELECT_IN;
+
+      if(result) {
+        /* this should never occur; the close state should be entered
+           at the time the error occurs */
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        state(conn, SSH_STOP);
+      }
+      break;
+    }
+    case SSH_SFTP_CLOSE:
+      if(sshc->handleSz)
+        rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle,
+                                sshc->handleSz);
+      else
+        rc = WS_SUCCESS; /* directory listing */
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(rc == WS_SUCCESS) {
+        state(conn, SSH_STOP);
+        return CURLE_OK;
+      }
+
+      failf(data, "wolfssh SFTP CLOSE failed: %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_READDIR_INIT:
+      Curl_pgrsSetDownloadSize(data, -1);
+      if(data->set.opt_no_body) {
+        state(conn, SSH_STOP);
+        break;
+      }
+      state(conn, SSH_SFTP_READDIR);
+      /* FALLTHROUGH */
+    case SSH_SFTP_READDIR:
+      name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
+      if(!name)
+        rc = wolfSSH_get_error(sshc->ssh_session);
+      else
+        rc = WS_SUCCESS;
+
+      if(rc == WS_WANT_READ) {
+        *block = TRUE;
+        conn->waitfor = KEEP_RECV;
+        return CURLE_OK;
+      }
+      else if(rc == WS_WANT_WRITE) {
+        *block = TRUE;
+        conn->waitfor = KEEP_SEND;
+        return CURLE_OK;
+      }
+      else if(name && (rc == WS_SUCCESS)) {
+        WS_SFTPNAME *origname = name;
+        result = CURLE_OK;
+        while(name) {
+          char *line = aprintf("%s\n",
+                               data->set.ftp_list_only ?
+                               name->fName : name->lName);
+          if(line == NULL) {
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                     line, strlen(line));
+          free(line);
+          if(result) {
+            sshc->actualcode = result;
+            break;
+          }
+          name = name->next;
+        }
+        wolfSSH_SFTPNAME_list_free(origname);
+        state(conn, SSH_STOP);
+        return result;
+      }
+      failf(data, "wolfssh SFTP ls failed: %d", rc);
+      return CURLE_SSH;
+
+    case SSH_SFTP_SHUTDOWN:
+      Curl_safefree(sshc->homedir);
+      wolfSSH_free(sshc->ssh_session);
+      wolfSSH_CTX_free(sshc->ctx);
+      state(conn, SSH_STOP);
+      return CURLE_OK;
+    default:
+      break;
+    }
+  } while(!rc && (sshc->state != SSH_STOP));
+  return result;
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode wssh_multi_statemach(struct connectdata *conn, bool *done)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+  bool block; /* we store the status and use that to provide a ssh_getsock()
+                 implementation */
+  do {
+    result = wssh_statemach_act(conn, &block);
+    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+    /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
+       try again */
+    if(*done) {
+      fprintf(stderr, "%s says DONE\n", __func__);
+    }
+  } while(!result && !*done && !block);
+
+  return result;
+}
+
+static
+CURLcode wscp_perform(struct connectdata *conn,
+                      bool *connected,
+                      bool *dophase_done)
+{
+  (void)conn;
+  (void)connected;
+  (void)dophase_done;
+  return CURLE_OK;
+}
+
+static
+CURLcode wsftp_perform(struct connectdata *conn,
+                       bool *connected,
+                       bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(conn, SSH_SFTP_QUOTE_INIT);
+
+  /* run the state-machine */
+  result = wssh_multi_statemach(conn, dophase_done);
+
+  *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+
+  return result;
+}
+
+/*
+ * The DO function is generic for both protocols.
+ */
+static CURLcode wssh_do(struct connectdata *conn, bool *done)
+{
+  CURLcode result;
+  bool connected = 0;
+  struct Curl_easy *data = conn->data;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  *done = FALSE; /* default to false */
+  data->req.size = -1; /* make sure this is unknown at this point */
+  sshc->actualcode = CURLE_OK; /* reset error code */
+  sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
+                                   variable */
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, -1);
+  Curl_pgrsSetDownloadSize(data, -1);
+
+  if(conn->handler->protocol & CURLPROTO_SCP)
+    result = wscp_perform(conn, &connected,  done);
+  else
+    result = wsftp_perform(conn, &connected,  done);
+
+  return result;
+}
+
+static CURLcode wssh_block_statemach(struct connectdata *conn,
+                                    bool disconnect)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+  struct Curl_easy *data = conn->data;
+
+  while((sshc->state != SSH_STOP) && !result) {
+    bool block;
+    timediff_t left = 1000;
+    struct curltime now = Curl_now();
+
+    result = wssh_statemach_act(conn, &block);
+    if(result)
+      break;
+
+    if(!disconnect) {
+      if(Curl_pgrsUpdate(conn))
+        return CURLE_ABORTED_BY_CALLBACK;
+
+      result = Curl_speedcheck(data, now);
+      if(result)
+        break;
+
+      left = Curl_timeleft(data, NULL, FALSE);
+      if(left < 0) {
+        failf(data, "Operation timed out");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+    }
+
+    if(!result) {
+      int dir = conn->waitfor;
+      curl_socket_t sock = conn->sock[FIRSTSOCKET];
+      curl_socket_t fd_read = CURL_SOCKET_BAD;
+      curl_socket_t fd_write = CURL_SOCKET_BAD;
+      if(dir == KEEP_RECV)
+        fd_read = sock;
+      else if(dir == KEEP_SEND)
+        fd_write = sock;
+
+      /* wait for the socket to become ready */
+      (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
+                              left>1000?1000:left); /* ignore result */
+    }
+  }
+
+  return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+   done functions */
+static CURLcode wssh_done(struct connectdata *conn, CURLcode status)
+{
+  CURLcode result = CURLE_OK;
+  struct SSHPROTO *sftp_scp = conn->data->req.protop;
+
+  if(!status) {
+    /* run the state-machine */
+    result = wssh_block_statemach(conn, FALSE);
+  }
+  else
+    result = status;
+
+  if(sftp_scp)
+    Curl_safefree(sftp_scp->path);
+  if(Curl_pgrsDone(conn))
+    return CURLE_ABORTED_BY_CALLBACK;
+
+  conn->data->req.keepon = 0; /* clear all bits */
+  return result;
+}
+
+#if 0
+static CURLcode wscp_done(struct connectdata *conn,
+                         CURLcode code, bool premature)
+{
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)code;
+  (void)premature;
+
+  return result;
+}
+
+static CURLcode wscp_doing(struct connectdata *conn,
+                          bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)dophase_done;
+
+  return result;
+}
+
+static CURLcode wscp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+  CURLcode result = CURLE_OK;
+  (void)conn;
+  (void)dead_connection;
+
+  return result;
+}
+#endif
+
+static CURLcode wsftp_done(struct connectdata *conn,
+                          CURLcode code, bool premature)
+{
+  (void)premature;
+  state(conn, SSH_SFTP_CLOSE);
+
+  return wssh_done(conn, code);
+}
+
+static CURLcode wsftp_doing(struct connectdata *conn,
+                           bool *dophase_done)
+{
+  CURLcode result = wssh_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+static CURLcode wsftp_disconnect(struct connectdata *conn, bool dead)
+{
+  CURLcode result = CURLE_OK;
+  (void)dead;
+
+  DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+
+  if(conn->proto.sshc.ssh_session) {
+    /* only if there's a session still around to use! */
+    state(conn, SSH_SFTP_SHUTDOWN);
+    result = wssh_block_statemach(conn, TRUE);
+  }
+
+  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+  return result;
+}
+
+static int wssh_getsock(struct connectdata *conn,
+                        curl_socket_t *sock)
+{
+  return wssh_perform_getsock(conn, sock);
+}
+
+static int wssh_perform_getsock(const struct connectdata *conn,
+                                curl_socket_t *sock)
+{
+  int bitmap = GETSOCK_BLANK;
+  int dir = conn->waitfor;
+  sock[0] = conn->sock[FIRSTSOCKET];
+
+  if(dir == KEEP_RECV)
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+  else if(dir == KEEP_SEND)
+    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+  return bitmap;
+}
+
+size_t Curl_ssh_version(char *buffer, size_t buflen)
+{
+  return msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
+}
+
+CURLcode Curl_ssh_init(void)
+{
+  return CURLE_OK;
+}
+void Curl_ssh_cleanup(void)
+{
+}
+
+#endif /* USE_WOLFSSH */
diff --git a/lib/vssh/wolfssh.h b/lib/vssh/wolfssh.h
new file mode 100644
index 000000000..a9b9a3b09
--- /dev/null
+++ b/lib/vssh/wolfssh.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_WOLFSSH_H
+#define HEADER_CURL_WOLFSSH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2019 - 2020, Daniel Stenberg, <address@hidden>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+extern const struct Curl_handler Curl_handler_sftp;
+
+#endif /* HEADER_CURL_WOLFSSH_H */

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]