tmate/tmate-session.c

187 lines
4.9 KiB
C
Raw Normal View History

2013-07-22 23:06:28 +02:00
#include <event2/dns.h>
#include <event2/util.h>
#include <event2/event.h>
2016-06-05 18:54:25 +02:00
#include <netinet/in.h>
2013-07-22 23:06:28 +02:00
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "tmate.h"
2016-03-27 00:00:16 +01:00
#define TMATE_DNS_RETRY_TIMEOUT 2
#define TMATE_RECONNECT_RETRY_TIMEOUT 2
2013-07-22 23:06:28 +02:00
struct tmate_session tmate_session;
static void lookup_and_connect(void);
2015-12-23 11:41:41 +01:00
static void on_dns_retry(__unused evutil_socket_t fd, __unused short what,
__unused void *arg)
2013-07-22 23:06:28 +02:00
{
lookup_and_connect();
}
static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr)
{
struct evutil_addrinfo *ai;
struct timeval tv;
const char *host = ptr;
2013-07-22 23:06:28 +02:00
if (errcode) {
tmate_status_message("%s lookup failure. Retrying in %d seconds (%s)",
host, TMATE_DNS_RETRY_TIMEOUT,
2013-07-22 23:06:28 +02:00
evutil_gai_strerror(errcode));
tv.tv_sec = TMATE_DNS_RETRY_TIMEOUT;
tv.tv_usec = 0;
2015-12-23 11:41:41 +01:00
evtimer_assign(&tmate_session.ev_dns_retry, tmate_session.ev_base,
on_dns_retry, NULL);
evtimer_add(&tmate_session.ev_dns_retry, &tv);
2013-07-22 23:06:28 +02:00
return;
}
tmate_status_message("Connecting to %s...", host);
2013-07-22 23:06:28 +02:00
for (ai = addr; ai; ai = ai->ai_next) {
char buf[128];
const char *ip = NULL;
if (ai->ai_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
ip = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
ip = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
}
tmate_debug("Trying server %s", ip);
/*
* Note: We don't deal with the client list. Clients manage it
* and free client structs when necessary.
*/
(void)tmate_ssh_client_alloc(&tmate_session, ip);
}
evutil_freeaddrinfo(addr);
/*
* XXX For some reason, freeing the DNS resolver makes MacOSX flip out...
* not sure what's going on...
2015-12-23 11:41:41 +01:00
* evdns_base_free(tmate_session.ev_dnsbase, 0);
* tmate_session.ev_dnsbase = NULL;
*/
2013-07-22 23:06:28 +02:00
}
static void lookup_and_connect(void)
{
struct evutil_addrinfo hints;
const char *tmate_server_host;
2013-07-22 23:06:28 +02:00
2015-12-23 11:41:41 +01:00
if (!tmate_session.ev_dnsbase)
tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1);
if (!tmate_session.ev_dnsbase)
2013-07-22 23:06:28 +02:00
tmate_fatal("Cannot initialize the DNS lookup service");
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = EVUTIL_AI_ADDRCONFIG;
2013-07-22 23:06:28 +02:00
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
2015-12-24 05:19:03 +01:00
tmate_server_host = options_get_string(global_options,
"tmate-server-host");
tmate_info("Looking up %s...", tmate_server_host);
2015-12-23 11:41:41 +01:00
(void)evdns_getaddrinfo(tmate_session.ev_dnsbase, tmate_server_host, NULL,
&hints, dns_cb, (void *)tmate_server_host);
2013-07-22 23:06:28 +02:00
}
2016-01-01 22:44:01 +01:00
static void __tmate_session_init(struct tmate_session *session,
struct event_base *base)
{
2016-01-01 22:44:01 +01:00
memset(session, 0, sizeof(*session));
2016-01-01 22:44:01 +01:00
session->ev_base = base;
2015-12-23 11:41:41 +01:00
2016-01-01 22:44:01 +01:00
/*
* Early initialization of encoder because we need to parse
* config files to get the server configs, but while we are parsing
* config files, we need to buffer bind commands and all for the
* slave.
* Decoder is setup later.
*/
tmate_encoder_init(&session->encoder, NULL, &tmate_session);
2013-07-22 23:06:28 +02:00
2016-01-01 22:44:01 +01:00
session->min_sx = -1;
session->min_sy = -1;
2013-07-23 01:45:34 +02:00
2016-01-01 22:44:01 +01:00
TAILQ_INIT(&session->clients);
}
2013-07-23 01:45:34 +02:00
2016-01-01 22:44:01 +01:00
void tmate_session_init(struct event_base *base)
{
__tmate_session_init(&tmate_session, base);
2013-07-22 23:06:28 +02:00
tmate_write_header();
}
void tmate_session_start(void)
{
2016-03-27 00:00:16 +01:00
/*
* We split init and start because:
* - We need to process the tmux config file during the connection as
* we are setting up the tmate identity.
* - While we are parsing the config file, we need to be able to
* serialize it, and so we need a worker encoder.
*/
tmate_write_ready();
lookup_and_connect();
}
2016-03-27 00:00:16 +01:00
static void on_reconnect_retry(__unused evutil_socket_t fd, __unused short what, void *arg)
{
struct tmate_session *session = arg;
if (session->last_server_ip) {
/*
* We have a previous server ip. Let's try that again first,
* but then connect to any server if it fails again.
*/
(void)tmate_ssh_client_alloc(&tmate_session, session->last_server_ip);
free(session->last_server_ip);
session->last_server_ip = NULL;
} else {
lookup_and_connect();
}
}
void tmate_reconnect_session(struct tmate_session *session, const char *message)
2016-03-27 00:00:16 +01:00
{
/*
* We no longer have an SSH connection. Time to reconnect.
* We'll reuse some of the session information if we can,
* and we'll try to reconnect to the same server if possible,
* to avoid an SSH connection string change.
*/
struct timeval tv = { .tv_sec = TMATE_RECONNECT_RETRY_TIMEOUT, .tv_usec = 0 };
evtimer_assign(&session->ev_connection_retry, session->ev_base,
on_reconnect_retry, session);
evtimer_add(&session->ev_connection_retry, &tv);
if (message)
tmate_status_message("Reconnecting... (%s)", message);
else
tmate_status_message("Reconnecting...");
2016-03-27 00:00:16 +01:00
/*
* This says that we'll need to send a snapshot of the current state.
* Until we have persisted logs...
*/
session->reconnected = true;
}