1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-11 12:05:06 -05:00

- Based on a patch by Vlad Grachov, libcurl now uses a new libssh2 0.19

function when built to support SCP and SFTP that helps the library to know
  in which direction a particular libssh2 operation would return EAGAIN so
  that libcurl knows what socket conditions to wait for before trying the
  function call again. Previously (and still when using libssh2 0.18 or
  earlier), libcurl will busy-loop in this situation when the easy interface
  is used!
This commit is contained in:
Daniel Stenberg 2008-11-24 13:59:51 +00:00
parent dd2fc45c27
commit 53a8a6e5a6
4 changed files with 87 additions and 22 deletions

View File

@ -6,6 +6,15 @@
Changelog Changelog
Daniel Stenberg (24 Nov 2008)
- Based on a patch by Vlad Grachov, libcurl now uses a new libssh2 0.19
function when built to support SCP and SFTP that helps the library to know
in which direction a particular libssh2 operation would return EAGAIN so
that libcurl knows what socket conditions to wait for before trying the
function call again. Previously (and still when using libssh2 0.18 or
earlier), libcurl will busy-loop in this situation when the easy interface
is used!
Daniel Fandrich (20 Nov 2008) Daniel Fandrich (20 Nov 2008)
- Automatically detect OpenBSD's CA cert bundle. - Automatically detect OpenBSD's CA cert bundle.

View File

@ -21,19 +21,16 @@ This release includes the following bugfixes:
the same server the same server
o memory leak with HTTP GSS/kerberos authentication o memory leak with HTTP GSS/kerberos authentication
o removed the default use of "Pragma: no-cache" o removed the default use of "Pragma: no-cache"
o fix SCP/SFTP busyloop by using a new libssh2 0.19 function
This release includes the following known bugs: This release includes the following known bugs:
o see docs/KNOWN_BUGS (http://curl.haxx.se/docs/knownbugs.html) o see docs/KNOWN_BUGS (http://curl.haxx.se/docs/knownbugs.html)
Other curl-related news:
o
This release would not have looked like this without help, code, reports and This release would not have looked like this without help, code, reports and
advice from friends like these: advice from friends like these:
Yang Tse, Daniel Fandrich, Jim Meyering, Christian Krause, Andreas Wurf, Yang Tse, Daniel Fandrich, Jim Meyering, Christian Krause, Andreas Wurf,
Markus Koetter, Josef Wolf Markus Koetter, Josef Wolf, Vlad Grachov
Thanks! (and sorry if I forgot to mention someone) Thanks! (and sorry if I forgot to mention someone)

View File

@ -1476,6 +1476,10 @@ if test X"$OPT_LIBSSH2" != Xno; then
LIBSSH2_ENABLED=1 LIBSSH2_ENABLED=1
AC_DEFINE(USE_LIBSSH2, 1, [if libSSH2 is in use]) AC_DEFINE(USE_LIBSSH2, 1, [if libSSH2 is in use])
AC_SUBST(USE_LIBSSH2, [1]) AC_SUBST(USE_LIBSSH2, [1])
dnl check for this function only present in libssh2 0.19+
AC_CHECK_FUNCS( libssh2_session_block_directions )
) )
if test X"$OPT_LIBSSH2" != Xoff && if test X"$OPT_LIBSSH2" != Xoff &&

View File

