改进:TP核心服务每60秒向已连接的客户端和远程主机发送keep-alive消息,防止连接中断。但仍保留无操作超时就断开的限制。

dev
Apex Liu 2020-06-19 02:22:26 +08:00
parent 7b46c3bc63
commit e7635e7756
4 changed files with 195 additions and 171 deletions

View File

@ -6,7 +6,8 @@ SshProxy g_ssh_proxy;
SshProxy::SshProxy() : SshProxy::SshProxy() :
ExThreadBase("ssh-proxy-thread"), ExThreadBase("ssh-proxy-thread"),
m_bind(NULL) { m_bind(NULL) {
m_timer_counter = 0; m_timer_counter_check_noop = 0;
m_timer_counter_send_keep_alive= 0;
m_noop_timeout_sec = 900; // default to 15 minutes. m_noop_timeout_sec = 900; // default to 15 minutes.
m_listener_running = false; m_listener_running = false;
} }
@ -59,21 +60,33 @@ bool SshProxy::init() {
} }
void SshProxy::timer() { void SshProxy::timer() {
// timer() will be called per one second, and I will do my job per 5 seconds. // timer() will be called per one second
m_timer_counter++; m_timer_counter_check_noop++;
if (m_timer_counter < 5) m_timer_counter_send_keep_alive++;
return;
m_timer_counter = 0; // check no-op per 5 seconds.
if (m_timer_counter_check_noop >= 5) {
m_timer_counter_check_noop = 0;
ExThreadSmartLock locker(m_lock); ExThreadSmartLock locker(m_lock);
ex_u32 t_now = (ex_u32) time(NULL); ex_u32 t_now = (ex_u32)time(NULL);
ts_ssh_sessions::iterator it; ts_ssh_sessions::iterator it;
for (it = m_sessions.begin(); it != m_sessions.end(); ++it) { for (it = m_sessions.begin(); it != m_sessions.end(); ++it) {
it->first->save_record(); it->first->save_record();
if (0 != m_noop_timeout_sec) if (0 != m_noop_timeout_sec)
it->first->check_noop_timeout(t_now, m_noop_timeout_sec); it->first->check_noop_timeout(t_now, m_noop_timeout_sec);
}
}
// send keep-alive every 60 seconds
if (m_timer_counter_send_keep_alive >= 60) {
m_timer_counter_send_keep_alive = 0;
ExThreadSmartLock locker(m_lock);
ts_ssh_sessions::iterator it;
for (it = m_sessions.begin(); it != m_sessions.end(); ++it) {
it->first->send_keep_alive();
}
} }
} }

View File

@ -26,7 +26,8 @@ protected:
private: private:
ssh_bind m_bind; ssh_bind m_bind;
int m_timer_counter; int m_timer_counter_check_noop;
int m_timer_counter_send_keep_alive;
ExThreadLock m_lock; ExThreadLock m_lock;
bool m_listener_running; bool m_listener_running;

View File

