fixed sftp_shutdown() for the blockiness and fixed libssh2_channel_close()

to work properly non-blocking
This commit is contained in:
Daniel Stenberg
2009-03-27 20:20:48 +00:00
parent ad8b49b208
commit 4353711127
4 changed files with 114 additions and 72 deletions

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2008-2009 by Daniel Stenberg * Copyright (c) 2008-2009 by Daniel Stenberg
* *
* All rights reserved. * All rights reserved.
@@ -2302,9 +2302,6 @@ channel_close(LIBSSH2_CHANNEL * channel)
_libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu", _libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu",
channel->local.id, channel->remote.id); channel->local.id, channel->remote.id);
if (channel->close_cb) {
LIBSSH2_CHANNEL_CLOSE(session, channel);
}
channel->local.close = 1; channel->local.close = 1;
channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE; channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
@@ -2329,20 +2326,25 @@ channel_close(LIBSSH2_CHANNEL * channel)
if (channel->close_state == libssh2_NB_state_sent) { if (channel->close_state == libssh2_NB_state_sent) {
/* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */ /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
if (!channel->remote.close) {
libssh2pack_t ret;
do { while (!channel->remote.close && !rc) {
ret = _libssh2_transport_read(session); rc = _libssh2_transport_read(session);
if (ret == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
return PACKET_EAGAIN; return PACKET_EAGAIN;
} else if (ret < 0) { }
rc = -1; else if (rc < 0)
} rc = -1;
} while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0)); else
rc = 0;
} }
} }
/* We call the callback last in this function to make it keep the local
data as long as EAGAIN is returned. */
if (channel->close_cb) {
LIBSSH2_CHANNEL_CLOSE(session, channel);
}
channel->close_state = libssh2_NB_state_idle; channel->close_state = libssh2_NB_state_idle;
return rc; return rc;
@@ -2357,9 +2359,7 @@ LIBSSH2_API int
libssh2_channel_close(LIBSSH2_CHANNEL *channel) libssh2_channel_close(LIBSSH2_CHANNEL *channel)
{ {
int rc; int rc;
BLOCK_ADJUST(rc, channel->session, channel_close(channel) ); BLOCK_ADJUST(rc, channel->session, channel_close(channel) );
return rc; return rc;
} }
@@ -2420,14 +2420,14 @@ libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel)
} }
/* /*
* channel_free * _libssh2_channel_free
* *
* Make sure a channel is closed, then remove the channel from the session * Make sure a channel is closed, then remove the channel from the session
* and free its resource(s) * and free its resource(s)
* *
* Returns 0 on success, negative on failure * Returns 0 on success, negative on failure
*/ */
static int channel_free(LIBSSH2_CHANNEL *channel) int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
{ {
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
unsigned char channel_id[4]; unsigned char channel_id[4];
@@ -2527,7 +2527,7 @@ LIBSSH2_API int
libssh2_channel_free(LIBSSH2_CHANNEL *channel) libssh2_channel_free(LIBSSH2_CHANNEL *channel)
{ {
int rc; int rc;
BLOCK_ADJUST(rc, channel->session, channel_free(channel)); BLOCK_ADJUST(rc, channel->session, _libssh2_channel_free(channel));
return rc; return rc;
} }
/* /*

View File

@@ -60,5 +60,15 @@ int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
*/ */
int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid); int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid);
/*
* _libssh2_channel_free
*
* Make sure a channel is closed, then remove the channel from the session
* and free its resource(s)
*
* Returns 0 on success, negative on failure
*/
int _libssh2_channel_free(LIBSSH2_CHANNEL *channel);
#endif /* __LIBSSH2_CHANNEL_H */ #endif /* __LIBSSH2_CHANNEL_H */

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> /* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
* Copyright (c) 2009 by Daniel Stenberg * Copyright (c) 2009 by Daniel Stenberg
* All rights reserved. * All rights reserved.
* *
@@ -1467,7 +1467,8 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
} }
if (active_fds) { if (active_fds) {
/* Don't block on the sockets if we have channels/listeners which are ready */ /* Don't block on the sockets if we have channels/listeners which
are ready */
timeout_remaining = 0; timeout_remaining = 0;
} }
#ifdef HAVE_POLL #ifdef HAVE_POLL

View File

