]> granicus.if.org Git - curl/commitdiff
- Implemented a protocol independent way to specify blocking direction, used by
authorKamil Dudka <kdudka@redhat.com>
Sat, 26 Sep 2009 08:31:48 +0000 (08:31 +0000)
committerKamil Dudka <kdudka@redhat.com>
Sat, 26 Sep 2009 08:31:48 +0000 (08:31 +0000)
  transfer.c for blocking. It is currently used only by SCP and SFTP protocols.
  This enhancement resolves an issue with 100% CPU usage during SFTP upload,
  reported by Vourhey.

CHANGES
lib/ssh.c
lib/transfer.c
lib/urldata.h

diff --git a/CHANGES b/CHANGES
index 39591485499beab0aecfa8e0b71ac3dcfbbc2661..1c8ac5bf99c8567929cc9b4b841e7288669048a0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,12 @@
 
                                   Changelog
 
+Kamil Dudka (26 Sep 2009)
+- Implemented a protocol independent way to specify blocking direction, used by
+  transfer.c for blocking. It is currently used only by SCP and SFTP protocols.
+  This enhancement resolves an issue with 100% CPU usage during SFTP upload,
+  reported by Vourhey.
+
 Daniel Stenberg (25 Sep 2009)
 - Chris Mumford filed bug report #2861587
   (http://curl.haxx.se/bug/view.cgi?id=2861587) identifying that libcurl used
index dc8ee8b8ef423387b1e61846fd4be15b5844a5d1..1503734eb3ae322cbc9929b81b73de02c397c147 100644 (file)
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -1500,6 +1500,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
                                  FIRSTSOCKET, NULL);
 
+    /* not set by Curl_setup_transfer to preserve keepon bits */
+    conn->sockfd = conn->writesockfd;
+
     if(result) {
       state(conn, SSH_SFTP_CLOSE);
       sshc->actualcode = result;
@@ -1911,6 +1914,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
   else {
     result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
                                  FALSE, NULL, -1, NULL);
+
+    /* not set by Curl_setup_transfer to preserve keepon bits */
+    conn->writesockfd = conn->sockfd;
+
+    /* FIXME: here should be explained why we need it to start the download */
+    conn->cselect_bits = CURL_CSELECT_IN;
   }
   if(result) {
     state(conn, SSH_SFTP_CLOSE);
@@ -2031,6 +2040,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
                                  FIRSTSOCKET, NULL);
 