@ -399,7 +399,7 @@ void SshSession::save_record() {
} }
void SshSession::check_noop_timeout(ex_u32 t_now, ex_u32 timeout) { void SshSession::check_noop_timeout(ex_u32 t_now, ex_u32 timeout) {
ExThreadSmartLock locker(m_lock); // ExThreadSmartLock locker(m_lock);
tp_channels::iterator it = m_channels.begin(); tp_channels::iterator it = m_channels.begin();
for (; it != m_channels.end(); ++it) { for (; it != m_channels.end(); ++it) {
if ((*it)->need_close) if ((*it)->need_close)
@ -415,6 +415,15 @@ void SshSession::check_noop_timeout(ex_u32 t_now, ex_u32 timeout) {
} }
} }
void SshSession::send_keep_alive() {
EXLOGD("[ssh] send keep-alive.\n");
if(m_srv_session)
ssh_send_keepalive(m_srv_session);
if (m_cli_session)
ssh_send_keepalive(m_cli_session);
}
int SshSession::_on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata) { int SshSession::_on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata) {
// here, `user` is the session-id we need. // here, `user` is the session-id we need.
SshSession *_this = (SshSession *) userdata; SshSession *_this = (SshSession *) userdata;

View File

@ -1,156 +1,157 @@
#ifndef __SSH_SESSION_H__ #ifndef __SSH_SESSION_H__
#define __SSH_SESSION_H__ #define __SSH_SESSION_H__
#include "ssh_recorder.h" #include "ssh_recorder.h"
#include <ex.h> #include <ex.h>
#include <libssh/libssh.h> #include <libssh/libssh.h>
#include <libssh/server.h> #include <libssh/server.h>
#include <libssh/callbacks.h> #include <libssh/callbacks.h>
#include <libssh/sftp.h> #include <libssh/sftp.h>
#include <vector> #include <vector>
#include <list> #include <list>
#define TS_SSH_CHANNEL_TYPE_UNKNOWN 0 #define TS_SSH_CHANNEL_TYPE_UNKNOWN 0
#define TS_SSH_CHANNEL_TYPE_SHELL 1 #define TS_SSH_CHANNEL_TYPE_SHELL 1
#define TS_SSH_CHANNEL_TYPE_SFTP 2 #define TS_SSH_CHANNEL_TYPE_SFTP 2
#define TP_SSH_CLIENT_SIDE 1 #define TP_SSH_CLIENT_SIDE 1
#define TP_SSH_SERVER_SIDE 2 #define TP_SSH_SERVER_SIDE 2
class SshProxy; class SshProxy;
class SshSession; class SshSession;
class TP_SSH_CHANNEL_PAIR { class TP_SSH_CHANNEL_PAIR {
friend class SshSession; friend class SshSession;
public: public:
TP_SSH_CHANNEL_PAIR(); TP_SSH_CHANNEL_PAIR();
private: private:
int type; // TS_SSH_CHANNEL_TYPE_SHELL or TS_SSH_CHANNEL_TYPE_SFTP int type; // TS_SSH_CHANNEL_TYPE_SHELL or TS_SSH_CHANNEL_TYPE_SFTP
ssh_channel cli_channel; ssh_channel cli_channel;
ssh_channel srv_channel; ssh_channel srv_channel;
TppSshRec rec; TppSshRec rec;
ex_u32 last_access_timestamp; ex_u32 last_access_timestamp;
int state; int state;
int db_id; int db_id;
int channel_id; // for debug only. int channel_id; // for debug only.
int win_width; // window width, in char count. int win_width; // window width, in char count.
bool is_first_server_data; bool is_first_server_data;
bool need_close; bool need_close;
// for ssh command record cache. // for ssh command record cache.
bool server_ready; bool server_ready;
bool maybe_cmd; bool maybe_cmd;
bool process_srv; bool process_srv;
bool client_single_char; bool client_single_char;
std::list<char> cmd_char_list; std::list<char> cmd_char_list;
std::list<char>::iterator cmd_char_pos; std::list<char>::iterator cmd_char_pos;
}; };
typedef std::list<TP_SSH_CHANNEL_PAIR*> tp_channels; typedef std::list<TP_SSH_CHANNEL_PAIR*> tp_channels;
class SshSession : public ExThreadBase class SshSession : public ExThreadBase
{ {
public: public:
SshSession(SshProxy* proxy, ssh_session sess_client); SshSession(SshProxy* proxy, ssh_session sess_client);
virtual ~SshSession(); virtual ~SshSession();
SshProxy* get_proxy(void) { return m_proxy; } SshProxy* get_proxy(void) { return m_proxy; }
TP_SSH_CHANNEL_PAIR* _get_channel_pair(int channel_side, ssh_channel channel); TP_SSH_CHANNEL_PAIR* _get_channel_pair(int channel_side, ssh_channel channel);
void client_ip(const char* ip) { m_client_ip = ip; } void client_ip(const char* ip) { m_client_ip = ip; }
const char* client_ip(void) const { return m_client_ip.c_str(); } const char* client_ip(void) const { return m_client_ip.c_str(); }
void client_port(ex_u16 port) { m_client_port = port; } void client_port(ex_u16 port) { m_client_port = port; }
ex_u16 client_port(void) const { return m_client_port; } ex_u16 client_port(void) const { return m_client_port; }
// save record cache into file. be called per 5 seconds. // save record cache into file. be called per 5 seconds.
void save_record(); void save_record();
// //
void check_noop_timeout(ex_u32 t_now, ex_u32 timeout); void check_noop_timeout(ex_u32 t_now, ex_u32 timeout);
void send_keep_alive();
const ex_astr& sid() { return m_sid; }
const ex_astr& sid() { return m_sid; }
protected:
void _thread_loop(); protected:
void _on_stop(); void _thread_loop();
void _on_stopped(); void _on_stop();
void _on_stopped();
// record an error when session connecting or auth-ing.
void _session_error(int err_code); // record an error when session connecting or auth-ing.
// when client<->server channel created, start to record. void _session_error(int err_code);
bool _record_begin(TP_SSH_CHANNEL_PAIR* cp); // when client<->server channel created, start to record.
// stop record because channel closed. bool _record_begin(TP_SSH_CHANNEL_PAIR* cp);
void _record_end(TP_SSH_CHANNEL_PAIR* cp); // stop record because channel closed.
void _record_end(TP_SSH_CHANNEL_PAIR* cp);
void _process_ssh_command(TP_SSH_CHANNEL_PAIR* cp, int from, const ex_u8* data, int len);
void _process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* data, int len); void _process_ssh_command(TP_SSH_CHANNEL_PAIR* cp, int from, const ex_u8* data, int len);
void _process_sftp_command(TP_SSH_CHANNEL_PAIR* cp, const ex_u8* data, int len);
private:
void _run(void); private:
void _run(void);
void _close_channels(void);
void _check_channels(void); void _close_channels(void);
void _check_channels(void);
static int _on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata);
static ssh_channel _on_new_channel_request(ssh_session session, void *userdata); static int _on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata);
static int _on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata); static ssh_channel _on_new_channel_request(ssh_session session, void *userdata);
static int _on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata); static int _on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata);
static void _on_client_channel_close(ssh_session session, ssh_channel channel, void* userdata); static int _on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata);
static int _on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata); static void _on_client_channel_close(ssh_session session, ssh_channel channel, void* userdata);
static int _on_client_pty_win_change(ssh_session session, ssh_channel channel, int width, int height, int pxwidth, int pwheight, void *userdata); static int _on_client_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata);
static int _on_client_pty_win_change(ssh_session session, ssh_channel channel, int width, int height, int pxwidth, int pwheight, void *userdata);
static int _on_client_channel_subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata);
static int _on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata); static int _on_client_channel_subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata);
static int _on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata);
static int _on_server_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata);
static void _on_server_channel_close(ssh_session session, ssh_channel channel, void* userdata); static int _on_server_channel_data(ssh_session session, ssh_channel channel, void *data, unsigned int len, int is_stderr, void *userdata);
static void _on_server_channel_close(ssh_session session, ssh_channel channel, void* userdata);
private:
SshProxy* m_proxy; private:
ssh_session m_cli_session; SshProxy* m_proxy;
ssh_session m_srv_session; ssh_session m_cli_session;
ssh_session m_srv_session;
ExThreadLock m_lock;
ExThreadLock m_lock;
ex_astr m_client_ip;
ex_u16 m_client_port; ex_astr m_client_ip;
ex_u16 m_client_port;
TPP_CONNECT_INFO* m_conn_info;
TPP_CONNECT_INFO* m_conn_info;
ex_astr m_sid;
ex_astr m_conn_ip; ex_astr m_sid;
ex_u16 m_conn_port; ex_astr m_conn_ip;
ex_astr m_acc_name; ex_u16 m_conn_port;
ex_astr m_acc_secret; ex_astr m_acc_name;
ex_u32 m_flags; ex_astr m_acc_secret;
int m_auth_type; ex_u32 m_flags;
int m_auth_type;
bool m_is_logon;
bool m_is_logon;
int m_ssh_ver;
int m_ssh_ver;
// 一个ssh_session中可以打开多个ssh_channel
tp_channels m_channels; // 一个ssh_session中可以打开多个ssh_channel
tp_channels m_channels;
bool m_have_error;
bool m_have_error;
bool m_recving_from_srv; // 是否正在从服务器接收数据?
bool m_recving_from_cli; // 是否正在从客户端接收数据? bool m_recving_from_srv; // 是否正在从服务器接收数据?
bool m_recving_from_cli; // 是否正在从客户端接收数据?
struct ssh_server_callbacks_struct m_srv_cb;
struct ssh_channel_callbacks_struct m_cli_channel_cb; struct ssh_server_callbacks_struct m_srv_cb;
struct ssh_channel_callbacks_struct m_srv_channel_cb; struct ssh_channel_callbacks_struct m_cli_channel_cb;
}; struct ssh_channel_callbacks_struct m_srv_channel_cb;
};
#endif // __SSH_SESSION_H__
#endif // __SSH_SESSION_H__