mirror of https://github.com/tp4a/teleport
貌似解决了SSH连接、断开连接但始终显示“使用中”的问题,还需要更大规模测试。
parent
17b843500e
commit
48dfcd964d
|
@ -0,0 +1,953 @@
|
||||||
|
/*
|
||||||
|
* session.c - non-networking functions
|
||||||
|
*
|
||||||
|
* This file is part of the SSH Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2005-2013 by Aris Adamantiadis
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The SSH Library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with the SSH Library; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libssh/priv.h"
|
||||||
|
#include "libssh/libssh.h"
|
||||||
|
#include "libssh/crypto.h"
|
||||||
|
#include "libssh/server.h"
|
||||||
|
#include "libssh/socket.h"
|
||||||
|
#ifdef WITH_SSH1
|
||||||
|
#include "libssh/ssh1.h"
|
||||||
|
#endif /* WITH_SSH1 */
|
||||||
|
#include "libssh/ssh2.h"
|
||||||
|
#include "libssh/agent.h"
|
||||||
|
#include "libssh/packet.h"
|
||||||
|
#include "libssh/session.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
|
#include "libssh/buffer.h"
|
||||||
|
#include "libssh/poll.h"
|
||||||
|
|
||||||
|
#define FIRST_CHANNEL 42 // why not ? it helps to find bugs.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup libssh_session The SSH session functions.
|
||||||
|
* @ingroup libssh
|
||||||
|
*
|
||||||
|
* Functions that manage a session.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new ssh session.
|
||||||
|
*
|
||||||
|
* @returns A new ssh_session pointer, NULL on error.
|
||||||
|
*/
|
||||||
|
ssh_session ssh_new(void) {
|
||||||
|
ssh_session session;
|
||||||
|
char *id = NULL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
session = malloc(sizeof (struct ssh_session_struct));
|
||||||
|
if (session == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ZERO_STRUCTP(session);
|
||||||
|
|
||||||
|
session->next_crypto = crypto_new();
|
||||||
|
if (session->next_crypto == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->socket = ssh_socket_new(session);
|
||||||
|
if (session->socket == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->out_buffer = ssh_buffer_new();
|
||||||
|
if (session->out_buffer == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->in_buffer=ssh_buffer_new();
|
||||||
|
if (session->in_buffer == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->alive = 0;
|
||||||
|
session->auth_methods = 0;
|
||||||
|
ssh_set_blocking(session, 1);
|
||||||
|
session->maxchannel = FIRST_CHANNEL;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
session->agent = agent_new(session);
|
||||||
|
if (session->agent == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
/* OPTIONS */
|
||||||
|
session->opts.StrictHostKeyChecking = 1;
|
||||||
|
session->opts.port = 0;
|
||||||
|
session->opts.fd = -1;
|
||||||
|
session->opts.ssh2 = 1;
|
||||||
|
session->opts.compressionlevel=7;
|
||||||
|
#ifdef WITH_SSH1
|
||||||
|
session->opts.ssh1 = 1;
|
||||||
|
#else
|
||||||
|
session->opts.ssh1 = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
session->opts.identity = ssh_list_new();
|
||||||
|
if (session->opts.identity == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("%d/id_ed25519");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->opts.identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ECC
|
||||||
|
id = strdup("%d/id_ecdsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->opts.identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
id = strdup("%d/id_rsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->opts.identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("%d/id_dsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->opts.identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("%d/identity");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->opts.identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(id);
|
||||||
|
ssh_free(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deallocate a SSH session handle.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session to free.
|
||||||
|
*
|
||||||
|
* @see ssh_disconnect()
|
||||||
|
* @see ssh_new()
|
||||||
|
*/
|
||||||
|
void ssh_free(ssh_session session) {
|
||||||
|
int i;
|
||||||
|
struct ssh_iterator *it;
|
||||||
|
|
||||||
|
if (session == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete all channels
|
||||||
|
*
|
||||||
|
* This needs the first thing we clean up cause if there is still an open
|
||||||
|
* channel we call ssh_channel_close() first. So we need a working socket
|
||||||
|
* and poll context for it.
|
||||||
|
*/
|
||||||
|
for (it = ssh_list_get_iterator(session->channels);
|
||||||
|
it != NULL;
|
||||||
|
it = ssh_list_get_iterator(session->channels)) {
|
||||||
|
ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
|
||||||
|
ssh_list_remove(session->channels, it);
|
||||||
|
}
|
||||||
|
ssh_list_free(session->channels);
|
||||||
|
session->channels = NULL;
|
||||||
|
|
||||||
|
#ifdef WITH_PCAP
|
||||||
|
if (session->pcap_ctx) {
|
||||||
|
ssh_pcap_context_free(session->pcap_ctx);
|
||||||
|
session->pcap_ctx = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ssh_socket_free(session->socket);
|
||||||
|
session->socket = NULL;
|
||||||
|
|
||||||
|
if (session->default_poll_ctx) {
|
||||||
|
ssh_poll_ctx_free(session->default_poll_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_buffer_free(session->in_buffer);
|
||||||
|
ssh_buffer_free(session->out_buffer);
|
||||||
|
session->in_buffer = session->out_buffer = NULL;
|
||||||
|
|
||||||
|
if (session->in_hashbuf != NULL) {
|
||||||
|
ssh_buffer_free(session->in_hashbuf);
|
||||||
|
}
|
||||||
|
if (session->out_hashbuf != NULL) {
|
||||||
|
ssh_buffer_free(session->out_hashbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_free(session->current_crypto);
|
||||||
|
crypto_free(session->next_crypto);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
agent_free(session->agent);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
ssh_key_free(session->srv.dsa_key);
|
||||||
|
session->srv.dsa_key = NULL;
|
||||||
|
ssh_key_free(session->srv.rsa_key);
|
||||||
|
session->srv.rsa_key = NULL;
|
||||||
|
ssh_key_free(session->srv.ecdsa_key);
|
||||||
|
session->srv.ecdsa_key = NULL;
|
||||||
|
ssh_key_free(session->srv.ed25519_key);
|
||||||
|
session->srv.ed25519_key = NULL;
|
||||||
|
|
||||||
|
if (session->ssh_message_list) {
|
||||||
|
ssh_message msg;
|
||||||
|
|
||||||
|
for (msg = ssh_list_pop_head(ssh_message, session->ssh_message_list);
|
||||||
|
msg != NULL;
|
||||||
|
msg = ssh_list_pop_head(ssh_message, session->ssh_message_list)) {
|
||||||
|
ssh_message_free(msg);
|
||||||
|
}
|
||||||
|
ssh_list_free(session->ssh_message_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->packet_callbacks) {
|
||||||
|
ssh_list_free(session->packet_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* options */
|
||||||
|
if (session->opts.identity) {
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
for (id = ssh_list_pop_head(char *, session->opts.identity);
|
||||||
|
id != NULL;
|
||||||
|
id = ssh_list_pop_head(char *, session->opts.identity)) {
|
||||||
|
SAFE_FREE(id);
|
||||||
|
}
|
||||||
|
ssh_list_free(session->opts.identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
ssh_agent_state_free (session->agent_state);
|
||||||
|
#endif
|
||||||
|
session->agent_state = NULL;
|
||||||
|
|
||||||
|
SAFE_FREE(session->auth_auto_state);
|
||||||
|
SAFE_FREE(session->serverbanner);
|
||||||
|
SAFE_FREE(session->clientbanner);
|
||||||
|
SAFE_FREE(session->banner);
|
||||||
|
|
||||||
|
SAFE_FREE(session->opts.bindaddr);
|
||||||
|
SAFE_FREE(session->opts.custombanner);
|
||||||
|
SAFE_FREE(session->opts.username);
|
||||||
|
SAFE_FREE(session->opts.host);
|
||||||
|
SAFE_FREE(session->opts.sshdir);
|
||||||
|
SAFE_FREE(session->opts.knownhosts);
|
||||||
|
SAFE_FREE(session->opts.ProxyCommand);
|
||||||
|
SAFE_FREE(session->opts.gss_server_identity);
|
||||||
|
SAFE_FREE(session->opts.gss_client_identity);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
if (session->opts.wanted_methods[i]) {
|
||||||
|
SAFE_FREE(session->opts.wanted_methods[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* burn connection, it could contain sensitive data */
|
||||||
|
BURN_BUFFER(session, sizeof(struct ssh_session_struct));
|
||||||
|
SAFE_FREE(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the client banner
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
*
|
||||||
|
* @return Returns the client banner string or NULL.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_clientbanner(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->clientbanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the server banner
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
*
|
||||||
|
* @return Returns the server banner string or NULL.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_serverbanner(ssh_session session) {
|
||||||
|
if(!session) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return session->serverbanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the name of the current key exchange algorithm.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
*
|
||||||
|
* @return Returns the key exchange algorithm string or NULL.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_kex_algo(ssh_session session) {
|
||||||
|
if ((session == NULL) ||
|
||||||
|
(session->current_crypto == NULL)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (session->current_crypto->kex_type) {
|
||||||
|
case SSH_KEX_DH_GROUP1_SHA1:
|
||||||
|
return "diffie-hellman-group1-sha1";
|
||||||
|
case SSH_KEX_DH_GROUP14_SHA1:
|
||||||
|
return "diffie-hellman-group14-sha1";
|
||||||
|
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||||
|
return "ecdh-sha2-nistp256";
|
||||||
|
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||||
|
return "curve25519-sha256@libssh.org";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the name of the input cipher for the given session.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session.
|
||||||
|
*
|
||||||
|
* @return Returns cipher name or NULL.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_cipher_in(ssh_session session) {
|
||||||
|
if ((session != NULL) &&
|
||||||
|
(session->current_crypto != NULL) &&
|
||||||
|
(session->current_crypto->in_cipher != NULL)) {
|
||||||
|
return session->current_crypto->in_cipher->name;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the name of the output cipher for the given session.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session.
|
||||||
|
*
|
||||||
|
* @return Returns cipher name or NULL.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_cipher_out(ssh_session session) {
|
||||||
|
if ((session != NULL) &&
|
||||||
|
(session->current_crypto != NULL) &&
|
||||||
|
(session->current_crypto->out_cipher != NULL)) {
|
||||||
|
return session->current_crypto->out_cipher->name;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the name of the input HMAC algorithm for the given session.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session.
|
||||||
|
*
|
||||||
|
* @return Returns HMAC algorithm name or NULL if unknown.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_hmac_in(ssh_session session) {
|
||||||
|
if ((session != NULL) &&
|
||||||
|
(session->current_crypto != NULL)) {
|
||||||
|
return ssh_hmac_type_to_string(session->current_crypto->in_hmac);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the name of the output HMAC algorithm for the given session.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session.
|
||||||
|
*
|
||||||
|
* @return Returns HMAC algorithm name or NULL if unknown.
|
||||||
|
*/
|
||||||
|
const char* ssh_get_hmac_out(ssh_session session) {
|
||||||
|
if ((session != NULL) &&
|
||||||
|
(session->current_crypto != NULL)) {
|
||||||
|
return ssh_hmac_type_to_string(session->current_crypto->out_hmac);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disconnect impolitely from a remote host by closing the socket.
|
||||||
|
*
|
||||||
|
* Suitable if you forked and want to destroy this session.
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session to disconnect.
|
||||||
|
*/
|
||||||
|
void ssh_silent_disconnect(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_socket_close(session->socket);
|
||||||
|
session->alive = 0;
|
||||||
|
ssh_disconnect(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the session in blocking/nonblocking mode.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to change.
|
||||||
|
*
|
||||||
|
* @param[in] blocking Zero for nonblocking mode.
|
||||||
|
*/
|
||||||
|
void ssh_set_blocking(ssh_session session, int blocking) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
session->flags &= ~SSH_SESSION_FLAG_BLOCKING;
|
||||||
|
session->flags |= blocking ? SSH_SESSION_FLAG_BLOCKING : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the blocking mode of libssh
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
* @returns 0 if the session is nonblocking,
|
||||||
|
* @returns 1 if the functions may block.
|
||||||
|
*/
|
||||||
|
int ssh_is_blocking(ssh_session session){
|
||||||
|
return (session->flags&SSH_SESSION_FLAG_BLOCKING) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Waits until the output socket is empty */
|
||||||
|
static int ssh_flush_termination(void *c){
|
||||||
|
ssh_session session = c;
|
||||||
|
if (ssh_socket_buffered_write_bytes(session->socket) == 0 ||
|
||||||
|
session->session_state == SSH_SESSION_STATE_ERROR)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Blocking flush of the outgoing buffer
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
* @param[in] timeout Set an upper limit on the time for which this function
|
||||||
|
* will block, in milliseconds. Specifying -1
|
||||||
|
* means an infinite timeout. This parameter is passed to
|
||||||
|
* the poll() function.
|
||||||
|
* @returns SSH_OK on success, SSH_AGAIN if timeout occurred,
|
||||||
|
* SSH_ERROR otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ssh_blocking_flush(ssh_session session, int timeout){
|
||||||
|
int rc;
|
||||||
|
if (session == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_handle_packets_termination(session, timeout,
|
||||||
|
ssh_flush_termination, session);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if (!ssh_flush_termination(session)) {
|
||||||
|
rc = SSH_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if we are connected.
|
||||||
|
*
|
||||||
|
* @param[in] session The session to check if it is connected.
|
||||||
|
*
|
||||||
|
* @return 1 if we are connected, 0 if not.
|
||||||
|
*/
|
||||||
|
int ssh_is_connected(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the fd of a connection.
|
||||||
|
*
|
||||||
|
* In case you'd need the file descriptor of the connection to the server/client.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @return The file descriptor of the connection, or -1 if it is
|
||||||
|
* not connected
|
||||||
|
*/
|
||||||
|
socket_t ssh_get_fd(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssh_socket_get_fd_in(session->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tell the session it has data to read on the file descriptor without
|
||||||
|
* blocking.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*/
|
||||||
|
void ssh_set_fd_toread(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_socket_set_read_wontblock(session->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tell the session it may write to the file descriptor without blocking.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*/
|
||||||
|
void ssh_set_fd_towrite(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_socket_set_write_wontblock(session->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tell the session it has an exception to catch on the file descriptor.
|
||||||
|
*
|
||||||
|
* \param[in] session The ssh session to use.
|
||||||
|
*/
|
||||||
|
void ssh_set_fd_except(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_socket_set_except(session->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Poll the current session for an event and call the appropriate
|
||||||
|
* callbacks. This function will not loop until the timeout is expired.
|
||||||
|
*
|
||||||
|
* This will block until one event happens.
|
||||||
|
*
|
||||||
|
* @param[in] session The session handle to use.
|
||||||
|
*
|
||||||
|
* @param[in] timeout Set an upper limit on the time for which this function
|
||||||
|
* will block, in milliseconds. Specifying SSH_TIMEOUT_INFINITE
|
||||||
|
* (-1) means an infinite timeout.
|
||||||
|
* Specifying SSH_TIMEOUT_USER means to use the timeout
|
||||||
|
* specified in options. 0 means poll will return immediately.
|
||||||
|
* This parameter is passed to the poll() function.
|
||||||
|
*
|
||||||
|
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||||
|
*/
|
||||||
|
int ssh_handle_packets(ssh_session session, int timeout) {
|
||||||
|
ssh_poll_handle spoll_in,spoll_out;
|
||||||
|
ssh_poll_ctx ctx;
|
||||||
|
int tm = timeout;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (session == NULL || session->socket == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
spoll_in = ssh_socket_get_poll_handle_in(session->socket);
|
||||||
|
spoll_out = ssh_socket_get_poll_handle_out(session->socket);
|
||||||
|
ssh_poll_add_events(spoll_in, POLLIN);
|
||||||
|
ctx = ssh_poll_get_ctx(spoll_in);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
ctx = ssh_poll_get_default_ctx(session);
|
||||||
|
ssh_poll_ctx_add(ctx, spoll_in);
|
||||||
|
if (spoll_in != spoll_out) {
|
||||||
|
ssh_poll_ctx_add(ctx, spoll_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout == SSH_TIMEOUT_USER) {
|
||||||
|
if (ssh_is_blocking(session))
|
||||||
|
tm = ssh_make_milliseconds(session->opts.timeout,
|
||||||
|
session->opts.timeout_usec);
|
||||||
|
else
|
||||||
|
tm = 0;
|
||||||
|
}
|
||||||
|
rc = ssh_poll_ctx_dopoll(ctx, tm);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Poll the current session for an event and call the appropriate
|
||||||
|
* callbacks.
|
||||||
|
*
|
||||||
|
* This will block until termination function returns true, or timeout expired.
|
||||||
|
*
|
||||||
|
* @param[in] session The session handle to use.
|
||||||
|
*
|
||||||
|
* @param[in] timeout Set an upper limit on the time for which this function
|
||||||
|
* will block, in milliseconds. Specifying SSH_TIMEOUT_INFINITE
|
||||||
|
* (-1) means an infinite timeout.
|
||||||
|
* Specifying SSH_TIMEOUT_USER means to use the timeout
|
||||||
|
* specified in options. 0 means poll will return immediately.
|
||||||
|
* SSH_TIMEOUT_DEFAULT uses blocking parameters of the session.
|
||||||
|
* This parameter is passed to the poll() function.
|
||||||
|
*
|
||||||
|
* @param[in] fct Termination function to be used to determine if it is
|
||||||
|
* possible to stop polling.
|
||||||
|
* @param[in] user User parameter to be passed to fct termination function.
|
||||||
|
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||||
|
*/
|
||||||
|
int ssh_handle_packets_termination(ssh_session session,
|
||||||
|
int timeout,
|
||||||
|
ssh_termination_function fct,
|
||||||
|
void *user)
|
||||||
|
{
|
||||||
|
struct ssh_timestamp ts;
|
||||||
|
int ret = SSH_OK;
|
||||||
|
int tm;
|
||||||
|
|
||||||
|
if (timeout == SSH_TIMEOUT_USER) {
|
||||||
|
if (ssh_is_blocking(session)) {
|
||||||
|
timeout = ssh_make_milliseconds(session->opts.timeout,
|
||||||
|
session->opts.timeout_usec);
|
||||||
|
} else {
|
||||||
|
timeout = SSH_TIMEOUT_NONBLOCKING;
|
||||||
|
}
|
||||||
|
} else if (timeout == SSH_TIMEOUT_DEFAULT) {
|
||||||
|
if (ssh_is_blocking(session)) {
|
||||||
|
// Apex.
|
||||||
|
// timeout = SSH_TIMEOUT_INFINITE;
|
||||||
|
timeout = ssh_make_milliseconds(session->opts.timeout,
|
||||||
|
session->opts.timeout_usec);
|
||||||
|
} else {
|
||||||
|
timeout = SSH_TIMEOUT_NONBLOCKING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* avoid unnecessary syscall for the SSH_TIMEOUT_NONBLOCKING case */
|
||||||
|
if (timeout != SSH_TIMEOUT_NONBLOCKING) {
|
||||||
|
ssh_timestamp_init(&ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
tm = timeout;
|
||||||
|
while(!fct(user)) {
|
||||||
|
ret = ssh_handle_packets(session, tm);
|
||||||
|
if (ret == SSH_ERROR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ssh_timeout_elapsed(&ts,timeout)) {
|
||||||
|
ret = fct(user) ? SSH_OK : SSH_AGAIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tm = ssh_timeout_update(&ts, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get session status
|
||||||
|
*
|
||||||
|
* @param session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @returns A bitmask including SSH_CLOSED, SSH_READ_PENDING, SSH_WRITE_PENDING
|
||||||
|
* or SSH_CLOSED_ERROR which respectively means the session is closed,
|
||||||
|
* has data to read on the connection socket and session was closed
|
||||||
|
* due to an error.
|
||||||
|
*/
|
||||||
|
int ssh_get_status(ssh_session session) {
|
||||||
|
int socketstate;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (session == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
socketstate = ssh_socket_get_status(session->socket);
|
||||||
|
|
||||||
|
if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
|
||||||
|
r |= SSH_CLOSED;
|
||||||
|
}
|
||||||
|
if (socketstate & SSH_READ_PENDING) {
|
||||||
|
r |= SSH_READ_PENDING;
|
||||||
|
}
|
||||||
|
if (socketstate & SSH_WRITE_PENDING) {
|
||||||
|
r |= SSH_WRITE_PENDING;
|
||||||
|
}
|
||||||
|
if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
|
||||||
|
(socketstate & SSH_CLOSED_ERROR)) ||
|
||||||
|
session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||||
|
r |= SSH_CLOSED_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get poll flags for an external mainloop
|
||||||
|
*
|
||||||
|
* @param session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @returns A bitmask including SSH_READ_PENDING or SSH_WRITE_PENDING.
|
||||||
|
* For SSH_READ_PENDING, your invocation of poll() should include
|
||||||
|
* POLLIN. For SSH_WRITE_PENDING, your invocation of poll() should
|
||||||
|
* include POLLOUT.
|
||||||
|
*/
|
||||||
|
int ssh_get_poll_flags(ssh_session session)
|
||||||
|
{
|
||||||
|
if (session == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssh_socket_get_poll_flags (session->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the disconnect message from the server.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @return The message sent by the server along with the
|
||||||
|
* disconnect, or NULL in which case the reason of the
|
||||||
|
* disconnect may be found with ssh_get_error.
|
||||||
|
*
|
||||||
|
* @see ssh_get_error()
|
||||||
|
*/
|
||||||
|
const char *ssh_get_disconnect_message(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
|
||||||
|
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||||
|
"Connection not closed yet");
|
||||||
|
} else if(!session->discon_msg) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Connection correctly closed but no disconnect message");
|
||||||
|
} else {
|
||||||
|
return session->discon_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the protocol version of the session.
|
||||||
|
*
|
||||||
|
* @param session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @return 1 or 2, for ssh1 or ssh2, < 0 on error.
|
||||||
|
*/
|
||||||
|
int ssh_get_version(ssh_session session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief Callback to be called when the socket received an exception code.
|
||||||
|
* @param user is a pointer to session
|
||||||
|
*/
|
||||||
|
void ssh_socket_exception_callback(int code, int errno_code, void *user){
|
||||||
|
ssh_session session=(ssh_session)user;
|
||||||
|
|
||||||
|
SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
|
||||||
|
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||||
|
if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
|
||||||
|
} else {
|
||||||
|
ssh_set_error(session, SSH_FATAL, "Socket error: %s", strerror(errno_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
session->ssh_connection_callback(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a message that should be ignored
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
* @param[in] data Data to be sent
|
||||||
|
*
|
||||||
|
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||||
|
*/
|
||||||
|
int ssh_send_ignore (ssh_session session, const char *data) {
|
||||||
|
#ifdef WITH_SSH1
|
||||||
|
const int type = session->version == 1 ? SSH_MSG_IGNORE : SSH2_MSG_IGNORE;
|
||||||
|
#else /* WITH_SSH1 */
|
||||||
|
const int type = SSH2_MSG_IGNORE;
|
||||||
|
#endif /* WITH_SSH1 */
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (ssh_socket_is_open(session->socket)) {
|
||||||
|
rc = ssh_buffer_pack(session->out_buffer,
|
||||||
|
"bs",
|
||||||
|
type,
|
||||||
|
data);
|
||||||
|
if (rc != SSH_OK){
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
packet_send(session);
|
||||||
|
ssh_handle_packets(session, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ssh_buffer_reinit(session->out_buffer);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a debug message
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session
|
||||||
|
* @param[in] message Data to be sent
|
||||||
|
* @param[in] always_display Message SHOULD be displayed by the server. It
|
||||||
|
* SHOULD NOT be displayed unless debugging
|
||||||
|
* information has been explicitly requested.
|
||||||
|
*
|
||||||
|
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||||
|
*/
|
||||||
|
int ssh_send_debug (ssh_session session, const char *message, int always_display) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (ssh_socket_is_open(session->socket)) {
|
||||||
|
#ifdef WITH_SSH1
|
||||||
|
if (session->version == 1) {
|
||||||
|
rc = ssh_buffer_pack(session->out_buffer,
|
||||||
|
"bs",
|
||||||
|
SSH_MSG_DEBUG,
|
||||||
|
message);
|
||||||
|
} else
|
||||||
|
#endif /* WITH_SSH1 */
|
||||||
|
{
|
||||||
|
rc = ssh_buffer_pack(session->out_buffer,
|
||||||
|
"bbsd",
|
||||||
|
SSH2_MSG_DEBUG,
|
||||||
|
always_display != 0 ? 1 : 0,
|
||||||
|
message,
|
||||||
|
0); /* empty language tag */
|
||||||
|
}
|
||||||
|
if (rc != SSH_OK) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
packet_send(session);
|
||||||
|
ssh_handle_packets(session, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ssh_buffer_reinit(session->out_buffer);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the session data counters.
|
||||||
|
*
|
||||||
|
* This functions sets the counter structures to be used to calculate data
|
||||||
|
* which comes in and goes out through the session at different levels.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* struct ssh_counter_struct scounter = {
|
||||||
|
* .in_bytes = 0,
|
||||||
|
* .out_bytes = 0,
|
||||||
|
* .in_packets = 0,
|
||||||
|
* .out_packets = 0
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct ssh_counter_struct rcounter = {
|
||||||
|
* .in_bytes = 0,
|
||||||
|
* .out_bytes = 0,
|
||||||
|
* .in_packets = 0,
|
||||||
|
* .out_packets = 0
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* ssh_set_counters(session, &scounter, &rcounter);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param[in] session The SSH session.
|
||||||
|
*
|
||||||
|
* @param[in] scounter Counter for byte data handled by the session sockets.
|
||||||
|
*
|
||||||
|
* @param[in] rcounter Counter for byte and packet data handled by the session,
|
||||||
|
* prior compression and SSH overhead.
|
||||||
|
*/
|
||||||
|
void ssh_set_counters(ssh_session session, ssh_counter scounter,
|
||||||
|
ssh_counter rcounter) {
|
||||||
|
if (session != NULL) {
|
||||||
|
session->socket_counter = scounter;
|
||||||
|
session->raw_counter = rcounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/* vim: set ts=4 sw=4 et cindent: */
|
|
@ -86,6 +86,7 @@ void SshProxy::_thread_loop()
|
||||||
{
|
{
|
||||||
// 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。
|
// 注意,ssh_new()出来的指针,如果遇到停止标志,本函数内部就释放了,否则这个指针交给了SshSession类实例管理,其析构时会释放。
|
||||||
ssh_session sess_to_client = ssh_new();
|
ssh_session sess_to_client = ssh_new();
|
||||||
|
ssh_set_blocking(sess_to_client, 1);
|
||||||
|
|
||||||
struct sockaddr_storage sock_client;
|
struct sockaddr_storage sock_client;
|
||||||
char ip[32] = { 0 };
|
char ip[32] = { 0 };
|
||||||
|
|
|
@ -117,7 +117,6 @@ bool SshSession::_on_session_begin(TP_SSH_CHANNEL_PAIR* cp)
|
||||||
|
|
||||||
void SshSession::_on_session_end(TP_SSH_CHANNEL_PAIR* cp)
|
void SshSession::_on_session_end(TP_SSH_CHANNEL_PAIR* cp)
|
||||||
{
|
{
|
||||||
EXLOGD("[ssh] inside call end(). db-id: %d\n", cp->db_id);
|
|
||||||
if (cp->db_id > 0)
|
if (cp->db_id > 0)
|
||||||
{
|
{
|
||||||
EXLOGD("[ssh] session db-id: %d, ret-code: %d\n", cp->db_id, cp->retcode);
|
EXLOGD("[ssh] session db-id: %d, ret-code: %d\n", cp->db_id, cp->retcode);
|
||||||
|
@ -143,8 +142,8 @@ void SshSession::_close_channels(void) {
|
||||||
ssh_channel ch = (*it)->srv_channel;
|
ssh_channel ch = (*it)->srv_channel;
|
||||||
if (ch != NULL) {
|
if (ch != NULL) {
|
||||||
if (!ssh_channel_is_closed(ch)) {
|
if (!ssh_channel_is_closed(ch)) {
|
||||||
if (!ssh_channel_is_eof(ch))
|
// if (!ssh_channel_is_eof(ch))
|
||||||
ssh_channel_send_eof(ch);
|
// ssh_channel_send_eof(ch);
|
||||||
ssh_channel_close(ch);
|
ssh_channel_close(ch);
|
||||||
}
|
}
|
||||||
ssh_channel_free(ch);
|
ssh_channel_free(ch);
|
||||||
|
@ -153,13 +152,14 @@ void SshSession::_close_channels(void) {
|
||||||
ch = (*it)->cli_channel;
|
ch = (*it)->cli_channel;
|
||||||
if (ch != NULL) {
|
if (ch != NULL) {
|
||||||
if (!ssh_channel_is_closed(ch)) {
|
if (!ssh_channel_is_closed(ch)) {
|
||||||
if (!ssh_channel_is_eof(ch))
|
// if (!ssh_channel_is_eof(ch))
|
||||||
ssh_channel_send_eof(ch);
|
// ssh_channel_send_eof(ch);
|
||||||
ssh_channel_close(ch);
|
ssh_channel_close(ch);
|
||||||
}
|
}
|
||||||
ssh_channel_free(ch);
|
ssh_channel_free(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXLOGD(" --- end by close all channel: %d\n", (*it)->db_id);
|
||||||
_on_session_end(*it);
|
_on_session_end(*it);
|
||||||
|
|
||||||
delete (*it);
|
delete (*it);
|
||||||
|
@ -168,6 +168,53 @@ void SshSession::_close_channels(void) {
|
||||||
m_channels.clear();
|
m_channels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SshSession::_check_channels() {
|
||||||
|
ExThreadSmartLock locker(m_lock);
|
||||||
|
|
||||||
|
EXLOGD("-- check channels, have %d\n", m_channels.size());
|
||||||
|
tp_channels::iterator it = m_channels.begin();
|
||||||
|
for (; it != m_channels.end(); ) {
|
||||||
|
EXLOGD("-- channel db-id: %d\n", (*it)->db_id);
|
||||||
|
bool closed = false;
|
||||||
|
ssh_channel cli = (*it)->cli_channel;
|
||||||
|
ssh_channel srv = (*it)->srv_channel;
|
||||||
|
if (cli != NULL) {
|
||||||
|
if (ssh_channel_is_closed(cli)) {
|
||||||
|
EXLOGD(" -- check server channel, already closed: %d\n", (*it)->db_id);
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (srv != NULL) {
|
||||||
|
if (ssh_channel_is_closed(srv)) {
|
||||||
|
EXLOGD(" -- check client channel, already closed: %d\n", (*it)->db_id);
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closed) {
|
||||||
|
EXLOGD(" --- end by check channel: %d\n", (*it)->db_id);
|
||||||
|
_on_session_end((*it));
|
||||||
|
|
||||||
|
if (!ssh_channel_is_closed(cli)) {
|
||||||
|
ssh_channel_close(cli);
|
||||||
|
}
|
||||||
|
ssh_channel_free(cli);
|
||||||
|
|
||||||
|
if (!ssh_channel_is_closed(srv)) {
|
||||||
|
ssh_channel_close(srv);
|
||||||
|
}
|
||||||
|
ssh_channel_free(srv);
|
||||||
|
|
||||||
|
delete (*it);
|
||||||
|
|
||||||
|
m_channels.erase(it++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SshSession::_run(void) {
|
void SshSession::_run(void) {
|
||||||
m_srv_cb.auth_password_function = _on_auth_password_request;
|
m_srv_cb.auth_password_function = _on_auth_password_request;
|
||||||
m_srv_cb.channel_open_request_session_function = _on_new_channel_request;
|
m_srv_cb.channel_open_request_session_function = _on_new_channel_request;
|
||||||
|
@ -227,7 +274,8 @@ void SshSession::_run(void) {
|
||||||
// 现在双方的连接已经建立好了,开始转发
|
// 现在双方的连接已经建立好了,开始转发
|
||||||
ssh_event_add_session(event_loop, m_srv_session);
|
ssh_event_add_session(event_loop, m_srv_session);
|
||||||
do {
|
do {
|
||||||
r = ssh_event_dopoll(event_loop, -1);
|
r = ssh_event_dopoll(event_loop, 5000);
|
||||||
|
//EXLOGD("ssh_event_dopoll() return %d.\n", r);
|
||||||
if (r == SSH_ERROR) {
|
if (r == SSH_ERROR) {
|
||||||
if (0 != ssh_get_error_code(m_cli_session))
|
if (0 != ssh_get_error_code(m_cli_session))
|
||||||
{
|
{
|
||||||
|
@ -240,6 +288,10 @@ void SshSession::_run(void) {
|
||||||
|
|
||||||
_close_channels();
|
_close_channels();
|
||||||
}
|
}
|
||||||
|
else if (r == SSH_AGAIN) {
|
||||||
|
// timeout.
|
||||||
|
_check_channels();
|
||||||
|
}
|
||||||
} while (m_channels.size() > 0);
|
} while (m_channels.size() > 0);
|
||||||
|
|
||||||
EXLOGV("[ssh] [%s:%d] all channel in this session are closed.\n", m_client_ip.c_str(), m_client_port);
|
EXLOGV("[ssh] [%s:%d] all channel in this session are closed.\n", m_client_ip.c_str(), m_client_port);
|
||||||
|
@ -258,7 +310,6 @@ void SshSession::save_record() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
// 这里拿到的user就是我们要的session-id。
|
// 这里拿到的user就是我们要的session-id。
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
@ -294,6 +345,7 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
// 现在尝试根据session-id获取得到的信息,连接并登录真正的SSH服务器
|
// 现在尝试根据session-id获取得到的信息,连接并登录真正的SSH服务器
|
||||||
EXLOGV("[ssh] try to connect to real SSH server %s:%d\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
EXLOGV("[ssh] try to connect to real SSH server %s:%d\n", _this->m_conn_ip.c_str(), _this->m_conn_port);
|
||||||
_this->m_srv_session = ssh_new();
|
_this->m_srv_session = ssh_new();
|
||||||
|
ssh_set_blocking(_this->m_srv_session, 1);
|
||||||
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_HOST, _this->m_conn_ip.c_str());
|
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_HOST, _this->m_conn_ip.c_str());
|
||||||
int port = (int)_this->m_conn_port;
|
int port = (int)_this->m_conn_port;
|
||||||
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_PORT, &port);
|
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_PORT, &port);
|
||||||
|
@ -318,6 +370,9 @@ int SshSession::_on_auth_password_request(ssh_session session, const char *user,
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_timeout = 10; // 10 sec.
|
||||||
|
ssh_options_set(_this->m_srv_session, SSH_OPTIONS_TIMEOUT, &_timeout);
|
||||||
|
|
||||||
// // 检查服务端支持的认证协议
|
// // 检查服务端支持的认证协议
|
||||||
ssh_userauth_none(_this->m_srv_session, NULL);
|
ssh_userauth_none(_this->m_srv_session, NULL);
|
||||||
// rc = ssh_userauth_none(_this->m_srv_session, NULL);
|
// rc = ssh_userauth_none(_this->m_srv_session, NULL);
|
||||||
|
@ -454,9 +509,10 @@ ssh_channel SshSession::_on_new_channel_request(ssh_session session, void *userd
|
||||||
EXLOGE("[ssh] can not create channel for server.\n");
|
EXLOGE("[ssh] can not create channel for server.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (ssh_channel_open_session(srv_channel)) {
|
if (SSH_OK != ssh_channel_open_session(srv_channel)) {
|
||||||
EXLOGE("[ssh] error opening channel to real server: %s\n", ssh_get_error(session));
|
EXLOGE("[ssh] error opening channel to real server: %s\n", ssh_get_error(_this->m_srv_session));
|
||||||
ssh_channel_free(cli_channel);
|
ssh_channel_free(cli_channel);
|
||||||
|
ssh_channel_free(srv_channel);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ssh_set_channel_callbacks(srv_channel, &_this->m_srv_channel_cb);
|
ssh_set_channel_callbacks(srv_channel, &_this->m_srv_channel_cb);
|
||||||
|
@ -871,11 +927,10 @@ void SshSession::_process_sftp_command(TppSshRec* rec, const ex_u8* data, int le
|
||||||
rec->record_command(msg);
|
rec->record_command(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SshSession::_on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata) {
|
int SshSession::_on_client_pty_request(ssh_session session, ssh_channel channel, const char *term, int x, int y, int px, int py, void *userdata) {
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
EXLOGD("[ssh] client request terminal: %s, (%d, %d) / (%d, %d)\n", term, x, y, px, py);
|
EXLOGD("[ssh] client request pty: %s, (%d, %d) / (%d, %d)\n", term, x, y, px, py);
|
||||||
|
|
||||||
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_CLIENT_SIDE, channel);
|
||||||
if (NULL == cp) {
|
if (NULL == cp) {
|
||||||
|
@ -885,7 +940,10 @@ int SshSession::_on_client_pty_request(ssh_session session, ssh_channel channel,
|
||||||
|
|
||||||
cp->rec.record_win_size_startup(x, y);
|
cp->rec.record_win_size_startup(x, y);
|
||||||
|
|
||||||
return ssh_channel_request_pty_size(cp->srv_channel, term, x, y);
|
int err = ssh_channel_request_pty_size(cp->srv_channel, term, x, y);
|
||||||
|
if(err != SSH_OK)
|
||||||
|
EXLOGD("[ssh] pty request from server got %d\n", err);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata) {
|
int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channel, void *userdata) {
|
||||||
|
@ -905,11 +963,13 @@ int SshSession::_on_client_shell_request(ssh_session session, ssh_channel channe
|
||||||
// FIXME: if client is putty, it will block here. the following function will never return.
|
// FIXME: if client is putty, it will block here. the following function will never return.
|
||||||
// at this time, can not write data to this channel. read from this channel with timeout, got 0 byte.
|
// at this time, can not write data to this channel. read from this channel with timeout, got 0 byte.
|
||||||
// I have no idea how to fix it... :(
|
// I have no idea how to fix it... :(
|
||||||
return ssh_channel_request_shell(cp->srv_channel);
|
int err = ssh_channel_request_shell(cp->srv_channel);
|
||||||
|
if (err != SSH_OK)
|
||||||
|
EXLOGD("[ssh] shell request from server got %d\n", err);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::_on_client_channel_close(ssh_session session, ssh_channel channel, void *userdata) {
|
void SshSession::_on_client_channel_close(ssh_session session, ssh_channel channel, void *userdata) {
|
||||||
EXLOGD("[ssh] on_client_channel_close().\n");
|
|
||||||
|
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
|
@ -920,57 +980,43 @@ void SshSession::_on_client_channel_close(ssh_session session, ssh_channel chann
|
||||||
}
|
}
|
||||||
|
|
||||||
EXLOGD("[ssh] on_client_channel_close(). db-id: %d\n", cp->db_id);
|
EXLOGD("[ssh] on_client_channel_close(). db-id: %d\n", cp->db_id);
|
||||||
|
int db_id = cp->db_id;
|
||||||
|
|
||||||
|
EXLOGD(" --- end by client channel close: %d\n", db_id);
|
||||||
|
_this->_on_session_end(cp);
|
||||||
|
|
||||||
if (cp->srv_channel == NULL) {
|
if (cp->srv_channel == NULL) {
|
||||||
EXLOGW("[ssh] when client channel close, server-channel not exists.\n");
|
EXLOGW("[ssh] when client channel close, server-channel not exists.\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!ssh_channel_is_closed(cp->srv_channel)) {
|
if (!ssh_channel_is_closed(cp->srv_channel)) {
|
||||||
// if (!ssh_channel_is_eof(cp->srv_channel)) {
|
|
||||||
// //EXLOGD("[ssh] when client channel close, send eof to server-channel.\n");
|
|
||||||
// ssh_channel_send_eof(cp->cli_channel);
|
|
||||||
// }
|
|
||||||
|
|
||||||
//EXLOGD("[ssh] when client channel close, close server-channel.\n");
|
|
||||||
ssh_channel_close(cp->srv_channel);
|
ssh_channel_close(cp->srv_channel);
|
||||||
|
|
||||||
// ssh_channel_free(cp->srv_channel);
|
|
||||||
// cp->srv_channel = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ssh_channel_is_closed(cp->cli_channel)) {
|
// if (!ssh_channel_is_closed(cp->cli_channel)) {
|
||||||
// if (!ssh_channel_is_eof(cp->cli_channel)) {
|
// ssh_channel_close(cp->cli_channel);
|
||||||
// //EXLOGD("[ssh] when client channel close, send eof to client-channel.\n");
|
|
||||||
// ssh_channel_send_eof(cp->cli_channel);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
//EXLOGD("[ssh] when client channel close, close client-channel.\n");
|
|
||||||
ssh_channel_close(cp->cli_channel);
|
|
||||||
|
|
||||||
// ssh_channel_free(cp->cli_channel);
|
|
||||||
// cp->cli_channel = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssh_channel_is_closed(cp->cli_channel) && ssh_channel_is_closed(cp->srv_channel))
|
if (ssh_channel_is_closed(cp->cli_channel) && ssh_channel_is_closed(cp->srv_channel))
|
||||||
{
|
{
|
||||||
ssh_channel_free(cp->cli_channel);
|
ssh_channel_free(cp->cli_channel);
|
||||||
|
cp->cli_channel = NULL;
|
||||||
ssh_channel_free(cp->srv_channel);
|
ssh_channel_free(cp->srv_channel);
|
||||||
|
cp->srv_channel = NULL;
|
||||||
|
|
||||||
ExThreadSmartLock locker(_this->m_lock);
|
ExThreadSmartLock locker(_this->m_lock);
|
||||||
|
|
||||||
EXLOGD("[ssh] on_client_channel_close() before call end(). db-id: %d\n", cp->db_id);
|
|
||||||
_this->_on_session_end(cp);
|
|
||||||
|
|
||||||
tp_channels::iterator it = _this->m_channels.begin();
|
tp_channels::iterator it = _this->m_channels.begin();
|
||||||
for (; it != _this->m_channels.end(); ++it) {
|
for (; it != _this->m_channels.end(); ++it) {
|
||||||
if ((*it) == cp) {
|
if ((*it) == cp) {
|
||||||
EXLOGD("--- client_channel_close(), erase: %d\n", cp->db_id);
|
EXLOGD("--- client_channel_close(), erase: %d\n", db_id);
|
||||||
delete (*it);
|
delete (*it);
|
||||||
_this->m_channels.erase(it);
|
_this->m_channels.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//_this->_check_channels();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,12 +1038,6 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
|
||||||
// if (NULL == info || NULL == info->channel) {
|
|
||||||
// EXLOGE("[ssh] when receive client channel data, not found server channel.\n");
|
|
||||||
// return SSH_ERROR;
|
|
||||||
// }
|
|
||||||
|
|
||||||
_this->m_recving_from_cli = true;
|
_this->m_recving_from_cli = true;
|
||||||
|
|
||||||
if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL)
|
if (cp->type == TS_SSH_CHANNEL_TYPE_SHELL)
|
||||||
|
@ -1023,6 +1063,8 @@ int SshSession::_on_client_channel_data(ssh_session session, ssh_channel channel
|
||||||
|
|
||||||
if (ret == SSH_ERROR) {
|
if (ret == SSH_ERROR) {
|
||||||
EXLOGE("[ssh] send data(%dB) to server failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
|
EXLOGE("[ssh] send data(%dB) to server failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
|
||||||
|
|
||||||
|
ssh_channel_close(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->m_recving_from_cli = false;
|
_this->m_recving_from_cli = false;
|
||||||
|
@ -1040,12 +1082,6 @@ int SshSession::_on_client_pty_win_change(ssh_session session, ssh_channel chann
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TS_SSH_CHANNEL_INFO *info = _this->_get_srv_channel(channel);
|
|
||||||
// if (NULL == info || NULL == info->channel) {
|
|
||||||
// EXLOGE("[ssh] when client pty win change, not found server channel.\n");
|
|
||||||
// return SSH_ERROR;
|
|
||||||
// }
|
|
||||||
|
|
||||||
cp->rec.record_win_size_change(width, height);
|
cp->rec.record_win_size_change(width, height);
|
||||||
|
|
||||||
return ssh_channel_change_pty_size(cp->srv_channel, width, height);
|
return ssh_channel_change_pty_size(cp->srv_channel, width, height);
|
||||||
|
@ -1068,28 +1104,15 @@ int SshSession::_on_client_channel_subsystem_request(ssh_session session, ssh_ch
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TS_SSH_CHANNEL_INFO *srv_info = _this->_get_srv_channel(channel);
|
|
||||||
// if (NULL == srv_info || NULL == srv_info->channel) {
|
|
||||||
// EXLOGE("[ssh] when receive client channel subsystem request, not found server channel.\n");
|
|
||||||
// return SSH_ERROR;
|
|
||||||
// }
|
|
||||||
// srv_info->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
|
||||||
//
|
|
||||||
// TS_SSH_CHANNEL_INFO *cli_info = _this->_get_cli_channel(srv_info->channel);
|
|
||||||
// if (NULL == cli_info || NULL == cli_info->channel) {
|
|
||||||
// EXLOGE("[ssh] when client request shell, not found client channel.\n");
|
|
||||||
// return SSH_ERROR;
|
|
||||||
// }
|
|
||||||
// cli_info->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
|
||||||
cp->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
cp->type = TS_SSH_CHANNEL_TYPE_SFTP;
|
||||||
|
|
||||||
g_ssh_env.session_update(cp->db_id, TP_PROTOCOL_TYPE_SSH_SFTP, TP_SESS_STAT_STARTED);
|
g_ssh_env.session_update(cp->db_id, TP_PROTOCOL_TYPE_SSH_SFTP, TP_SESS_STAT_STARTED);
|
||||||
|
|
||||||
|
//EXLOGD("[ssh] ---> request channel subsystem from server\n");
|
||||||
// 一个ssh会话打开了sftp通道,就将连接信息记录下来备用,随后这个session-id再次尝试连接时,我们允许其连接。
|
int err = ssh_channel_request_subsystem(cp->srv_channel, subsystem);
|
||||||
//_this->_enter_sftp_mode();
|
//EXLOGD("[ssh] <--- request channel subsystem from server\n");
|
||||||
|
if (err != SSH_OK)
|
||||||
return ssh_channel_request_subsystem(cp->srv_channel, subsystem);
|
EXLOGD("[ssh] request channel subsystem from server got %d\n", err);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SshSession::_on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata) {
|
int SshSession::_on_client_channel_exec_request(ssh_session session, ssh_channel channel, const char *command, void *userdata) {
|
||||||
|
@ -1201,6 +1224,7 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
|
|
||||||
if (ret == SSH_ERROR) {
|
if (ret == SSH_ERROR) {
|
||||||
EXLOGE("[ssh] send data(%dB) to client failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
|
EXLOGE("[ssh] send data(%dB) to client failed. [%d][cli:%s][srv:%s]\n", len, ret, ssh_get_error(_this->m_cli_session), ssh_get_error(_this->m_srv_session));
|
||||||
|
ssh_channel_close(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->m_recving_from_srv = false;
|
_this->m_recving_from_srv = false;
|
||||||
|
@ -1208,66 +1232,44 @@ int SshSession::_on_server_channel_data(ssh_session session, ssh_channel channel
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshSession::_on_server_channel_close(ssh_session session, ssh_channel channel, void *userdata) {
|
void SshSession::_on_server_channel_close(ssh_session session, ssh_channel channel, void *userdata) {
|
||||||
EXLOGD("[ssh] on_server_channel_close().\n");
|
|
||||||
|
|
||||||
SshSession *_this = (SshSession *)userdata;
|
SshSession *_this = (SshSession *)userdata;
|
||||||
|
|
||||||
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_SERVER_SIDE, channel);
|
TP_SSH_CHANNEL_PAIR* cp = _this->_get_channel_pair(TP_SSH_SERVER_SIDE, channel);
|
||||||
if (NULL == cp) {
|
if (NULL == cp) {
|
||||||
EXLOGE("[ssh] when server channel close, not found channel pair.\n");
|
EXLOGE("[ssh] when server channel close, not found channel pair.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int db_id = cp->db_id;
|
||||||
|
EXLOGD(" --- end by server channel close: %d\n", db_id);
|
||||||
|
_this->_on_session_end(cp);
|
||||||
|
|
||||||
// will the server-channel exist, the client-channel must exist too.
|
// will the server-channel exist, the client-channel must exist too.
|
||||||
if (cp->cli_channel == NULL) {
|
if (cp->cli_channel == NULL) {
|
||||||
EXLOGE("[ssh] when server channel close, client-channel not exists.\n");
|
EXLOGE("[ssh] when server channel close, client-channel not exists.\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!ssh_channel_is_closed(cp->cli_channel)) {
|
if (!ssh_channel_is_closed(cp->cli_channel)) {
|
||||||
// if (!ssh_channel_is_eof(cp->cli_channel)) {
|
|
||||||
// //EXLOGD("[ssh] when server channel close, send eof to client-channel.\n");
|
|
||||||
// ssh_channel_send_eof(cp->cli_channel);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//EXLOGD("[ssh] when server channel close, close client-channel.\n");
|
|
||||||
ssh_channel_close(cp->cli_channel);
|
ssh_channel_close(cp->cli_channel);
|
||||||
|
|
||||||
// ssh_channel_free(cp->cli_channel);
|
|
||||||
// cp->cli_channel = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ssh_channel_is_closed(cp->srv_channel)) {
|
// if (!ssh_channel_is_closed(cp->srv_channel)) {
|
||||||
// if (!ssh_channel_is_eof(cp->srv_channel)) {
|
// ssh_channel_close(cp->srv_channel);
|
||||||
// //EXLOGD("[ssh] when server channel close, send eof to server-channel.\n");
|
|
||||||
// ssh_channel_send_eof(cp->srv_channel);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
//EXLOGD("[ssh] when server channel close, close server-channel.\n");
|
|
||||||
ssh_channel_close(cp->srv_channel);
|
|
||||||
|
|
||||||
// ssh_channel_free(cp->srv_channel);
|
|
||||||
// cp->srv_channel = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ssh_channel_is_closed(cp->cli_channel) && ssh_channel_is_closed(cp->srv_channel))
|
if (ssh_channel_is_closed(cp->cli_channel) && ssh_channel_is_closed(cp->srv_channel))
|
||||||
{
|
{
|
||||||
// ssh_channel_close(cp->cli_channel);
|
|
||||||
ssh_channel_free(cp->cli_channel);
|
ssh_channel_free(cp->cli_channel);
|
||||||
cp->cli_channel = NULL;
|
cp->cli_channel = NULL;
|
||||||
// ssh_channel_close(cp->srv_channel);
|
|
||||||
ssh_channel_free(cp->srv_channel);
|
ssh_channel_free(cp->srv_channel);
|
||||||
cp->srv_channel = NULL;
|
cp->srv_channel = NULL;
|
||||||
|
|
||||||
ExThreadSmartLock locker(_this->m_lock);
|
ExThreadSmartLock locker(_this->m_lock);
|
||||||
|
|
||||||
EXLOGD("[ssh] on_server_channel_close() before call end(). db-id: %d\n", cp->db_id);
|
|
||||||
_this->_on_session_end(cp);
|
|
||||||
|
|
||||||
tp_channels::iterator it = _this->m_channels.begin();
|
tp_channels::iterator it = _this->m_channels.begin();
|
||||||
for (; it != _this->m_channels.end(); ++it) {
|
for (; it != _this->m_channels.end(); ++it) {
|
||||||
if ((*it) == cp) {
|
if ((*it) == cp) {
|
||||||
EXLOGD("--- server_channel_close(), erase: %d\n", cp->db_id);
|
EXLOGD("--- server_channel_close(), erase: %d\n", db_id);
|
||||||
delete (*it);
|
delete (*it);
|
||||||
_this->m_channels.erase(it);
|
_this->m_channels.erase(it);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -78,6 +78,10 @@ private:
|
||||||
void _run(void);
|
void _run(void);
|
||||||
|
|
||||||
void _close_channels(void);
|
void _close_channels(void);
|
||||||
|
void _check_channels(void);
|
||||||
|
|
||||||
|
// void _client_channel_closed(TP_SSH_CHANNEL_PAIR* cp, bool& need_removed);
|
||||||
|
// void _server_channel_closed(TP_SSH_CHANNEL_PAIR* cp, bool& need_removed);
|
||||||
|
|
||||||
static int _on_auth_password_request(ssh_session session, const char *user, const char *password, void *userdata);
|
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 ssh_channel _on_new_channel_request(ssh_session session, void *userdata);
|
||||||
|
|
Loading…
Reference in New Issue