Packet queueing mechanism allows data which immediately follows

open confirmation to get ignored.  Work around this by adding the channel
to the list before opening it.
This commit is contained in:
Sara Golemon
2004-12-17 04:27:29 +00:00
parent 26e7e66ecf
commit 6fdf9c9c06

View File

@@ -72,7 +72,6 @@ static unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session)
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id)
{
LIBSSH2_CHANNEL *channel = session->channels.head;
while (channel) {
if (channel->local.id == channel_id) {
return channel;
@@ -104,15 +103,39 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, char *channel_type, int channel_type_len, int window_size, int packet_size,
char *message, int message_len)
{
LIBSSH2_CHANNEL *channel;
LIBSSH2_CHANNEL *channel = NULL;
unsigned long local_channel = libssh2_channel_nextid(session);
unsigned char *s, *packet;
unsigned char *s, *packet = NULL;
unsigned long packet_len = channel_type_len + message_len + 17; /* packet_type(1) + channel_type_len(4) + sender_channel(4) +
window_size(4) + packet_size(4) */
unsigned char *data;
unsigned char *data = NULL;
unsigned long data_len;
int polls = 0;
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
return NULL;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->channel_type_len = channel_type_len;
channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
if (!channel->channel_type) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
LIBSSH2_FREE(session, channel);
return NULL;
}
memcpy(channel->channel_type, channel_type, channel_type_len);
/* REMEMBER: local as in locally sourced */
channel->local.id = local_channel;
channel->remote.window_size = window_size;
channel->remote.window_size_initial = window_size;
channel->remote.packet_size = packet_size;
libssh2_channel_add(session, channel);
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0);
@@ -132,8 +155,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
LIBSSH2_FREE(session, packet);
return NULL;
goto channel_error;
}
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
@@ -146,62 +168,62 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
/* TODO: provide reason code and description */
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
LIBSSH2_FREE(session, data);
LIBSSH2_FREE(session, packet);
return NULL;
goto channel_error;
}
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
/* Give up waiting */
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
LIBSSH2_FREE(session, packet);
return NULL;
goto channel_error;
}
}
LIBSSH2_FREE(session, packet);
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
if (!channel) {
/* Play nice and close that channel that we're not going to use after all */
data[3] = SSH_MSG_CHANNEL_CLOSE;
libssh2_packet_write(session, data + 3, 5);
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
LIBSSH2_FREE(session, data);
return NULL;
}
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
channel->channel_type_len = channel_type_len;
channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
if (!channel->channel_type) {
/* Play nice and close that channel that we're not going to use after all */
data[4] = SSH_MSG_CHANNEL_CLOSE;
libssh2_packet_write(session, data + 4, 5);
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
LIBSSH2_FREE(session, channel);
return NULL;
}
memcpy(channel->channel_type, channel_type, channel_type_len);
/* REMEMBER: local as in locally sourced */
channel->local.id = local_channel;
channel->remote.id = libssh2_ntohu32(data + 5);
channel->local.window_size = libssh2_ntohu32(data + 9);
channel->local.window_size_initial = libssh2_ntohu32(data + 9);
channel->local.packet_size = libssh2_ntohu32(data + 13);
channel->remote.id = libssh2_ntohu32(data + 5);
channel->remote.window_size = window_size;
channel->remote.window_size_initial = window_size;
channel->remote.packet_size = packet_size;
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, data);
libssh2_channel_add(session, channel);
return channel;
channel_error:
if (data) {
LIBSSH2_FREE(session, data);
}
if (packet) {
LIBSSH2_FREE(session, packet);
}
if (channel) {
unsigned char channel_id[4];
LIBSSH2_FREE(session, channel->channel_type);
if (channel->next) {
channel->next->prev = channel->prev;
}
if (channel->prev) {
channel->prev->next = channel->next;
}
if (session->channels.head == channel) {
session->channels.head = channel->next;
}
if (session->channels.tail == channel) {
session->channels.tail = channel->prev;
}
/* Clear out packets meant for this channel */
libssh2_htonu32(channel_id, channel->local.id);
while ((libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0) ||
(libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0)) {
LIBSSH2_FREE(session, data);
}
LIBSSH2_FREE(session, channel);
}
return NULL;
}
/* }}} */
@@ -210,6 +232,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
*/
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport)
{
LIBSSH2_CHANNEL *channel;
unsigned char *message, *s;
unsigned long host_len = strlen(host), shost_len = strlen(shost);
unsigned long message_len = host_len + shost_len + 16; /* host_len(4) + port(4) + shost_len(4) + sport(4) */
@@ -227,7 +250,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
memcpy(s, shost, shost_len); s += shost_len;
libssh2_htonu32(s, sport); s += 4;
return libssh2_channel_open_ex(session, "direct-tcpip", sizeof("direct-tcpip") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, message, message_len);
channel = libssh2_channel_open_ex(session, "direct-tcpip", sizeof("direct-tcpip") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, message, message_len);
LIBSSH2_FREE(session, message);
return channel;
}
/* }}} */