]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ssh: tracing and better pollset handling
authorStefan Eissing <stefan@eissing.org>
Fri, 28 Nov 2025 11:49:16 +0000 (12:49 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 28 Nov 2025 15:05:43 +0000 (16:05 +0100)
Remove connection member `waitfor` and keep it in the SSH connection
meta. Add `ssh` to supported tracing features, convert many DEBUGF
printgs to traces.

Closes #19745

docs/libcurl/curl_global_trace.md
lib/curl_trc.c
lib/curl_trc.h
lib/urldata.h
lib/vssh/libssh.c
lib/vssh/libssh2.c
lib/vssh/ssh.h

index 0459eab6747d48913c4f8a52e3cfcecf59f8990d..10ec21b4bd43d6b27e163c816f9b3a5e37204215 100644 (file)
@@ -130,6 +130,10 @@ states.
 Traces reading of upload data from the application in order to send it to the
 server.
 
+## `ssh`
+
+Tracing of SSH related protocols SCP and SFTP.
+
 ## `ssls`
 
 Tracing of SSL Session handling, e.g. caching/import/export.
index cc06c77e9d9ac78e642898ac68fd535a32c5f0f0..42711ed01c0520fb2131993d1645e6b636b2b0a7 100644 (file)
@@ -453,6 +453,24 @@ void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
 }
 #endif /* USE_SSL */
 
