GUACAMOLE-203: Merge support for SSH/SFTP connection keep-alive packets.
This commit is contained in:
commit
d9c1ce7738
@ -98,7 +98,7 @@ void guac_common_ssh_uninit();
|
|||||||
* if the connection or authentication were not successful.
|
* if the connection or authentication were not successful.
|
||||||
*/
|
*/
|
||||||
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||||
const char* hostname, const char* port, guac_common_ssh_user* user);
|
const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects and destroys the given SSH session, freeing all associated
|
* Disconnects and destroys the given SSH session, freeing all associated
|
||||||
|
@ -414,7 +414,7 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
||||||
const char* hostname, const char* port, guac_common_ssh_user* user) {
|
const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive) {
|
||||||
|
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@ -532,6 +532,20 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Warn if keepalive below minimum value */
|
||||||
|
if (keepalive < 0) {
|
||||||
|
keepalive = 0;
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING, "negative keepalive intervals "
|
||||||
|
"are converted to 0, disabling keepalive.");
|
||||||
|
}
|
||||||
|
else if (keepalive == 1) {
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING, "keepalive interval will "
|
||||||
|
"be rounded up to minimum value of 2.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure session keepalive */
|
||||||
|
libssh2_keepalive_config(common_session->session, 1, keepalive);
|
||||||
|
|
||||||
/* Return created session */
|
/* Return created session */
|
||||||
return common_session;
|
return common_session;
|
||||||
|
|
||||||
|
@ -977,7 +977,7 @@ void* guac_rdp_client_thread(void* data) {
|
|||||||
/* Attempt SSH connection */
|
/* Attempt SSH connection */
|
||||||
rdp_client->sftp_session =
|
rdp_client->sftp_session =
|
||||||
guac_common_ssh_create_session(client, settings->sftp_hostname,
|
guac_common_ssh_create_session(client, settings->sftp_hostname,
|
||||||
settings->sftp_port, rdp_client->sftp_user);
|
settings->sftp_port, rdp_client->sftp_user, settings->sftp_server_alive_interval);
|
||||||
|
|
||||||
/* Fail if SSH connection does not succeed */
|
/* Fail if SSH connection does not succeed */
|
||||||
if (rdp_client->sftp_session == NULL) {
|
if (rdp_client->sftp_session == NULL) {
|
||||||
|
@ -84,6 +84,7 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
|
|||||||
"sftp-private-key",
|
"sftp-private-key",
|
||||||
"sftp-passphrase",
|
"sftp-passphrase",
|
||||||
"sftp-directory",
|
"sftp-directory",
|
||||||
|
"sftp-server-alive-interval",
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
"recording-path",
|
"recording-path",
|
||||||
@ -366,6 +367,13 @@ enum RDP_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_SFTP_DIRECTORY,
|
IDX_SFTP_DIRECTORY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval at which SSH keepalive messages are sent to the server for
|
||||||
|
* SFTP connections. The default is 0 (disabling keepalives), and a value
|
||||||
|
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
|
||||||
|
* cases.
|
||||||
|
*/
|
||||||
|
IDX_SFTP_SERVER_ALIVE_INTERVAL,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -775,6 +783,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
settings->sftp_directory =
|
settings->sftp_directory =
|
||||||
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
IDX_SFTP_DIRECTORY, NULL);
|
IDX_SFTP_DIRECTORY, NULL);
|
||||||
|
|
||||||
|
/* Default keepalive value */
|
||||||
|
settings->sftp_server_alive_interval =
|
||||||
|
guac_user_parse_args_int(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
|
IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Read recording path */
|
/* Read recording path */
|
||||||
|
@ -359,6 +359,14 @@ typedef struct guac_rdp_settings {
|
|||||||
* the destination directory is otherwise ambiguous).
|
* the destination directory is otherwise ambiguous).
|
||||||
*/
|
*/
|
||||||
char* sftp_directory;
|
char* sftp_directory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval at which SSH keepalive messages are sent to the server for
|
||||||
|
* SFTP connections. The default is 0 (disabling keepalives), and a value
|
||||||
|
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
|
||||||
|
* cases.
|
||||||
|
*/
|
||||||
|
int sftp_server_alive_interval;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +51,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
|
|||||||
"recording-name",
|
"recording-name",
|
||||||
"create-recording-path",
|
"create-recording-path",
|
||||||
"read-only",
|
"read-only",
|
||||||
|
"server-alive-interval",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,6 +166,13 @@ enum SSH_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_READ_ONLY,
|
IDX_READ_ONLY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of seconds between sending alive packets. A default of 0
|
||||||
|
* tells SSH not to send these packets. A value of 1 is automatically
|
||||||
|
* changed by libssh2 to 2 to avoid busy-loop corner cases.
|
||||||
|
*/
|
||||||
|
IDX_SERVER_ALIVE_INTERVAL,
|
||||||
|
|
||||||
SSH_ARGS_COUNT
|
SSH_ARGS_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -279,6 +287,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
|
|||||||
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
IDX_CREATE_RECORDING_PATH, false);
|
IDX_CREATE_RECORDING_PATH, false);
|
||||||
|
|
||||||
|
/* Parse server alive interval */
|
||||||
|
settings->server_alive_interval =
|
||||||
|
guac_user_parse_args_int(user, GUAC_SSH_CLIENT_ARGS, argv,
|
||||||
|
IDX_SERVER_ALIVE_INTERVAL, 0);
|
||||||
|
|
||||||
/* Parsing was successful */
|
/* Parsing was successful */
|
||||||
return settings;
|
return settings;
|
||||||
|
|
||||||
|
@ -53,6 +53,11 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_SSH_DEFAULT_RECORDING_NAME "recording"
|
#define GUAC_SSH_DEFAULT_RECORDING_NAME "recording"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default polling timeout for SSH activity in milliseconds.
|
||||||
|
*/
|
||||||
|
#define GUAC_SSH_DEFAULT_POLL_TIMEOUT 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings for the SSH connection. The values for this structure are parsed
|
* Settings for the SSH connection. The values for this structure are parsed
|
||||||
* from the arguments given during the Guacamole protocol handshake using the
|
* from the arguments given during the Guacamole protocol handshake using the
|
||||||
@ -181,6 +186,11 @@ typedef struct guac_ssh_settings {
|
|||||||
*/
|
*/
|
||||||
bool create_recording_path;
|
bool create_recording_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of seconds between sending server alive messages.
|
||||||
|
*/
|
||||||
|
int server_alive_interval;
|
||||||
|
|
||||||
} guac_ssh_settings;
|
} guac_ssh_settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -218,7 +218,7 @@ void* ssh_client_thread(void* data) {
|
|||||||
|
|
||||||
/* Open SSH session */
|
/* Open SSH session */
|
||||||
ssh_client->session = guac_common_ssh_create_session(client,
|
ssh_client->session = guac_common_ssh_create_session(client,
|
||||||
settings->hostname, settings->port, ssh_client->user);
|
settings->hostname, settings->port, ssh_client->user, settings->server_alive_interval);
|
||||||
if (ssh_client->session == NULL) {
|
if (ssh_client->session == NULL) {
|
||||||
/* Already aborted within guac_common_ssh_create_session() */
|
/* Already aborted within guac_common_ssh_create_session() */
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -258,7 +258,7 @@ void* ssh_client_thread(void* data) {
|
|||||||
guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
|
guac_client_log(client, GUAC_LOG_DEBUG, "Reconnecting for SFTP...");
|
||||||
ssh_client->sftp_session =
|
ssh_client->sftp_session =
|
||||||
guac_common_ssh_create_session(client, settings->hostname,
|
guac_common_ssh_create_session(client, settings->hostname,
|
||||||
settings->port, ssh_client->user);
|
settings->port, ssh_client->user, settings->server_alive_interval);
|
||||||
if (ssh_client->sftp_session == NULL) {
|
if (ssh_client->sftp_session == NULL) {
|
||||||
/* Already aborted within guac_common_ssh_create_session() */
|
/* Already aborted within guac_common_ssh_create_session() */
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -323,6 +323,9 @@ void* ssh_client_thread(void* data) {
|
|||||||
/* Track total amount of data read */
|
/* Track total amount of data read */
|
||||||
int total_read = 0;
|
int total_read = 0;
|
||||||
|
|
||||||
|
/* Timeout for polling socket activity */
|
||||||
|
int timeout;
|
||||||
|
|
||||||
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
pthread_mutex_lock(&(ssh_client->term_channel_lock));
|
||||||
|
|
||||||
/* Stop reading at EOF */
|
/* Stop reading at EOF */
|
||||||
@ -331,6 +334,17 @@ void* ssh_client_thread(void* data) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send keepalive at configured interval */
|
||||||
|
if (settings->server_alive_interval > 0) {
|
||||||
|
timeout = 0;
|
||||||
|
if (libssh2_keepalive_send(ssh_client->session->session, &timeout) > 0)
|
||||||
|
break;
|
||||||
|
timeout *= 1000;
|
||||||
|
}
|
||||||
|
/* If keepalive is not configured, sleep for the default of 1 second */
|
||||||
|
else
|
||||||
|
timeout = GUAC_SSH_DEFAULT_POLL_TIMEOUT;
|
||||||
|
|
||||||
/* Read terminal data */
|
/* Read terminal data */
|
||||||
bytes_read = libssh2_channel_read(ssh_client->term_channel,
|
bytes_read = libssh2_channel_read(ssh_client->term_channel,
|
||||||
buffer, sizeof(buffer));
|
buffer, sizeof(buffer));
|
||||||
@ -370,8 +384,8 @@ void* ssh_client_thread(void* data) {
|
|||||||
.revents = 0,
|
.revents = 0,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
/* Wait up to one second */
|
/* Wait up to computed timeout */
|
||||||
if (poll(fds, 1, 1000) < 0)
|
if (poll(fds, 1, timeout) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ const char* GUAC_VNC_CLIENT_ARGS[] = {
|
|||||||
"sftp-private-key",
|
"sftp-private-key",
|
||||||
"sftp-passphrase",
|
"sftp-passphrase",
|
||||||
"sftp-directory",
|
"sftp-directory",
|
||||||
|
"sftp-server-alive-interval",
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
"recording-path",
|
"recording-path",
|
||||||
@ -227,6 +228,14 @@ enum VNC_ARGS_IDX {
|
|||||||
* the destination directory is otherwise ambiguous).
|
* the destination directory is otherwise ambiguous).
|
||||||
*/
|
*/
|
||||||
IDX_SFTP_DIRECTORY,
|
IDX_SFTP_DIRECTORY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval at which SSH keepalive messages are sent to the server for
|
||||||
|
* SFTP connections. The default is 0 (disabling keepalives), and a value
|
||||||
|
* of 1 is automatically incremented to 2 by libssh2 to avoid busy loop corner
|
||||||
|
* cases.
|
||||||
|
*/
|
||||||
|
IDX_SFTP_SERVER_ALIVE_INTERVAL,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,6 +404,11 @@ guac_vnc_settings* guac_vnc_parse_args(guac_user* user,
|
|||||||
settings->sftp_directory =
|
settings->sftp_directory =
|
||||||
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
|
guac_user_parse_args_string(user, GUAC_VNC_CLIENT_ARGS, argv,
|
||||||
IDX_SFTP_DIRECTORY, NULL);
|
IDX_SFTP_DIRECTORY, NULL);
|
||||||
|
|
||||||
|
/* Default keepalive value */
|
||||||
|
settings->sftp_server_alive_interval =
|
||||||
|
guac_user_parse_args_int(user, GUAC_VNC_CLIENT_ARGS, argv,
|
||||||
|
IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Read recording path */
|
/* Read recording path */
|
||||||
|
@ -173,6 +173,14 @@ typedef struct guac_vnc_settings {
|
|||||||
* the destination directory is otherwise ambiguous).
|
* the destination directory is otherwise ambiguous).
|
||||||
*/
|
*/
|
||||||
char* sftp_directory;
|
char* sftp_directory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval at which SSH keepalive messages are sent to the server for
|
||||||
|
* SFTP connections. The default is 0 (disabling keepalives), and a value
|
||||||
|
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
|
||||||
|
* cases.
|
||||||
|
*/
|
||||||
|
int sftp_server_alive_interval;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,7 +261,7 @@ void* guac_vnc_client_thread(void* data) {
|
|||||||
/* Attempt SSH connection */
|
/* Attempt SSH connection */
|
||||||
vnc_client->sftp_session =
|
vnc_client->sftp_session =
|
||||||
guac_common_ssh_create_session(client, settings->sftp_hostname,
|
guac_common_ssh_create_session(client, settings->sftp_hostname,
|
||||||
settings->sftp_port, vnc_client->sftp_user);
|
settings->sftp_port, vnc_client->sftp_user, settings->sftp_server_alive_interval);
|
||||||
|
|
||||||
/* Fail if SSH connection does not succeed */
|
/* Fail if SSH connection does not succeed */
|
||||||
if (vnc_client->sftp_session == NULL) {
|
if (vnc_client->sftp_session == NULL) {
|
||||||
|
Loading…
Reference in New Issue
Block a user