@@ -38,6 +38,7 @@
#include "libssh2_priv.h" #include "libssh2_priv.h"
#include "libssh2_sftp.h" #include "libssh2_sftp.h"
#include "channel.h"
/* Note: Version 6 was documented at the time of writing /* Note: Version 6 was documented at the time of writing
* However it was marked as "DO NOT IMPLEMENT" due to pending changes * However it was marked as "DO NOT IMPLEMENT" due to pending changes
@@ -83,6 +84,8 @@
/* S_IFDIR */ /* S_IFDIR */
#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000 #define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000
static int sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
/* libssh2_htonu64 /* libssh2_htonu64
*/ */
static void static void
@@ -516,10 +519,19 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
(void) session_abstract; (void) session_abstract;
(void) channel; (void) channel;
#if 0
/* EEEK! While it might sound like a neat idea to make this code loop over
all the outstanding handles and close them, that is going to cause
EAGAIN to get returned and this callback system is not designed to
handle this very nicely so thus we now DEMAND that the app closes its
handles instead!
*/
/* Loop through handles closing them */ /* Loop through handles closing them */
while (sftp->handles) { while (sftp->handles) {
libssh2_sftp_close_handle(sftp->handles); sftp_close_handle(sftp->handles);
} }
#endif
/* Free the partial packet storage for sftp_packet_read */ /* Free the partial packet storage for sftp_packet_read */
if (sftp->partial_packet) { if (sftp->partial_packet) {
@@ -688,7 +700,8 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
} }
LIBSSH2_FREE(session, data); LIBSSH2_FREE(session, data);
/* Make sure that when the channel gets closed, the SFTP service is shut down too */ /* Make sure that when the channel gets closed, the SFTP service is shut
down too */
session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp; session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp;
session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor; session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor;
@@ -718,61 +731,79 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
return ptr; return ptr;
} }
/*
* sftp_shutdown
*
* Shutsdown the SFTP subsystem
*/
static int
sftp_shutdown(LIBSSH2_SFTP *sftp)
{
int rc;
LIBSSH2_SESSION *session = sftp->channel->session;
/*
* Make sure all memory used in the state variables are free
*/
if (sftp->partial_packet) {
LIBSSH2_FREE(session, sftp->partial_packet);
sftp->partial_packet = NULL;
}
if (sftp->open_packet) {
LIBSSH2_FREE(session, sftp->open_packet);
sftp->open_packet = NULL;
}
if (sftp->readdir_packet) {
LIBSSH2_FREE(session, sftp->readdir_packet);
sftp->readdir_packet = NULL;
}
if (sftp->write_packet) {
LIBSSH2_FREE(session, sftp->write_packet);
sftp->write_packet = NULL;
}
if (sftp->fstat_packet) {
LIBSSH2_FREE(session, sftp->fstat_packet);
sftp->fstat_packet = NULL;
}
if (sftp->unlink_packet) {
LIBSSH2_FREE(session, sftp->unlink_packet);
sftp->unlink_packet = NULL;
}
if (sftp->rename_packet) {
LIBSSH2_FREE(session, sftp->rename_packet);
sftp->rename_packet = NULL;
}
if (sftp->mkdir_packet) {
LIBSSH2_FREE(session, sftp->mkdir_packet);
sftp->mkdir_packet = NULL;
}
if (sftp->rmdir_packet) {
LIBSSH2_FREE(session, sftp->rmdir_packet);
sftp->rmdir_packet = NULL;
}
if (sftp->stat_packet) {
LIBSSH2_FREE(session, sftp->stat_packet);
sftp->stat_packet = NULL;
}
if (sftp->symlink_packet) {
LIBSSH2_FREE(session, sftp->symlink_packet);
sftp->symlink_packet = NULL;
}
rc = _libssh2_channel_free(sftp->channel);
return rc;
}
/* libssh2_sftp_shutdown /* libssh2_sftp_shutdown
* Shutsdown the SFTP subsystem * Shutsdown the SFTP subsystem
*/ */
LIBSSH2_API int LIBSSH2_API int
libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp)
{ {
/* int rc;
* Make sure all memory used in the state variables are free BLOCK_ADJUST(rc, sftp->channel->session,
*/ sftp_shutdown(sftp));
if (sftp->partial_packet) { return rc;
LIBSSH2_FREE(sftp->channel->session, sftp->partial_packet);
sftp->partial_packet = NULL;
}
if (sftp->open_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->open_packet);
sftp->open_packet = NULL;
}
if (sftp->readdir_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->readdir_packet);
sftp->readdir_packet = NULL;
}
if (sftp->write_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->write_packet);
sftp->write_packet = NULL;
}
if (sftp->fstat_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->fstat_packet);
sftp->fstat_packet = NULL;
}
if (sftp->unlink_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->unlink_packet);
sftp->unlink_packet = NULL;
}
if (sftp->rename_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->rename_packet);
sftp->rename_packet = NULL;
}
if (sftp->mkdir_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->mkdir_packet);
sftp->mkdir_packet = NULL;
}
if (sftp->rmdir_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->rmdir_packet);
sftp->rmdir_packet = NULL;
}
if (sftp->stat_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->stat_packet);
sftp->stat_packet = NULL;
}
if (sftp->symlink_packet) {
LIBSSH2_FREE(sftp->channel->session, sftp->symlink_packet);
sftp->symlink_packet = NULL;
}
return libssh2_channel_free(sftp->channel);
} }
/* ******************************* /* *******************************