+#ifdef USE_SSH
+struct curl_trc_feat Curl_trc_feat_ssh = {
+  "SSH",
+  CURL_LOG_LVL_NONE,
+};
+
+void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) {
+    va_list ap;
+    va_start(ap, fmt);
+    trc_infof(data, &Curl_trc_feat_ssh, NULL, 0, fmt, ap);
+    va_end(ap);
+  }
+}
+#endif /* USE_SSH */
+
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 struct curl_trc_feat Curl_trc_feat_ws = {
   "WS",
@@ -500,6 +518,9 @@ static struct trc_feat_def trc_feats[] = {
 #ifdef USE_SSL
   { &Curl_trc_feat_ssls,      TRC_CT_NETWORK },
 #endif
+#ifdef USE_SSH
+  { &Curl_trc_feat_ssh,      TRC_CT_PROTOCOL },
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
   { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
 #endif
@@ -696,6 +717,13 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
   (void)data; (void)fmt;
 }
 #endif
+#ifdef USE_SSH
+void Curl_trc_ssh(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data;
+  (void)fmt;
+}
+#endif
 #ifdef USE_SSL
 void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
 {
index 1a3f8f374e2d836219ad6b4c323d47fead9bdab5..0ce76ed7effac9ba38214d2ab1f48d56b9f3e081 100644 (file)
@@ -117,6 +117,11 @@ extern struct curl_trc_feat Curl_trc_feat_ssls;
 void Curl_trc_ssls(struct Curl_easy *data,
                    const char *fmt, ...) CURL_PRINTF(2, 3);
 #endif
+#ifdef USE_SSH
+extern struct curl_trc_feat Curl_trc_feat_ssh;
+void Curl_trc_ssh(struct Curl_easy *data,
+                   const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 extern struct curl_trc_feat Curl_trc_feat_ws;
 void Curl_trc_ws(struct Curl_easy *data,
@@ -168,6 +173,11 @@ void Curl_trc_ws(struct Curl_easy *data,
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) \
          Curl_trc_ssls(data, __VA_ARGS__); } while(0)
 #endif /* USE_SSL */
+#ifdef USE_SSH
+#define CURL_TRC_SSH(data, ...) \
+  do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssh)) \
+         Curl_trc_ssh(data, __VA_ARGS__); } while(0)
+#endif /* USE_SSH */
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS(data, ...)                             \
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
@@ -193,6 +203,9 @@ void Curl_trc_ws(struct Curl_easy *data,
 #ifdef USE_SSL
 #define CURL_TRC_SSLS  Curl_trc_ssls
 #endif
+#ifdef USE_SSH
+#define CURL_TRC_SSH  Curl_trc_ssh
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS    Curl_trc_ws
 #endif
index debc2a3e0aa0aad6318395956ff815383a37a1a2..2d28718181a9651a847cfed2fadf87fa2feb16aa 100644 (file)
@@ -713,7 +713,6 @@ struct connectdata {
      wrong connections. */
   char *localdev;
   unsigned short localportrange;
-  int waitfor;      /* current READ/WRITE bits to wait for */
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   int socks5_gssapi_enctype;
 #endif
index a5997a6f6cf970771b006ca4b62c11c3dd7dd0b3..2b605e4a61840c0ed858c24382c05f8502762bd8 100644 (file)
@@ -210,26 +210,9 @@ static CURLcode sftp_error_to_CURLE(int err)
   return CURLE_SSH;
 }
 
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-#define myssh_to(x,y,z) myssh_set_state(x,y,z, __LINE__)
-#else
-#define myssh_to(x,y,z) myssh_set_state(x,y,z)
-#endif
-
-/*
- * SSH State machine related code
- */
-/* This is the ONLY way to change SSH state! */
-static void myssh_set_state(struct Curl_easy *data,
-                            struct ssh_conn *sshc,
-                            sshstate nowstate
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-                          , int lineno
-#endif
-  )
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+static const char *myssh_statename(sshstate state)
 {
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  /* for debug purposes */
   static const char *const names[] = {
     "SSH_STOP",
     "SSH_INIT",
@@ -292,14 +275,34 @@ static void myssh_set_state(struct Curl_easy *data,
     "SSH_SESSION_FREE",
     "QUIT"
   };
+  /* a precaution to make sure the lists are in sync */
+  DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST);
+  return ((size_t)state < CURL_ARRAYSIZE(names)) ? names[state] : "";
+}
+#else
+#define myssh_statename(x)    ""
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
 
+
+#define myssh_to(x,y,z) myssh_set_state(x,y,z)
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void myssh_set_state(struct Curl_easy *data,
+                            struct ssh_conn *sshc,
+                            sshstate nowstate)
+{
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
   if(sshc->state != nowstate) {
-    infof(data, "SSH %p state change from %s to %s (line %d)",
-          (void *) sshc, names[sshc->state], names[nowstate],
-          lineno);
+    CURL_TRC_SSH(data, "[%s] -> [%s]",
+                 myssh_statename(sshc->state),
+                 myssh_statename(nowstate));
   }
-#endif
+#else
   (void)data;
+#endif
   sshc->state = nowstate;
 }
 
@@ -887,7 +890,7 @@ static int myssh_in_S_STARTUP(struct Curl_easy *data,
 
   myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
   if(rc == SSH_AGAIN) {
-    DEBUGF(infof(data, "ssh_connect -> EAGAIN"));
+    CURL_TRC_SSH(data, "connect -> EAGAIN");
   }
   else if(rc != SSH_OK) {
     failf(data, "Failure establishing ssh session");
@@ -1259,10 +1262,6 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data,
   /* not set by Curl_xfer_setup to preserve keepon bits */
   data->conn->recv_idx = FIRSTSOCKET;
 
-  /* store this original bitmask setup to use later on if we cannot
-     figure out a "real" bitmask */
-  sshc->orig_waitfor = data->req.keepon;
-
   /* since we do not really wait for anything at this point, we want the
      state machine to move on as soon as possible so we mark this as dirty */
   Curl_multi_mark_dirty(data);
@@ -1401,7 +1400,7 @@ static int myssh_in_SFTP_CLOSE(struct Curl_easy *data,
   }
   Curl_safefree(sshp->path);
 
-  DEBUGF(infof(data, "SFTP DONE done"));
+  CURL_TRC_SSH(data, "SFTP DONE done");
 
   /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
      After nextstate is executed, the control should come back to
@@ -1485,7 +1484,7 @@ static int myssh_in_SFTP_REALPATH(struct Curl_easy *data,
      we get the homedir here, we get the "workingpath" in the DO action
      since the homedir will remain the same between request but the
      working path will not. */
-  DEBUGF(infof(data, "SSH CONNECT phase done"));
+  CURL_TRC_SSH(data, "CONNECT phase done");
   myssh_to(data, sshc, SSH_STOP);
   return SSH_NO_ERROR;
 }
@@ -2285,10 +2284,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data,
       /* not set by Curl_xfer_setup to preserve keepon bits */
       data->conn->recv_idx = FIRSTSOCKET;
 
-      /* store this original bitmask setup to use later on if we cannot
-         figure out a "real" bitmask */
-      sshc->orig_waitfor = data->req.keepon;
-
       myssh_to(data, sshc, SSH_STOP);
 
       break;
@@ -2357,7 +2352,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data,
         ssh_scp_free(sshc->scp_session);
         sshc->scp_session = NULL;
       }
-      DEBUGF(infof(data, "SCP DONE phase complete"));
+      CURL_TRC_SSH(data, "SCP DONE phase complete");
 
       ssh_set_blocking(sshc->ssh_session, 0);
 
@@ -2422,7 +2417,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data,
   }
   if(!result && (sshc->state == SSH_STOP))
     result = sshc->actualcode;
-  DEBUGF(infof(data, "SSH: myssh_statemach_act -> %d", result));
+  CURL_TRC_SSH(data, "[%s] statemachine() -> %d, block=%d",
+               myssh_statename(sshc->state), result, *block);
   return result;
 }
 
@@ -2432,33 +2428,45 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data,
 static CURLcode myssh_pollset(struct Curl_easy *data,
                               struct easy_pollset *ps)
 {
-  int flags = 0;
   struct connectdata *conn = data->conn;
-  if(conn->waitfor & KEEP_RECV)
-    flags |= CURL_POLL_IN;
-  if(conn->waitfor & KEEP_SEND)
-    flags |= CURL_POLL_OUT;
-  if(!conn->waitfor)
-    flags |= CURL_POLL_OUT;
-  return flags ?
-    Curl_pollset_change(data, ps, conn->sock[FIRSTSOCKET], flags, 0) :
-    CURLE_OK;
+  struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int waitfor;
+
+  if(!sshc || (sock == CURL_SOCKET_BAD))
+    return CURLE_FAILED_INIT;
+
+  waitfor = sshc->waitfor ? sshc->waitfor : data->req.keepon;
+  if(waitfor) {
+    int flags = 0;
+    if(waitfor & KEEP_RECV)
+      flags |= CURL_POLL_IN;
+    if(waitfor & KEEP_SEND)
+      flags |= CURL_POLL_OUT;
+    DEBUGASSERT(flags);
+    CURL_TRC_SSH(data, "pollset, flags=%x", flags);
+    return Curl_pollset_change(data, ps, sock, flags, 0);
+  }
+  /* While we still have a session, we listen incoming data. */
+  if(sshc->ssh_session)
+    return Curl_pollset_change(data, ps, sock, CURL_POLL_IN, 0);
+  return CURLE_OK;
 }
 
 static void myssh_block2waitfor(struct connectdata *conn,
                                 struct ssh_conn *sshc,
                                 bool block)
 {
+  (void)conn;
   if(block) {
     int dir = ssh_get_poll_flags(sshc->ssh_session);
     /* translate the libssh define bits into our own bit defines */
-    conn->waitfor =
+    sshc->waitfor =
       ((dir & SSH_READ_PENDING) ? KEEP_RECV : 0) |
       ((dir & SSH_WRITE_PENDING) ? KEEP_SEND : 0);
   }
   else
-    /* if it did not block, use the original set */
-    conn->waitfor = sshc->orig_waitfor;
+    sshc->waitfor = 0;
 }
 
 /* called repeatedly until done from multi.c */
@@ -2584,6 +2592,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
   if(!sshc || !ssh)
     return CURLE_FAILED_INIT;
 
+  CURL_TRC_SSH(data, "myssh_connect");
   if(conn->handler->protocol & CURLPROTO_SCP) {
     conn->recv[FIRSTSOCKET] = scp_recv;
     conn->send[FIRSTSOCKET] = scp_send;
@@ -2618,6 +2627,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
     /* ignore */
   }
 
+  CURL_TRC_SSH(data, "myssh_connect, set socket=%" FMT_SOCKET_T, sock);
   rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_FD, &sock);
   if(rc != SSH_OK) {
     failf(data, "Could not set socket");
@@ -2691,7 +2701,7 @@ static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
   result = myssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
   return result;
 }
