-static void check_dead_connections(void)
-{
- avl_node_t *node, *next;
- connection_t *c;
-
- cp();
-
- for(node = connection_tree->head; node; node = next) {
- next = node->next;
- c = node->data;
-
- if(c->last_ping_time + pingtimeout < now) {
- if(c->status.active) {
- if(c->status.pinged) {
- ifdebug(CONNECTIONS) logger(LOG_INFO, _("%s (%s) didn't respond to PING in %ld seconds"),
- c->name, c->hostname, now - c->last_ping_time);
- c->status.timeout = true;
- terminate_connection(c, true);
- } else if(c->last_ping_time + pinginterval < now) {
- send_ping(c);
- }
+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);