@ -40,6 +40,13 @@
#error "this requires libssh2 0.16 or later" #error "this requires libssh2 0.16 or later"
#endif #endif
#if !defined(HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION) && \
(LIBSSH2_VERSION_NUM >= 0x001300)
/* this is just a check for non-configure based systems to get this properly
setup if libssh2 0.19+ is used */
#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION 1
#endif
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -103,6 +110,7 @@
#include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "strtoofft.h" #include "strtoofft.h"
#include "multiif.h" #include "multiif.h"
#include "select.h"
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h> #include <curl/mprintf.h>
@ -421,7 +429,14 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
return CURLE_OK; return CURLE_OK;
} }
static CURLcode ssh_statemach_act(struct connectdata *conn) /*
* ssh_statemach_act() runs the SSH statemachine "one round" and returns. The
* data the pointer 'block' points to will be set to TRUE if the libssh2
* function returns LIBSSH2_ERROR_EAGAIN meaning it wants to be called again
* when the socket is ready
*/
static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
@ -432,8 +447,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
const char *fingerprint; const char *fingerprint;
#endif /* CURL_LIBSSH2_DEBUG */ #endif /* CURL_LIBSSH2_DEBUG */
const char *host_public_key_md5; const char *host_public_key_md5;
int rc,i; int rc = LIBSSH2_ERROR_NONE, i;
int err; int err;
*block = 0; /* we're not blocking by default */
switch(sshc->state) { switch(sshc->state) {
case SSH_S_STARTUP: case SSH_S_STARTUP:
@ -519,6 +535,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->authlist) { if(!sshc->authlist) {
if((err = libssh2_session_last_errno(sshc->ssh_session)) == if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -729,6 +746,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->sftp_session) { if(!sshc->sftp_session) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -996,21 +1014,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
* This takes an extra protocol round trip. * This takes an extra protocol round trip.
*/ */
rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2, rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2,
&sshc->quote_attrs); &sshc->quote_attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
} }
else if(rc != 0) { /* get those attributes */ else if(rc != 0) { /* get those attributes */
err = libssh2_sftp_last_error(sshc->sftp_session); err = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path1);
sshc->quote_path1 = NULL; sshc->quote_path1 = NULL;
Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->quote_path2);
sshc->quote_path2 = NULL; sshc->quote_path2 = NULL;
failf(data, "Attempt to get SFTP stats failed: %s", failf(data, "Attempt to get SFTP stats failed: %s",
sftp_libssh2_strerror(err)); sftp_libssh2_strerror(err));
state(conn, SSH_SFTP_CLOSE); state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_QUOTE_ERROR; sshc->actualcode = CURLE_QUOTE_ERROR;
break; break;
} }
} }
@ -1233,6 +1251,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->sftp_handle) { if(!sshc->sftp_handle) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -1387,6 +1406,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->sftp_handle) { if(!sshc->sftp_handle) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -1421,6 +1441,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
PATH_MAX, PATH_MAX,
&sshc->readdir_attrs); &sshc->readdir_attrs);
if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) { if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
if(sshc->readdir_len > 0) { if(sshc->readdir_len > 0) {
@ -1521,6 +1542,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
sshc->readdir_filename, sshc->readdir_filename,
PATH_MAX); PATH_MAX);
if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) { if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
Curl_safefree(sshc->readdir_linkPath); Curl_safefree(sshc->readdir_linkPath);
@ -1578,6 +1600,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
case SSH_SFTP_READDIR_DONE: case SSH_SFTP_READDIR_DONE:
if(libssh2_sftp_closedir(sshc->sftp_handle) == if(libssh2_sftp_closedir(sshc->sftp_handle) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
sshc->sftp_handle = NULL; sshc->sftp_handle = NULL;
@ -1601,6 +1624,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->sftp_handle) { if(!sshc->sftp_handle) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -1814,6 +1838,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->ssh_channel) { if(!sshc->ssh_channel) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -1860,6 +1885,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if(!sshc->ssh_channel) { if(!sshc->ssh_channel) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
rc = LIBSSH2_ERROR_EAGAIN;
break; break;
} }
else { else {
@ -2011,6 +2037,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
break; break;
} }
if(rc == LIBSSH2_ERROR_EAGAIN) {
/* we would block, we need to wait for the socket to be ready (in the
right direction too)! */
*block = TRUE;
}
return result; return result;
} }
@ -2019,8 +2051,11 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
{ {
struct ssh_conn *sshc = &conn->proto.sshc; struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
bool block_we_ignore; /* we don't care about EAGAIN at this point, but TODO:
we _should_ store the status and use that to
provide a ssh_getsock() implementation */
result = ssh_statemach_act(conn); result = ssh_statemach_act(conn, &block_we_ignore);
*done = (bool)(sshc->state == SSH_STOP); *done = (bool)(sshc->state == SSH_STOP);
return result; return result;
@ -2031,8 +2066,28 @@ static CURLcode ssh_easy_statemach(struct connectdata *conn)
struct ssh_conn *sshc = &conn->proto.sshc; struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
while((sshc->state != SSH_STOP) && !result) while((sshc->state != SSH_STOP) && !result) {
result = ssh_statemach_act(conn); bool block;
result = ssh_statemach_act(conn, &block);
#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
if((CURLE_OK == result) && block) {
int dir = libssh2_session_block_directions(sshc->ssh_session);
curl_socket_t sock = conn->sock[FIRSTSOCKET];
curl_socket_t fd_read = CURL_SOCKET_BAD;
curl_socket_t fd_write = CURL_SOCKET_BAD;
if (LIBSSH2_SESSION_BLOCK_INBOUND & dir) {
fd_read = sock;
}
if (LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) {
fd_write = sock;
}
/* wait for the socket to become ready */
Curl_socket_ready(fd_read, fd_write, 1000); /* ignore result */
}
#endif
}
return result; return result;
} }