@@ -2712,7 +2722,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
 
-  DEBUGF(infof(data, "DO phase starts"));
+  CURL_TRC_SSH(data, "DO phase starts");
 
   *dophase_done = FALSE;        /* not done yet */
   if(!sshc)
@@ -2726,7 +2736,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
 
   return result;
@@ -2959,7 +2969,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   CURLcode result = CURLE_OK;
 
-  DEBUGF(infof(data, "DO phase starts"));
+  CURL_TRC_SSH(data, "DO phase starts");
 
   *dophase_done = FALSE; /* not done yet */
   if(!sshc)
@@ -2974,7 +2984,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
 
   return result;
@@ -2986,7 +2996,7 @@ static CURLcode sftp_doing(struct Curl_easy *data,
 {
   CURLcode result = myssh_multi_statemach(data, dophase_done);
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
   return result;
 }
@@ -3003,7 +3013,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)dead_connection;
 
-  DEBUGF(infof(data, "SSH DISCONNECT starts now"));
+  CURL_TRC_SSH(data, "DISCONNECT starts now");
 
   if(sshc && sshc->ssh_session) {
     /* only if there is a session still around to use! */
@@ -3011,7 +3021,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
     result = myssh_block_statemach(data, sshc, sshp, TRUE);
   }
 
-  DEBUGF(infof(data, "SSH DISCONNECT is done"));
+  CURL_TRC_SSH(data, "DISCONNECT is done");
   return result;
 }
 
