Commit b49dcfb5 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

- Jeff Weber reported memory leaks with aborted SCP and SFTP transfers and

  provided excellent repeat recipes. I fixed the cases I managed to reproduce
  but Jeff still got some (SCP) problems even after these fixes:
  http://curl.haxx.se/mail/lib-2008-05/0342.html
parent c62d5534
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,12 @@
                                  Changelog
                                  Changelog




Daniel Stenberg (28 May 2008)
- Jeff Weber reported memory leaks with aborted SCP and SFTP transfers and
  provided excellent repeat recipes. I fixed the cases I managed to reproduce
  but Jeff still got some (SCP) problems even after these fixes:
  http://curl.haxx.se/mail/lib-2008-05/0342.html

Daniel Stenberg (26 May 2008)
Daniel Stenberg (26 May 2008)
- Bug report #1973352 (http://curl.haxx.se/bug/view.cgi?id=1973352) identified
- Bug report #1973352 (http://curl.haxx.se/bug/view.cgi?id=1973352) identified
  how the HTTP redirect following code didn't properly follow to a new URL if
  how the HTTP redirect following code didn't properly follow to a new URL if
+2 −1
Original line number Original line Diff line number Diff line
@@ -38,6 +38,7 @@ This release includes the following bugfixes:
 o several curl_multi_socket() fixes
 o several curl_multi_socket() fixes
 o builds fine for Haiku OS
 o builds fine for Haiku OS
 o follow redirect with only a new query string
 o follow redirect with only a new query string
 o SCP and SFTP memory leaks on aborted transfers


This release includes the following known bugs:
This release includes the following known bugs:


@@ -60,6 +61,6 @@ advice from friends like these:
 Rafa Muyo, Andre Guibert de Bruet, Brock Noland, Sandor Feldi, Stefan Krause,
 Rafa Muyo, Andre Guibert de Bruet, Brock Noland, Sandor Feldi, Stefan Krause,
 David Shaw, Norbert Frese, Bart Whiteley, Jean-Francois Bertrand, Ben Van Hof,
 David Shaw, Norbert Frese, Bart Whiteley, Jean-Francois Bertrand, Ben Van Hof,
 Yuriy Sosov, Christopher Palow, Yang Tse, Liam Healy, Nikolai Kondrashov,
 Yuriy Sosov, Christopher Palow, Yang Tse, Liam Healy, Nikolai Kondrashov,
 David Rosenstrauch, Andreas Faerber, Scott McCreary
 David Rosenstrauch, Andreas Faerber, Scott McCreary, Jeff Weber


        Thanks! (and sorry if I forgot to mention someone)
        Thanks! (and sorry if I forgot to mention someone)
