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 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.
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;
*/
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.
*
* \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.
+ * @param node A pointer to a struct meshlink_node describing the node.
*
* @return This function returns the device class of the @a node, or -1 in case of an error.
*/
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.
*
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
#include <errno.h>
#include <assert.h>
#include <sys/time.h>
+#include <dirent.h>
#include "meshlink.h"
#include "devtools.h"
assert(!meshlink_get_node(mesh[1], name[2]));
assert(!meshlink_get_node(mesh[2], name[1]));
+ // Check default blacklist status
+
+ assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_self(mesh[0])));
+ assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
+ assert(meshlink_get_node_blacklisted(mesh[1], meshlink_get_node(mesh[1], name[2])));
+ assert(meshlink_get_node_blacklisted(mesh[2], meshlink_get_node(mesh[2], name[1])));
+
+ // Generate an invitation for a node that is about to be blacklisted
+
+ char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
+ assert(invitation);
+ free(invitation);
+
// Whitelisting and blacklisting by name should work.
assert(meshlink_whitelist_by_name(mesh[0], "quux"));
assert(meshlink_blacklist_by_name(mesh[0], "xyzzy"));
+ assert(meshlink_get_node(mesh[0], "quux"));
+ assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux")));
+ assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "xyzzy")));
+
+ meshlink_node_t **nodes = NULL;
+ size_t nnodes = 0;
+ nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
+ assert(nnodes == 1);
+ assert(!strcmp(nodes[0]->name, "xyzzy"));
+
+ nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
+ assert(nnodes == 4);
+ assert(!strcmp(nodes[0]->name, "bar"));
+ assert(!strcmp(nodes[1]->name, "baz"));
+ assert(!strcmp(nodes[2]->name, "foo"));
+ assert(!strcmp(nodes[3]->name, "quux"));
+
+ free(nodes);
+
+ // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
+
+ assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
+
+ DIR *dir = opendir("blacklist_conf.0/current/invitations");
+ assert(dir);
+ struct dirent *ent;
+
+ while((ent = readdir(dir))) {
+ assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."));
+ }
+
+ closedir(dir);
// Since these nodes now exist we should be able to forget them.
assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
+ assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
// Start the nodes.
set_sync_flag(&bar_disconnected, false);
assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
assert(wait_sync_flag(&bar_disconnected, 5));
+ assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
// Whitelist bar
set_sync_flag(&bar_connected, false);
assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
assert(wait_sync_flag(&bar_connected, 15));
+ assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
// Bar should not connect to baz
assert(meshlink_whitelist(mesh[1], baz));
assert(meshlink_whitelist(mesh[2], bar));
+ assert(!meshlink_get_node_blacklisted(mesh[1], baz));
+ assert(!meshlink_get_node_blacklisted(mesh[2], bar));
// They should connect to each other