+    /* not set by Curl_setup_transfer to preserve keepon bits */
+    conn->sockfd = conn->writesockfd;
+
     if(result) {
       state(conn, SSH_SCP_CHANNEL_FREE);
       sshc->actualcode = result;
@@ -2080,6 +2092,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     result = Curl_setup_transfer(conn, FIRSTSOCKET,
                                  bytecount, FALSE, NULL, -1, NULL);
 
+    /* not set by Curl_setup_transfer to preserve keepon bits */
+    conn->writesockfd = conn->sockfd;
+
+    /* FIXME: here should be explained why we need it to start the download */
+    conn->cselect_bits = CURL_CSELECT_IN;
+
     if(result) {
       state(conn, SSH_SCP_CHANNEL_FREE);
       sshc->actualcode = result;
@@ -2232,10 +2250,10 @@ static int ssh_perform_getsock(const struct connectdata *conn,
 
   sock[0] = conn->sock[FIRSTSOCKET];
 
-  if(conn->proto.sshc.waitfor & KEEP_RECV)
+  if(conn->waitfor & KEEP_RECV)
     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
 
-  if(conn->proto.sshc.waitfor & KEEP_SEND)
+  if(conn->waitfor & KEEP_SEND)
     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
 
   return bitmap;
@@ -2279,15 +2297,17 @@ static void ssh_block2waitfor(struct connectdata *conn, bool block)
 {
   struct ssh_conn *sshc = &conn->proto.sshc;
   int dir;
-  if(block && (dir = libssh2_session_block_directions(sshc->ssh_session))) {
+  if(!block)
+    conn->waitfor = 0;
+  else if((dir = libssh2_session_block_directions(sshc->ssh_session))) {
     /* translate the libssh2 define bits into our own bit defines */
-    sshc->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
+    conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
       ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
   }
   else
     /* It didn't block or libssh2 didn't reveal in which direction, put back
        the original set */
-    sshc->waitfor = sshc->orig_waitfor;
+    conn->waitfor = sshc->orig_waitfor;
 }
 #else
   /* no libssh2 directional support so we simply don't know */
index 5bd742f47e3464ee9cc69bf5be65921aa6bbe8e7..5ea420905e1134ea3db7982c41fe7b66f14c84a1 100644 (file)
@@ -1652,10 +1652,6 @@ CURLcode Curl_readwrite(struct connectdata *conn,
 
   if((k->keepon & KEEP_RECVBITS) == KEEP_RECV) {
     fd_read = conn->sockfd;
-#if defined(USE_LIBSSH2)
-    if(conn->protocol & (PROT_SCP|PROT_SFTP))
-      select_res |= CURL_CSELECT_IN;
-#endif /* USE_LIBSSH2 */
   } else
     fd_read = CURL_SOCKET_BAD;
 
@@ -1884,33 +1880,39 @@ Transfer(struct connectdata *conn)
     return CURLE_OK;
 
   while(!done) {
-    curl_socket_t fd_read;
-    curl_socket_t fd_write;
+    curl_socket_t fd_read = conn->sockfd;
+    curl_socket_t fd_write = conn->writesockfd;
+    int keepon = k->keepon;
+
+    if(conn->waitfor) {
+      /* if waitfor is set, get the RECV and SEND bits from that but keep the
+         other bits */
+      keepon &= ~ (KEEP_RECV|KEEP_SEND);
+      keepon |= conn->waitfor & (KEEP_RECV|KEEP_SEND);
+    }
 
     /* limit-rate logic: if speed exceeds threshold, then do not include fd in
        select set. The current speed is recalculated in each Curl_readwrite()
        call */
-    if((k->keepon & KEEP_SEND) &&
+    if((keepon & KEEP_SEND) &&
         (!data->set.max_send_speed ||
          (data->progress.ulspeed < data->set.max_send_speed) )) {
-      fd_write = conn->writesockfd;
       k->keepon &= ~KEEP_SEND_HOLD;
     }
     else {
       fd_write = CURL_SOCKET_BAD;
-      if(k->keepon & KEEP_SEND)
+      if(keepon & KEEP_SEND)
         k->keepon |= KEEP_SEND_HOLD; /* hold it */
     }
 
-    if((k->keepon & KEEP_RECV) &&
+    if((keepon & KEEP_RECV) &&
         (!data->set.max_recv_speed ||
          (data->progress.dlspeed < data->set.max_recv_speed)) ) {
-      fd_read = conn->sockfd;
       k->keepon &= ~KEEP_RECV_HOLD;
     }
     else {
       fd_read = CURL_SOCKET_BAD;
-      if(k->keepon & KEEP_RECV)
+      if(keepon & KEEP_RECV)
         k->keepon |= KEEP_RECV_HOLD; /* hold it */
     }
 
index bc2eff96008c6eb16bbb1a0b868fba8af3c52f71..b185c290530657870f77f88fc2ba769c05772e0e 100644 (file)
@@ -568,7 +568,6 @@ struct ssh_conn {
   LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
   LIBSSH2_SFTP *sftp_session;   /* SFTP handle */
   LIBSSH2_SFTP_HANDLE *sftp_handle;
-  int waitfor;                  /* current READ/WRITE bits to wait for */
   int orig_waitfor;             /* default READ/WRITE bits wait for */
 
   /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
@@ -1075,6 +1074,8 @@ struct connectdata {
   } proto;
 
   int cselect_bits; /* bitmask of socket events */
+  int waitfor;      /* current READ/WRITE bits to wait for */
+
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   int socks5_gssapi_enctype;
 #endif