-int setup_myself(void)
-{
- config_t const *cfg;
-cp
- myself = new_conn_list();
-
- if(!(cfg = get_config_val(myvpnip)))
- {
- syslog(LOG_ERR, _("No value for my VPN IP given"));
- return -1;
- }
-
- myself->vpn_ip = cfg->data.ip->ip;
- myself->vpn_mask = cfg->data.ip->mask;
- myself->flags = 0;
-
- if(!(cfg = get_config_val(listenport)))
- myself->port = 655;
- else
- myself->port = cfg->data.val;
-
- if(cfg = get_config_val(indirectdata))
- if(cfg->data.val)
- myself->flags |= EXPORTINDIRECTDATA;
-
- if((myself->meta_socket = setup_listen_meta_socket(myself->port)) < 0)
- {
- syslog(LOG_ERR, _("Unable to set up a listening socket"));
- return -1;
- }
-
- if((myself->socket = setup_vpn_in_socket(myself->port)) < 0)
- {
- syslog(LOG_ERR, _("Unable to set up an incoming vpn data socket"));
- close(myself->meta_socket);
- return -1;
- }
-
- myself->status.active = 1;
-
- syslog(LOG_NOTICE, _("Ready: listening on port %d."), myself->port);
-cp
- return 0;
-}
+static void timeout_handler(void *data) {
+
+ bool close_all_connections = false;
+
+ /*
+ timeout_handler will start after 30 seconds from start of tincd
+ hold information about the elapsed time since last time the handler
+ has been run
+ */
+ long sleep_time = now.tv_sec - last_periodic_run_time.tv_sec;
+
+ /*
+ It seems that finding sane default value is harder than expected
+ Since we send every second a UDP packet to make holepunching work
+ And default UDP state expire on firewalls is between 15-30 seconds
+ we drop all connections after 60 Seconds - UDPDiscoveryTimeout=30
+ by default
+ */
+ if(sleep_time > 2 * udp_discovery_timeout) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Awaking from dead after %ld seconds of sleep", sleep_time);
+ /*
+ Do not send any packets to tinc after we wake up.
+ The other node probably closed our connection but we still
+ are holding context information to them. This may happen on
+ laptops or any other hardware which can be suspended for some time.
+ Sending any data to node that wasn't expecting it will produce
+ annoying and misleading errors on the other side about failed signature
+ verification and or about missing sptps context
+ */
+ close_all_connections = true;
+ }
+
+ last_periodic_run_time = now;
+
+ for list_each(connection_t, c, connection_list) {
+ // control connections (eg. tinc ctl) do not have any timeout
+ if(c->status.control) {
+ continue;
+ }
+
+ if(close_all_connections) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Forcing connection close after sleep time %s (%s)", c->name, c->hostname);
+ terminate_connection(c, c->edge);
+ continue;
+ }
+
+ // Bail out early if we haven't reached the ping timeout for this node yet
+ if(c->last_ping_time + pingtimeout > now.tv_sec) {
+ continue;
+ }
+
+ // timeout during connection establishing
+ if(!c->edge) {
+ if(c->status.connecting) {
+ logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
+ } else {
+ logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
+ }
+
+ terminate_connection(c, c->edge);
+ continue;
+ }
+
+ // helps in UDP holepunching
+ try_tx(c->node, false);
+
+ // timeout during ping
+ if(c->status.pinged) {
+ logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)(now.tv_sec - c->last_ping_time));
+ terminate_connection(c, c->edge);
+ continue;
+ }
+
+ // check whether we need to send a new ping
+ if(c->last_ping_time + pinginterval <= now.tv_sec) {
+ send_ping(c);
+ }
+ }