+/*
+ Check if the other end is active.
+ If we have sent packets, but didn't receive any,
+ then possibly the other end is dead. We send a
+ PING request over the meta connection. If the other
+ end does not reply in time, we consider them dead
+ and close the connection.
+*/
+static void timeout_handler(event_loop_t *loop, void *data) {
+ assert(data);
+
+ meshlink_handle_t *mesh = loop->data;
+ logger(mesh, MESHLINK_DEBUG, "timeout_handler()");
+
+ for list_each(connection_t, c, mesh->connections) {
+ int pingtimeout = c->node ? mesh->dev_class_traits[c->node->devclass].pingtimeout : default_timeout;
+ int pinginterval = c->node ? mesh->dev_class_traits[c->node->devclass].pinginterval : default_interval;
+
+ if(c->outgoing && c->outgoing->timeout < 5) {
+ pingtimeout = 1;
+ }
+
+ // Also make sure that if outstanding key requests for the UDP counterpart of a connection has timed out, we restart it.
+ if(c->node) {
+ if(c->node->status.waitingforkey && c->node->last_req_key + pingtimeout <= mesh->loop.now.tv_sec) {
+ send_req_key(mesh, c->node);
+ }
+ }
+
+ if(c->last_ping_time + pingtimeout <= mesh->loop.now.tv_sec) {
+ if(c->status.active) {
+ if(c->status.pinged) {
+ logger(mesh, MESHLINK_INFO, "%s didn't respond to PING in %ld seconds", c->name, (long)mesh->loop.now.tv_sec - c->last_ping_time);
+ } else if(c->last_ping_time + pinginterval <= mesh->loop.now.tv_sec) {
+ send_ping(mesh, c);
+ continue;
+ } else {
+ continue;
+ }
+ } else {
+ if(c->status.connecting) {
+ logger(mesh, MESHLINK_WARNING, "Timeout while connecting to %s", c->name);
+ } else {
+ logger(mesh, MESHLINK_WARNING, "Timeout from %s during authentication", c->name);
+ }