index 4ac9d89f1ad54b4d5569e4811ba6fc27ad9c0a78..31ef5092d3dabb0b491659ebb05080d0b9e24a63 100644 (file)
@@ -280,17 +280,10 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free)
     Curl_cfree(ptr);
 }
 
-/*
- * SSH State machine related code
- */
-/* This is the ONLY way to change SSH state! */
-static void myssh_state(struct Curl_easy *data,
-                        struct ssh_conn *sshc,
-                        sshstate nowstate)
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+static const char *myssh_statename(sshstate state)
 {
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  /* for debug purposes */
-  static const char * const names[] = {
+  static const char *const names[] = {
     "SSH_STOP",
     "SSH_INIT",
     "SSH_S_STARTUP",
@@ -352,16 +345,34 @@ static void myssh_state(struct Curl_easy *data,
     "SSH_SESSION_FREE",
     "QUIT"
   };
-
   /* a precaution to make sure the lists are in sync */
   DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST);
+  return ((size_t)state < CURL_ARRAYSIZE(names)) ? names[state] : "";
+}
+#else
+#define myssh_statename(x)    ""
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
 
+
+#define myssh_state(x,y,z) myssh_set_state(x,y,z)
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void myssh_set_state(struct Curl_easy *data,
+                            struct ssh_conn *sshc,
+                            sshstate nowstate)
+{
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
   if(sshc->state != nowstate) {
-    infof(data, "SFTP %p state change from %s to %s",
-          (void *)sshc, names[sshc->state], names[nowstate]);
+    CURL_TRC_SSH(data, "[%s] -> [%s]",
+                 myssh_statename(sshc->state),
+                 myssh_statename(nowstate));
   }
-#endif
+#else
   (void)data;
+#endif
   sshc->state = nowstate;
 }
 
@@ -1172,10 +1183,6 @@ sftp_upload_init(struct Curl_easy *data,
   /* not set by Curl_xfer_setup to preserve keepon bits */
   data->conn->recv_idx = FIRSTSOCKET;
 
-  /* store this original bitmask setup to use later on if we cannot
-     figure out a "real" bitmask */
-  sshc->orig_waitfor = data->req.keepon;
-
   /* since we do not really wait for anything at this point, we want the
      state machine to move on as soon as possible so mark this as dirty */
   Curl_multi_mark_dirty(data);
@@ -1951,8 +1958,7 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data,
       /* in this case, the error was not in the SFTP level but for example a
          time-out or similar */
       result = CURLE_SSH;
-    DEBUGF(infof(data, "error = %lu makes libcurl = %d",
-                 sftperr, (int)result));
+    CURL_TRC_SSH(data, "error = %lu makes libcurl = %d", sftperr, (int)result);
     return result;
   }
 
@@ -1960,7 +1966,7 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data,
      get the homedir here, we get the "workingpath" in the DO action since the
      homedir will remain the same between request but the working path will
      not. */
-  DEBUGF(infof(data, "SSH CONNECT phase done"));
+  CURL_TRC_SSH(data, "CONNECT phase done");
   return CURLE_OK;
 }
 
