+ logger(mesh, MESHLINK_DEBUG, "--- autoconnect end ---");
+ }
+
+ for splay_each(node_t, n, mesh->nodes) {
+ if(n->status.dirty) {
+ if(!node_write_config(mesh, n)) {
+ logger(mesh, MESHLINK_DEBUG, "Could not update %s", n->name);
+ }
+
+ n->status.dirty = false;
+ }
+
+ if(n->status.validkey && n->last_req_key + 3600 < mesh->loop.now.tv_sec) {
+ logger(mesh, MESHLINK_DEBUG, "SPTPS key renewal for node %s", n->name);
+ devtool_sptps_renewal_probe((meshlink_node_t *)n);
+
+ if(!sptps_force_kex(&n->sptps)) {
+ logger(mesh, MESHLINK_ERROR, "SPTPS key renewal for node %s failed", n->name);
+ n->status.validkey = false;
+ sptps_stop(&n->sptps);
+ n->status.waitingforkey = false;
+ n->last_req_key = -3600;
+ } else {
+ n->last_req_key = mesh->loop.now.tv_sec;
+ }
+ }
+ }
+
+ timeout_set(&mesh->loop, data, &(struct timespec) {
+ timeout, prng(mesh, TIMER_FUDGE)
+ });
+}
+
+void handle_meta_connection_data(meshlink_handle_t *mesh, connection_t *c) {
+ if(!receive_meta(mesh, c)) {
+ terminate_connection(mesh, c, c->status.active);
+ return;
+ }
+}
+
+void retry(meshlink_handle_t *mesh) {
+ /* Reset the reconnection timers for all outgoing connections */
+ for list_each(outgoing_t, outgoing, mesh->outgoings) {
+ outgoing->timeout = 0;
+
+ if(outgoing->ev.cb) {
+ timeout_set(&mesh->loop, &outgoing->ev, &(struct timespec) {
+ 0, 0
+ });
+ }
+ }
+
+ /* For active connections, check if their addresses are still valid.
+ * If yes, reset their ping timers, otherwise terminate them. */
+ for list_each(connection_t, c, mesh->connections) {
+ if(!c->status.active) {
+ continue;
+ }
+
+ if(!c->status.pinged) {
+ c->last_ping_time = -3600;
+ }
+
+ sockaddr_t sa;
+ socklen_t salen = sizeof(sa);
+
+ if(getsockname(c->socket, &sa.sa, &salen)) {
+ continue;
+ }
+
+ switch(sa.sa.sa_family) {
+ case AF_INET:
+ sa.in.sin_port = 0;
+ break;
+
+ case AF_INET6:
+ sa.in6.sin6_port = 0;
+ break;
+
+ default:
+ continue;
+ }
+
+ int sock = socket(sa.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if(sock != -1) {