mirror of
https://github.com/libssh2/libssh2.git
synced 2025-08-08 19:02:07 +03:00
send custom channel requests
This commit is contained in:
@@ -816,6 +816,19 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
|
|||||||
sizeof("subsystem") - 1, (subsystem), \
|
sizeof("subsystem") - 1, (subsystem), \
|
||||||
(unsigned int)strlen(subsystem))
|
(unsigned int)strlen(subsystem))
|
||||||
|
|
||||||
|
/* Deliver custom channel request.
|
||||||
|
|
||||||
|
data is allowed to be NULL when data_len is zero
|
||||||
|
|
||||||
|
While you can wait for reply this needs to be either success or failure as
|
||||||
|
there is no way to bring back anything else. */
|
||||||
|
LIBSSH2_API int libssh2_channel_custom_request(LIBSSH2_CHANNEL *channel,
|
||||||
|
int want_reply,
|
||||||
|
const char *request_type,
|
||||||
|
unsigned int request_type_len,
|
||||||
|
const char *data,
|
||||||
|
unsigned int data_len);
|
||||||
|
|
||||||
LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
|
LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
|
||||||
int stream_id, char *buf,
|
int stream_id, char *buf,
|
||||||
size_t buflen);
|
size_t buflen);
|
||||||
|
122
src/channel.c
122
src/channel.c
@@ -1273,6 +1273,125 @@ libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int channel_custom_request(LIBSSH2_CHANNEL *channel, int want_reply,
|
||||||
|
const char *request_type, unsigned int request_type_len,
|
||||||
|
const char *data, unsigned int data_len) {
|
||||||
|
LIBSSH2_SESSION *session = channel->session;
|
||||||
|
static const unsigned char reply_codes[3] =
|
||||||
|
{ SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(channel->channel_custom_state == libssh2_NB_state_idle) {
|
||||||
|
/* 10 = packet_type(1) + channel(4) + request_type_len(4) + want_reply(1) */
|
||||||
|
channel->channel_custom_packet_len = 10 + request_type_len + data_len;
|
||||||
|
|
||||||
|
/* Zero the whole thing out */
|
||||||
|
memset(&channel->channel_custom_packet_requirev_state, 0,
|
||||||
|
sizeof(channel->channel_custom_packet_requirev_state));
|
||||||
|
|
||||||
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
||||||
|
"custom request on channel %lu/%lu %.*s",
|
||||||
|
channel->local.id, channel->remote.id,
|
||||||
|
request_type_len, request_type);
|
||||||
|
|
||||||
|
/* make sure there isn't previous packet we would leak */
|
||||||
|
if(channel->channel_custom_packet) {
|
||||||
|
LIBSSH2_FREE(session, channel->channel_custom_packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate memory for packet */
|
||||||
|
channel->channel_custom_packet =
|
||||||
|
LIBSSH2_ALLOC(session, channel->channel_custom_packet_len);
|
||||||
|
if(!channel->channel_custom_packet) {
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
||||||
|
"Unable to allocate memory for custom channel request");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compose packet */
|
||||||
|
unsigned char *s = channel->channel_custom_packet;
|
||||||
|
*(s++) = SSH_MSG_CHANNEL_REQUEST;
|
||||||
|
_libssh2_store_u32(&s, channel->remote.id);
|
||||||
|
_libssh2_store_str(&s, request_type, request_type_len);
|
||||||
|
*(s++) = want_reply;
|
||||||
|
if(data_len > 0) {
|
||||||
|
memcpy(s, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
channel->channel_custom_state = libssh2_NB_state_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(channel->channel_custom_state == libssh2_NB_state_created) {
|
||||||
|
rc = _libssh2_transport_send(session, channel->channel_custom_packet,
|
||||||
|
channel->channel_custom_packet_len,
|
||||||
|
NULL, 0);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
_libssh2_error(session, rc,
|
||||||
|
"Would block sending custom channel request");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else if(rc) {
|
||||||
|
channel->channel_custom_state = libssh2_NB_state_idle;
|
||||||
|
return _libssh2_error(session, rc,
|
||||||
|
"Unable to send custom channel request packet");
|
||||||
|
}
|
||||||
|
_libssh2_htonu32(channel->channel_custom_local_channel, channel->local.id);
|
||||||
|
channel->channel_custom_state = libssh2_NB_state_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(channel->channel_custom_state == libssh2_NB_state_sent) {
|
||||||
|
if(!want_reply) {
|
||||||
|
channel->channel_custom_state = libssh2_NB_state_idle;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *data = 0;
|
||||||
|
size_t data_len = 0;
|
||||||
|
unsigned char code = 0;
|
||||||
|
|
||||||
|
rc = _libssh2_packet_requirev(
|
||||||
|
session, reply_codes, &data, &data_len, 1,
|
||||||
|
channel->channel_custom_local_channel,
|
||||||
|
4, &channel->channel_custom_packet_requirev_state);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else if(rc) {
|
||||||
|
channel->channel_custom_state = libssh2_NB_state_idle;
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
|
||||||
|
"Failed custom channel request");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data_len >= 1) {
|
||||||
|
code = data[0];
|
||||||
|
}
|
||||||
|
if(data) LIBSSH2_FREE(session, data);
|
||||||
|
channel->channel_custom_state = libssh2_NB_state_idle;
|
||||||
|
|
||||||
|
if(code == SSH_MSG_CHANNEL_SUCCESS) return 0;
|
||||||
|
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
|
||||||
|
"Failed custom channel request");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
|
||||||
|
"Unable to complete custom channel request");
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBSSH2_API int
|
||||||
|
libssh2_channel_custom_request(LIBSSH2_CHANNEL *channel, int want_reply,
|
||||||
|
const char *request_type, unsigned int request_type_len,
|
||||||
|
const char *data, unsigned int data_len) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if(!channel)
|
||||||
|
return LIBSSH2_ERROR_BAD_USE;
|
||||||
|
|
||||||
|
BLOCK_ADJUST(rc, channel->session,
|
||||||
|
channel_custom_request(channel, want_reply, request_type,
|
||||||
|
request_type_len, data, data_len));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Keep this an even number */
|
/* Keep this an even number */
|
||||||
#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
|
#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32
|
||||||
|
|
||||||
@@ -2792,6 +2911,9 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
|
|||||||
if(channel->process_packet) {
|
if(channel->process_packet) {
|
||||||
LIBSSH2_FREE(session, channel->process_packet);
|
LIBSSH2_FREE(session, channel->process_packet);
|
||||||
}
|
}
|
||||||
|
if(channel->channel_custom_packet) {
|
||||||
|
LIBSSH2_FREE(session, channel->channel_custom_packet);
|
||||||
|
}
|
||||||
|
|
||||||
LIBSSH2_FREE(session, channel);
|
LIBSSH2_FREE(session, channel);
|
||||||
|
|
||||||
|
@@ -419,6 +419,13 @@ struct _LIBSSH2_CHANNEL
|
|||||||
unsigned char process_local_channel[4];
|
unsigned char process_local_channel[4];
|
||||||
packet_requirev_state_t process_packet_requirev_state;
|
packet_requirev_state_t process_packet_requirev_state;
|
||||||
|
|
||||||
|
/* State variables used in libssh2_channel_custom_request() */
|
||||||
|
libssh2_nonblocking_states channel_custom_state;
|
||||||
|
unsigned char *channel_custom_packet;
|
||||||
|
size_t channel_custom_packet_len;
|
||||||
|
unsigned char channel_custom_local_channel[4];
|
||||||
|
packet_requirev_state_t channel_custom_packet_requirev_state;
|
||||||
|
|
||||||
/* State variables used in libssh2_channel_flush_ex() */
|
/* State variables used in libssh2_channel_flush_ex() */
|
||||||
libssh2_nonblocking_states flush_state;
|
libssh2_nonblocking_states flush_state;
|
||||||
size_t flush_refund_bytes;
|
size_t flush_refund_bytes;
|
||||||
|
Reference in New Issue
Block a user