From: Guus Sliepen <guus@meshlink.io>
Date: Wed, 22 Jul 2020 18:29:22 +0000 (+0200)
Subject: Add devtool_set_meta_status_cb().
X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=b2d1ccdaf1554f2f34e8acb86f89190cb93b6634;p=meshlink

Add devtool_set_meta_status_cb().

This function is similar to meshlink_set_node_status_cb(), except that
this callback will only be called when a meta-connection to a node is
activated or terminated. This is mainly useful for the test suite.
---

diff --git a/src/devtools.c b/src/devtools.c
index 22a0818b..2a98e595 100644
--- a/src/devtools.c
+++ b/src/devtools.c
@@ -367,3 +367,17 @@ void devtool_force_sptps_renewal(meshlink_handle_t *mesh, meshlink_node_t *node)
 		c->last_key_renewal = -3600;
 	}
 }
+
+void devtool_set_meta_status_cb(meshlink_handle_t *mesh, meshlink_node_status_cb_t cb) {
+	if(!mesh) {
+		meshlink_errno = MESHLINK_EINVAL;
+		return;
+	}
+
+	if(pthread_mutex_lock(&mesh->mutex) != 0) {
+		abort();
+	}
+
+	mesh->meta_status_cb = cb;
+	pthread_mutex_unlock(&mesh->mutex);
+}
diff --git a/src/devtools.h b/src/devtools.h
index 44965c37..786e2900 100644
--- a/src/devtools.h
+++ b/src/devtools.h
@@ -195,4 +195,18 @@ void devtool_force_sptps_renewal(meshlink_handle_t *mesh, meshlink_node_t *node)
  */
 extern void (*devtool_set_inviter_commits_first)(bool inviter_commited_first);
 
+/// Set the meta-connection status callback.
+/** This functions sets the callback that is called whenever a meta-connection is made or closed.
+ *  The callback is run in MeshLink's own thread.
+ *  It is therefore important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ *  to hand the data over to the application's thread.
+ *  The callback should also not block itself and return as quickly as possible.
+ *
+ *  \memberof meshlink_handle
+ *  @param mesh      A handle which represents an instance of MeshLink.
+ *  @param cb        A pointer to the function which will be called when a node's meta-connection status changes.
+ *                   If a NULL pointer is given, the callback will be disabled.
+ */
+void devtool_set_meta_status_cb(struct meshlink_handle *mesh, meshlink_node_status_cb_t cb);
+
 #endif
diff --git a/src/meshlink.sym b/src/meshlink.sym
index 6be514ae..00f8fa38 100644
--- a/src/meshlink.sym
+++ b/src/meshlink.sym
@@ -5,6 +5,7 @@ devtool_get_all_submeshes
 devtool_get_node_status
 devtool_keyrotate_probe
 devtool_open_in_netns
+devtool_set_meta_status_cb
 devtool_set_inviter_commits_first
 devtool_trybind_probe
 meshlink_add_address
diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h
index c75e6957..588c630a 100644
--- a/src/meshlink_internal.h
+++ b/src/meshlink_internal.h
@@ -135,6 +135,7 @@ struct meshlink_handle {
 
 	// Infrequently used callbacks
 	meshlink_node_status_cb_t node_status_cb;
+	meshlink_node_status_cb_t meta_status_cb;
 	meshlink_node_pmtu_cb_t node_pmtu_cb;
 	meshlink_channel_accept_cb_t channel_accept_cb;
 	meshlink_node_duplicate_cb_t node_duplicate_cb;
diff --git a/src/net.c b/src/net.c
index 6fd90e19..9dc9598a 100644
--- a/src/net.c
+++ b/src/net.c
@@ -54,12 +54,16 @@ static const int default_interval = 60;
 void terminate_connection(meshlink_handle_t *mesh, connection_t *c, bool report) {
 	logger(mesh, MESHLINK_INFO, "Closing connection with %s", c->name);
 
-	c->status.active = false;
-
 	if(c->node && c->node->connection == c) {
+		if(c->status.active && mesh->meta_status_cb) {
+			mesh->meta_status_cb(mesh, (meshlink_node_t *)c->node, false);
+		}
+
 		c->node->connection = NULL;
 	}
 
+	c->status.active = false;
+
 	if(c->edge) {
 		if(report) {
 			send_del_edge(mesh, mesh->everyone, c->edge, 0);
diff --git a/src/protocol_auth.c b/src/protocol_auth.c
index 201cac9f..2154faae 100644
--- a/src/protocol_auth.c
+++ b/src/protocol_auth.c
@@ -370,6 +370,10 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
 
 	logger(mesh, MESHLINK_INFO, "Connection with %s activated", c->name);
 
+	if(mesh->meta_status_cb) {
+		mesh->meta_status_cb(mesh, (meshlink_node_t *)n, true);
+	}
+
 	/* Send him everything we know */
 
 	send_everything(mesh, c);