1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-30 13:01:23 +03:00

Add support for async global requests

Normally the infamous packet_wait() synchronous call
is gone in all SSH2 client code.
This commit is contained in:
Aris Adamantiadis
2010-01-06 21:48:44 +01:00
parent 84e6aca5c5
commit ef5dc6cd2b
4 changed files with 92 additions and 21 deletions

View File

@@ -68,6 +68,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf);
SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail);
SSH_PACKET_CALLBACK(ssh_packet_channel_success);
SSH_PACKET_CALLBACK(ssh_packet_channel_failure);
SSH_PACKET_CALLBACK(ssh_request_success);
SSH_PACKET_CALLBACK(ssh_request_denied);
ssh_channel channel_new(ssh_session session);
int channel_default_bufferize(ssh_channel channel, void *data, int len,

View File

@@ -25,6 +25,7 @@
#include "libssh/packet.h"
#include "libssh/pcap.h"
#include "libssh/auth.h"
#include "libssh/channels.h"
typedef struct ssh_kbdint_struct* ssh_kbdint;
@@ -82,7 +83,7 @@ struct ssh_session_struct {
int dh_handshake_state;
enum ssh_auth_service_state_e auth_service_state;
enum ssh_auth_state_e auth_state;
enum ssh_channel_request_state_e global_req_state;
ssh_string dh_server_signature; //information used by dh_handshake.
KEX server_kex;
KEX client_kex;

View File

@@ -1499,13 +1499,70 @@ ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms) {
return channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
}
/** @internal
* @brief handle a SSH_REQUEST_SUCCESS packet normally sent after a global request.
*/
SSH_PACKET_CALLBACK(ssh_request_success){
(void)type;
(void)user;
(void)packet;
enter_function();
ssh_log(session, SSH_LOG_PACKET,
"Received SSH_REQUEST_SUCCESS");
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){
ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_SUCCESS received in incorrect state %d",
session->global_req_state);
} else {
session->global_req_state=SSH_CHANNEL_REQ_STATE_ACCEPTED;
}
leave_function();
return SSH_PACKET_USED;
}
/** @internal
* @brief handle a SSH_REQUEST_DENIED packet normally sent after a global request.
*/
SSH_PACKET_CALLBACK(ssh_request_denied){
(void)type;
(void)user;
(void)packet;
enter_function();
ssh_log(session, SSH_LOG_PACKET,
"Received SSH_REQUEST_FAILURE");
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING){
ssh_log(session, SSH_LOG_RARE, "SSH_REQUEST_DENIED received in incorrect state %d",
session->global_req_state);
} else {
session->global_req_state=SSH_CHANNEL_REQ_STATE_DENIED;
}
leave_function();
return SSH_PACKET_USED;
}
/** @brief sends a global request (needed for forward listening) and wait
* for the result.
* @param session ssh session handle
* @param request the type of request (defined in RFC)
* @param buffer additional data to put in packet
* @param reply expect a reply from server
* @return SSH_OK or SSH_ERROR
*/
static int global_request(ssh_session session, const char *request,
ssh_buffer buffer, int reply) {
ssh_string req = NULL;
int rc = SSH_ERROR;
enter_function();
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_FATAL,"Invalid state in start of global_request()");
leave_function();
return rc;
}
req = string_from_char(request);
if (req == NULL) {
goto error;
@@ -1517,6 +1574,7 @@ static int global_request(ssh_session session, const char *request,
goto error;
}
string_free(req);
req=NULL;
if (buffer != NULL) {
if (buffer_add_data(session->out_buffer, buffer_get(buffer),
@@ -1524,40 +1582,50 @@ static int global_request(ssh_session session, const char *request,
goto error;
}
}
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
if (packet_send(session) != SSH_OK) {
leave_function();
return rc;
}
ssh_log(session, SSH_LOG_RARE,
ssh_log(session, SSH_LOG_PACKET,
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
if (reply == 0) {
session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
leave_function();
return SSH_OK;
}
rc = packet_wait(session, SSH2_MSG_REQUEST_SUCCESS, 1);
if (rc == SSH_ERROR) {
if (session->in_packet.type == SSH2_MSG_REQUEST_FAILURE) {
ssh_log(session, SSH_LOG_PACKET,
"%s channel request failed", request);
ssh_set_error(session, SSH_REQUEST_DENIED,
"Channel request %s failed", request);
} else {
ssh_log(session, SSH_LOG_RARE,
"Received an unexpected %d message", session->in_packet.type);
while(session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING){
rc=ssh_handle_packets(session);
if(rc==SSH_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
break;
}
} else {
ssh_log(session, SSH_LOG_RARE, "Received a SUCCESS");
}
switch(session->global_req_state){
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
ssh_log(session, SSH_LOG_PROTOCOL, "Global request %s success",request);
rc=SSH_OK;
break;
case SSH_CHANNEL_REQ_STATE_DENIED:
ssh_log(session, SSH_LOG_PACKET,
"Global request %s failed", request);
ssh_set_error(session, SSH_REQUEST_DENIED,
"Global request %s failed", request);
rc=SSH_ERROR;
break;
case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_NONE:
case SSH_CHANNEL_REQ_STATE_PENDING:
rc=SSH_ERROR;
break;
}
leave_function();
return rc;
error:
buffer_reinit(session->out_buffer);
string_free(req);
leave_function();
return rc;
}

View File

@@ -78,8 +78,8 @@ ssh_packet_callback default_packet_handlers[]= {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //62-79
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, //#define SSH2_MSG_GLOBAL_REQUEST 80
NULL, //#define SSH2_MSG_REQUEST_SUCCESS 81
NULL, //#define SSH2_MSG_REQUEST_FAILURE 82
ssh_request_success, //#define SSH2_MSG_REQUEST_SUCCESS 81
ssh_request_denied, //#define SSH2_MSG_REQUEST_FAILURE 82
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 83-89
NULL, //#define SSH2_MSG_CHANNEL_OPEN 90
ssh_packet_channel_open_conf, //#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91