+static meshlink_node_t **meshlink_get_all_nodes_by_condition(meshlink_handle_t *mesh, const void *condition, meshlink_node_t **nodes, size_t *nmemb, search_node_by_condition_t search_node) {
+ meshlink_node_t **result;
+
+ pthread_mutex_lock(&mesh->mutex);
+
+ *nmemb = 0;
+
+ for splay_each(node_t, n, mesh->nodes) {
+ if(search_node(n, condition)) {
+ ++*nmemb;
+ }
+ }
+
+ if(*nmemb == 0) {
+ free(nodes);
+ pthread_mutex_unlock(&mesh->mutex);
+ return NULL;
+ }
+
+ result = realloc(nodes, *nmemb * sizeof(*nodes));
+
+ if(result) {
+ meshlink_node_t **p = result;
+
+ for splay_each(node_t, n, mesh->nodes) {
+ if(search_node(n, condition)) {
+ *p++ = (meshlink_node_t *)n;
+ }
+ }
+ } else {
+ *nmemb = 0;
+ free(nodes);
+ meshlink_errno = MESHLINK_ENOMEM;
+ }
+
+ pthread_mutex_unlock(&mesh->mutex);
+
+ return result;
+}
+
+static bool search_node_by_dev_class(const node_t *node, const void *condition) {
+ dev_class_t *devclass = (dev_class_t *)condition;
+
+ if(*devclass == (dev_class_t)node->devclass) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool search_node_by_submesh(const node_t *node, const void *condition) {
+ if(condition == node->submesh) {
+ return true;
+ }
+
+ return false;
+}
+
+struct time_range {
+ time_t start;
+ time_t end;
+};
+
+static bool search_node_by_last_reachable(const node_t *node, const void *condition) {
+ const struct time_range *range = condition;
+ time_t start = node->last_reachable;
+ time_t end = node->last_unreachable;
+
+ if(end < start) {
+ end = time(NULL);
+
+ if(end < start) {
+ start = end;
+ }
+ }
+
+ if(range->end >= range->start) {
+ return start <= range->end && end >= range->start;
+ } else {
+ return start > range->start || end < range->end;
+ }
+}
+
+meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, dev_class_t devclass, meshlink_node_t **nodes, size_t *nmemb) {
+ if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT || !nmemb) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ return meshlink_get_all_nodes_by_condition(mesh, &devclass, nodes, nmemb, search_node_by_dev_class);
+}
+
+meshlink_node_t **meshlink_get_all_nodes_by_submesh(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, meshlink_node_t **nodes, size_t *nmemb) {
+ if(!mesh || !submesh || !nmemb) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ return meshlink_get_all_nodes_by_condition(mesh, submesh, nodes, nmemb, search_node_by_submesh);
+}
+
+meshlink_node_t **meshlink_get_all_nodes_by_last_reachable(meshlink_handle_t *mesh, time_t start, time_t end, meshlink_node_t **nodes, size_t *nmemb) {
+ if(!mesh || !nmemb) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ struct time_range range = {start, end};
+
+ return meshlink_get_all_nodes_by_condition(mesh, &range, nodes, nmemb, search_node_by_last_reachable);
+}
+
+dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) {
+ if(!mesh || !node) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return -1;
+ }
+
+ dev_class_t devclass;
+
+ pthread_mutex_lock(&mesh->mutex);
+
+ devclass = ((node_t *)node)->devclass;
+
+ pthread_mutex_unlock(&mesh->mutex);
+
+ return devclass;
+}
+
+meshlink_submesh_t *meshlink_get_node_submesh(meshlink_handle_t *mesh, meshlink_node_t *node) {
+ if(!mesh || !node) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ node_t *n = (node_t *)node;
+
+ meshlink_submesh_t *s;
+
+ s = (meshlink_submesh_t *)n->submesh;
+
+ return s;
+}
+
+bool meshlink_get_node_reachability(struct meshlink_handle *mesh, struct meshlink_node *node, time_t *last_reachable, time_t *last_unreachable) {
+ if(!mesh || !node) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return NULL;
+ }
+
+ node_t *n = (node_t *)node;
+ bool reachable;
+
+ pthread_mutex_lock(&mesh->mutex);
+ reachable = n->status.reachable && !n->status.blacklisted;
+
+ if(last_reachable) {
+ *last_reachable = n->last_reachable;
+ }
+
+ if(last_unreachable) {
+ *last_unreachable = n->last_unreachable;
+ }
+
+ pthread_mutex_unlock(&mesh->mutex);
+
+ return reachable;
+}
+