+static void check_reachability(meshlink_handle_t *mesh) {
+ /* Check reachability status. */
+
+ for splay_each(node_t, n, mesh->nodes) {
+ /* Check for nodes that have changed session_id */
+ if(n->status.visited && n->prevedge && n->prevedge->reverse->session_id != n->session_id) {
+ n->session_id = n->prevedge->reverse->session_id;
+
+ if(n->utcp) {
+ utcp_abort_all_connections(n->utcp);
+ }
+
+ if(n->status.visited == n->status.reachable) {
+ /* This session replaces the previous one without changing reachability status.
+ * We still need to reset the UDP SPTPS state.
+ */
+ n->status.validkey = false;
+ sptps_stop(&n->sptps);
+ n->status.waitingforkey = false;
+ n->last_req_key = 0;
+
+ n->status.udp_confirmed = false;
+ n->maxmtu = MTU;
+ n->minmtu = 0;
+ n->mtuprobes = 0;
+
+ timeout_del(&mesh->loop, &n->mtutimeout);
+ }
+ }
+
+ if(n->status.visited != n->status.reachable) {
+ n->status.reachable = !n->status.reachable;
+ n->last_state_change = mesh->loop.now.tv_sec;
+
+ if(n->status.reachable) {
+ logger(mesh, MESHLINK_DEBUG, "Node %s became reachable", n->name);
+ } else {
+ logger(mesh, MESHLINK_DEBUG, "Node %s became unreachable", n->name);
+ }
+
+ /* TODO: only clear status.validkey if node is unreachable? */
+
+ n->status.validkey = false;
+ sptps_stop(&n->sptps);
+ n->status.waitingforkey = false;
+ n->last_req_key = 0;
+
+ n->status.udp_confirmed = false;
+ n->maxmtu = MTU;
+ n->minmtu = 0;
+ n->mtuprobes = 0;
+
+ timeout_del(&mesh->loop, &n->mtutimeout);
+
+ if(!n->status.blacklisted) {
+ update_node_status(mesh, n);
+ }
+
+ if(!n->status.reachable) {
+ update_node_udp(mesh, n, NULL);
+ n->status.broadcast = false;
+ } else if(n->connection) {
+ if(n->connection->status.initiator) {
+ send_req_key(mesh, n);
+ }
+ }
+
+ if(n->utcp) {
+ utcp_offline(n->utcp, !n->status.reachable);
+ }
+ }
+ }
+}