From 77bd3c121550dfb7c94d37360a49914898f64069 Mon Sep 17 00:00:00 2001 From: Mikhail Gusarov Date: Thu, 23 Jun 2005 05:55:01 +0000 Subject: [PATCH] 'exit-status' information packet handling added --- include/libssh2.h | 3 ++- include/libssh2_priv.h | 3 +++ src/channel.c | 34 ++++++++++++++++++++++------------ src/packet.c | 25 +++++++++++++++++++++---- 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index a7dffce8..3a3e4f44 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -323,7 +323,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c #define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport); -#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) +#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize); #define libssh2_channel_forward_listen(session, port) libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) @@ -376,6 +376,7 @@ LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid); #define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) #define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) +LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); diff --git a/include/libssh2_priv.h b/include/libssh2_priv.h index 60be4700..73e792ff 100644 --- a/include/libssh2_priv.h +++ b/include/libssh2_priv.h @@ -112,6 +112,9 @@ struct _LIBSSH2_CHANNEL { int blocking; + /* channel's program exit status */ + int exit_status; + libssh2_channel_data local, remote; unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */ diff --git a/src/channel.c b/src/channel.c index e91a11ca..d244478b 100644 --- a/src/channel.c +++ b/src/channel.c @@ -7,17 +7,17 @@ * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the - * following disclaimer. + * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials - * provided with the distribution. + * provided with the distribution. * * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, @@ -99,7 +99,7 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long } \ (channel)->next = NULL; \ (session)->channels.tail = (channel); \ - (channel)->session = (session); \ + (channel)->session = (session); \ } /* {{{ libssh2_channel_open_session @@ -112,7 +112,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c LIBSSH2_CHANNEL *channel = NULL; unsigned long local_channel = libssh2_channel_nextid(session); 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) */ unsigned char *data = NULL; unsigned long data_len; @@ -468,7 +468,7 @@ LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varnam LIBSSH2_SESSION *session = channel->session; unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4]; unsigned long data_len; - unsigned long packet_len = varname_len + value_len + 21; /* packet_type(1) + channel_id(4) + request_len(4) + request(3)"env" + + unsigned long packet_len = varname_len + value_len + 21; /* packet_type(1) + channel_id(4) + request_len(4) + request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */ #ifdef LIBSSH2_DEBUG_CONNECTION @@ -528,7 +528,7 @@ LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *t LIBSSH2_SESSION *session = channel->session; unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4]; unsigned long data_len; - unsigned long packet_len = term_len + modes_len + 41; /* packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) + want_reply(1) + + unsigned long packet_len = term_len + modes_len + 41; /* packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) + want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) + height_px(4) + modes_len(4) */ #ifdef LIBSSH2_DEBUG_CONNECTION @@ -598,7 +598,7 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_ unsigned long data_len; unsigned long proto_len = auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1); unsigned long cookie_len = auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN; - unsigned long packet_len = proto_len + cookie_len + 41; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) + + unsigned long packet_len = proto_len + cookie_len + 41; /* packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + want_reply(1) + single_cnx(4) + proto_len(4) + cookie_len(4) + screen_num(4) */ #ifdef LIBSSH2_DEBUG_CONNECTION @@ -787,6 +787,16 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid) } /* }}} */ +/* {{{ libssh2_channel_get_exit_status + * Return the channel's program exit status + */ +LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel) +{ + return channel->exit_status; +} + +/* }}} */ + /* {{{ libssh2_channel_receive_window_adjust * Adjust the receive window for a channel by adjustment bytes * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 @@ -1057,7 +1067,7 @@ LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel) LIBSSH2_PACKET *packet = session->packets.head; while (packet) { - if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) && + if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) { /* There's data waiting to be read yet, mask the EOF status */ return 0; @@ -1122,7 +1132,7 @@ LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel) return -1; } - /* channel->remote.close *might* not be set yet, Well... + /* channel->remote.close *might* not be set yet, Well... * We've sent the close packet, what more do you want? * Just let packet_add ignore it when it finally arrives */ diff --git a/src/packet.c b/src/packet.c index a765fce4..d3326bc1 100644 --- a/src/packet.c +++ b/src/packet.c @@ -156,7 +156,7 @@ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char if (libssh2_packet_write(session, packet, 17)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0); - return -1; + return -1; } /* Link the channel into the end of the queue list */ @@ -269,7 +269,7 @@ inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data if (libssh2_packet_write(session, packet, 17)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0); - return -1; + return -1; } /* Link the channel into the session */ @@ -497,6 +497,23 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz return 0; } break; + case SSH_MSG_CHANNEL_REQUEST: + { + if (libssh2_ntohu32(data+5) == sizeof("exit-status") - 1 + && !memcmp("exit-status", data + 9, sizeof("exit-status") - 1)) { + + /* we've got "exit-status" packet. Set the session value */ + LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1)); + + if (channel) { +#ifdef LIBSSH2_DEBUG_CONNECTION + _libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status received for channel %lu/%lu", channel->local.id, channel->remote.id); +#endif + channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status")); + } + } + } + break; case SSH_MSG_CHANNEL_CLOSE: { LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1)); @@ -900,7 +917,7 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) /* {{{ libssh2_packet_ask * Scan the brigade for a matching packet type, optionally poll the socket for a packet first */ -int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, +int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket) { LIBSSH2_PACKET *packet = session->packets.head; @@ -945,7 +962,7 @@ int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, u /* {{{ libssh2_packet_askv * Scan for any of a list of packet types in the brigade, optionally poll the socket for a packet first */ -int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, +int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket) { int i, packet_types_len = strlen(packet_types);