mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-11 18:50:28 +09:00
Squashed commit of the following:
commit 43fad8dfd977637c31fade76ace2905f6528c3bc Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Fri Nov 27 18:39:06 2009 +0100 adaptation to the new ssh_poll_handle object name commit 1e5e6ac4605adf10d437d04f0fd4b7e66024853c Merge: 3fd92a0... 810adad... Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Fri Nov 27 18:33:06 2009 +0100 Merge branch 'master' into badcode/libssh_async commit 3fd92a08eb74b1447a9ff4ca4e1d137475c62cc6 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Mon Nov 2 14:25:46 2009 +0100 Compiles again commit 8910d7b9692418c9ccea0234f6d49674d238dc16 Merge: e83f1b5... cce34a6... Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Mon Nov 2 12:47:34 2009 +0100 Merge branch 'master' into libssh_async Very big merge ! Conflicts: include/libssh/callbacks.h include/libssh/priv.h libssh/channels.c libssh/messages.c libssh/packet.c libssh/server.c libssh/session.c libssh/socket.c commit e83f1b593219e183082b015315f09bfe95a29cfc Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Mon Nov 2 12:07:01 2009 +0100 rename callback.h commit dffa7b730e8f39e2198de18ab69a8e57bef95e58 Merge: 5a8b748... de8808c... Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Tue Sep 15 10:50:07 2009 +0200 Merge branch 'master' of git://git.libssh.org/projects/libssh/libssh into libssh_async commit 5a8b7484f36599d28f2c0c14a23b76bfc7257638 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Sun Sep 13 12:55:18 2009 +0200 More updates to callback system commit 18620c20d5e4e62107093f7fd330e553493253fa Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Sat Sep 12 22:26:52 2009 +0200 Same thing with channel_rcv_data commit fc4a56f6726e409a5866272923f1cbebfc821af3 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Sat Sep 12 22:17:45 2009 +0200 added a few packet handlers for channels commit 4b6bb4fd00b10cf1321a764126f277ab204bffe3 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Fri Sep 11 23:15:25 2009 +0300 sample packet handlers + bugfixes commit 2784d09d6dec0a8f868912d14f90d860233b3f82 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Fri Sep 11 20:30:50 2009 +0300 Packet callbacks nearly finished Need tests and implementation of some packet callbacks commit cd3ea43f20c9ae2f54576ca98a0ea75c5d4299d3 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Thu Sep 10 12:46:02 2009 +0300 First step of async packet handling The socket to packet handler is nearly done (needs testing) I still need to define the interface for callbacks. commit 487f4d2a900a5fe3b90ceda4460ab7d38d7ad722 Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Tue Sep 8 23:24:09 2009 +0300 Almost complete socket callback system Finished the callback function so it bufferizes data when callee does not use it. Flushes the buffer automaticaly after a ssh_socket_nonblocking_flush commit 23571f22fac9e40c855dfa99569bba181a39648b Author: Aris Adamantiadis <aris@0xbadc0de.be> Date: Tue Sep 8 22:22:32 2009 +0300 First draft of a callback system
This commit is contained in:
@@ -32,7 +32,21 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
typedef void (*ssh_callback_int) (void *user, int code);
|
||||||
|
/** @internal
|
||||||
|
* @brief callback for data received messages.
|
||||||
|
* @param user user-supplied pointer sent along with all callback messages
|
||||||
|
* @param data data retrieved from the socket or stream
|
||||||
|
* @param len number of bytes available from this stream
|
||||||
|
* @returns number of bytes processed by the callee. The remaining bytes will
|
||||||
|
* be sent in the next callback message, when more data is available.
|
||||||
|
*/
|
||||||
|
typedef int (*ssh_callback_data) (void *user, const void *data, size_t len);
|
||||||
|
typedef void (*ssh_callback_int_int) (void *user, int code, int errno_code);
|
||||||
|
|
||||||
|
typedef int (*ssh_message_callback) (ssh_session, void *user, ssh_message message);
|
||||||
|
typedef int (*ssh_channel_callback_int) (ssh_channel channel, void *user, int code);
|
||||||
|
typedef int (*ssh_channel_callback_data) (ssh_channel channel, void *user, int code, void *data, size_t len);
|
||||||
/**
|
/**
|
||||||
* @brief SSH authentication callback.
|
* @brief SSH authentication callback.
|
||||||
*
|
*
|
||||||
@@ -68,9 +82,36 @@ struct ssh_callbacks_struct {
|
|||||||
* of connection steps completed.
|
* of connection steps completed.
|
||||||
*/
|
*/
|
||||||
void (*connect_status_function)(void *userdata, float status);
|
void (*connect_status_function)(void *userdata, float status);
|
||||||
|
/* To be cleaned up */
|
||||||
|
ssh_callback_int connection_progress;
|
||||||
|
void *connection_progress_user;
|
||||||
|
ssh_channel_callback_int channel_write_confirm;
|
||||||
|
void *channel_write_confirm_user;
|
||||||
|
ssh_channel_callback_data channel_read_available;
|
||||||
|
void *channel_read_available_user;
|
||||||
};
|
};
|
||||||
|
typedef struct ssh_callbacks_struct *ssh_callbacks;
|
||||||
|
|
||||||
typedef struct ssh_callbacks_struct * ssh_callbacks;
|
/* This are the callbacks exported by the socket structure
|
||||||
|
* They are called by the socket module when a socket event appears
|
||||||
|
*/
|
||||||
|
struct ssh_socket_callbacks_struct {
|
||||||
|
ssh_callback_data data;
|
||||||
|
ssh_callback_int controlflow;
|
||||||
|
ssh_callback_int_int exception;
|
||||||
|
ssh_callback_int_int connected;
|
||||||
|
void *user;
|
||||||
|
};
|
||||||
|
typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks;
|
||||||
|
|
||||||
|
#define SSH_SOCKET_FLOW_WRITEWILLBLOCK (1<<0)
|
||||||
|
#define SSH_SOCKET_FLOW_WRITEWONTBLOCK (1<<1)
|
||||||
|
#define SSH_SOCKET_EXCEPTION_EOF (1<<0)
|
||||||
|
#define SSH_SOCKET_EXCEPTION_ERROR (1<<1)
|
||||||
|
|
||||||
|
#define SSH_SOCKET_CONNECTED_OK (1<<0)
|
||||||
|
#define SSH_SOCKET_CONNECTED_ERROR (1<<1)
|
||||||
|
#define SSH_SOCKET_CONNECTED_TIMEOUT (1<<2)
|
||||||
|
|
||||||
/** Initializes an ssh_callbacks_struct
|
/** Initializes an ssh_callbacks_struct
|
||||||
* A call to this macro is mandatory when you have set a new
|
* A call to this macro is mandatory when you have set a new
|
||||||
@@ -82,6 +123,21 @@ typedef struct ssh_callbacks_struct * ssh_callbacks;
|
|||||||
(p)->size=sizeof(*(p)); \
|
(p)->size=sizeof(*(p)); \
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
|
/* These are the callback exported by the packet layer
|
||||||
|
* and are called each time a packet shows up
|
||||||
|
* */
|
||||||
|
typedef int (*ssh_packet_callback) (ssh_session, void *user, uint8_t code, ssh_buffer packet);
|
||||||
|
|
||||||
|
struct ssh_packet_callbacks_struct {
|
||||||
|
/** Index of the first packet type being handled */
|
||||||
|
u_int8_t start;
|
||||||
|
/** Number of packets being handled by this callback struct */
|
||||||
|
u_int8_t n_callbacks;
|
||||||
|
/** A pointer to n_callbacks packet callbacks */
|
||||||
|
ssh_packet_callback *callbacks;
|
||||||
|
void *user;
|
||||||
|
};
|
||||||
|
typedef struct ssh_packet_callbacks_struct *ssh_packet_callbacks;
|
||||||
/**
|
/**
|
||||||
* @brief Set the callback functions.
|
* @brief Set the callback functions.
|
||||||
*
|
*
|
||||||
@@ -106,6 +162,12 @@ typedef struct ssh_callbacks_struct * ssh_callbacks;
|
|||||||
*/
|
*/
|
||||||
LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
||||||
|
|
||||||
|
/** return values for a ssh_packet_callback */
|
||||||
|
/** Packet was used and should not be parsed by another callback */
|
||||||
|
#define SSH_PACKET_USED 1
|
||||||
|
/** Packet was not used and should be passed to any other callback
|
||||||
|
* available */
|
||||||
|
#define SSH_PACKET_NOT_USED 2
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ struct ssh_message_struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void message_handle(ssh_session session, uint32_t type);
|
//void message_handle(ssh_session session, uint32_t type);
|
||||||
int ssh_execute_message_callbacks(ssh_session session);
|
int ssh_execute_message_callbacks(ssh_session session);
|
||||||
|
|
||||||
#endif /* MESSAGES_H_ */
|
#endif /* MESSAGES_H_ */
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#include "libssh/libssh.h"
|
#include "libssh/libssh.h"
|
||||||
#include "libssh/callbacks.h"
|
#include "libssh/callbacks.h"
|
||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
|
|
||||||
/* some constants */
|
/* some constants */
|
||||||
#define MAX_PACKET_LEN 262144
|
#define MAX_PACKET_LEN 262144
|
||||||
#define ERROR_BUFFERLEN 1024
|
#define ERROR_BUFFERLEN 1024
|
||||||
@@ -90,7 +91,7 @@ struct ssh_keys_struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_message_struct;
|
struct ssh_message_struct;
|
||||||
|
struct ssh_poll_handle_struct;
|
||||||
|
|
||||||
/* server data */
|
/* server data */
|
||||||
|
|
||||||
@@ -113,6 +114,14 @@ struct ssh_bind_struct {
|
|||||||
int toaccept;
|
int toaccept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct socket;
|
||||||
|
struct ssh_poll;
|
||||||
|
void ssh_socket_set_callbacks(struct socket *s, ssh_socket_callbacks callbacks);
|
||||||
|
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, int fd, int revents, void *s);
|
||||||
|
void ssh_socket_register_pollcallback(struct socket *s, struct ssh_poll_handle_struct *p);
|
||||||
|
|
||||||
|
int ssh_packet_disconnect_callback(ssh_session session, void *user, u_int8_t type, ssh_buffer packet);
|
||||||
|
int ssh_packet_ignore_callback(ssh_session session, void *user, u_int8_t type, ssh_buffer packet);
|
||||||
|
|
||||||
/* client.c */
|
/* client.c */
|
||||||
|
|
||||||
@@ -134,6 +143,11 @@ unsigned char *packet_encrypt(ssh_session session,void *packet,unsigned int len)
|
|||||||
/* it returns the hmac buffer if exists*/
|
/* it returns the hmac buffer if exists*/
|
||||||
int packet_hmac_verify(ssh_session session,ssh_buffer buffer,unsigned char *mac);
|
int packet_hmac_verify(ssh_session session,ssh_buffer buffer,unsigned char *mac);
|
||||||
|
|
||||||
|
int ssh_packet_socket_callback(void *user, const void *data, size_t len);
|
||||||
|
void ssh_packet_register_socket_callback(ssh_session session, struct socket *s);
|
||||||
|
void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks);
|
||||||
|
void ssh_packet_set_default_callbacks(ssh_session session);
|
||||||
|
void ssh_packet_process(ssh_session session, u_int8_t type);
|
||||||
/* connect.c */
|
/* connect.c */
|
||||||
int ssh_regex_init(void);
|
int ssh_regex_init(void);
|
||||||
void ssh_regex_finalize(void);
|
void ssh_regex_finalize(void);
|
||||||
@@ -152,6 +166,11 @@ char **space_tokenize(const char *chain);
|
|||||||
int ssh_get_kex1(ssh_session session);
|
int ssh_get_kex1(ssh_session session);
|
||||||
char *ssh_find_matching(const char *in_d, const char *what_d);
|
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||||
|
|
||||||
|
int channel_rcv_change_window(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
|
||||||
|
int channel_rcv_eof(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
|
||||||
|
int channel_rcv_close(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
|
||||||
|
int channel_rcv_request(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
|
||||||
|
int channel_rcv_data(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
|
||||||
/* in base64.c */
|
/* in base64.c */
|
||||||
ssh_buffer base64_to_bin(const char *source);
|
ssh_buffer base64_to_bin(const char *source);
|
||||||
unsigned char *bin_to_base64(const unsigned char *source, int len);
|
unsigned char *bin_to_base64(const unsigned char *source, int len);
|
||||||
@@ -183,6 +202,7 @@ int channel_write1(ssh_channel channel, const void *data, int len);
|
|||||||
/* match.c */
|
/* match.c */
|
||||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||||
|
|
||||||
|
int message_handle(ssh_session session, void *user, uint8_t type, ssh_buffer packet);
|
||||||
/* log.c */
|
/* log.c */
|
||||||
|
|
||||||
#ifndef __FUNCTION__
|
#ifndef __FUNCTION__
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ struct ssh_session_struct {
|
|||||||
int log_indent; /* indentation level in enter_function logs */
|
int log_indent; /* indentation level in enter_function logs */
|
||||||
|
|
||||||
ssh_callbacks callbacks; /* Callbacks to user functions */
|
ssh_callbacks callbacks; /* Callbacks to user functions */
|
||||||
|
struct ssh_packet_callbacks_struct default_packet_callbacks;
|
||||||
|
struct ssh_list *packet_callbacks;
|
||||||
|
struct ssh_socket_callbacks_struct socket_callbacks;
|
||||||
/* options */
|
/* options */
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
ssh_pcap_context pcap_ctx; /* pcap debugging context */
|
ssh_pcap_context pcap_ctx; /* pcap debugging context */
|
||||||
@@ -114,6 +116,7 @@ struct ssh_session_struct {
|
|||||||
socket_t fd;
|
socket_t fd;
|
||||||
int ssh2;
|
int ssh2;
|
||||||
int ssh1;
|
int ssh1;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int ssh_handle_packets(ssh_session session);
|
int ssh_handle_packets(ssh_session session);
|
||||||
|
|||||||
@@ -314,11 +314,13 @@ static ssh_channel channel_from_msg(ssh_session session) {
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void channel_rcv_change_window(ssh_session session) {
|
int channel_rcv_change_window(ssh_session session, void *user, u_int8_t type, ssh_buffer packet) {
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
uint32_t bytes;
|
uint32_t bytes;
|
||||||
int rc;
|
int rc;
|
||||||
|
(void)user;
|
||||||
|
(void)type;
|
||||||
|
(void)packet;
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
channel = channel_from_msg(session);
|
channel = channel_from_msg(session);
|
||||||
@@ -331,7 +333,7 @@ static void channel_rcv_change_window(ssh_session session) {
|
|||||||
ssh_log(session, SSH_LOG_PACKET,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
"Error getting a window adjust message: invalid packet");
|
"Error getting a window adjust message: invalid packet");
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = ntohl(bytes);
|
bytes = ntohl(bytes);
|
||||||
@@ -345,22 +347,29 @@ static void channel_rcv_change_window(ssh_session session) {
|
|||||||
channel->remote_window += bytes;
|
channel->remote_window += bytes;
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* is_stderr is set to 1 if the data are extended, ie stderr */
|
/* is_stderr is set to 1 if the data are extended, ie stderr */
|
||||||
static void channel_rcv_data(ssh_session session,int is_stderr) {
|
int channel_rcv_data(ssh_session session, void *user, u_int8_t type, ssh_buffer packet) {
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
ssh_string str;
|
ssh_string str;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
int is_stderr;
|
||||||
|
(void)user;
|
||||||
|
(void)packet;
|
||||||
enter_function();
|
enter_function();
|
||||||
|
if(type==SSH2_MSG_CHANNEL_DATA)
|
||||||
|
is_stderr=0;
|
||||||
|
else
|
||||||
|
is_stderr=1;
|
||||||
|
|
||||||
channel = channel_from_msg(session);
|
channel = channel_from_msg(session);
|
||||||
if (channel == NULL) {
|
if (channel == NULL) {
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
"%s", ssh_get_error(session));
|
"%s", ssh_get_error(session));
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_stderr) {
|
if (is_stderr) {
|
||||||
@@ -373,7 +382,7 @@ static void channel_rcv_data(ssh_session session,int is_stderr) {
|
|||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Invalid data packet!");
|
ssh_log(session, SSH_LOG_PACKET, "Invalid data packet!");
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
len = string_len(str);
|
len = string_len(str);
|
||||||
|
|
||||||
@@ -396,7 +405,7 @@ static void channel_rcv_data(ssh_session session,int is_stderr) {
|
|||||||
is_stderr) < 0) {
|
is_stderr) < 0) {
|
||||||
string_free(str);
|
string_free(str);
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len <= channel->local_window) {
|
if (len <= channel->local_window) {
|
||||||
@@ -412,18 +421,21 @@ static void channel_rcv_data(ssh_session session,int is_stderr) {
|
|||||||
|
|
||||||
string_free(str);
|
string_free(str);
|
||||||
leave_function();
|
leave_function();
|
||||||
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void channel_rcv_eof(ssh_session session) {
|
int channel_rcv_eof(ssh_session session, void *user, u_int8_t type, ssh_buffer packet) {
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
|
(void)user;
|
||||||
|
(void)type;
|
||||||
|
(void)packet;
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
channel = channel_from_msg(session);
|
channel = channel_from_msg(session);
|
||||||
if (channel == NULL) {
|
if (channel == NULL) {
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
|
ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
@@ -434,134 +446,142 @@ static void channel_rcv_eof(ssh_session session) {
|
|||||||
channel->remote_eof = 1;
|
channel->remote_eof = 1;
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void channel_rcv_close(ssh_session session) {
|
int channel_rcv_close(ssh_session session, void *user, u_int8_t type, ssh_buffer packet) {
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
|
(void)user;
|
||||||
|
(void)type;
|
||||||
|
(void)packet;
|
||||||
|
enter_function();
|
||||||
|
|
||||||
enter_function();
|
channel = channel_from_msg(session);
|
||||||
|
if (channel == NULL) {
|
||||||
|
ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
|
||||||
|
leave_function();
|
||||||
|
return SSH_PACKET_USED;
|
||||||
|
}
|
||||||
|
|
||||||
channel = channel_from_msg(session);
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
if (channel == NULL) {
|
"Received close on channel (%d:%d)",
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session));
|
channel->local_channel,
|
||||||
leave_function();
|
channel->remote_channel);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
if ((channel->stdout_buffer &&
|
||||||
"Received close on channel (%d:%d)",
|
buffer_get_rest_len(channel->stdout_buffer) > 0) ||
|
||||||
channel->local_channel,
|
(channel->stderr_buffer &&
|
||||||
channel->remote_channel);
|
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
|
||||||
|
channel->delayed_close = 1;
|
||||||
|
} else {
|
||||||
|
channel->open = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((channel->stdout_buffer &&
|
if (channel->remote_eof == 0) {
|
||||||
buffer_get_rest_len(channel->stdout_buffer) > 0) ||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
(channel->stderr_buffer &&
|
"Remote host not polite enough to send an eof before close");
|
||||||
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
|
}
|
||||||
channel->delayed_close = 1;
|
channel->remote_eof = 1;
|
||||||
} else {
|
/*
|
||||||
channel->open = 0;
|
* The remote eof doesn't break things if there was still data into read
|
||||||
}
|
* buffer because the eof is ignored until the buffer is empty.
|
||||||
|
*/
|
||||||
|
|
||||||
if (channel->remote_eof == 0) {
|
leave_function();
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
return SSH_PACKET_USED;
|
||||||
"Remote host not polite enough to send an eof before close");
|
|
||||||
}
|
|
||||||
channel->remote_eof = 1;
|
|
||||||
/*
|
|
||||||
* The remote eof doesn't break things if there was still data into read
|
|
||||||
* buffer because the eof is ignored until the buffer is empty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
leave_function();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void channel_rcv_request(ssh_session session) {
|
int channel_rcv_request(ssh_session session, void *user, u_int8_t type, ssh_buffer packet) {
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
ssh_string request_s;
|
ssh_string request_s;
|
||||||
char *request;
|
char *request;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
uint32_t startpos = session->in_buffer->pos;
|
uint32_t startpos = session->in_buffer->pos;
|
||||||
|
(void)user;
|
||||||
|
(void)type;
|
||||||
|
(void)packet;
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
channel = channel_from_msg(session);
|
channel = channel_from_msg(session);
|
||||||
if (channel == NULL) {
|
if (channel == NULL) {
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session));
|
ssh_log(session, SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session));
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
request_s = buffer_get_ssh_string(session->in_buffer);
|
request_s = buffer_get_ssh_string(session->in_buffer);
|
||||||
if (request_s == NULL) {
|
if (request_s == NULL) {
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
|
ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
request = string_to_char(request_s);
|
request = string_to_char(request_s);
|
||||||
string_free(request_s);
|
string_free(request_s);
|
||||||
if (request == NULL) {
|
if (request == NULL) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_get_u8(session->in_buffer, (uint8_t *) &status);
|
buffer_get_u8(session->in_buffer, (uint8_t *) &status);
|
||||||
|
|
||||||
if (strcmp(request,"exit-status") == 0) {
|
if (strcmp(request,"exit-status") == 0) {
|
||||||
SAFE_FREE(request);
|
SAFE_FREE(request);
|
||||||
ssh_log(session, SSH_LOG_PACKET, "received exit-status");
|
ssh_log(session, SSH_LOG_PACKET, "received exit-status");
|
||||||
buffer_get_u32(session->in_buffer, &status);
|
buffer_get_u32(session->in_buffer, &status);
|
||||||
channel->exit_status = ntohl(status);
|
channel->exit_status = ntohl(status);
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return ;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(request, "exit-signal") == 0) {
|
if (strcmp(request, "exit-signal") == 0) {
|
||||||
const char *core = "(core dumped)";
|
const char *core = "(core dumped)";
|
||||||
ssh_string signal_s;
|
ssh_string signal_s;
|
||||||
char *signal;
|
char *signal;
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
SAFE_FREE(request);
|
SAFE_FREE(request);
|
||||||
|
|
||||||
signal_s = buffer_get_ssh_string(session->in_buffer);
|
signal_s = buffer_get_ssh_string(session->in_buffer);
|
||||||
if (signal_s == NULL) {
|
if (signal_s == NULL) {
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
|
ssh_log(session, SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST");
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
signal = string_to_char(signal_s);
|
signal = string_to_char(signal_s);
|
||||||
string_free(signal_s);
|
string_free(signal_s);
|
||||||
if (signal == NULL) {
|
if (signal == NULL) {
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_get_u8(session->in_buffer, &i);
|
buffer_get_u8(session->in_buffer, &i);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
core = "";
|
core = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET,
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
"Remote connection closed by signal SIG %s %s", signal, core);
|
"Remote connection closed by signal SIG %s %s", signal, core);
|
||||||
SAFE_FREE(signal);
|
SAFE_FREE(signal);
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return;
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO call message_handle since it handles channel requests as messages */
|
/* TODO call message_handle since it handles channel requests as messages */
|
||||||
/* *but* reset buffer before !! */
|
/* *but* reset buffer before !! */
|
||||||
|
|
||||||
session->in_buffer->pos = startpos;
|
session->in_buffer->pos = startpos;
|
||||||
message_handle(session, SSH2_MSG_CHANNEL_REQUEST);
|
message_handle(session, NULL, SSH2_MSG_CHANNEL_REQUEST, session->in_buffer);
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Unknown request %s", request);
|
ssh_log(session, SSH_LOG_PACKET, "Unknown request %s", request);
|
||||||
SAFE_FREE(request);
|
SAFE_FREE(request);
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
return SSH_PACKET_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -575,22 +595,12 @@ void channel_handle(ssh_session session, int type){
|
|||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
||||||
channel_rcv_change_window(session);
|
|
||||||
break;
|
|
||||||
case SSH2_MSG_CHANNEL_DATA:
|
|
||||||
channel_rcv_data(session,0);
|
|
||||||
break;
|
|
||||||
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
|
||||||
channel_rcv_data(session,1);
|
|
||||||
break;
|
|
||||||
case SSH2_MSG_CHANNEL_EOF:
|
|
||||||
channel_rcv_eof(session);
|
|
||||||
break;
|
|
||||||
case SSH2_MSG_CHANNEL_CLOSE:
|
|
||||||
channel_rcv_close(session);
|
|
||||||
break;
|
|
||||||
case SSH2_MSG_CHANNEL_REQUEST:
|
case SSH2_MSG_CHANNEL_REQUEST:
|
||||||
channel_rcv_request(session);
|
case SSH2_MSG_CHANNEL_CLOSE:
|
||||||
|
case SSH2_MSG_CHANNEL_EOF:
|
||||||
|
case SSH2_MSG_CHANNEL_DATA:
|
||||||
|
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||||
|
ssh_packet_process(session, type);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
|
|||||||
@@ -856,15 +856,20 @@ void ssh_message_free(ssh_message msg){
|
|||||||
* \param type packet type
|
* \param type packet type
|
||||||
* \returns nothing
|
* \returns nothing
|
||||||
*/
|
*/
|
||||||
void message_handle(ssh_session session, uint32_t type){
|
int message_handle(ssh_session session, void *user, uint8_t type, ssh_buffer packet){
|
||||||
ssh_message msg=ssh_message_retrieve(session,type);
|
ssh_message msg=ssh_message_retrieve(session,type);
|
||||||
ssh_log(session,SSH_LOG_PROTOCOL,"Stacking message from packet type %d",type);
|
ssh_log(session,SSH_LOG_PROTOCOL,"Stacking message from packet type %d",type);
|
||||||
if(msg){
|
(void)user;
|
||||||
if(!session->ssh_message_list){
|
(void)packet;
|
||||||
session->ssh_message_list=ssh_list_new();
|
if(msg){
|
||||||
}
|
if(!session->ssh_message_list){
|
||||||
ssh_list_add(session->ssh_message_list,msg);
|
session->ssh_message_list=ssh_list_new();
|
||||||
}
|
}
|
||||||
|
ssh_list_add(session->ssh_message_list,msg);
|
||||||
|
return SSH_PACKET_USED;
|
||||||
|
} else {
|
||||||
|
return SSH_PACKET_NOT_USED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
314
libssh/packet.c
314
libssh/packet.c
@@ -40,10 +40,57 @@
|
|||||||
#include "libssh/packet.h"
|
#include "libssh/packet.h"
|
||||||
#include "libssh/socket.h"
|
#include "libssh/socket.h"
|
||||||
#include "libssh/channels.h"
|
#include "libssh/channels.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/messages.h"
|
#include "libssh/messages.h"
|
||||||
#include "libssh/pcap.h"
|
#include "libssh/pcap.h"
|
||||||
|
|
||||||
|
ssh_packet_callback default_packet_handlers[]= {
|
||||||
|
|
||||||
|
ssh_packet_disconnect_callback, //#define SSH2_MSG_DISCONNECT 1
|
||||||
|
ssh_packet_ignore_callback, //#define SSH2_MSG_IGNORE 2
|
||||||
|
NULL, //#define SSH2_MSG_UNIMPLEMENTED 3
|
||||||
|
ssh_packet_ignore_callback, //#define SSH2_MSG_DEBUG 4
|
||||||
|
NULL, //#define SSH2_MSG_SERVICE_REQUEST 5
|
||||||
|
NULL, //#define SSH2_MSG_SERVICE_ACCEPT 6
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, // 7-19
|
||||||
|
NULL, //#define SSH2_MSG_KEXINIT 20
|
||||||
|
NULL, //#define SSH2_MSG_NEWKEYS 21
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, //22-29
|
||||||
|
NULL, //#define SSH2_MSG_KEXDH_INIT 30 SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||||
|
NULL, // #define SSH2_MSG_KEXDH_REPLY 31 SSH2_MSG_KEX_DH_GEX_GROUP 31
|
||||||
|
NULL, //#define SSH2_MSG_KEX_DH_GEX_INIT 32
|
||||||
|
NULL, //#define SSH2_MSG_KEX_DH_GEX_REPLY 33
|
||||||
|
NULL, //#define SSH2_MSG_KEX_DH_GEX_REQUEST 34
|
||||||
|
NULL, NULL, NULL, NULL, NULL, // 35-49
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, //#define SSH2_MSG_USERAUTH_REQUEST 50
|
||||||
|
NULL, //#define SSH2_MSG_USERAUTH_FAILURE 51
|
||||||
|
NULL, //#define SSH2_MSG_USERAUTH_SUCCESS 52
|
||||||
|
NULL, //#define SSH2_MSG_USERAUTH_BANNER 53
|
||||||
|
NULL, //#define SSH2_MSG_USERAUTH_PK_OK 60 SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||||
|
//SSH2_MSG_USERAUTH_INFO_REQUEST 60
|
||||||
|
NULL, //#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
|
||||||
|
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
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // 83-89
|
||||||
|
NULL, //#define SSH2_MSG_CHANNEL_OPEN 90
|
||||||
|
NULL, //#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||||
|
NULL, //#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
|
||||||
|
channel_rcv_change_window, //#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
|
||||||
|
channel_rcv_data, //#define SSH2_MSG_CHANNEL_DATA 94
|
||||||
|
channel_rcv_data, //#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
|
||||||
|
channel_rcv_eof, //#define SSH2_MSG_CHANNEL_EOF 96
|
||||||
|
channel_rcv_close, //#define SSH2_MSG_CHANNEL_CLOSE 97
|
||||||
|
channel_rcv_request, //#define SSH2_MSG_CHANNEL_REQUEST 98
|
||||||
|
NULL, //#define SSH2_MSG_CHANNEL_SUCCESS 99
|
||||||
|
NULL, //#define SSH2_MSG_CHANNEL_FAILURE 100
|
||||||
|
};
|
||||||
|
|
||||||
/* XXX include selected mac size */
|
/* XXX include selected mac size */
|
||||||
static int macsize=SHA_DIGEST_LEN;
|
static int macsize=SHA_DIGEST_LEN;
|
||||||
|
|
||||||
@@ -54,6 +101,243 @@ static int macsize=SHA_DIGEST_LEN;
|
|||||||
|
|
||||||
#define PACKET_STATE_INIT 0
|
#define PACKET_STATE_INIT 0
|
||||||
#define PACKET_STATE_SIZEREAD 1
|
#define PACKET_STATE_SIZEREAD 1
|
||||||
|
#define PACKET_STATE_PROCESSING 2
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @handles a data received event. It then calls the handlers for the different packet types
|
||||||
|
* or and exception handler callback.
|
||||||
|
* @param user pointer to current ssh_session
|
||||||
|
* @param data pointer to the data received
|
||||||
|
* @len length of data received. It might not be enough for a complete packet
|
||||||
|
* @returns number of bytes read and processed.
|
||||||
|
*/
|
||||||
|
int ssh_packet_socket_callback(void *user, const void *data, size_t receivedlen){
|
||||||
|
ssh_session session=(ssh_session) user;
|
||||||
|
unsigned int blocksize = (session->current_crypto ?
|
||||||
|
session->current_crypto->in_cipher->blocksize : 8);
|
||||||
|
int current_macsize = session->current_crypto ? macsize : 0;
|
||||||
|
unsigned char mac[30] = {0};
|
||||||
|
char buffer[16] = {0};
|
||||||
|
void *packet=NULL;
|
||||||
|
int to_be_read;
|
||||||
|
int rc = SSH_ERROR;
|
||||||
|
uint32_t len;
|
||||||
|
uint8_t padding;
|
||||||
|
size_t processed=0; /* number of byte processed from the callback */
|
||||||
|
|
||||||
|
enter_function();
|
||||||
|
|
||||||
|
switch(session->packet_state) {
|
||||||
|
case PACKET_STATE_INIT:
|
||||||
|
if(receivedlen < blocksize){
|
||||||
|
/* We didn't receive enough data to read at least one block size, give up */
|
||||||
|
leave_function();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(&session->in_packet, 0, sizeof(PACKET));
|
||||||
|
|
||||||
|
if (session->in_buffer) {
|
||||||
|
if (buffer_reinit(session->in_buffer) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
session->in_buffer = buffer_new();
|
||||||
|
if (session->in_buffer == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer,data,blocksize);
|
||||||
|
processed += blocksize;
|
||||||
|
len = packet_decrypt_len(session, buffer);
|
||||||
|
|
||||||
|
if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len > MAX_PACKET_LEN) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"read_packet(): Packet len too high(%u %.4x)", len, len);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
to_be_read = len - blocksize + sizeof(uint32_t);
|
||||||
|
if (to_be_read < 0) {
|
||||||
|
/* remote sshd sends invalid sizes? */
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"given numbers of bytes left to be read < 0 (%d)!", to_be_read);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* saves the status of the current operations */
|
||||||
|
session->in_packet.len = len;
|
||||||
|
session->packet_state = PACKET_STATE_SIZEREAD;
|
||||||
|
case PACKET_STATE_SIZEREAD:
|
||||||
|
len = session->in_packet.len;
|
||||||
|
to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
|
||||||
|
/* if to_be_read is zero, the whole packet was blocksize bytes. */
|
||||||
|
if (to_be_read != 0) {
|
||||||
|
if(receivedlen - processed < (unsigned int)to_be_read){
|
||||||
|
/* give up, not enough data in buffer */
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
rc = SSH_ERROR;
|
||||||
|
|
||||||
|
packet = (unsigned char *)data + processed;
|
||||||
|
// ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
|
||||||
|
|
||||||
|
ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len);
|
||||||
|
|
||||||
|
if (buffer_add_data(session->in_buffer, packet,
|
||||||
|
to_be_read - current_macsize) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
processed += to_be_read - current_macsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->current_crypto) {
|
||||||
|
/*
|
||||||
|
* decrypt the rest of the packet (blocksize bytes already
|
||||||
|
* have been decrypted)
|
||||||
|
*/
|
||||||
|
if (packet_decrypt(session,
|
||||||
|
((uint8_t*)buffer_get(session->in_buffer) + blocksize),
|
||||||
|
buffer_get_len(session->in_buffer) - blocksize) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Decrypt error");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
/* copy the last part from the incoming buffer */
|
||||||
|
memcpy(mac,(unsigned char *)packet + to_be_read - current_macsize, macsize);
|
||||||
|
|
||||||
|
if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "HMAC error");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip the size field which has been processed before */
|
||||||
|
buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
|
||||||
|
|
||||||
|
if (buffer_get_u8(session->in_buffer, &padding) == 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
|
"%hhd bytes padding, %d bytes left in buffer",
|
||||||
|
padding, buffer_get_rest_len(session->in_buffer));
|
||||||
|
|
||||||
|
if (padding > buffer_get_rest_len(session->in_buffer)) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Invalid padding: %d (%d resting)",
|
||||||
|
padding,
|
||||||
|
buffer_get_rest_len(session->in_buffer));
|
||||||
|
#ifdef DEBUG_CRYPTO
|
||||||
|
ssh_print_hexa("incrimined packet",
|
||||||
|
buffer_get(session->in_buffer),
|
||||||
|
buffer_get_len(session->in_buffer));
|
||||||
|
#endif
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
buffer_pass_bytes_end(session->in_buffer, padding);
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
|
"After padding, %d bytes left in buffer",
|
||||||
|
buffer_get_rest_len(session->in_buffer));
|
||||||
|
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
|
||||||
|
if (session->current_crypto && session->current_crypto->do_compress_in) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ...");
|
||||||
|
if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
session->recv_seq++;
|
||||||
|
/* We don't want to rewrite a new packet while still executing the packet callbacks */
|
||||||
|
session->packet_state = PACKET_STATE_PROCESSING;
|
||||||
|
packet_translate(session);
|
||||||
|
/* execute callbacks */
|
||||||
|
ssh_packet_process(session, session->in_packet.type);
|
||||||
|
session->packet_state = PACKET_STATE_INIT;
|
||||||
|
leave_function();
|
||||||
|
return processed;
|
||||||
|
case PACKET_STATE_PROCESSING:
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Nested packet processing. Delaying.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Invalid state into packet_read2(): %d",
|
||||||
|
session->packet_state);
|
||||||
|
|
||||||
|
error:
|
||||||
|
leave_function();
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_packet_register_socket_callback(ssh_session session, struct socket *s){
|
||||||
|
session->socket_callbacks.data=ssh_packet_socket_callback;
|
||||||
|
session->socket_callbacks.connected=NULL;
|
||||||
|
session->socket_callbacks.controlflow=NULL;
|
||||||
|
session->socket_callbacks.exception=NULL;
|
||||||
|
session->socket_callbacks.user=session;
|
||||||
|
ssh_socket_set_callbacks(s,&session->socket_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief sets the callbacks for the packet layer
|
||||||
|
*/
|
||||||
|
void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
|
||||||
|
if(session->packet_callbacks == NULL){
|
||||||
|
session->packet_callbacks = ssh_list_new();
|
||||||
|
}
|
||||||
|
ssh_list_add(session->packet_callbacks,callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief sets the default packet handlers
|
||||||
|
*/
|
||||||
|
void ssh_packet_set_default_callbacks(ssh_session session){
|
||||||
|
session->default_packet_callbacks.start=0;
|
||||||
|
session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
|
||||||
|
session->default_packet_callbacks.user=session;
|
||||||
|
session->default_packet_callbacks.callbacks=default_packet_handlers;
|
||||||
|
ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal
|
||||||
|
* @brief dispatch the call of packet handlers callbacks for a received packet
|
||||||
|
* @param type type of packet
|
||||||
|
*/
|
||||||
|
void ssh_packet_process(ssh_session session, u_int8_t type){
|
||||||
|
struct ssh_iterator *i;
|
||||||
|
int r;
|
||||||
|
ssh_packet_callbacks cb;
|
||||||
|
enter_function();
|
||||||
|
ssh_log(session,SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
|
||||||
|
if(session->packet_callbacks == NULL){
|
||||||
|
ssh_log(session,SSH_LOG_RARE,"Packet callback is not initialized !");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
i=ssh_list_get_iterator(session->packet_callbacks);
|
||||||
|
while(i != NULL){
|
||||||
|
cb=ssh_iterator_value(ssh_packet_callbacks,i);
|
||||||
|
i=i->next;
|
||||||
|
if(!cb)
|
||||||
|
continue;
|
||||||
|
if(cb->start > type)
|
||||||
|
continue;
|
||||||
|
if(cb->start + cb->n_callbacks > type)
|
||||||
|
continue;
|
||||||
|
if(cb->callbacks[type - cb->start]==NULL)
|
||||||
|
continue;
|
||||||
|
r=cb->callbacks[type - cb->start](session,cb->user,type,session->in_buffer);
|
||||||
|
if(r==SSH_PACKET_USED)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error:
|
||||||
|
leave_function();
|
||||||
|
}
|
||||||
|
|
||||||
static int packet_read2(ssh_session session) {
|
static int packet_read2(ssh_session session) {
|
||||||
unsigned int blocksize = (session->current_crypto ?
|
unsigned int blocksize = (session->current_crypto ?
|
||||||
@@ -624,10 +908,7 @@ int packet_send(ssh_session session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void packet_parse(ssh_session session) {
|
void packet_parse(ssh_session session) {
|
||||||
ssh_string error_s = NULL;
|
uint8_t type = session->in_packet.type;
|
||||||
char *error = NULL;
|
|
||||||
uint32_t type = session->in_packet.type;
|
|
||||||
uint32_t tmp;
|
|
||||||
|
|
||||||
#ifdef WITH_SSH1
|
#ifdef WITH_SSH1
|
||||||
if (session->version == 1) {
|
if (session->version == 1) {
|
||||||
@@ -657,41 +938,20 @@ void packet_parse(ssh_session session) {
|
|||||||
#endif /* WITH_SSH1 */
|
#endif /* WITH_SSH1 */
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SSH2_MSG_DISCONNECT:
|
case SSH2_MSG_DISCONNECT:
|
||||||
buffer_get_u32(session->in_buffer, &tmp);
|
|
||||||
error_s = buffer_get_ssh_string(session->in_buffer);
|
|
||||||
if (error_s == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
error = string_to_char(error_s);
|
|
||||||
string_free(error_s);
|
|
||||||
if (error == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT\n");
|
|
||||||
ssh_set_error(session, SSH_FATAL,
|
|
||||||
"Received SSH_MSG_DISCONNECT: %s",error);
|
|
||||||
|
|
||||||
SAFE_FREE(error);
|
|
||||||
|
|
||||||
ssh_socket_close(session->socket);
|
|
||||||
session->alive = 0;
|
|
||||||
|
|
||||||
return;
|
|
||||||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
||||||
case SSH2_MSG_CHANNEL_DATA:
|
case SSH2_MSG_CHANNEL_DATA:
|
||||||
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
||||||
case SSH2_MSG_CHANNEL_REQUEST:
|
case SSH2_MSG_CHANNEL_REQUEST:
|
||||||
case SSH2_MSG_CHANNEL_EOF:
|
case SSH2_MSG_CHANNEL_EOF:
|
||||||
case SSH2_MSG_CHANNEL_CLOSE:
|
case SSH2_MSG_CHANNEL_CLOSE:
|
||||||
channel_handle(session,type);
|
|
||||||
return;
|
|
||||||
case SSH2_MSG_IGNORE:
|
case SSH2_MSG_IGNORE:
|
||||||
case SSH2_MSG_DEBUG:
|
case SSH2_MSG_DEBUG:
|
||||||
|
ssh_packet_process(session,type);
|
||||||
return;
|
return;
|
||||||
case SSH2_MSG_SERVICE_REQUEST:
|
case SSH2_MSG_SERVICE_REQUEST:
|
||||||
case SSH2_MSG_USERAUTH_REQUEST:
|
case SSH2_MSG_USERAUTH_REQUEST:
|
||||||
case SSH2_MSG_CHANNEL_OPEN:
|
case SSH2_MSG_CHANNEL_OPEN:
|
||||||
message_handle(session,type);
|
message_handle(session,NULL,type,session->in_buffer);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type);
|
ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type);
|
||||||
|
|||||||
@@ -857,8 +857,8 @@ char *ssh_message_channel_request_subsystem(ssh_message msg){
|
|||||||
* must take care of the response).
|
* must take care of the response).
|
||||||
*/
|
*/
|
||||||
void ssh_set_message_callback(ssh_session session,
|
void ssh_set_message_callback(ssh_session session,
|
||||||
int(*ssh_message_callback)(ssh_session session, ssh_message msg)){
|
int(*ssh_message_callback_)(ssh_session session, ssh_message msg)){
|
||||||
session->ssh_message_callback=ssh_message_callback;
|
session->ssh_message_callback=ssh_message_callback_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_execute_message_callbacks(ssh_session session){
|
int ssh_execute_message_callbacks(ssh_session session){
|
||||||
|
|||||||
@@ -28,10 +28,12 @@
|
|||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
#include "libssh/server.h"
|
#include "libssh/server.h"
|
||||||
#include "libssh/socket.h"
|
#include "libssh/socket.h"
|
||||||
|
#include "libssh/ssh2.h"
|
||||||
#include "libssh/agent.h"
|
#include "libssh/agent.h"
|
||||||
#include "libssh/packet.h"
|
#include "libssh/packet.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/misc.h"
|
#include "libssh/misc.h"
|
||||||
|
#include "libssh/buffer.h"
|
||||||
|
|
||||||
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
||||||
|
|
||||||
@@ -363,5 +365,44 @@ int ssh_get_version(ssh_session session) {
|
|||||||
return session->version;
|
return session->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief handles a SSH_DISCONNECT packet
|
||||||
|
*/
|
||||||
|
int ssh_packet_disconnect_callback(ssh_session session, void *user, u_int8_t type, ssh_buffer packet){
|
||||||
|
u_int32_t code;
|
||||||
|
char *error;
|
||||||
|
ssh_string error_s;
|
||||||
|
(void)user;
|
||||||
|
(void)type;
|
||||||
|
buffer_get_u32(packet, &code);
|
||||||
|
error_s = buffer_get_ssh_string(packet);
|
||||||
|
if (error_s != NULL) {
|
||||||
|
error = string_to_char(error_s);
|
||||||
|
string_free(error_s);
|
||||||
|
}
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code,error);
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Received SSH_MSG_DISCONNECT: %d:%s",code,error);
|
||||||
|
SAFE_FREE(error);
|
||||||
|
|
||||||
|
ssh_socket_close(session->socket);
|
||||||
|
session->alive = 0;
|
||||||
|
/* TODO: handle a graceful disconnect */
|
||||||
|
return SSH_PACKET_USED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief handles a SSH_IGNORE and SSH_DEBUG packet
|
||||||
|
*/
|
||||||
|
int ssh_packet_ignore_callback(ssh_session session, void *user, u_int8_t type, ssh_buffer packet){
|
||||||
|
(void)user;
|
||||||
|
(void)type;
|
||||||
|
(void)packet;
|
||||||
|
ssh_log(session,SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG");
|
||||||
|
/* TODO: handle a graceful disconnect */
|
||||||
|
return SSH_PACKET_USED;
|
||||||
|
}
|
||||||
/** @} */
|
/** @} */
|
||||||
/* vim: set ts=2 sw=2 et cindent: */
|
/* vim: set ts=2 sw=2 et cindent: */
|
||||||
|
|||||||
139
libssh/socket.c
139
libssh/socket.c
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the SSH Library
|
* This file is part of the SSH Library
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008 by Aris Adamantiadis
|
* Copyright (c) 2008,2009 by Aris Adamantiadis
|
||||||
*
|
*
|
||||||
* The SSH Library is free software; you can redistribute it and/or modify
|
* The SSH Library is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
@@ -34,11 +34,11 @@
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#endif
|
#endif
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
|
#include "libssh/callbacks.h"
|
||||||
#include "libssh/socket.h"
|
#include "libssh/socket.h"
|
||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
#include "libssh/poll.h"
|
#include "libssh/poll.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
|
|
||||||
/** \defgroup ssh_socket SSH Sockets
|
/** \defgroup ssh_socket SSH Sockets
|
||||||
* \addtogroup ssh_socket
|
* \addtogroup ssh_socket
|
||||||
* @{
|
* @{
|
||||||
@@ -54,8 +54,14 @@ struct socket {
|
|||||||
ssh_buffer out_buffer;
|
ssh_buffer out_buffer;
|
||||||
ssh_buffer in_buffer;
|
ssh_buffer in_buffer;
|
||||||
ssh_session session;
|
ssh_session session;
|
||||||
|
ssh_socket_callbacks callbacks;
|
||||||
|
ssh_poll_handle poll;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, uint32_t len);
|
||||||
|
static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
|
||||||
|
uint32_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* \internal
|
* \internal
|
||||||
* \brief inits the socket system (windows specific)
|
* \brief inits the socket system (windows specific)
|
||||||
@@ -103,7 +109,78 @@ struct socket *ssh_socket_new(ssh_session session) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* \internal
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief the socket callbacks, i.e. callbacks to be called
|
||||||
|
* upon a socket event
|
||||||
|
* @param callbacks a ssh_socket_callback object reference
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ssh_socket_set_callbacks(struct socket *s, ssh_socket_callbacks callbacks){
|
||||||
|
s->callbacks=callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ssh_socket_pollcallback(ssh_poll_handle p, int fd, int revents, void *v_s){
|
||||||
|
struct socket *s=(struct socket *)v_s;
|
||||||
|
char buffer[4096];
|
||||||
|
int r,w;
|
||||||
|
(void)fd;
|
||||||
|
if(revents & POLLERR){
|
||||||
|
s->data_except=1;
|
||||||
|
/* force a read to get an explanation */
|
||||||
|
revents |= POLLIN;
|
||||||
|
}
|
||||||
|
if(revents & POLLIN){
|
||||||
|
s->data_to_read=1;
|
||||||
|
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
|
||||||
|
if(r<0){
|
||||||
|
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
||||||
|
if(s->callbacks){
|
||||||
|
s->callbacks->exception(s->callbacks->user,
|
||||||
|
SSH_SOCKET_EXCEPTION_ERROR,
|
||||||
|
s->last_errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r==0){
|
||||||
|
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
|
||||||
|
if(s->callbacks){
|
||||||
|
s->callbacks->exception(s->callbacks->user,
|
||||||
|
SSH_SOCKET_EXCEPTION_EOF,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(r>0){
|
||||||
|
/* Bufferize the data and then call the callback */
|
||||||
|
buffer_add_data(s->in_buffer,buffer,r);
|
||||||
|
if(s->callbacks){
|
||||||
|
r= s->callbacks->data(s->callbacks->user,
|
||||||
|
buffer_get_rest(s->in_buffer), buffer_get_rest_len(s->in_buffer));
|
||||||
|
buffer_pass_bytes(s->in_buffer,r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(revents & POLLOUT){
|
||||||
|
s->data_to_write=1;
|
||||||
|
/* If buffered data is pending, write it */
|
||||||
|
if(buffer_get_rest_len(s->out_buffer) > 0){
|
||||||
|
w=ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
|
||||||
|
buffer_get_rest_len(s->out_buffer));
|
||||||
|
} else if(s->callbacks){
|
||||||
|
/* Otherwise advertise the upper level that write can be done */
|
||||||
|
s->callbacks->controlflow(s->callbacks->user,SSH_SOCKET_FLOW_WRITEWONTBLOCK);
|
||||||
|
ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLOUT);
|
||||||
|
/* TODO: Find a way to put back POLLOUT when buffering occurs */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssh_socket_register_pollcallback(struct socket *s, ssh_poll_handle p){
|
||||||
|
ssh_poll_set_callback(p,ssh_socket_pollcallback,s);
|
||||||
|
s->poll=p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \internal
|
||||||
* \brief Deletes a socket object
|
* \brief Deletes a socket object
|
||||||
*/
|
*/
|
||||||
void ssh_socket_free(struct socket *s){
|
void ssh_socket_free(struct socket *s){
|
||||||
@@ -225,7 +302,10 @@ static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
|
|||||||
s->last_errno = errno;
|
s->last_errno = errno;
|
||||||
#endif
|
#endif
|
||||||
s->data_to_write = 0;
|
s->data_to_write = 0;
|
||||||
|
/* Reactive the POLLOUT detector in the poll multiplexer system */
|
||||||
|
if(s->poll){
|
||||||
|
ssh_poll_set_events(s->poll,ssh_poll_get_events(s->poll) | POLLOUT);
|
||||||
|
}
|
||||||
if (w < 0) {
|
if (w < 0) {
|
||||||
s->data_except = 1;
|
s->data_except = 1;
|
||||||
}
|
}
|
||||||
@@ -337,7 +417,6 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WRITE_BUFFERING_THRESHOLD 65536
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief buffered write of data
|
* \brief buffered write of data
|
||||||
* \returns SSH_OK, or SSH_ERROR
|
* \returns SSH_OK, or SSH_ERROR
|
||||||
@@ -345,22 +424,12 @@ int ssh_socket_read(struct socket *s, void *buffer, int len){
|
|||||||
*/
|
*/
|
||||||
int ssh_socket_write(struct socket *s, const void *buffer, int len) {
|
int ssh_socket_write(struct socket *s, const void *buffer, int len) {
|
||||||
ssh_session session = s->session;
|
ssh_session session = s->session;
|
||||||
int rc = SSH_ERROR;
|
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
if (buffer_add_data(s->out_buffer, buffer, len) < 0) {
|
if (buffer_add_data(s->out_buffer, buffer, len) < 0) {
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD) {
|
|
||||||
rc = ssh_socket_nonblocking_flush(s);
|
|
||||||
} else {
|
|
||||||
rc = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -509,64 +578,46 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief nonblocking flush of the output buffer
|
* \brief starts a nonblocking flush of the output buffer
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
int ssh_socket_nonblocking_flush(struct socket *s) {
|
int ssh_socket_nonblocking_flush(struct socket *s) {
|
||||||
ssh_session session = s->session;
|
ssh_session session = s->session;
|
||||||
int except;
|
|
||||||
int can_write;
|
|
||||||
int w;
|
int w;
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
|
|
||||||
/* internally sets data_to_write */
|
|
||||||
if (ssh_socket_poll(s, &can_write, &except) < 0) {
|
|
||||||
leave_function();
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ssh_socket_is_open(s)) {
|
if (!ssh_socket_is_open(s)) {
|
||||||
session->alive = 0;
|
session->alive = 0;
|
||||||
/* FIXME use ssh_socket_get_errno */
|
/* FIXME use ssh_socket_get_errno */
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Writing packet: error on socket (or connection closed): %s",
|
"Writing packet: error on socket (or connection closed): %s",
|
||||||
strerror(errno));
|
strerror(s->last_errno));
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(s->data_to_write && buffer_get_rest_len(s->out_buffer) > 0) {
|
if (s->data_to_write && buffer_get_rest_len(s->out_buffer) > 0) {
|
||||||
if (ssh_socket_is_open(s)) {
|
w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
|
||||||
w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
|
buffer_get_rest_len(s->out_buffer));
|
||||||
buffer_get_rest_len(s->out_buffer));
|
|
||||||
} else {
|
|
||||||
/* write failed */
|
|
||||||
w =- 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w < 0) {
|
if (w < 0) {
|
||||||
session->alive = 0;
|
session->alive = 0;
|
||||||
ssh_socket_close(s);
|
ssh_socket_close(s);
|
||||||
/* FIXME use ssh_socket_get_errno() */
|
/* FIXME use ssh_socket_get_errno() */
|
||||||
ssh_set_error(session, SSH_FATAL,
|
ssh_set_error(session, SSH_FATAL,
|
||||||
"Writing packet: error on socket (or connection closed): %s",
|
"Writing packet: error on socket (or connection closed): %s",
|
||||||
strerror(errno));
|
strerror(s->last_errno));
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_pass_bytes(s->out_buffer, w);
|
buffer_pass_bytes(s->out_buffer, w);
|
||||||
/* refresh the socket status */
|
|
||||||
if (ssh_socket_poll(session->socket, &can_write, &except) < 0) {
|
|
||||||
leave_function();
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is there some data pending? */
|
/* Is there some data pending? */
|
||||||
if (buffer_get_rest_len(s->out_buffer) > 0) {
|
if (buffer_get_rest_len(s->out_buffer) > 0 && s->poll) {
|
||||||
|
/* force the poll system to catch pollout events */
|
||||||
|
ssh_poll_set_events(s->poll, ssh_poll_get_events(s->poll) |POLLOUT);
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AGAIN;
|
return SSH_AGAIN;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user