X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fdevtools.c;h=c1578e65532eceb6d2e5f8c543c24719b9797507;hb=79703f03cde61be1023813486ed3a9521b88f689;hp=1cb2d5e88f6e4890d0d3d96761f04fa622cb2e78;hpb=196806f90f40fcc0cf727abd4bed6bc5aefff5ff;p=meshlink diff --git a/src/devtools.c b/src/devtools.c index 1cb2d5e8..c1578e65 100644 --- a/src/devtools.c +++ b/src/devtools.c @@ -1,5 +1,24 @@ +/* + devtools.c -- Debugging and quality control functions. + Copyright (C) 2014, 2017 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ #include "system.h" +#include #include "logger.h" #include "meshlink_internal.h" @@ -10,26 +29,77 @@ #include "devtools.h" -static int node_compare(const void *a, const void *b) { - if(a < b) - return -1; +/* Return an array of edges in the current network graph. + * Data captures the current state and will not be updated. + * Caller must deallocate data when done. + */ +devtool_edge_t *devtool_get_all_edges(meshlink_handle_t *mesh, devtool_edge_t *edges, size_t *nmemb) { + if(!mesh || !nmemb || (*nmemb && !edges)) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + pthread_mutex_lock(&(mesh->mesh_mutex)); + + devtool_edge_t *result = NULL; + int result_size = 0; + + result_size = mesh->edges->count / 2; + + // if result is smaller than edges, we have to dealloc all the excess devtool_edge_t + if(result_size > *nmemb) + result = realloc(edges, result_size * sizeof(*result)); + else + result = edges; + + if(result) { + devtool_edge_t *p = result; + int n = 0; + + for splay_each(edge_t, e, mesh->edges) { + // skip edges that do not represent a two-directional connection + if((!e->reverse) || (e->reverse->to != e->from)) + continue; + + // don't count edges twice + if(e->to < e->from) + continue; - if(a > b) - return 1; + assert(n < result_size); - return 0; + p->from = (meshlink_node_t *)e->from; + p->to = (meshlink_node_t *)e->to; + p->address = e->address.storage; + p->options = e->options; + p->weight = e->weight; + + n++; + p++; + } + + // shrink result to the actual amount of memory used + result = realloc(result, n * sizeof(*result)); + *nmemb = n; + } else { + *nmemb = 0; + meshlink_errno = MESHLINK_ENOMEM; + } + + pthread_mutex_unlock(&(mesh->mesh_mutex)); + + return result; } -static bool fstrwrite(const char* str, FILE* stream) { +static bool fstrwrite(const char *str, FILE *stream) { size_t len = strlen(str); - if(fwrite((void*)str, 1, len, stream) != len) + if(fwrite((void *)str, 1, len, stream) != len) return false; return true; } -static const char* __itoa(int value) { +static const char *__itoa(int value) { static char buffer[sizeof(int) * 8 + 1]; // not thread safe if(snprintf(buffer, sizeof(buffer), "%d", value) == -1) @@ -38,7 +108,7 @@ static const char* __itoa(int value) { return buffer; } -bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream) { +bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE *stream) { bool result = true; pthread_mutex_lock(&(mesh->mesh_mutex)); @@ -48,7 +118,7 @@ bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream) size_t edge_count = 0; meshlink_node_t **nodes = meshlink_get_all_nodes(mesh, NULL, &node_count); - meshlink_edge_t **edges = meshlink_get_all_edges_state(mesh, NULL, &edge_count); + devtool_edge_t *edges = devtool_get_all_edges(mesh, NULL, &edge_count); if((!nodes && node_count != 0) || (!edges && edge_count != 0)) goto fail; @@ -62,19 +132,19 @@ bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream) goto fail; for(size_t i = 0; i < node_count; ++i) { - if(!fstrwrite("\t\t\"", stream) || !fstrwrite(((node_t*)nodes[i])->name, stream) || !fstrwrite("\": {\n", stream)) + if(!fstrwrite("\t\t\"", stream) || !fstrwrite(((node_t *)nodes[i])->name, stream) || !fstrwrite("\": {\n", stream)) goto fail; - if(!fstrwrite("\t\t\t\"name\": \"", stream) || !fstrwrite(((node_t*)nodes[i])->name, stream) || !fstrwrite("\",\n", stream)) + if(!fstrwrite("\t\t\t\"name\": \"", stream) || !fstrwrite(((node_t *)nodes[i])->name, stream) || !fstrwrite("\",\n", stream)) goto fail; - if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(((node_t*)nodes[i])->options), stream) || !fstrwrite(",\n", stream)) + if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(((node_t *)nodes[i])->options), stream) || !fstrwrite(",\n", stream)) goto fail; - if(!fstrwrite("\t\t\t\"devclass\": ", stream) || !fstrwrite(__itoa(((node_t*)nodes[i])->devclass), stream) || !fstrwrite("\n", stream)) + if(!fstrwrite("\t\t\t\"devclass\": ", stream) || !fstrwrite(__itoa(((node_t *)nodes[i])->devclass), stream) || !fstrwrite("\n", stream)) goto fail; - if(!fstrwrite((i+1) != node_count ? "\t\t},\n" : "\t\t}\n", stream)) + if(!fstrwrite((i + 1) != node_count ? "\t\t},\n" : "\t\t}\n", stream)) goto fail; } @@ -87,17 +157,17 @@ bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream) goto fail; for(size_t i = 0; i < edge_count; ++i) { - if(!fstrwrite("\t\t\"", stream) || !fstrwrite(edges[i]->from->name, stream) || !fstrwrite("_to_", stream) || !fstrwrite(edges[i]->to->name, stream) || !fstrwrite("\": {\n", stream)) + if(!fstrwrite("\t\t\"", stream) || !fstrwrite(edges[i].from->name, stream) || !fstrwrite("_to_", stream) || !fstrwrite(edges[i].to->name, stream) || !fstrwrite("\": {\n", stream)) goto fail; - if(!fstrwrite("\t\t\t\"from\": \"", stream) || !fstrwrite(edges[i]->from->name, stream) || !fstrwrite("\",\n", stream)) + if(!fstrwrite("\t\t\t\"from\": \"", stream) || !fstrwrite(edges[i].from->name, stream) || !fstrwrite("\",\n", stream)) goto fail; - if(!fstrwrite("\t\t\t\"to\": \"", stream) || !fstrwrite(edges[i]->to->name, stream) || !fstrwrite("\",\n", stream)) + if(!fstrwrite("\t\t\t\"to\": \"", stream) || !fstrwrite(edges[i].to->name, stream) || !fstrwrite("\",\n", stream)) goto fail; char *host = NULL, *port = NULL, *address = NULL; - sockaddr2str((const sockaddr_t *)&(edges[i]->address), &host, &port); + sockaddr2str((const sockaddr_t *) & (edges[i].address), &host, &port); if(host && port) xasprintf(&address, "{ \"host\": \"%s\", \"port\": %s }", host, port); @@ -112,13 +182,13 @@ bool devtool_export_json_all_edges_state(meshlink_handle_t *mesh, FILE* stream) free(address); - if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(edges[i]->options), stream) || !fstrwrite(",\n", stream)) + if(!fstrwrite("\t\t\t\"options\": ", stream) || !fstrwrite(__itoa(edges[i].options), stream) || !fstrwrite(",\n", stream)) goto fail; - if(!fstrwrite("\t\t\t\"weight\": ", stream) || !fstrwrite(__itoa(edges[i]->weight), stream) || !fstrwrite("\n", stream)) + if(!fstrwrite("\t\t\t\"weight\": ", stream) || !fstrwrite(__itoa(edges[i].weight), stream) || !fstrwrite("\n", stream)) goto fail; - if(!fstrwrite((i+1) != edge_count ? "\t\t},\n" : "\t\t}\n", stream)) + if(!fstrwrite((i + 1) != edge_count ? "\t\t},\n" : "\t\t}\n", stream)) goto fail; } @@ -136,15 +206,8 @@ fail: result = false; done: - - if(nodes) - free(nodes); - - for(size_t i = 0; edges && i < edge_count; ++i) - free(edges[i]); - - if(nodes) - free(edges); + free(nodes); + free(edges); pthread_mutex_unlock(&(mesh->mesh_mutex));