X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fstatistics%2Fgnunet-statistics.c;h=bf111ade2a88b17bac1ec2edc927b9beec406865;hb=a12b8c2c4cbf952c8c305cde193bb25c13a0912b;hp=2747f7adc64f6043a11850f4d365d77aebdbe1a0;hpb=b304cd75b7d0e9afdc5cba6aae184bb0fb2ec5bd;p=oweals%2Fgnunet.git diff --git a/src/statistics/gnunet-statistics.c b/src/statistics/gnunet-statistics.c index 2747f7adc..bf111ade2 100644 --- a/src/statistics/gnunet-statistics.c +++ b/src/statistics/gnunet-statistics.c @@ -1,21 +1,21 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + Copyright (C) 2001, 2002, 2004-2007, 2009, 2016 GNUnet e.V. - GNUnet 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 3, or (at your - option) any later version. + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. GNUnet 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. + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + SPDX-License-Identifier: AGPL3.0-or-later */ /** @@ -25,13 +25,10 @@ * @author Igor Wronsky */ #include "platform.h" -#include "gnunet_getopt_lib.h" -#include "gnunet_program_lib.h" #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" #include "statistics.h" -#define GET_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) /** * Final status code. @@ -43,6 +40,11 @@ static int ret; */ static char *subsystem; +/** + * The path of the testbed data. + */ +static char *path_testbed; + /** * Set to the specific stat value that we are after (or NULL for all). */ @@ -63,6 +65,11 @@ static int watch; */ static int quiet; +/** + * @brief Separator string for csv. + */ +static char *csv_separator; + /** * Remote host */ @@ -71,7 +78,7 @@ static char *remote_host; /** * Remote host's port */ -static unsigned long long remote_port; +static unsigned long long remote_port; /** * Value to set @@ -83,6 +90,175 @@ static unsigned long long set_val; */ static int set_value; +/** + * @brief Representation of all (testbed) nodes. + */ +static struct Node { + /** + * @brief Index of the node in this array. + */ + unsigned index_node; + + /** + * @brief Configuration handle for this node + */ + struct GNUNET_CONFIGURATION_Handle *conf; + + /** + * Handle for pending GET operation. + */ + struct GNUNET_STATISTICS_GetHandle *gh; + + /** + * @brief Statistics handle nodes. + */ + struct GNUNET_STATISTICS_Handle *handle; + /** + * @brief Identifier for shutdown task for this node. + */ + struct GNUNET_SCHEDULER_Task *shutdown_task; +} *nodes; + +/** + * @brief Number of configurations of all (testbed) nodes. + */ +static unsigned num_nodes; + +/** + * @brief Set of values for a combination of subsystem and name. + */ +struct ValueSet +{ + /** + * @brief Subsystem of the valueset. + */ + char *subsystem; + + /** + * @brief Name of the valueset. + */ + char *name; + + /** + * @brief The values. + */ + uint64_t *values; + + /** + * @brief Persistence of the values. + */ + int is_persistent; +}; + +/** + * @brief Collection of all values (represented with #ValueSet). + */ +static struct GNUNET_CONTAINER_MultiHashMap *values; + +/** + * @brief Number of nodes that have their values ready. + */ +static int num_nodes_ready; + +/** + * @brief Number of nodes that have their values ready. + */ +static int num_nodes_ready_shutdown; + +/** + * @brief Create a new #ValueSet + * + * @param subsystem Subsystem of the valueset. + * @param name Name of the valueset. + * @param num_values Number of values in valueset - number of peers. + * @param is_persistent Persistence status of values. + * + * @return Newly allocated #ValueSet. + */ +static struct ValueSet * +new_value_set (const char *subsystem, + const char *name, + unsigned num_values, + int is_persistent) +{ + struct ValueSet *value_set; + + value_set = GNUNET_new (struct ValueSet); + value_set->subsystem = GNUNET_strdup (subsystem); + value_set->name = GNUNET_strdup (name); + value_set->values = GNUNET_new_array (num_values, uint64_t); + value_set->is_persistent = persistent; + return value_set; +} + +/** + * @brief Print the (collected) values. + * + * Implements #GNUNET_CONTAINER_HashMapIterator. + * + * @param cls Closure - unused + * @param key #GNUNET_HashCode key of #GNUNET_CONTAINER_MultiHashMap iterator - + * unused + * @param value Values represented as #ValueSet. + * + * @return GNUNET_YES - continue iteration. + */ +static int +printer (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get(); + const char *now_str; + struct ValueSet *value_set = value; + + if (quiet == GNUNET_NO) + { + if (GNUNET_YES == watch) + { + now_str = GNUNET_STRINGS_absolute_time_to_string (now); + FPRINTF (stdout, + "%24s%s %s%s%12s%s %s%50s%s%s ", + now_str, + csv_separator, + value_set->is_persistent ? "!" : " ", + csv_separator, + value_set->subsystem, + csv_separator, + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + _(value_set->name), + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + (0 == strlen (csv_separator) ? ":": csv_separator)); + } + else + { + FPRINTF (stdout, + "%s%s%12s%s %s%50s%s%s ", + value_set->is_persistent ? "!" : " ", + csv_separator, + value_set->subsystem, + csv_separator, + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + _(value_set->name), + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + (0 == strlen (csv_separator) ? ":": csv_separator)); + } + } + for (unsigned i = 0; i < num_nodes; i++) + { + FPRINTF (stdout, + "%16llu%s", + (unsigned long long) value_set->values[i], + csv_separator); + } + FPRINTF (stdout, "\n"); + GNUNET_free (value_set->subsystem); + GNUNET_free (value_set->name); + GNUNET_free (value_set->values); + GNUNET_free (value_set); + return GNUNET_YES; +} + /** * Callback function to process statistic values. * @@ -90,145 +266,295 @@ static int set_value; * @param subsystem name of subsystem that created the statistic * @param name the name of the datum * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration */ static int -printer (void *cls, const char *subsystem, const char *name, uint64_t value, - int is_persistent) +printer_watch (void *cls, + const char *subsystem, + const char *name, + uint64_t value, + int is_persistent) { struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get(); - const char * now_str; + const char *now_str; if (quiet == GNUNET_NO) { if (GNUNET_YES == watch) { - now_str = GNUNET_STRINGS_absolute_time_to_string(now); - FPRINTF (stdout, "%24s %s%12s %50s: %16llu \n", + now_str = GNUNET_STRINGS_absolute_time_to_string (now); + FPRINTF (stdout, + "%24s%s %s%s%12s%s %s%50s%s%s %16llu\n", now_str, + csv_separator, is_persistent ? "!" : " ", - subsystem, _(name), (unsigned long long) value); + csv_separator, + subsystem, + csv_separator, + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + _(name), + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + (0 == strlen (csv_separator) ? ":": csv_separator), + (unsigned long long) value); } else { - FPRINTF (stdout, "%s%12s %50s: %16llu \n", + FPRINTF (stdout, + "%s%s%12s%s %s%50s%s%s %16llu\n", is_persistent ? "!" : " ", - subsystem, _(name), (unsigned long long) value); + csv_separator, + subsystem, + csv_separator, + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + _(name), + (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */ + (0 == strlen (csv_separator) ? ":": csv_separator), + (unsigned long long) value); } } else - FPRINTF (stdout, "%llu\n", (unsigned long long) value); + FPRINTF (stdout, + "%llu\n", + (unsigned long long) value); return GNUNET_OK; } - /** - * Function called last by the statistics code. + * @brief Clean all data structures related to given node. * - * @param cls closure - * @param success GNUNET_OK if statistics were - * successfully obtained, GNUNET_SYSERR if not. + * Also clears global structures if we are the last node to clean. + * + * @param cls the index of the node */ static void -cleanup (void *cls, int success) +clean_node (void *cls) { + const unsigned index_node = *(unsigned *) cls; + struct GNUNET_STATISTICS_Handle *h; + struct GNUNET_STATISTICS_GetHandle *gh; - if (success != GNUNET_OK) + if ( (NULL != path_testbed) && /* were issued with -t option */ + (NULL != nodes[index_node].conf) ) { - if (NULL == remote_host) - FPRINTF (stderr, "%s", _("Failed to obtain statistics.\n")); - else - FPRINTF (stderr, _("Failed to obtain statistics from host `%s:%llu'\n"), - remote_host, remote_port); - ret = 1; + GNUNET_CONFIGURATION_destroy (nodes[index_node].conf); + nodes[index_node].conf = NULL; } - GNUNET_SCHEDULER_shutdown (); -} + h = nodes[index_node].handle; + gh = nodes[index_node].gh; + + if (NULL != gh) + { + GNUNET_STATISTICS_get_cancel (gh); + gh = NULL; + } + if (GNUNET_YES == watch) + { + GNUNET_assert (GNUNET_OK == + GNUNET_STATISTICS_watch_cancel (h, + subsystem, + name, + &printer_watch, + &nodes[index_node].index_node)); + } + + if (NULL != h) + { + GNUNET_STATISTICS_destroy (h, GNUNET_NO); + h = NULL; + } + + num_nodes_ready_shutdown++; + if (num_nodes == num_nodes_ready_shutdown) + { + GNUNET_array_grow (nodes, num_nodes, 0); + GNUNET_CONTAINER_multihashmap_destroy (values); + } +} /** - * Function run on shutdown to clean up. + * @brief Print and shutdown * - * @param cls the statistics handle - * @param tc scheduler context + * @param cls unused */ static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +print_finish (void *cls) { - struct GNUNET_STATISTICS_Handle *h = cls; - - if (NULL == h) - return; - GNUNET_STATISTICS_watch_cancel (h, subsystem, name, &printer, h); - GNUNET_STATISTICS_destroy (h, GNUNET_NO); - h = NULL; + GNUNET_CONTAINER_multihashmap_iterate (values, printer, NULL); + GNUNET_SCHEDULER_shutdown(); } - - +/** + * @brief Called once all statistic values are available. + * + * Implements #GNUNET_STATISTICS_Callback + * + * @param cls Closure - The index of the node. + * @param succes Whether statistics were obtained successfully. + */ static void -resolver_test_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +continuation_print (void *cls, + int success) { - struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_STATISTICS_Handle *h; + const unsigned index_node = *(unsigned *) cls; - if (NULL != remote_host) + nodes[index_node].gh = NULL; + if (GNUNET_OK != success) { - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) - { - FPRINTF (stderr, _("Trying to connect to remote host, but service `%s' is not running\n"), "resolver"); - return; - } + if (NULL == remote_host) + FPRINTF (stderr, + "%s", + _("Failed to obtain statistics.\n")); + else + FPRINTF (stderr, + _("Failed to obtain statistics from host `%s:%llu'\n"), + remote_host, + remote_port); + ret = 1; + } + if (NULL != nodes[index_node].shutdown_task) + { + GNUNET_SCHEDULER_cancel (nodes[index_node].shutdown_task); + nodes[index_node].shutdown_task = NULL; + } + GNUNET_SCHEDULER_add_now (clean_node, &nodes[index_node].index_node); + num_nodes_ready++; + if (num_nodes_ready == num_nodes) + { + GNUNET_SCHEDULER_add_now (print_finish, NULL); + } +} - /* connect to a remote host */ - if (0 == remote_port) - { - if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "statistics", "PORT", &remote_port)) - { - FPRINTF (stderr, _("A port is required to connect to host `%s'\n"), remote_host); - return; - } - } - else if (65535 <= remote_port) - { - FPRINTF (stderr, _("A port has to be between 1 and 65535 to connect to host `%s'\n"), remote_host); - return; - } +/** + * Function called last by the statistics code. + * + * @param cls closure + * @param success #GNUNET_OK if statistics were + * successfully obtained, #GNUNET_SYSERR if not. + */ +static void +cleanup (void *cls, + int success) +{ + for (unsigned i = 0; i < num_nodes; i++) + { + nodes[i].gh = NULL; + } + if (GNUNET_OK != success) + { + if (NULL == remote_host) + FPRINTF (stderr, + "%s", + _("Failed to obtain statistics.\n")); + else + FPRINTF (stderr, + _("Failed to obtain statistics from host `%s:%llu'\n"), + remote_host, + remote_port); + ret = 1; + } + GNUNET_SCHEDULER_shutdown (); +} - /* Manipulate configuration */ - GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle *) cfg, "statistics", "UNIXPATH", ""); - GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle *) cfg, "statistics", "HOSTNAME", remote_host); - GNUNET_CONFIGURATION_set_value_number ((struct GNUNET_CONFIGURATION_Handle *) cfg, "statistics", "PORT", remote_port); +/** + * @brief Iterate over statistics values and store them in #values. + * They will be printed once all are available. + * + * @param cls Cosure - Node index. + * @param subsystem Subsystem of the value. + * @param name Name of the value. + * @param value Value itself. + * @param is_persistent Persistence. + * + * @return GNUNET_OK - continue. + */ +static int +collector (void *cls, + const char *subsystem, + const char *name, + uint64_t value, + int is_persistent) +{ + const unsigned index_node = *(unsigned *) cls; + struct GNUNET_HashCode *key; + struct GNUNET_HashCode hc; + char *subsys_name; + unsigned len_subsys_name; + struct ValueSet *value_set; + + len_subsys_name = strlen (subsystem) + 3 + strlen (name) + 1; + subsys_name = GNUNET_malloc (len_subsys_name); + SPRINTF (subsys_name, "%s---%s", subsystem, name); + key = &hc; + GNUNET_CRYPTO_hash (subsys_name, len_subsys_name, key); + GNUNET_free (subsys_name); + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (values, key)) + { + // get + value_set = GNUNET_CONTAINER_multihashmap_get (values, key); } + else + { + // new + value_set = new_value_set (subsystem, name, num_nodes, is_persistent); + } + // write + value_set->values[index_node] = value; + // put + GNUNET_CONTAINER_multihashmap_put (values, key, value_set, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + return GNUNET_OK; +} + +/** + * Main task that does the actual work. + * + * @param cls closure with our configuration + */ +static void +main_task (void *cls) +{ + unsigned index_node = *(unsigned *) cls; + const struct GNUNET_CONFIGURATION_Handle *cfg = nodes[index_node].conf; if (set_value) { - if (subsystem == NULL) + if (NULL == subsystem) { - FPRINTF (stderr, "%s", _("Missing argument: subsystem \n")); + FPRINTF (stderr, + "%s", + _("Missing argument: subsystem \n")); ret = 1; return; } - if (name == NULL) + if (NULL == name) { - FPRINTF (stderr, "%s", _("Missing argument: name\n")); + FPRINTF (stderr, + "%s", + _("Missing argument: name\n")); ret = 1; return; } - h = GNUNET_STATISTICS_create (subsystem, cfg); - if (NULL == h) + nodes[index_node].handle = GNUNET_STATISTICS_create (subsystem, + cfg); + if (NULL == nodes[index_node].handle) { ret = 1; return; } - GNUNET_STATISTICS_set (h, name, (uint64_t) set_val, persistent); - GNUNET_STATISTICS_destroy (h, GNUNET_YES); - h = NULL; + GNUNET_STATISTICS_set (nodes[index_node].handle, + name, + (uint64_t) set_val, + persistent); + GNUNET_STATISTICS_destroy (nodes[index_node].handle, + GNUNET_YES); + nodes[index_node].handle = NULL; return; } - if (NULL == (h = GNUNET_STATISTICS_create ("gnunet-statistics", cfg))) + if (NULL == (nodes[index_node].handle = GNUNET_STATISTICS_create ("gnunet-statistics", + cfg))) { ret = 1; return; @@ -236,32 +562,143 @@ resolver_test_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (GNUNET_NO == watch) { if (NULL == - GNUNET_STATISTICS_get (h, subsystem, name, GET_TIMEOUT, &cleanup, - &printer, h)) - cleanup (h, GNUNET_SYSERR); + (nodes[index_node].gh = GNUNET_STATISTICS_get (nodes[index_node].handle, + subsystem, + name, + &continuation_print, + &collector, + &nodes[index_node].index_node)) ) + cleanup (nodes[index_node].handle, + GNUNET_SYSERR); } else { - if ((NULL == subsystem) || (NULL == name)) + if ( (NULL == subsystem) || + (NULL == name) ) { printf (_("No subsystem or name given\n")); - GNUNET_STATISTICS_destroy (h, GNUNET_NO); - h = NULL; + GNUNET_STATISTICS_destroy (nodes[index_node].handle, + GNUNET_NO); + nodes[index_node].handle = NULL; ret = 1; return; } - if (GNUNET_OK != GNUNET_STATISTICS_watch (h, subsystem, name, &printer, h)) + if (GNUNET_OK != + GNUNET_STATISTICS_watch (nodes[index_node].handle, + subsystem, + name, + &printer_watch, + &nodes[index_node].index_node)) { - fprintf (stderr, _("Failed to initialize watch routine\n")); - GNUNET_SCHEDULER_add_now (&shutdown_task, h); + fprintf (stderr, + _("Failed to initialize watch routine\n")); + nodes[index_node].shutdown_task = + GNUNET_SCHEDULER_add_now (&clean_node, + &nodes[index_node].index_node); return; } } - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, h); + nodes[index_node].shutdown_task = + GNUNET_SCHEDULER_add_shutdown (&clean_node, + &nodes[index_node].index_node); +} +/** + * @brief Iter over content of a node's directory to check for existence of a + * config file. + * + * Implements #GNUNET_FileNameCallback + * + * @param cls pointer to indicate success + * @param filename filename inside the directory of the potential node + * + * @return to continue iteration or not to + */ +static int +iter_check_config (void *cls, + const char *filename) +{ + if (0 == strncmp (GNUNET_STRINGS_get_short_name (filename), "config", 6)) + { + /* Found the config - stop iteration successfully */ + GNUNET_array_grow (nodes, num_nodes, num_nodes+1); + nodes[num_nodes-1].conf = GNUNET_CONFIGURATION_create(); + nodes[num_nodes-1].index_node = num_nodes-1; + if (GNUNET_OK != GNUNET_CONFIGURATION_load (nodes[num_nodes-1].conf, filename)) + { + FPRINTF (stderr, "Failed loading config `%s'\n", filename); + return GNUNET_SYSERR; + } + return GNUNET_NO; + } + else + { + /* Continue iteration */ + return GNUNET_OK; + } } +/** + * @brief Iterates over filenames in testbed directory. + * + * Implements #GNUNET_FileNameCallback + * + * Checks if the file is a directory for a testbed node + * and counts the nodes. + * + * @param cls counter of nodes + * @param filename full path of the file in testbed + * + * @return status whether to continue iteration + */ +static int +iter_testbed_path (void *cls, + const char *filename) +{ + unsigned index_node; + + GNUNET_assert (NULL != filename); + if (1 == SSCANF (GNUNET_STRINGS_get_short_name (filename), + "%u", + &index_node)) + { + if (-1 == GNUNET_DISK_directory_scan (filename, + iter_check_config, + NULL)) + { + /* This is probably no directory for a testbed node + * Go on with iteration */ + return GNUNET_OK; + } + return GNUNET_OK; + } + return GNUNET_OK; +} + +/** + * @brief Count the number of nodes running in the testbed + * + * @param path_testbed path to the testbed data + * + * @return number of running nodes + */ +static int +discover_testbed_nodes (const char *path_testbed) +{ + int num_dir_entries; + + num_dir_entries = GNUNET_DISK_directory_scan (path_testbed, + iter_testbed_path, + NULL); + if (-1 == num_dir_entries) + { + FPRINTF (stderr, + "Failure during scanning directory `%s'\n", + path_testbed); + return -1; + } + return 0; +} /** * Main function that will be run by the scheduler. @@ -272,26 +709,96 @@ resolver_test_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param cfg configuration */ static void -run (void *cls, char *const *args, const char *cfgfile, +run (void *cls, + char *const *args, + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { + struct GNUNET_CONFIGURATION_Handle *c; + + c = (struct GNUNET_CONFIGURATION_Handle *) cfg; set_value = GNUNET_NO; + if (NULL == csv_separator) csv_separator = ""; if (NULL != args[0]) { - if (1 != SSCANF (args[0], "%llu", &set_val)) + if (1 != SSCANF (args[0], + "%llu", + &set_val)) + { + FPRINTF (stderr, + _("Invalid argument `%s'\n"), + args[0]); + ret = 1; + return; + } + set_value = GNUNET_YES; + } + if (NULL != remote_host) + { + if (0 == remote_port) + { + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, + "statistics", + "PORT", + &remote_port)) { - FPRINTF (stderr, _("Invalid argument `%s'\n"), args[0]); - ret = 1; - return; + FPRINTF (stderr, + _("A port is required to connect to host `%s'\n"), + remote_host); + return; } - set_value = GNUNET_YES; - } + } + else if (65535 <= remote_port) + { + FPRINTF (stderr, + _("A port has to be between 1 and 65535 to connect to host `%s'\n"), + remote_host); + return; + } - if (NULL != remote_host) - GNUNET_CLIENT_service_test ("resolver", cfg, GNUNET_TIME_UNIT_SECONDS, &resolver_test_task, (void *) cfg); + /* Manipulate configuration */ + GNUNET_CONFIGURATION_set_value_string (c, + "statistics", + "UNIXPATH", + ""); + GNUNET_CONFIGURATION_set_value_string (c, + "statistics", + "HOSTNAME", + remote_host); + GNUNET_CONFIGURATION_set_value_number (c, + "statistics", + "PORT", + remote_port); + } + if (NULL == path_testbed) + { + values = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); + GNUNET_array_grow (nodes, num_nodes, 1); + nodes[0].index_node = 0; + nodes[0].conf = c; + GNUNET_SCHEDULER_add_now (&main_task, &nodes[0].index_node); + } else - GNUNET_SCHEDULER_add_now (&resolver_test_task, (void *) cfg); - + { + if (GNUNET_YES == watch) + { + printf (_("Not able to watch testbed nodes (yet - feel free to implement)\n")); + ret = 1; + return; + } + values = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO); + if (-1 == discover_testbed_nodes (path_testbed)) + { + return; + } + /* For each config/node collect statistics */ + for (unsigned i = 0; i < num_nodes; i++) + { + GNUNET_SCHEDULER_add_now (&main_task, + &nodes[i].index_node); + } + } } @@ -305,40 +812,76 @@ run (void *cls, char *const *args, const char *cfgfile, int main (int argc, char *const *argv) { - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'n', "name", "NAME", - gettext_noop ("limit output to statistics for the given NAME"), 1, - &GNUNET_GETOPT_set_string, &name}, - {'p', "persistent", NULL, - gettext_noop ("make the value being set persistent"), 0, - &GNUNET_GETOPT_set_one, &persistent}, - {'s', "subsystem", "SUBSYSTEM", - gettext_noop ("limit output to the given SUBSYSTEM"), 1, - &GNUNET_GETOPT_set_string, &subsystem}, - {'q', "quiet", NULL, - gettext_noop ("just print the statistics value"), 0, - &GNUNET_GETOPT_set_one, &quiet}, - {'w', "watch", NULL, - gettext_noop ("watch value continuously"), 0, - &GNUNET_GETOPT_set_one, &watch}, - {'r', "remote", NULL, - gettext_noop ("connect to remote host"), 1, - &GNUNET_GETOPT_set_string, &remote_host}, - {'o', "port", NULL, - gettext_noop ("port for remote host"), 1, - &GNUNET_GETOPT_set_uint, &remote_port}, + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('n', + "name", + "NAME", + gettext_noop ("limit output to statistics for the given NAME"), + &name), + + GNUNET_GETOPT_option_flag ('p', + "persistent", + gettext_noop ("make the value being set persistent"), + &persistent), + + GNUNET_GETOPT_option_string ('s', + "subsystem", + "SUBSYSTEM", + gettext_noop ("limit output to the given SUBSYSTEM"), + &subsystem), + + GNUNET_GETOPT_option_string ('S', + "csv-separator", + "CSV_SEPARATOR", + gettext_noop ("use as csv separator"), + &csv_separator), + + GNUNET_GETOPT_option_filename ('t', + "testbed", + "TESTBED", + gettext_noop ("path to the folder containing the testbed data"), + &path_testbed), + + GNUNET_GETOPT_option_flag ('q', + "quiet", + gettext_noop ("just print the statistics value"), + &quiet), + + GNUNET_GETOPT_option_flag ('w', + "watch", + gettext_noop ("watch value continuously"), + &watch), + + GNUNET_GETOPT_option_string ('r', + "remote", + "REMOTE", + gettext_noop ("connect to remote host"), + &remote_host), + + GNUNET_GETOPT_option_ulong ('o', + "port", + "PORT", + gettext_noop ("port for remote host"), + &remote_port), + GNUNET_GETOPT_OPTION_END }; remote_port = 0; remote_host = NULL; - if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) + if (GNUNET_OK != + GNUNET_STRINGS_get_utf8_args (argc, argv, + &argc, &argv)) return 2; ret = (GNUNET_OK == - GNUNET_PROGRAM_run (argc, argv, "gnunet-statistics [options [value]]", + GNUNET_PROGRAM_run (argc, + argv, + "gnunet-statistics [options [value]]", gettext_noop ("Print statistics about GNUnet operations."), - options, &run, NULL)) ? ret : 1; + options, + &run, + NULL)) ? ret : 1; GNUNET_free_non_null (remote_host); GNUNET_free ((void*) argv); return ret;