@@ -2418,7 +2424,7 @@ static CURLcode ssh_state_sftp_close(struct Curl_easy *data,
 
   Curl_safefree(sshp->path);
 
-  DEBUGF(infof(data, "SFTP DONE done"));
+  CURL_TRC_SSH(data, "SFTP DONE done");
 
   /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
      After nextstate is executed, the control should come back to
@@ -2542,10 +2548,6 @@ static CURLcode ssh_state_scp_upload_init(struct Curl_easy *data,
   /* not set by Curl_xfer_setup to preserve keepon bits */
   data->conn->recv_idx = FIRSTSOCKET;
 
-  /* store this original bitmask setup to use later on if we cannot
-     figure out a "real" bitmask */
-  sshc->orig_waitfor = data->req.keepon;
-
   myssh_state(data, sshc, SSH_STOP);
 
   return CURLE_OK;
@@ -3008,7 +3010,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data,
         }
         sshc->ssh_channel = NULL;
       }
-      DEBUGF(infof(data, "SCP DONE phase complete"));
+      CURL_TRC_SSH(data, "SCP DONE phase complete");
       myssh_state(data, sshc, SSH_STOP);
       break;
 
@@ -3042,6 +3044,8 @@ static CURLcode ssh_statemachine(struct Curl_easy *data,
     *block = TRUE;
     result = CURLE_OK;
   }
+  CURL_TRC_SSH(data, "[%s] statemachine() -> %d, block=%d",
+               myssh_statename(sshc->state), result, *block);
 
   return result;
 }
