diff --git a/CHANGES b/CHANGES index 395914854..1c8ac5bf9 100644 --- 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 diff --git a/lib/ssh.c b/lib/ssh.c index dc8ee8b8e..1503734eb 100644 --- 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 */ diff --git a/lib/transfer.c b/lib/transfer.c index 5bd742f47..5ea420905 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -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 */ } diff --git a/lib/urldata.h b/lib/urldata.h index bc2eff960..b185c2905 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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