From a4544c0117867d5cc0830497b1626f810ccc0743 Mon Sep 17 00:00:00 2001 From: Keith Dart Date: Fri, 11 Feb 2022 23:20:48 -0800 Subject: [PATCH] channel: add support for "signal" message Can send specific signals to remote process. Allows for slightly improved remote process management, if the server supports it. Integration-patches-by: Viktor Szakats * doc updates * change `signame_len` to `size_t` * variable scopes * fix checksrc warnings Closes #672 Closes #991 --- docs/Makefile.am | 1 + docs/libssh2_channel_signal_ex.3 | 32 ++++++++++++ include/libssh2.h | 6 +++ src/channel.c | 84 ++++++++++++++++++++++++++++++++ src/libssh2_priv.h | 5 ++ 5 files changed, 128 insertions(+) create mode 100644 docs/libssh2_channel_signal_ex.3 diff --git a/docs/Makefile.am b/docs/Makefile.am index 8e998638..bb2e4434 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -50,6 +50,7 @@ dist_man_MANS = \ libssh2_channel_setenv.3 \ libssh2_channel_setenv_ex.3 \ libssh2_channel_shell.3 \ + libssh2_channel_signal_ex.3 \ libssh2_channel_subsystem.3 \ libssh2_channel_wait_closed.3 \ libssh2_channel_wait_eof.3 \ diff --git a/docs/libssh2_channel_signal_ex.3 b/docs/libssh2_channel_signal_ex.3 new file mode 100644 index 00000000..236657e3 --- /dev/null +++ b/docs/libssh2_channel_signal_ex.3 @@ -0,0 +1,32 @@ +.TH libssh2_channel_signal_ex 3 "20 Apr 2023" "libssh2 1.11.0" "libssh2 manual" +.SH NAME +libssh2_channel_signal_ex -- Send a signal to process previously opened on channel. +.SH SYNOPSIS +.nf +#include + +int +libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +.fi +.SH DESCRIPTION +A signal can be delivered to the remote process/service. Some servers or +systems may not implement signals, in which case they will probably ignore this +message. + +\fIchannel\fP - Previously opened channel instance such as returned by +.BR libssh2_channel_open_ex(3) + +\fIsigname\fP - The signal name is the same as the signal name constant, without the leading "SIG". + +\fIsigname_len\fP - Length of passed signal name parameter. + +There is also a macro \fIlibssh2_channel_signal(channel, signame)\fP that supplies the strlen of the signame. + +.SH RETURN VALUE +Normal channel error codes. +LIBSSH2_ERROR_EAGAIN when it would block. + +.SH SEE ALSO +.BR libssh2_channel_get_exit_signal(3) diff --git a/include/libssh2.h b/include/libssh2.h index 0a09c40f..68bab7c8 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -850,6 +850,12 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, #define libssh2_channel_x11_req(channel, screen_number) \ libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) +LIBSSH2_API int libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len); +#define libssh2_channel_signal(channel, signame) \ + libssh2_channel_signal_ex((channel), signame, strlen(signame)) + LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, diff --git a/src/channel.c b/src/channel.c index ed3032a7..1c119cfc 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2987,3 +2987,87 @@ libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, return channel->local.window_size; } + +/* A signal can be delivered to the remote process/service using the + following message. Some systems may not implement signals, in which + case they SHOULD ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "signal" + boolean FALSE + string signal name (without the "SIG" prefix) + + 'signal name' values will be encoded as discussed in the passage + describing SSH_MSG_CHANNEL_REQUEST messages using "exit-signal" in + this section. + */ +static int channel_signal(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +{ + LIBSSH2_SESSION *session = channel->session; + int retcode = LIBSSH2_ERROR_PROTO; + + if(channel->sendsignal_state == libssh2_NB_state_idle) { + unsigned char *s; + + /* 20 = packet_type(1) + channel(4) + + signal_len + sizeof(signal) - 1 + want_reply(1) + + signame_len_len(4) */ + channel->sendsignal_packet_len = 20 + signame_len; + + s = channel->sendsignal_packet = + LIBSSH2_ALLOC(session, channel->sendsignal_packet_len); + if(!channel->sendsignal_packet) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "signal request"); + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, "signal", sizeof("signal") - 1); + *(s++) = 0x00; /* Don't reply */ + _libssh2_store_str(&s, signame, signame_len); + + channel->sendsignal_state = libssh2_NB_state_created; + } + + if(channel->sendsignal_state == libssh2_NB_state_created) { + int rc; + + rc = _libssh2_transport_send(session, channel->sendsignal_packet, + channel->sendsignal_packet_len, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, "Would block sending signal request"); + return rc; + } + else if(rc) { + LIBSSH2_FREE(session, channel->sendsignal_packet); + channel->sendsignal_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send signal packet"); + } + LIBSSH2_FREE(session, channel->sendsignal_packet); + retcode = LIBSSH2_ERROR_NONE; + } + + channel->sendsignal_state = libssh2_NB_state_idle; + + return retcode; +} + +LIBSSH2_API int +libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_signal(channel, signame, signame_len)); + return rc; +} diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 55e1a4ab..0ba35db4 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -466,6 +466,11 @@ struct _LIBSSH2_CHANNEL size_t req_auth_agent_packet_len; unsigned char req_auth_agent_local_channel[4]; packet_requirev_state_t req_auth_agent_requirev_state; + + /* State variables used in libssh2_channel_signal_ex() */ + libssh2_nonblocking_states sendsignal_state; + unsigned char *sendsignal_packet; + size_t sendsignal_packet_len; }; struct _LIBSSH2_LISTENER