@@ -3051,15 +3055,29 @@ static CURLcode ssh_statemachine(struct Curl_easy *data,
 static CURLcode ssh_pollset(struct Curl_easy *data,
                             struct easy_pollset *ps)
 {
-  int flags = 0;
   struct connectdata *conn = data->conn;
-  if(conn->waitfor & KEEP_RECV)
-    flags |= CURL_POLL_IN;
-  if(conn->waitfor & KEEP_SEND)
-    flags |= CURL_POLL_OUT;
-  return flags ?
-    Curl_pollset_change(data, ps, conn->sock[FIRSTSOCKET], flags, 0) :
-    CURLE_OK;
+  struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int waitfor;
+
+  if(!sshc || (sock == CURL_SOCKET_BAD))
+    return CURLE_FAILED_INIT;
+
+  waitfor = sshc->waitfor ? sshc->waitfor : data->req.keepon;
+  if(waitfor) {
+    int flags = 0;
+    if(waitfor & KEEP_RECV)
+      flags |= CURL_POLL_IN;
+    if(waitfor & KEEP_SEND)
+      flags |= CURL_POLL_OUT;
+    DEBUGASSERT(flags);
+    CURL_TRC_SSH(data, "pollset, flags=%x", flags);
+    return Curl_pollset_change(data, ps, sock, flags, 0);
+  }
+  /* While we still have a session, we listen incoming data. */
+  if(sshc->ssh_session)
+    return Curl_pollset_change(data, ps, sock, CURL_POLL_IN, 0);
+  return CURLE_OK;
 }
 
 /*
@@ -3073,20 +3091,18 @@ static void ssh_block2waitfor(struct Curl_easy *data,
                               struct ssh_conn *sshc,
                               bool block)
 {
-  struct connectdata *conn = data->conn;
   int dir = 0;
+  (void)data;
   if(block) {
     dir = libssh2_session_block_directions(sshc->ssh_session);
     if(dir) {
       /* translate the libssh2 define bits into our own bit defines */
-      conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND) ? KEEP_RECV : 0) |
+      sshc->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND) ? KEEP_RECV : 0) |
         ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND) ? KEEP_SEND : 0);
     }
   }
   if(!dir)
-    /* It did not block or libssh2 did not reveal in which direction, put back
-       the original set */
-    conn->waitfor = sshc->orig_waitfor;
+    sshc->waitfor = 0;
 }
 
 /* called repeatedly until done from multi.c */
@@ -3468,7 +3484,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   CURLcode result = CURLE_OK;
 
-  DEBUGF(infof(data, "DO phase starts"));
+  CURL_TRC_SSH(data, "DO phase starts");
 
   *dophase_done = FALSE; /* not done yet */
   if(!sshc)
@@ -3483,7 +3499,7 @@ CURLcode scp_perform(struct Curl_easy *data,
   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
 
   return result;
@@ -3497,7 +3513,7 @@ static CURLcode scp_doing(struct Curl_easy *data,
   result = ssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
   return result;
 }
@@ -3778,7 +3794,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   CURLcode result = CURLE_OK;
 
-  DEBUGF(infof(data, "DO phase starts"));
+  CURL_TRC_SSH(data, "DO phase starts");
 
   *dophase_done = FALSE; /* not done yet */
   if(!sshc)
@@ -3793,7 +3809,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
   *connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
 
   return result;
@@ -3806,7 +3822,7 @@ static CURLcode sftp_doing(struct Curl_easy *data,
   CURLcode result = ssh_multi_statemach(data, dophase_done);
 
   if(*dophase_done) {
-    DEBUGF(infof(data, "DO phase is complete"));
+    CURL_TRC_SSH(data, "DO phase is complete");
   }
   return result;
 }
@@ -3825,10 +3841,10 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
   if(sshc) {
     if(sshc->ssh_session) {
       /* only if there is a session still around to use! */
-      DEBUGF(infof(data, "SSH DISCONNECT starts now"));
+      CURL_TRC_SSH(data, "DISCONNECT starts now");
       myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
       result = ssh_block_statemach(data, sshc, sshp, TRUE);
-      DEBUGF(infof(data, "SSH DISCONNECT is done -> %d", result));
+      CURL_TRC_SSH(data, "DISCONNECT is done -> %d", result);
     }
     sshc_cleanup(sshc, data, TRUE);
   }
index 5317351478fc047550acf75ae6f55e10d10bbc0b..92ae72a6a76195d12aedb79cb9271873e9f0e02b 100644 (file)
@@ -156,7 +156,8 @@ struct ssh_conn {
   int secondCreateDirs;         /* counter use by the code to see if the
                                    second attempt has been made to change
                                    to/create a directory */
-  int orig_waitfor;             /* default READ/WRITE bits wait for */
+  int waitfor;                  /* KEEP_RECV/KEEP_SEND bits overriding
+                                   pollset given flags */
   char *slash_pos;              /* used by the SFTP_CREATE_DIRS state */
 
 #ifdef USE_LIBSSH