+56 −31
Original line number Original line Diff line number Diff line
@@ -1698,6 +1698,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
    break;
    break;


  case SSH_SFTP_SHUTDOWN:
  case SSH_SFTP_SHUTDOWN:
    /* during times we get here due to a broken transfer and then the
       sftp_handle might not have been taken down so make sure that is done
       before we proceed */

    if(sshc->sftp_handle) {
      rc = libssh2_sftp_close(sshc->sftp_handle);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      else if(rc < 0) {
        infof(data, "Failed to close libssh2 file\n");
      }
      sshc->sftp_handle = NULL;
    }
    if(sshc->sftp_session) {
    if(sshc->sftp_session) {
      rc = libssh2_sftp_shutdown(sshc->sftp_session);
      rc = libssh2_sftp_shutdown(sshc->sftp_session);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
      if(rc == LIBSSH2_ERROR_EAGAIN) {
@@ -1893,6 +1907,20 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
    break;
    break;


  case SSH_SESSION_DISCONNECT:
  case SSH_SESSION_DISCONNECT:
    /* during weird times when we've been prematurely aborted, the channel
       is still alive when we reach this state and we MUST kill the channel
       properly first */
    if(sshc->ssh_channel) {
      rc = libssh2_channel_free(sshc->ssh_channel);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      else if(rc < 0) {
        infof(data, "Failed to free libssh2 scp subsystem\n");
      }
      sshc->ssh_channel = NULL;
    }

    if(sshc->ssh_session) {
    if(sshc->ssh_session) {
      rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
      rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
      if(rc == LIBSSH2_ERROR_EAGAIN) {
      if(rc == LIBSSH2_ERROR_EAGAIN) {
@@ -2152,23 +2180,25 @@ static CURLcode scp_disconnect(struct connectdata *conn)
  Curl_safefree(conn->data->state.proto.ssh);
  Curl_safefree(conn->data->state.proto.ssh);
  conn->data->state.proto.ssh = NULL;
  conn->data->state.proto.ssh = NULL;


  if(conn->proto.sshc.ssh_session) {
    /* only if there's a session still around to use! */

    state(conn, SSH_SESSION_DISCONNECT);
    state(conn, SSH_SESSION_DISCONNECT);


    result = ssh_easy_statemach(conn);
    result = ssh_easy_statemach(conn);
  }


  return result;
  return result;
}
}


static CURLcode scp_done(struct connectdata *conn, CURLcode status,
/* generic done function for both SCP and SFTP called from their specific
                         bool premature)
   done functions */
static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
{
{
  CURLcode result = CURLE_OK;
  CURLcode result = CURLE_OK;
  bool done = FALSE;
  bool done = FALSE;
  (void)premature; /* not used */
  (void)status; /* unused */


  if(status == CURLE_OK) {
  if(status == CURLE_OK) {
    state(conn, SSH_SCP_DONE);
    /* run the state-machine */
    /* run the state-machine */
    if(conn->data->state.used_interface == Curl_if_multi) {
    if(conn->data->state.used_interface == Curl_if_multi) {
      result = ssh_multi_statemach(conn, &done);
      result = ssh_multi_statemach(conn, &done);
@@ -2185,12 +2215,25 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status,


  if(done) {
  if(done) {
    struct SSHPROTO *sftp_scp = conn->data->state.proto.ssh;
    struct SSHPROTO *sftp_scp = conn->data->state.proto.ssh;

    Curl_safefree(sftp_scp->path);
    Curl_safefree(sftp_scp->path);
    sftp_scp->path = NULL;
    sftp_scp->path = NULL;
    Curl_pgrsDone(conn);
    Curl_pgrsDone(conn);
  }
  }


  return result;
  return result;
}


static CURLcode scp_done(struct connectdata *conn, CURLcode status,
                         bool premature)
{
  (void)premature; /* not used */

  if(status == CURLE_OK)
    state(conn, SSH_SCP_DONE);

  return ssh_done(conn, status);


}
}


@@ -2295,8 +2338,11 @@ static CURLcode sftp_disconnect(struct connectdata *conn)
  Curl_safefree(conn->data->state.proto.ssh);
  Curl_safefree(conn->data->state.proto.ssh);
  conn->data->state.proto.ssh = NULL;
  conn->data->state.proto.ssh = NULL;


  if(conn->proto.sshc.ssh_session) {
    /* only if there's a session still around to use! */
    state(conn, SSH_SFTP_SHUTDOWN);
    state(conn, SSH_SFTP_SHUTDOWN);
    result = ssh_easy_statemach(conn);
    result = ssh_easy_statemach(conn);
  }


  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));


@@ -2307,12 +2353,8 @@ static CURLcode sftp_disconnect(struct connectdata *conn)
static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
                               bool premature)
                               bool premature)
{
{
  CURLcode result = CURLE_OK;
  bool done = FALSE;
  struct ssh_conn *sshc = &conn->proto.sshc;
  struct ssh_conn *sshc = &conn->proto.sshc;


  (void)status; /* unused */

  if(status == CURLE_OK) {
  if(status == CURLE_OK) {
    /* Before we shut down, see if there are any post-quote commands to send: */
    /* Before we shut down, see if there are any post-quote commands to send: */
    if(!status && !premature && conn->data->set.postquote) {
    if(!status && !premature && conn->data->set.postquote) {
@@ -2321,25 +2363,8 @@ static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
    }
    }
    else
    else
      state(conn, SSH_SFTP_CLOSE);
      state(conn, SSH_SFTP_CLOSE);

    /* run the state-machine */
    if(conn->data->state.used_interface == Curl_if_multi)
      result = ssh_multi_statemach(conn, &done);
    else {
      result = ssh_easy_statemach(conn);
      done = TRUE;
  }
  }
  }
  return ssh_done(conn, status);
  else {
    result = status;
    done = TRUE;
  }

  if(done) {
    Curl_pgrsDone(conn);
  }

  return result;
}
}


/* return number of sent bytes */
/* return number of sent bytes */