mirror of
https://github.com/tmate-io/tmate.git
synced 2025-06-22 18:41:35 +02:00
Fix keepalive bug
This commit is contained in:
parent
2b14611544
commit
2b86031308
@ -36,6 +36,9 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr)
|
|||||||
struct evutil_addrinfo *ai;
|
struct evutil_addrinfo *ai;
|
||||||
const char *host = ptr;
|
const char *host = ptr;
|
||||||
|
|
||||||
|
evdns_base_free(tmate_session.ev_dnsbase, 0);
|
||||||
|
tmate_session.ev_dnsbase = NULL;
|
||||||
|
|
||||||
if (errcode) {
|
if (errcode) {
|
||||||
struct tmate_session *session = &tmate_session;
|
struct tmate_session *session = &tmate_session;
|
||||||
|
|
||||||
@ -81,9 +84,6 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr)
|
|||||||
connect_ssh_client(ssh_clients[i]);
|
connect_ssh_client(ssh_clients[i]);
|
||||||
|
|
||||||
evutil_freeaddrinfo(addr);
|
evutil_freeaddrinfo(addr);
|
||||||
|
|
||||||
evdns_base_free(tmate_session.ev_dnsbase, 0);
|
|
||||||
tmate_session.ev_dnsbase = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lookup_and_connect(void)
|
static void lookup_and_connect(void)
|
||||||
|
@ -167,57 +167,84 @@ static void request_passphrase(struct tmate_ssh_client *client)
|
|||||||
data->password_cb_private = client;
|
data->password_cb_private = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KEEPALIVE_CNT 3
|
#define KEEPALIVE_IDLE 30
|
||||||
#define KEEPALIVE_IDLE 20
|
#define KEEPALIVE_CNT 4
|
||||||
#define KEEPALIVE_INTVL 10
|
#define KEEPALIVE_INTVL 11
|
||||||
|
#define WRITE_TIMEOUT 80
|
||||||
|
|
||||||
static void tune_socket_opts(int fd)
|
static void tune_socket_opts(int fd)
|
||||||
{
|
{
|
||||||
#define SSO(level, optname, val) ({ \
|
#define SSO(level, optname, val) ({ \
|
||||||
int _flag = val; \
|
int _flag = val; \
|
||||||
if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \
|
if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \
|
||||||
tmate_debug("setsockopt(" #level ", " #optname ", %d) failed", val); \
|
tmate_info("setsockopt(" #level ", " #optname ", %d) failed", val); \
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
|
||||||
SSO(IPPROTO_TCP, TCP_NODELAY, 1);
|
SSO(IPPROTO_TCP, TCP_NODELAY, 1);
|
||||||
SSO(SOL_SOCKET, SO_KEEPALIVE, 1);
|
SSO(SOL_SOCKET, SO_KEEPALIVE, 1);
|
||||||
#ifdef TCP_KEEPALIVE
|
#ifdef TCP_KEEPALIVE
|
||||||
|
/*
|
||||||
|
* The TCP_KEEPALIVE options enable to specify the amount of time, in
|
||||||
|
* seconds, that the connection must be idle before keepalive probes
|
||||||
|
* (if enabled) are sent.
|
||||||
|
*/
|
||||||
SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE);
|
SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE);
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCP_KEEPCNT
|
|
||||||
SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT);
|
|
||||||
#endif
|
|
||||||
#ifdef TCP_KEEPIDLE
|
#ifdef TCP_KEEPIDLE
|
||||||
|
/*
|
||||||
|
* Same as TCP_KEEPALIVE, but on different systems
|
||||||
|
*/
|
||||||
SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE);
|
SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef TCP_KEEPCNT
|
||||||
|
/*
|
||||||
|
* When keepalive probes are enabled, this option will set the number
|
||||||
|
* of times a keepalive probe should be repeated if the peer is not
|
||||||
|
* responding. After this many probes, the connection will be closed.
|
||||||
|
*/
|
||||||
|
SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT);
|
||||||
|
#endif
|
||||||
#ifdef TCP_KEEPINTVL
|
#ifdef TCP_KEEPINTVL
|
||||||
|
/*
|
||||||
|
* When keepalive probes are enabled, this option will set the amount
|
||||||
|
* of time in seconds between successive keepalives sent to probe an
|
||||||
|
* unresponsive peer.
|
||||||
|
*/
|
||||||
SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL);
|
SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef TCP_USER_TIMEOUT
|
||||||
|
/*
|
||||||
|
* This option takes an unsigned int as an argument. When the
|
||||||
|
* value is greater than 0, it specifies the maximum amount of
|
||||||
|
* time in milliseconds that transmitted data may remain
|
||||||
|
* unacknowledged before TCP will forcibly close the
|
||||||
|
* corresponding connection and return ETIMEDOUT to the
|
||||||
|
* application.
|
||||||
|
*/
|
||||||
|
SSO(IPPROTO_TCP, TCP_USER_TIMEOUT, 1000*WRITE_TIMEOUT);
|
||||||
|
#endif
|
||||||
#undef SSO
|
#undef SSO
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket)
|
static void init_conn_fd(struct tmate_ssh_client *client)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (client->has_init_conn_fd)
|
if (client->ev_ssh)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((fd = ssh_get_fd(client->session)) < 0)
|
if ((fd = ssh_get_fd(client->session)) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (tune_socket)
|
tune_socket_opts(fd);
|
||||||
tune_socket_opts(fd);
|
|
||||||
|
|
||||||
assert(!client->ev_ssh);
|
client->ev_ssh = event_new(client->tmate_session->ev_base, fd,
|
||||||
client->ev_ssh = event_new(client->tmate_session->ev_base,
|
EV_READ | EV_PERSIST,
|
||||||
fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client);
|
__on_ssh_client_event, client);
|
||||||
if (!client->ev_ssh)
|
if (!client->ev_ssh)
|
||||||
tmate_fatal("out of memory");
|
tmate_fatal("out of memory");
|
||||||
event_add(client->ev_ssh, NULL);
|
event_add(client->ev_ssh, NULL);
|
||||||
|
|
||||||
client->has_init_conn_fd = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_ssh_client_event(struct tmate_ssh_client *client)
|
static void on_ssh_client_event(struct tmate_ssh_client *client)
|
||||||
@ -273,14 +300,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
|
|||||||
case SSH_CONNECT:
|
case SSH_CONNECT:
|
||||||
switch (ssh_connect(session)) {
|
switch (ssh_connect(session)) {
|
||||||
case SSH_AGAIN:
|
case SSH_AGAIN:
|
||||||
init_conn_fd(client, false);
|
init_conn_fd(client);
|
||||||
return;
|
return;
|
||||||
case SSH_ERROR:
|
case SSH_ERROR:
|
||||||
kill_ssh_client(client, "Error connecting: %s",
|
kill_ssh_client(client, "Error connecting: %s",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
return;
|
return;
|
||||||
case SSH_OK:
|
case SSH_OK:
|
||||||
init_conn_fd(client, true);
|
init_conn_fd(client);
|
||||||
|
|
||||||
tmate_debug("Establishing connection to %s", client->server_ip);
|
tmate_debug("Establishing connection to %s", client->server_ip);
|
||||||
client->state = SSH_AUTH_SERVER;
|
client->state = SSH_AUTH_SERVER;
|
||||||
@ -482,10 +509,10 @@ static void kill_ssh_client(struct tmate_ssh_client *client,
|
|||||||
|
|
||||||
tmate_debug("SSH client killed (%s)", client->server_ip);
|
tmate_debug("SSH client killed (%s)", client->server_ip);
|
||||||
|
|
||||||
if (client->has_init_conn_fd) {
|
if (client->ev_ssh) {
|
||||||
event_del(client->ev_ssh);
|
event_del(client->ev_ssh);
|
||||||
event_free(client->ev_ssh);
|
event_free(client->ev_ssh);
|
||||||
client->has_init_conn_fd = false;
|
client->ev_ssh = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->state == SSH_READY) {
|
if (client->state == SSH_READY) {
|
||||||
@ -548,7 +575,5 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
|
|||||||
client->channel = NULL;
|
client->channel = NULL;
|
||||||
client->has_encoder = 0;
|
client->has_encoder = 0;
|
||||||
|
|
||||||
client->has_init_conn_fd = false;
|
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
1
tmate.h
1
tmate.h
@ -141,7 +141,6 @@ struct tmate_ssh_client {
|
|||||||
ssh_session session;
|
ssh_session session;
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
|
|
||||||
bool has_init_conn_fd;
|
|
||||||
struct event *ev_ssh;
|
struct event *ev_ssh;
|
||||||
};
|
};
|
||||||
TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client);
|
TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user