1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

* Updates for the latest version of libssh2, specifically

libssh2_sftp_shutdown() and libssh2_session_free() can now return
  LIBSSH2_ERROR_EAGAIN.

* Fix the _send() and _recv() return values so non-blocking works
This commit is contained in:
James Housley 2007-06-12 21:32:45 +00:00
parent 6f59e19b91
commit ab7e7144ef
2 changed files with 129 additions and 72 deletions

194
lib/ssh.c
View File

@ -258,6 +258,8 @@ static void state(struct connectdata *conn, ftpstate state)
"SSH_SFTP_INIT", "SSH_SFTP_INIT",
"SSH_SFTP_REALPATH", "SSH_SFTP_REALPATH",
"SSH_GET_WORKINGPATH", "SSH_GET_WORKINGPATH",
"SSH_SFTP_SHUTDOWN",
"SSH_SESSION_FREE",
"QUIT" "QUIT"
}; };
#endif #endif
@ -295,10 +297,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
} }
else if (rc) { else if (rc) {
failf(data, "Failure establishing ssh session"); failf(data, "Failure establishing ssh session");
libssh2_session_free(ssh->ssh_session); state(conn, SSH_SESSION_FREE);
ssh->ssh_session = NULL; sshc->actualCode = CURLE_FAILED_INIT;
state(conn, SSH_STOP);
result = CURLE_FAILED_INIT;
break; break;
} }
@ -347,10 +347,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
LIBSSH2_ERROR_EAGAIN) { LIBSSH2_ERROR_EAGAIN) {
break; break;
} else { } else {
libssh2_session_free(ssh->ssh_session); state(conn, SSH_SESSION_FREE);
ssh->ssh_session = NULL; sshc->actualCode = CURLE_OUT_OF_MEMORY;
state(conn, SSH_STOP);
result = CURLE_OUT_OF_MEMORY;
break; break;
} }
} }
@ -491,10 +489,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
case SSH_AUTH_DONE: case SSH_AUTH_DONE:
if (!sshc->authed) { if (!sshc->authed) {
failf(data, "Authentication failure"); failf(data, "Authentication failure");
libssh2_session_free(ssh->ssh_session); state(conn, SSH_SESSION_FREE);
ssh->ssh_session = NULL; sshc->actualCode = CURLE_LOGIN_DENIED;
state(conn, SSH_STOP);
result = CURLE_LOGIN_DENIED;
break; break;
} }
@ -524,10 +520,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
break; break;
} else { } else {
failf(data, "Failure initialising sftp session\n"); failf(data, "Failure initialising sftp session\n");
libssh2_session_free(ssh->ssh_session); state(conn, SSH_SESSION_FREE);
ssh->ssh_session = NULL; sshc->actualCode = CURLE_FAILED_INIT;
state(conn, SSH_STOP);
result = CURLE_FAILED_INIT;
break; break;
} }
} }
@ -551,12 +545,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
tempHome[rc] = '\0'; tempHome[rc] = '\0';
ssh->homedir = (char *)strdup(tempHome); ssh->homedir = (char *)strdup(tempHome);
if (!ssh->homedir) { if (!ssh->homedir) {
libssh2_sftp_shutdown(ssh->sftp_session); state(conn, SSH_SFTP_SHUTDOWN);
ssh->sftp_session = NULL; sshc->actualCode = CURLE_OUT_OF_MEMORY;
libssh2_session_free(ssh->ssh_session);
ssh->ssh_session = NULL;
state(conn, SSH_STOP);
result = CURLE_OUT_OF_MEMORY;
break; break;
} }
} else { } else {
@ -588,11 +578,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
if (conn->protocol == PROT_SCP) { if (conn->protocol == PROT_SCP) {
real_path = (char *)malloc(working_path_len+1); real_path = (char *)malloc(working_path_len+1);
if (real_path == NULL) { if (real_path == NULL) {
libssh2_session_free(ssh->ssh_session);
ssh->ssh_session = NULL;
Curl_safefree(working_path); Curl_safefree(working_path);
state(conn, SSH_STOP); state(conn, SSH_SESSION_FREE);
result = CURLE_OUT_OF_MEMORY; sshc->actualCode = CURLE_OUT_OF_MEMORY;
break; break;
} }
if (working_path[1] == '~') if (working_path[1] == '~')
@ -607,15 +595,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
real_path = (char *)malloc(strlen(ssh->homedir) + real_path = (char *)malloc(strlen(ssh->homedir) +
working_path_len + 1); working_path_len + 1);
if (real_path == NULL) { if (real_path == NULL) {
libssh2_sftp_shutdown(ssh->sftp_session);
ssh->sftp_session = NULL;
libssh2_session_free(ssh->ssh_session);
ssh->ssh_session = NULL;
Curl_safefree(ssh->homedir); Curl_safefree(ssh->homedir);
ssh->homedir = NULL; ssh->homedir = NULL;
Curl_safefree(working_path); Curl_safefree(working_path);
state(conn, SSH_STOP); state(conn, SSH_SFTP_SHUTDOWN);
result = CURLE_OUT_OF_MEMORY; sshc->actualCode = CURLE_OUT_OF_MEMORY;
break; break;
} }
/* It is referenced to the home directory, so strip the /* It is referenced to the home directory, so strip the
@ -631,47 +615,50 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
else { else {
real_path = (char *)malloc(working_path_len+1); real_path = (char *)malloc(working_path_len+1);
if (real_path == NULL) { if (real_path == NULL) {
libssh2_sftp_shutdown(ssh->sftp_session);
ssh->sftp_session = NULL;
libssh2_session_free(ssh->ssh_session);
ssh->ssh_session = NULL;
Curl_safefree(ssh->homedir); Curl_safefree(ssh->homedir);
ssh->homedir = NULL; ssh->homedir = NULL;
Curl_safefree(working_path); Curl_safefree(working_path);
state(conn, SSH_STOP); state(conn, SSH_SFTP_SHUTDOWN);
result = CURLE_OUT_OF_MEMORY; sshc->actualCode = CURLE_OUT_OF_MEMORY;
break; break;
} }
memcpy(real_path, working_path, 1+working_path_len); memcpy(real_path, working_path, 1+working_path_len);
} }
} }
else { else {
libssh2_session_free(ssh->ssh_session);
ssh->ssh_session = NULL;
Curl_safefree(working_path); Curl_safefree(working_path);
state(conn, SSH_STOP); state(conn, SSH_SESSION_FREE);
result = CURLE_FAILED_INIT; sshc->actualCode = CURLE_FAILED_INIT;
break; break;
} }
Curl_safefree(working_path); Curl_safefree(working_path);
ssh->path = real_path; ssh->path = real_path;
/*
*****************************************
*****************************************
** TEMPORARY **
*****************************************
*****************************************
*/
/* Set libssh2 to non-blocking, since cURL is all non-blocking */
libssh2_session_set_blocking(ssh->ssh_session, 1);
/* Connect is all done */ /* Connect is all done */
state(conn, SSH_STOP); state(conn, SSH_STOP);
} }
break; break;
case SSH_SFTP_SHUTDOWN:
rc = libssh2_sftp_shutdown(ssh->sftp_session);
if (rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
ssh->sftp_session = NULL;
state(conn, SSH_SESSION_FREE);
break;
case SSH_SESSION_FREE:
rc = libssh2_session_free(ssh->ssh_session);
if (rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
ssh->ssh_session = NULL;
state(conn, SSH_STOP);
result = sshc->actualCode;
break;
case SSH_QUIT: case SSH_QUIT:
/* fallthrough, just stop! */ /* fallthrough, just stop! */
default: default:
@ -1277,6 +1264,11 @@ ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
nwrite = (ssize_t) nwrite = (ssize_t)
libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel, libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel,
mem, len); mem, len);
#if (LIBSSH2_APINO >= 200706012030)
if (nwrite == LIBSSH2_ERROR_EAGAIN) {
return 0;
}
#endif
#endif #endif
(void)sockindex; (void)sockindex;
return nwrite; return nwrite;
@ -1710,9 +1702,17 @@ CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
} }
if (sftp->sftp_session) { if (sftp->sftp_session) {
#if (LIBSSH2_APINO >= 200706012030)
while ((ret = libssh2_sftp_shutdown(sftp->sftp_session)) ==
LIBSSH2_ERROR_EAGAIN);
if (ret < 0) {
infof(conn->data, "Failed to stop libssh2 sftp subsystem\n");
}
#else /* !(LIBSSH2_APINO >= 200706012030) */
if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) { if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) {
infof(conn->data, "Failed to stop libssh2 sftp subsystem\n"); infof(conn->data, "Failed to stop libssh2 sftp subsystem\n");
} }
#endif /* !(LIBSSH2_APINO >= 200706012030) */
} }
if (sftp->ssh_channel) { if (sftp->ssh_channel) {
@ -1764,11 +1764,39 @@ ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
#else #else
nwrite = (ssize_t) nwrite = (ssize_t)
libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
#if (LIBSSH2_APINO >= 200706012030)
if (nwrite == LIBSSH2_ERROR_EAGAIN) {
return 0;
}
#endif
#endif #endif
(void)sockindex; (void)sockindex;
return nwrite; return nwrite;
} }
/*
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
* a regular CURLcode value.
*/
ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
char *mem, size_t len)
{
ssize_t nread;
(void)sockindex;
/* libssh2_sftp_read() returns size_t !*/
#if defined(LIBSSH2SFTP_EAGAIN) && (LIBSSH2_APINO < 200706012030)
/* we prefer the non-blocking API but that didn't exist previously */
nread = (ssize_t)
libssh2_sftp_readnb(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
#else
nread = (ssize_t)
libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
#endif
return nread;
}
/* The get_pathname() function is being borrowed from OpenSSH sftp.c /* The get_pathname() function is being borrowed from OpenSSH sftp.c
version 4.6p1. */ version 4.6p1. */
/* /*
@ -2188,28 +2216,54 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
return CURLE_OK; return CURLE_OK;
} }
/* /*
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return * Create the path sftp->path on the remote site
* a regular CURLcode value. * returns CURL_OK on success, -1 on failure
*/ */
ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex, static CURLcode sftp_create_dirs(struct connectdata *conn) {
char *mem, size_t len) CURLcode result = CURLE_OK;
{ unsigned int sftp_err = 0;
ssize_t nread; int rc;
(void)sockindex; struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
/* libssh2_sftp_read() returns size_t !*/ if (strlen(sftp->path) > 1) {
char *slash_pos = sftp->path + 1; /* ignore the leading '/' */
#if defined(LIBSSH2SFTP_EAGAIN) && (LIBSSH2_APINO < 200706012030) while ((slash_pos = strchr(slash_pos, '/')) != NULL) {
/* we prefer the non-blocking API but that didn't exist previously */ *slash_pos = 0;
nread = (ssize_t)
libssh2_sftp_readnb(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); infof(conn->data, "Creating directory '%s'\n", sftp->path);
#else /* 'mode' - parameter is preliminary - default to 0644 */
nread = (ssize_t) #if (LIBSSH2_APINO >= 200706012030)
libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len); while ((rc = libssh2_sftp_mkdir(sftp->sftp_session, sftp->path,
#endif LIBSSH2_SFTP_S_IRWXU |
return nread; LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH)) ==
LIBSSH2_ERROR_EAGAIN);
#else /* !(LIBSSH2_APINO >= 200706012030) */
rc = libssh2_sftp_mkdir(sftp->sftp_session, sftp->path,
LIBSSH2_SFTP_S_IRWXU |
LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP |
LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH);
#endif /* !(LIBSSH2_APINO >= 200706012030) */
*slash_pos = '/';
++slash_pos;
if (rc == -1) {
/* abort if failure wasn't that the dir already exists or the
* permission was denied (creation might succeed further
* down the path) - retry on unspecific FAILURE also
*/
sftp_err = libssh2_sftp_last_error(sftp->sftp_session);
if ((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
(sftp_err != LIBSSH2_FX_FAILURE) &&
(sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
result = -1;
break;
}
}
}
}
return result;
} }
#endif /* USE_LIBSSH2 */ #endif /* USE_LIBSSH2 */

View File

@ -425,6 +425,8 @@ typedef enum {
SSH_SFTP_INIT, SSH_SFTP_INIT,
SSH_SFTP_REALPATH, SSH_SFTP_REALPATH,
SSH_GET_WORKINGPATH, SSH_GET_WORKINGPATH,
SSH_SFTP_SHUTDOWN,
SSH_SESSION_FREE,
SSH_QUIT, SSH_QUIT,
SSH_LAST /* never used */ SSH_LAST /* never used */
} sshstate; } sshstate;
@ -453,6 +455,7 @@ struct ssh_conn {
char rsa[PATH_MAX]; char rsa[PATH_MAX];
bool authed; bool authed;
sshstate state; /* always use ssh.c:state() to change state! */ sshstate state; /* always use ssh.c:state() to change state! */
CURLcode actualCode; /* the actual error code */
}; };