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:
122
src/channel.c
122
src/channel.c
@@ -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 *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id)
|
||||||
{
|
{
|
||||||
LIBSSH2_CHANNEL *channel = session->channels.head;
|
LIBSSH2_CHANNEL *channel = session->channels.head;
|
||||||
|
|
||||||
while (channel) {
|
while (channel) {
|
||||||
if (channel->local.id == channel_id) {
|
if (channel->local.id == channel_id) {
|
||||||
return channel;
|
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,
|
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)
|
char *message, int message_len)
|
||||||
{
|
{
|
||||||
LIBSSH2_CHANNEL *channel;
|
LIBSSH2_CHANNEL *channel = NULL;
|
||||||
unsigned long local_channel = libssh2_channel_nextid(session);
|
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) +
|
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) */
|
window_size(4) + packet_size(4) */
|
||||||
unsigned char *data;
|
unsigned char *data = NULL;
|
||||||
unsigned long data_len;
|
unsigned long data_len;
|
||||||
int polls = 0;
|
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);
|
s = packet = LIBSSH2_ALLOC(session, packet_len);
|
||||||
if (!packet) {
|
if (!packet) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0);
|
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)) {
|
if (libssh2_packet_write(session, packet, packet_len)) {
|
||||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
|
||||||
LIBSSH2_FREE(session, packet);
|
goto channel_error;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
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 */
|
/* TODO: provide reason code and description */
|
||||||
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
|
||||||
LIBSSH2_FREE(session, data);
|
goto channel_error;
|
||||||
LIBSSH2_FREE(session, packet);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
usleep(LIBSSH2_SOCKET_POLL_UDELAY);
|
||||||
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
|
||||||
/* Give up waiting */
|
/* Give up waiting */
|
||||||
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
|
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timed out waiting for response", 0);
|
||||||
LIBSSH2_FREE(session, packet);
|
goto channel_error;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LIBSSH2_FREE(session, packet);
|
|
||||||
|
|
||||||
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
channel->remote.id = libssh2_ntohu32(data + 5);
|
||||||
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->local.window_size = libssh2_ntohu32(data + 9);
|
channel->local.window_size = libssh2_ntohu32(data + 9);
|
||||||
channel->local.window_size_initial = libssh2_ntohu32(data + 9);
|
channel->local.window_size_initial = libssh2_ntohu32(data + 9);
|
||||||
channel->local.packet_size = libssh2_ntohu32(data + 13);
|
channel->local.packet_size = libssh2_ntohu32(data + 13);
|
||||||
|
|
||||||
channel->remote.id = libssh2_ntohu32(data + 5);
|
LIBSSH2_FREE(session, packet);
|
||||||
channel->remote.window_size = window_size;
|
|
||||||
channel->remote.window_size_initial = window_size;
|
|
||||||
channel->remote.packet_size = packet_size;
|
|
||||||
|
|
||||||
LIBSSH2_FREE(session, data);
|
LIBSSH2_FREE(session, data);
|
||||||
|
|
||||||
libssh2_channel_add(session, channel);
|
|
||||||
|
|
||||||
return 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_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 char *message, *s;
|
||||||
unsigned long host_len = strlen(host), shost_len = strlen(shost);
|
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) */
|
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;
|
memcpy(s, shost, shost_len); s += shost_len;
|
||||||
libssh2_htonu32(s, sport); s += 4;
|
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;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user