Keep the internal tracking of the blacklist status of each node for now.
(void)meshlink_errno;
}
- /// This functions is called whenever MeshLink is blacklisted by another node.
- virtual void blacklisted(node *peer) {
- /* do nothing */
- (void)peer;
- }
-
/// This functions is called whenever MeshLink a meta-connection attempt is made.
virtual void connection_try(node *peer) {
/* do nothing */
meshlink_set_node_duplicate_cb(handle, &node_duplicate_trampoline);
meshlink_set_log_cb(handle, MESHLINK_DEBUG, &log_trampoline);
meshlink_set_error_cb(handle, &error_trampoline);
- meshlink_set_blacklisted_cb(handle, &blacklisted_trampoline);
meshlink_set_channel_listen_cb(handle, &channel_listen_trampoline);
meshlink_set_channel_accept_cb(handle, &channel_accept_trampoline);
meshlink_set_connection_try_cb(handle, &connection_try_trampoline);
return meshlink_get_node_reachability(handle, node, last_reachable, last_unreachable);
}
- /// Get a node's blacklist status.
- /** This function returns the current blacklist status of a given node.
- *
- * @param node A pointer to a meshlink::node describing the node.
- *
- * @return This function returns true if the node is currently blacklisted, false otherwise.
- */
- bool get_node_blacklisted(node *node) {
- return meshlink_get_node_blacklisted(handle, node);
- }
-
/// Get a handle for a specific submesh.
/** This function returns a handle for the submesh with the given name.
*
return (node **)meshlink_get_all_nodes(handle, (meshlink_node_t **)nodes, nmemb);
}
- /// Get a list of all nodes by blacklist status.
- /** This function returns a list with handles for all the nodes who were either blacklisted or whitelisted.
- *
- * @param blacklisted If true, a list of blacklisted nodes will be returned, otherwise whitelisted nodes.
- * @param nodes A pointer to an array of pointers to meshlink::node, which should be allocated by the application.
- * @param nmemb The maximum number of pointers that can be stored in the nodes array.
- *
- * @return A pointer to an array containing pointers to all known nodes with the given blacklist status.
- * If the @a nodes argument was not NULL, then the return value can either be the same value or a different value.
- * If it is a new value, the old value of @a nodes should not be used anymore.
- * If the new value is NULL, then the old array will have been freed by MeshLink.
- */
- node **get_all_nodes_by_blacklisted(bool blacklisted, node **nodes, size_t *nmemb) {
- return (node **)meshlink_get_all_nodes_by_blacklisted(handle, blacklisted, (meshlink_node_t **)nodes, nmemb);
- }
-
/// Sign data using the local node's MeshLink key.
/** This function signs data using the local node's MeshLink key.
* The generated signature can be securely verified by other nodes.
/** This sets the policy MeshLink uses when it has new information about nodes.
* By default, all udpates will be stored to disk (unless an ephemeral instance has been opened).
* Setting the policy to MESHLINK_STORAGE_KEYS_ONLY, only updates that contain new keys for nodes
- * are stored, as well as blacklist/whitelist settings.
+ * are stored.
* By setting the policy to MESHLINK_STORAGE_DISABLED, no updates will be stored.
*
* @param policy The storage policy to use.
return meshlink_forget_node(handle, node);
}
- /// Blacklist a node from the mesh.
- /** This function causes the local node to blacklist another node.
- * The local node will drop any existing connections to that node,
- * and will not send data to it nor accept any data received from it any more.
- *
- * @param node A pointer to a meshlink::node describing the node to be blacklisted.
- *
- * @return This function returns true if the node has been whitelisted, false otherwise.
- */
- bool blacklist(node *node) {
- return meshlink_blacklist(handle, node);
- }
-
- /// Blacklist a node from the mesh by name.
- /** This function causes the local node to blacklist another node by name.
- * The local node will drop any existing connections to that node,
- * and will not send data to it nor accept any data received from it any more.
- *
- * If no node by the given name is known, it is created.
- *
- * @param name The name of the node to blacklist.
- *
- * @return This function returns true if the node has been blacklisted, false otherwise.
- */
- bool blacklist_by_name(const char *name) {
- return meshlink_blacklist_by_name(handle, name);
- }
-
- /// Whitelist a node on the mesh.
- /** This function causes the local node to whitelist another node.
- * The local node will allow connections to and from that node,
- * and will send data to it and accept any data received from it.
- *
- * @param node A pointer to a meshlink::node describing the node to be whitelisted.
- *
- * @return This function returns true if the node has been whitelisted, false otherwise.
- */
- bool whitelist(node *node) {
- return meshlink_whitelist(handle, node);
- }
-
- /// Whitelist a node on the mesh by name.
- /** This function causes the local node to whitelist a node by name.
- * The local node will allow connections to and from that node,
- * and will send data to it and accept any data received from it.
- *
- * If no node by the given name is known, it is created.
- * This is useful if new nodes are blacklisted by default.
- *
- * \memberof meshlink_node
- * @param name The name of the node to whitelist.
- *
- * @return This function returns true if the node has been whitelisted, false otherwise.
- */
- bool whitelist_by_name(const char *name) {
- return meshlink_whitelist_by_name(handle, name);
- }
-
/// Set the poll callback.
/** This functions sets the callback that is called whenever data can be sent to another node.
* The callback is run in MeshLink's own thread.
that->error(meshlink_errno);
}
- static void blacklisted_trampoline(meshlink_handle_t *handle, meshlink_node_t *peer) {
- if(!(handle->priv)) {
- return;
- }
-
- meshlink::mesh *that = static_cast<mesh *>(handle->priv);
- that->blacklisted(static_cast<node *>(peer));
- }
-
static void connection_try_trampoline(meshlink_handle_t *handle, meshlink_node_t *peer) {
if(!(handle->priv)) {
return;
pthread_mutex_unlock(&mesh->mutex);
}
-void meshlink_set_blacklisted_cb(struct meshlink_handle *mesh, meshlink_blacklisted_cb_t cb) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_set_blacklisted_cb(%p)", (void *)(intptr_t)cb);
-
- if(!mesh) {
- meshlink_errno = MESHLINK_EINVAL;
- return;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- mesh->blacklisted_cb = cb;
- pthread_mutex_unlock(&mesh->mutex);
-}
-
static bool prepare_packet(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len, vpn_packet_t *packet) {
meshlink_packethdr_t *hdr;
return false;
}
-static bool search_node_by_blacklisted(const node_t *node, const void *condition) {
- return *(bool *)condition == node->status.blacklisted;
-}
-
static bool search_node_by_submesh(const node_t *node, const void *condition) {
if(condition == node->submesh) {
return true;
return meshlink_get_all_nodes_by_condition(mesh, &range, nodes, nmemb, search_node_by_last_reachable);
}
-meshlink_node_t **meshlink_get_all_nodes_by_blacklisted(meshlink_handle_t *mesh, bool blacklisted, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || !nmemb) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- return meshlink_get_all_nodes_by_condition(mesh, &blacklisted, nodes, nmemb, search_node_by_blacklisted);
-}
-
dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) {
if(!mesh || !node) {
meshlink_errno = MESHLINK_EINVAL;
return devclass;
}
-bool meshlink_get_node_blacklisted(meshlink_handle_t *mesh, meshlink_node_t *node) {
- if(!mesh) {
- meshlink_errno = MESHLINK_EINVAL;
- }
-
- if(!node) {
- return mesh->default_blacklist;
- }
-
- bool blacklisted;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- blacklisted = ((node_t *)node)->status.blacklisted;
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return blacklisted;
-}
-
meshlink_submesh_t *meshlink_get_node_submesh(meshlink_handle_t *mesh, meshlink_node_t *node) {
if(!mesh || !node) {
meshlink_errno = MESHLINK_EINVAL;
return true;
}
-static bool blacklist(meshlink_handle_t *mesh, node_t *n) {
- if(n == mesh->self) {
- logger(mesh, MESHLINK_ERROR, "%s blacklisting itself?\n", n->name);
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(n->status.blacklisted) {
- logger(mesh, MESHLINK_DEBUG, "Node %s already blacklisted\n", n->name);
- return true;
- }
-
- n->status.blacklisted = true;
-
- /* Immediately shut down any connections we have with the blacklisted node.
- * We can't call terminate_connection(), because we might be called from a callback function.
- */
- for list_each(connection_t, c, mesh->connections) {
- if(c->node == n) {
- if(c->status.active) {
- send_error(mesh, c, BLACKLISTED, "blacklisted");
- }
-
- shutdown(c->socket, SHUT_RDWR);
- }
- }
-
- utcp_reset_all_connections(n->utcp);
-
- n->mtu = 0;
- n->minmtu = 0;
- n->maxmtu = MTU;
- n->mtuprobes = 0;
- n->status.udp_confirmed = false;
-
- if(n->status.reachable) {
- n->last_unreachable = time(NULL);
- }
-
- /* Graph updates will suppress status updates for blacklisted nodes, so we need to
- * manually call the status callback if necessary.
- */
- if(n->status.reachable && mesh->node_status_cb) {
- mesh->node_status_cb(mesh, (meshlink_node_t *)n, false);
- }
-
- return node_write_config(mesh, n, true) && config_sync(mesh, "current");
-}
-
-bool meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_blacklist(%s)", node ? node->name : "(null)");
-
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- if(!blacklist(mesh, (node_t *)node)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
- return true;
-}
-
-bool meshlink_blacklist_by_name(meshlink_handle_t *mesh, const char *name) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_blacklist_by_name(%s)", name ? name : "(null)");
-
- if(!mesh || !name) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- node_t *n = lookup_node(mesh, (char *)name);
-
- if(!n) {
- n = new_node();
- n->name = xstrdup(name);
- node_add(mesh, n);
- }
-
- if(!blacklist(mesh, (node_t *)n)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", name);
- return true;
-}
-
-static bool whitelist(meshlink_handle_t *mesh, node_t *n) {
- if(n == mesh->self) {
- logger(mesh, MESHLINK_ERROR, "%s whitelisting itself?\n", n->name);
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(!n->status.blacklisted) {
- logger(mesh, MESHLINK_DEBUG, "Node %s was already whitelisted\n", n->name);
- return true;
- }
-
- n->status.blacklisted = false;
-
- if(n->status.reachable) {
- n->last_reachable = time(NULL);
- update_node_status(mesh, n);
- }
-
- return node_write_config(mesh, n, true) && config_sync(mesh, "current");
-}
-
-bool meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_whitelist(%s)", node ? node->name : "(null)");
-
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- if(!whitelist(mesh, (node_t *)node)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Whitelisted %s.\n", node->name);
- return true;
-}
-
-bool meshlink_whitelist_by_name(meshlink_handle_t *mesh, const char *name) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_whitelist_by_name(%s)", name ? name : "(null)");
-
- if(!mesh || !name) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- node_t *n = lookup_node(mesh, (char *)name);
-
- if(!n) {
- n = new_node();
- n->name = xstrdup(name);
- node_add(mesh, n);
- }
-
- if(!whitelist(mesh, (node_t *)n)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Whitelisted %s.\n", name);
- return true;
-}
-
-void meshlink_set_default_blacklist(meshlink_handle_t *mesh, bool blacklist) {
- mesh->default_blacklist = blacklist;
-}
-
bool meshlink_forget_node(meshlink_handle_t *mesh, meshlink_node_t *node) {
logger(mesh, MESHLINK_DEBUG, "meshlink_forget_node(%s)", node ? node->name : "(null)");
*/
void meshlink_set_error_cb(struct meshlink_handle *mesh, meshlink_error_cb_t cb);
-/// A callback for receiving blacklisted conditions encountered by the MeshLink thread.
-/** @param mesh A handle which represents an instance of MeshLink, or NULL.
- * @param node The node that blacklisted the local node.
- */
-typedef void (*meshlink_blacklisted_cb_t)(struct meshlink_handle *mesh, struct meshlink_node *node);
-
-/// Set the blacklisted callback.
-/** This functions sets the callback that is called whenever MeshLink detects that it is blacklisted by another node.
- *
- * The callback is run in MeshLink's own thread.
- * It is 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, or NULL.
- * @param cb A pointer to the function which will be called when a serious error is encountered.
- * If a NULL pointer is given, the callback will be disabled.
- */
-void meshlink_set_blacklisted_cb(struct meshlink_handle *mesh, meshlink_blacklisted_cb_t cb);
-
/// Send data to another node.
/** This functions sends one packet of data to another node in the mesh.
* The packet is sent using UDP semantics, which means that
*/
struct meshlink_node **meshlink_get_all_nodes_by_last_reachable(struct meshlink_handle *mesh, time_t start, time_t end, struct meshlink_node **nodes, size_t *nmemb) __attribute__((__warn_unused_result__));
-/// Get the list of all nodes by blacklist status.
-/** This function returns a list with handles for all the nodes who were either blacklisted or whitelisted.
- *
- * \memberof meshlink_handle
- * @param mesh A handle which represents an instance of MeshLink.
- * @param blacklisted If true, a list of blacklisted nodes will be returned, otherwise whitelisted nodes.
- * @param nodes A pointer to a previously allocated array of pointers to struct meshlink_node, or NULL in which case MeshLink will allocate a new array.
- * The application can supply an array it allocated itself with malloc, or the return value from the previous call to this function (which is the preferred way).
- * The application is allowed to call free() on the array whenever it wishes.
- * The pointers in the array are valid until meshlink_close() is called.
- * @param nmemb A pointer to a variable holding the number of nodes that were reachable within the period given by @a start and @a end.
- * In case the @a nodes argument is not NULL, MeshLink might call realloc() on the array to change its size.
- * The contents of this variable will be changed to reflect the new size of the array.
- *
- * @return A pointer to an array containing pointers to all known nodes with the given blacklist status.
- * If the @a nodes argument was not NULL, then the return value can either be the same value or a different value.
- * If it is a new value, the old value of @a nodes should not be used anymore.
- * If the new value is NULL, then the old array will have been freed by MeshLink.
- */
-struct meshlink_node **meshlink_get_all_nodes_by_blacklisted(struct meshlink_handle *mesh, bool blacklisted, struct meshlink_node **nodes, size_t *nmemb) __attribute__((__warn_unused_result__));
-
/// Get the node's device class.
/** This function returns the device class of the given node.
*
*/
dev_class_t meshlink_get_node_dev_class(struct meshlink_handle *mesh, struct meshlink_node *node) __attribute__((__warn_unused_result__));
-/// Get the node's blacklist status.
-/** This function returns the given node is blacklisted.
- *
- * \memberof meshlink_node
- * @param mesh A handle which represents an instance of MeshLink.
- * @param node A pointer to a struct meshlink_node describing the node.
- *
- * @return This function returns true if the node is blacklisted, false otherwise.
- */
-bool meshlink_get_node_blacklisted(struct meshlink_handle *mesh, struct meshlink_node *node) __attribute__((__warn_unused_result__));
-
/// Get the node's submesh handle.
/** This function returns the submesh handle of the given node.
*
*/
bool meshlink_forget_node(struct meshlink_handle *mesh, struct meshlink_node *node);
-/// Blacklist a node from the mesh.
-/** This function causes the local node to blacklist another node.
- * The local node will drop any existing connections to that node,
- * and will not send data to it nor accept any data received from it any more.
- *
- * \memberof meshlink_node
- * @param mesh A handle which represents an instance of MeshLink.
- * @param node A pointer to a struct meshlink_node describing the node to be blacklisted.
- *
- * @return This function returns true if the node has been blacklisted, false otherwise.
- */
-bool meshlink_blacklist(struct meshlink_handle *mesh, struct meshlink_node *node) __attribute__((__warn_unused_result__));
-
-/// Blacklist a node from the mesh by name.
-/** This function causes the local node to blacklist another node by name.
- * The local node will drop any existing connections to that node,
- * and will not send data to it nor accept any data received from it any more.
- *
- * If no node by the given name is known, it is created.
- *
- * \memberof meshlink_node
- * @param mesh A handle which represents an instance of MeshLink.
- * @param name The name of the node to blacklist.
- *
- * @return This function returns true if the node has been blacklisted, false otherwise.
- */
-bool meshlink_blacklist_by_name(struct meshlink_handle *mesh, const char *name) __attribute__((__warn_unused_result__));
-
-/// Whitelist a node on the mesh.
-/** This function causes the local node to whitelist a previously blacklisted node.
- * The local node will allow connections to and from that node,
- * and will send data to it and accept any data received from it.
- *
- * \memberof meshlink_node
- * @param mesh A handle which represents an instance of MeshLink.
- * @param node A pointer to a struct meshlink_node describing the node to be whitelisted.
- *
- * @return This function returns true if the node has been whitelisted, false otherwise.
- */
-bool meshlink_whitelist(struct meshlink_handle *mesh, struct meshlink_node *node) __attribute__((__warn_unused_result__));
-
-/// Whitelist a node on the mesh by name.
-/** This function causes the local node to whitelist a node by name.
- * The local node will allow connections to and from that node,
- * and will send data to it and accept any data received from it.
- *
- * If no node by the given name is known, it is created.
- * This is useful if new nodes are blacklisted by default.
- *
- * \memberof meshlink_node
- * @param mesh A handle which represents an instance of MeshLink.
- * @param name The name of the node to whitelist.
- *
- * @return This function returns true if the node has been whitelisted, false otherwise.
- */
-bool meshlink_whitelist_by_name(struct meshlink_handle *mesh, const char *name) __attribute__((__warn_unused_result__));
-
-/// Set whether new nodes are blacklisted by default.
-/** This function sets the blacklist behaviour for newly discovered nodes.
- * If set to true, new nodes will be automatically blacklisted.
- * If set to false, which is the default, new nodes are automatically whitelisted.
- * The whitelist/blacklist status of a node may be changed afterwards with the
- * meshlink_whitelist() and meshlink_blacklist() functions.
- *
- * \memberof meshlink_handle
- * @param mesh A handle which represents an instance of MeshLink.
- * @param blacklist True if new nodes are to be blacklisted, false if whitelisted.
- */
-void meshlink_set_default_blacklist(struct meshlink_handle *mesh, bool blacklist);
-
/// A callback for listening for incoming channels.
/** This function is called whenever a remote node wants to open a channel to the local node.
* This callback should only make a decision whether to accept or reject this channel.
/** This sets the policy MeshLink uses when it has new information about nodes.
* By default, all udpates will be stored to disk (unless an ephemeral instance has been opened).
* Setting the policy to MESHLINK_STORAGE_KEYS_ONLY, only updates that contain new keys for nodes
- * are stored, as well as blacklist/whitelist settings.
+ * are stored.
* By setting the policy to MESHLINK_STORAGE_DISABLED, no updates will be stored.
*
* \memberof meshlink_handle
devtool_trybind_probe
meshlink_add_address
meshlink_add_external_address
-meshlink_blacklist
-meshlink_blacklist_by_name
meshlink_channel_abort
meshlink_channel_aio_fd_receive
meshlink_channel_aio_fd_send
meshlink_export
meshlink_forget_node
meshlink_get_all_nodes
-meshlink_get_all_nodes_by_blacklisted
meshlink_get_all_nodes_by_dev_class
meshlink_get_all_nodes_by_last_reachable
meshlink_get_all_nodes_by_submesh
meshlink_get_fingerprint
meshlink_get_local_address_for_family
meshlink_get_node
-meshlink_get_node_blacklisted
meshlink_get_node_dev_class
meshlink_get_node_reachability
meshlink_get_node_submesh
meshlink_open_params_set_storage_policy
meshlink_reset_timers
meshlink_send
-meshlink_set_blacklisted_cb
meshlink_set_canonical_address
meshlink_set_channel_accept_cb
meshlink_set_channel_flags
meshlink_set_channel_sndbuf
meshlink_set_channel_sndbuf_storage
meshlink_set_connection_try_cb
-meshlink_set_default_blacklist
meshlink_set_dev_class_fast_retry_period
meshlink_set_dev_class_maxtimeout
meshlink_set_dev_class_timeouts
meshlink_strerror
meshlink_submesh_open
meshlink_verify
-meshlink_whitelist
-meshlink_whitelist_by_name
meshlink_node_duplicate_cb_t node_duplicate_cb;
meshlink_connection_try_cb_t connection_try_cb;
meshlink_error_cb_t error_cb;
- meshlink_blacklisted_cb_t blacklisted_cb;
// Mesh parameters
char *appname;
int netns;
- bool default_blacklist;
bool inviter_commits_first;
// Configuration
if(!from) {
from = new_node();
from->status.dirty = true;
- from->status.blacklisted = mesh->default_blacklist;
+ from->status.blacklisted = false;
from->name = xstrdup(from_name);
from->devclass = from_devclass;
if(!to) {
to = new_node();
to->status.dirty = true;
- to->status.blacklisted = mesh->default_blacklist;
+ to->status.blacklisted = false;
to->name = xstrdup(to_name);
to->devclass = to_devclass;
logger(mesh, MESHLINK_INFO, "Error message from %s: %d: %s", c->name, err, errorstring);
- switch(err) {
- case BLACKLISTED:
- if(mesh->blacklisted_cb) {
- mesh->blacklisted_cb(mesh, (meshlink_node_t *)lookup_node(mesh, c->name));
- }
- }
-
return false;
}
TESTS = \
basic \
basicpp \
- blacklist \
channels \
channels-aio \
channels-aio-abort \
api_set_node_status_cb \
basic \
basicpp \
- blacklist \
channels \
channels-aio \
channels-aio-abort \
basicpp_SOURCES = basicpp.cpp utils.c utils.h
basicpp_LDADD = $(top_builddir)/src/libmeshlink.la
-blacklist_SOURCES = blacklist.c utils.c utils.h
-blacklist_LDADD = $(top_builddir)/src/libmeshlink.la
-
channels_SOURCES = channels.c utils.c utils.h
channels_LDADD = $(top_builddir)/src/libmeshlink.la
static void handle_duplicate(meshlink_handle_t *mesh, meshlink_node_t *node) {
set_sync_flag(&duplicate_detected, true);
- assert(meshlink_blacklist(mesh, node));
}
int main(void) {