gnunet-statistics.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2001, 2002, 2004-2007, 2009, 2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file statistics/gnunet-statistics.c
  18. * @brief tool to obtain statistics
  19. * @author Christian Grothoff
  20. * @author Igor Wronsky
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_statistics_service.h"
  25. #include "statistics.h"
  26. /**
  27. * Final status code.
  28. */
  29. static int ret;
  30. /**
  31. * Set to subsystem that we're going to get stats for (or NULL for all).
  32. */
  33. static char *subsystem;
  34. /**
  35. * The path of the testbed data.
  36. */
  37. static char *path_testbed;
  38. /**
  39. * Set to the specific stat value that we are after (or NULL for all).
  40. */
  41. static char *name;
  42. /**
  43. * Make the value that is being set persistent.
  44. */
  45. static int persistent;
  46. /**
  47. * Watch value continuously
  48. */
  49. static int watch;
  50. /**
  51. * Quiet mode
  52. */
  53. static int quiet;
  54. /**
  55. * @brief Separator string for csv.
  56. */
  57. static char *csv_separator;
  58. /**
  59. * Remote host
  60. */
  61. static char *remote_host;
  62. /**
  63. * Remote host's port
  64. */
  65. static unsigned long long remote_port;
  66. /**
  67. * Value to set
  68. */
  69. static unsigned long long set_val;
  70. /**
  71. * Set operation
  72. */
  73. static int set_value;
  74. /**
  75. * @brief Representation of all (testbed) nodes.
  76. */
  77. static struct Node {
  78. /**
  79. * @brief Index of the node in this array.
  80. */
  81. unsigned index_node;
  82. /**
  83. * @brief Configuration handle for this node
  84. */
  85. struct GNUNET_CONFIGURATION_Handle *conf;
  86. /**
  87. * Handle for pending GET operation.
  88. */
  89. struct GNUNET_STATISTICS_GetHandle *gh;
  90. /**
  91. * @brief Statistics handle nodes.
  92. */
  93. struct GNUNET_STATISTICS_Handle *handle;
  94. /**
  95. * @brief Identifier for shutdown task for this node.
  96. */
  97. struct GNUNET_SCHEDULER_Task *shutdown_task;
  98. } *nodes;
  99. /**
  100. * @brief Number of configurations of all (testbed) nodes.
  101. */
  102. static unsigned num_nodes;
  103. /**
  104. * @brief Set of values for a combination of subsystem and name.
  105. */
  106. struct ValueSet
  107. {
  108. /**
  109. * @brief Subsystem of the valueset.
  110. */
  111. char *subsystem;
  112. /**
  113. * @brief Name of the valueset.
  114. */
  115. char *name;
  116. /**
  117. * @brief The values.
  118. */
  119. uint64_t *values;
  120. /**
  121. * @brief Persistence of the values.
  122. */
  123. int is_persistent;
  124. };
  125. /**
  126. * @brief Collection of all values (represented with #ValueSet).
  127. */
  128. static struct GNUNET_CONTAINER_MultiHashMap *values;
  129. /**
  130. * @brief Number of nodes that have their values ready.
  131. */
  132. static int num_nodes_ready;
  133. /**
  134. * @brief Number of nodes that have their values ready.
  135. */
  136. static int num_nodes_ready_shutdown;
  137. /**
  138. * @brief Create a new #ValueSet
  139. *
  140. * @param subsystem Subsystem of the valueset.
  141. * @param name Name of the valueset.
  142. * @param num_values Number of values in valueset - number of peers.
  143. * @param is_persistent Persistence status of values.
  144. *
  145. * @return Newly allocated #ValueSet.
  146. */
  147. static struct ValueSet *
  148. new_value_set (const char *subsystem,
  149. const char *name,
  150. unsigned num_values,
  151. int is_persistent)
  152. {
  153. struct ValueSet *value_set;
  154. value_set = GNUNET_new (struct ValueSet);
  155. value_set->subsystem = GNUNET_strdup (subsystem);
  156. value_set->name = GNUNET_strdup (name);
  157. value_set->values = GNUNET_new_array (num_values, uint64_t);
  158. value_set->is_persistent = persistent;
  159. return value_set;
  160. }
  161. /**
  162. * @brief Print the (collected) values.
  163. *
  164. * Implements #GNUNET_CONTAINER_HashMapIterator.
  165. *
  166. * @param cls Closure - unused
  167. * @param key #GNUNET_HashCode key of #GNUNET_CONTAINER_MultiHashMap iterator -
  168. * unused
  169. * @param value Values represented as #ValueSet.
  170. *
  171. * @return GNUNET_YES - continue iteration.
  172. */
  173. static int
  174. printer (void *cls,
  175. const struct GNUNET_HashCode *key,
  176. void *value)
  177. {
  178. struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
  179. const char *now_str;
  180. struct ValueSet *value_set = value;
  181. if (quiet == GNUNET_NO)
  182. {
  183. if (GNUNET_YES == watch)
  184. {
  185. now_str = GNUNET_STRINGS_absolute_time_to_string (now);
  186. FPRINTF (stdout,
  187. "%24s%s %s%s%12s%s %s%50s%s%s ",
  188. now_str,
  189. csv_separator,
  190. value_set->is_persistent ? "!" : " ",
  191. csv_separator,
  192. value_set->subsystem,
  193. csv_separator,
  194. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  195. _(value_set->name),
  196. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  197. (0 == strlen (csv_separator) ? ":": csv_separator));
  198. }
  199. else
  200. {
  201. FPRINTF (stdout,
  202. "%s%s%12s%s %s%50s%s%s ",
  203. value_set->is_persistent ? "!" : " ",
  204. csv_separator,
  205. value_set->subsystem,
  206. csv_separator,
  207. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  208. _(value_set->name),
  209. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  210. (0 == strlen (csv_separator) ? ":": csv_separator));
  211. }
  212. }
  213. for (unsigned i = 0; i < num_nodes; i++)
  214. {
  215. FPRINTF (stdout,
  216. "%16llu%s",
  217. (unsigned long long) value_set->values[i],
  218. csv_separator);
  219. }
  220. FPRINTF (stdout, "\n");
  221. GNUNET_free (value_set->subsystem);
  222. GNUNET_free (value_set->name);
  223. GNUNET_free (value_set->values);
  224. GNUNET_free (value_set);
  225. return GNUNET_YES;
  226. }
  227. /**
  228. * Callback function to process statistic values.
  229. *
  230. * @param cls closure
  231. * @param subsystem name of subsystem that created the statistic
  232. * @param name the name of the datum
  233. * @param value the current value
  234. * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
  235. * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
  236. */
  237. static int
  238. printer_watch (void *cls,
  239. const char *subsystem,
  240. const char *name,
  241. uint64_t value,
  242. int is_persistent)
  243. {
  244. struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get();
  245. const char *now_str;
  246. if (quiet == GNUNET_NO)
  247. {
  248. if (GNUNET_YES == watch)
  249. {
  250. now_str = GNUNET_STRINGS_absolute_time_to_string (now);
  251. FPRINTF (stdout,
  252. "%24s%s %s%s%12s%s %s%50s%s%s %16llu\n",
  253. now_str,
  254. csv_separator,
  255. is_persistent ? "!" : " ",
  256. csv_separator,
  257. subsystem,
  258. csv_separator,
  259. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  260. _(name),
  261. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  262. (0 == strlen (csv_separator) ? ":": csv_separator),
  263. (unsigned long long) value);
  264. }
  265. else
  266. {
  267. FPRINTF (stdout,
  268. "%s%s%12s%s %s%50s%s%s %16llu\n",
  269. is_persistent ? "!" : " ",
  270. csv_separator,
  271. subsystem,
  272. csv_separator,
  273. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  274. _(name),
  275. (0 == strlen (csv_separator) ? "": "\""), /* quotes if csv */
  276. (0 == strlen (csv_separator) ? ":": csv_separator),
  277. (unsigned long long) value);
  278. }
  279. }
  280. else
  281. FPRINTF (stdout,
  282. "%llu\n",
  283. (unsigned long long) value);
  284. return GNUNET_OK;
  285. }
  286. /**
  287. * @brief Clean all data structures related to given node.
  288. *
  289. * Also clears global structures if we are the last node to clean.
  290. *
  291. * @param cls the index of the node
  292. */
  293. static void
  294. clean_node (void *cls)
  295. {
  296. const unsigned index_node = *(unsigned *) cls;
  297. struct GNUNET_STATISTICS_Handle *h;
  298. struct GNUNET_STATISTICS_GetHandle *gh;
  299. if ( (NULL != path_testbed) && /* were issued with -t <testbed-path> option */
  300. (NULL != nodes[index_node].conf) )
  301. {
  302. GNUNET_CONFIGURATION_destroy (nodes[index_node].conf);
  303. nodes[index_node].conf = NULL;
  304. }
  305. h = nodes[index_node].handle;
  306. gh = nodes[index_node].gh;
  307. if (NULL != gh)
  308. {
  309. GNUNET_STATISTICS_get_cancel (gh);
  310. gh = NULL;
  311. }
  312. if (GNUNET_YES == watch)
  313. {
  314. GNUNET_assert (GNUNET_OK ==
  315. GNUNET_STATISTICS_watch_cancel (h,
  316. subsystem,
  317. name,
  318. &printer_watch,
  319. &nodes[index_node].index_node));
  320. }
  321. if (NULL != h)
  322. {
  323. GNUNET_STATISTICS_destroy (h, GNUNET_NO);
  324. h = NULL;
  325. }
  326. num_nodes_ready_shutdown++;
  327. if (num_nodes == num_nodes_ready_shutdown)
  328. {
  329. GNUNET_array_grow (nodes, num_nodes, 0);
  330. GNUNET_CONTAINER_multihashmap_destroy (values);
  331. }
  332. }
  333. /**
  334. * @brief Print and shutdown
  335. *
  336. * @param cls unused
  337. */
  338. static void
  339. print_finish (void *cls)
  340. {
  341. GNUNET_CONTAINER_multihashmap_iterate (values, printer, NULL);
  342. GNUNET_SCHEDULER_shutdown();
  343. }
  344. /**
  345. * @brief Called once all statistic values are available.
  346. *
  347. * Implements #GNUNET_STATISTICS_Callback
  348. *
  349. * @param cls Closure - The index of the node.
  350. * @param succes Whether statistics were obtained successfully.
  351. */
  352. static void
  353. continuation_print (void *cls,
  354. int success)
  355. {
  356. const unsigned index_node = *(unsigned *) cls;
  357. nodes[index_node].gh = NULL;
  358. if (GNUNET_OK != success)
  359. {
  360. if (NULL == remote_host)
  361. FPRINTF (stderr,
  362. "%s",
  363. _("Failed to obtain statistics.\n"));
  364. else
  365. FPRINTF (stderr,
  366. _("Failed to obtain statistics from host `%s:%llu'\n"),
  367. remote_host,
  368. remote_port);
  369. ret = 1;
  370. }
  371. if (NULL != nodes[index_node].shutdown_task)
  372. {
  373. GNUNET_SCHEDULER_cancel (nodes[index_node].shutdown_task);
  374. nodes[index_node].shutdown_task = NULL;
  375. }
  376. GNUNET_SCHEDULER_add_now (clean_node, &nodes[index_node].index_node);
  377. num_nodes_ready++;
  378. if (num_nodes_ready == num_nodes)
  379. {
  380. GNUNET_SCHEDULER_add_now (print_finish, NULL);
  381. }
  382. }
  383. /**
  384. * Function called last by the statistics code.
  385. *
  386. * @param cls closure
  387. * @param success #GNUNET_OK if statistics were
  388. * successfully obtained, #GNUNET_SYSERR if not.
  389. */
  390. static void
  391. cleanup (void *cls,
  392. int success)
  393. {
  394. for (unsigned i = 0; i < num_nodes; i++)
  395. {
  396. nodes[i].gh = NULL;
  397. }
  398. if (GNUNET_OK != success)
  399. {
  400. if (NULL == remote_host)
  401. FPRINTF (stderr,
  402. "%s",
  403. _("Failed to obtain statistics.\n"));
  404. else
  405. FPRINTF (stderr,
  406. _("Failed to obtain statistics from host `%s:%llu'\n"),
  407. remote_host,
  408. remote_port);
  409. ret = 1;
  410. }
  411. GNUNET_SCHEDULER_shutdown ();
  412. }
  413. /**
  414. * @brief Iterate over statistics values and store them in #values.
  415. * They will be printed once all are available.
  416. *
  417. * @param cls Cosure - Node index.
  418. * @param subsystem Subsystem of the value.
  419. * @param name Name of the value.
  420. * @param value Value itself.
  421. * @param is_persistent Persistence.
  422. *
  423. * @return GNUNET_OK - continue.
  424. */
  425. static int
  426. collector (void *cls,
  427. const char *subsystem,
  428. const char *name,
  429. uint64_t value,
  430. int is_persistent)
  431. {
  432. const unsigned index_node = *(unsigned *) cls;
  433. struct GNUNET_HashCode *key;
  434. struct GNUNET_HashCode hc;
  435. char *subsys_name;
  436. unsigned len_subsys_name;
  437. struct ValueSet *value_set;
  438. len_subsys_name = strlen (subsystem) + 3 + strlen (name) + 1;
  439. subsys_name = GNUNET_malloc (len_subsys_name);
  440. SPRINTF (subsys_name, "%s---%s", subsystem, name);
  441. key = &hc;
  442. GNUNET_CRYPTO_hash (subsys_name, len_subsys_name, key);
  443. GNUNET_free (subsys_name);
  444. if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (values, key))
  445. {
  446. // get
  447. value_set = GNUNET_CONTAINER_multihashmap_get (values, key);
  448. }
  449. else
  450. {
  451. // new
  452. value_set = new_value_set (subsystem, name, num_nodes, is_persistent);
  453. }
  454. // write
  455. value_set->values[index_node] = value;
  456. // put
  457. GNUNET_CONTAINER_multihashmap_put (values, key, value_set,
  458. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
  459. return GNUNET_OK;
  460. }
  461. /**
  462. * Main task that does the actual work.
  463. *
  464. * @param cls closure with our configuration
  465. */
  466. static void
  467. main_task (void *cls)
  468. {
  469. unsigned index_node = *(unsigned *) cls;
  470. const struct GNUNET_CONFIGURATION_Handle *cfg = nodes[index_node].conf;
  471. if (set_value)
  472. {
  473. if (NULL == subsystem)
  474. {
  475. FPRINTF (stderr,
  476. "%s",
  477. _("Missing argument: subsystem \n"));
  478. ret = 1;
  479. return;
  480. }
  481. if (NULL == name)
  482. {
  483. FPRINTF (stderr,
  484. "%s",
  485. _("Missing argument: name\n"));
  486. ret = 1;
  487. return;
  488. }
  489. nodes[index_node].handle = GNUNET_STATISTICS_create (subsystem,
  490. cfg);
  491. if (NULL == nodes[index_node].handle)
  492. {
  493. ret = 1;
  494. return;
  495. }
  496. GNUNET_STATISTICS_set (nodes[index_node].handle,
  497. name,
  498. (uint64_t) set_val,
  499. persistent);
  500. GNUNET_STATISTICS_destroy (nodes[index_node].handle,
  501. GNUNET_YES);
  502. nodes[index_node].handle = NULL;
  503. return;
  504. }
  505. if (NULL == (nodes[index_node].handle = GNUNET_STATISTICS_create ("gnunet-statistics",
  506. cfg)))
  507. {
  508. ret = 1;
  509. return;
  510. }
  511. if (GNUNET_NO == watch)
  512. {
  513. if (NULL ==
  514. (nodes[index_node].gh = GNUNET_STATISTICS_get (nodes[index_node].handle,
  515. subsystem,
  516. name,
  517. &continuation_print,
  518. &collector,
  519. &nodes[index_node].index_node)) )
  520. cleanup (nodes[index_node].handle,
  521. GNUNET_SYSERR);
  522. }
  523. else
  524. {
  525. if ( (NULL == subsystem) ||
  526. (NULL == name) )
  527. {
  528. printf (_("No subsystem or name given\n"));
  529. GNUNET_STATISTICS_destroy (nodes[index_node].handle,
  530. GNUNET_NO);
  531. nodes[index_node].handle = NULL;
  532. ret = 1;
  533. return;
  534. }
  535. if (GNUNET_OK !=
  536. GNUNET_STATISTICS_watch (nodes[index_node].handle,
  537. subsystem,
  538. name,
  539. &printer_watch,
  540. &nodes[index_node].index_node))
  541. {
  542. fprintf (stderr,
  543. _("Failed to initialize watch routine\n"));
  544. nodes[index_node].shutdown_task =
  545. GNUNET_SCHEDULER_add_now (&clean_node,
  546. &nodes[index_node].index_node);
  547. return;
  548. }
  549. }
  550. nodes[index_node].shutdown_task =
  551. GNUNET_SCHEDULER_add_shutdown (&clean_node,
  552. &nodes[index_node].index_node);
  553. }
  554. /**
  555. * @brief Iter over content of a node's directory to check for existence of a
  556. * config file.
  557. *
  558. * Implements #GNUNET_FileNameCallback
  559. *
  560. * @param cls pointer to indicate success
  561. * @param filename filename inside the directory of the potential node
  562. *
  563. * @return to continue iteration or not to
  564. */
  565. static int
  566. iter_check_config (void *cls,
  567. const char *filename)
  568. {
  569. if (0 == strncmp (GNUNET_STRINGS_get_short_name (filename), "config", 6))
  570. {
  571. /* Found the config - stop iteration successfully */
  572. GNUNET_array_grow (nodes, num_nodes, num_nodes+1);
  573. nodes[num_nodes-1].conf = GNUNET_CONFIGURATION_create();
  574. nodes[num_nodes-1].index_node = num_nodes-1;
  575. if (GNUNET_OK != GNUNET_CONFIGURATION_load (nodes[num_nodes-1].conf, filename))
  576. {
  577. FPRINTF (stderr, "Failed loading config `%s'\n", filename);
  578. return GNUNET_SYSERR;
  579. }
  580. return GNUNET_NO;
  581. }
  582. else
  583. {
  584. /* Continue iteration */
  585. return GNUNET_OK;
  586. }
  587. }
  588. /**
  589. * @brief Iterates over filenames in testbed directory.
  590. *
  591. * Implements #GNUNET_FileNameCallback
  592. *
  593. * Checks if the file is a directory for a testbed node
  594. * and counts the nodes.
  595. *
  596. * @param cls counter of nodes
  597. * @param filename full path of the file in testbed
  598. *
  599. * @return status whether to continue iteration
  600. */
  601. static int
  602. iter_testbed_path (void *cls,
  603. const char *filename)
  604. {
  605. unsigned index_node;
  606. GNUNET_assert (NULL != filename);
  607. if (1 == SSCANF (GNUNET_STRINGS_get_short_name (filename),
  608. "%u",
  609. &index_node))
  610. {
  611. if (-1 == GNUNET_DISK_directory_scan (filename,
  612. iter_check_config,
  613. NULL))
  614. {
  615. /* This is probably no directory for a testbed node
  616. * Go on with iteration */
  617. return GNUNET_OK;
  618. }
  619. return GNUNET_OK;
  620. }
  621. return GNUNET_OK;
  622. }
  623. /**
  624. * @brief Count the number of nodes running in the testbed
  625. *
  626. * @param path_testbed path to the testbed data
  627. *
  628. * @return number of running nodes
  629. */
  630. static int
  631. discover_testbed_nodes (const char *path_testbed)
  632. {
  633. int num_dir_entries;
  634. num_dir_entries = GNUNET_DISK_directory_scan (path_testbed,
  635. iter_testbed_path,
  636. NULL);
  637. if (-1 == num_dir_entries)
  638. {
  639. FPRINTF (stderr,
  640. "Failure during scanning directory `%s'\n",
  641. path_testbed);
  642. return -1;
  643. }
  644. return 0;
  645. }
  646. /**
  647. * Main function that will be run by the scheduler.
  648. *
  649. * @param cls closure
  650. * @param args remaining command-line arguments
  651. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  652. * @param cfg configuration
  653. */
  654. static void
  655. run (void *cls,
  656. char *const *args,
  657. const char *cfgfile,
  658. const struct GNUNET_CONFIGURATION_Handle *cfg)
  659. {
  660. struct GNUNET_CONFIGURATION_Handle *c;
  661. c = (struct GNUNET_CONFIGURATION_Handle *) cfg;
  662. set_value = GNUNET_NO;
  663. if (NULL == csv_separator) csv_separator = "";
  664. if (NULL != args[0])
  665. {
  666. if (1 != SSCANF (args[0],
  667. "%llu",
  668. &set_val))
  669. {
  670. FPRINTF (stderr,
  671. _("Invalid argument `%s'\n"),
  672. args[0]);
  673. ret = 1;
  674. return;
  675. }
  676. set_value = GNUNET_YES;
  677. }
  678. if (NULL != remote_host)
  679. {
  680. if (0 == remote_port)
  681. {
  682. if (GNUNET_SYSERR ==
  683. GNUNET_CONFIGURATION_get_value_number (cfg,
  684. "statistics",
  685. "PORT",
  686. &remote_port))
  687. {
  688. FPRINTF (stderr,
  689. _("A port is required to connect to host `%s'\n"),
  690. remote_host);
  691. return;
  692. }
  693. }
  694. else if (65535 <= remote_port)
  695. {
  696. FPRINTF (stderr,
  697. _("A port has to be between 1 and 65535 to connect to host `%s'\n"),
  698. remote_host);
  699. return;
  700. }
  701. /* Manipulate configuration */
  702. GNUNET_CONFIGURATION_set_value_string (c,
  703. "statistics",
  704. "UNIXPATH",
  705. "");
  706. GNUNET_CONFIGURATION_set_value_string (c,
  707. "statistics",
  708. "HOSTNAME",
  709. remote_host);
  710. GNUNET_CONFIGURATION_set_value_number (c,
  711. "statistics",
  712. "PORT",
  713. remote_port);
  714. }
  715. if (NULL == path_testbed)
  716. {
  717. values = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
  718. GNUNET_array_grow (nodes, num_nodes, 1);
  719. nodes[0].index_node = 0;
  720. nodes[0].conf = c;
  721. GNUNET_SCHEDULER_add_now (&main_task, &nodes[0].index_node);
  722. }
  723. else
  724. {
  725. if (GNUNET_YES == watch)
  726. {
  727. printf (_("Not able to watch testbed nodes (yet - feel free to implement)\n"));
  728. ret = 1;
  729. return;
  730. }
  731. values = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
  732. if (-1 == discover_testbed_nodes (path_testbed))
  733. {
  734. return;
  735. }
  736. /* For each config/node collect statistics */
  737. for (unsigned i = 0; i < num_nodes; i++)
  738. {
  739. GNUNET_SCHEDULER_add_now (&main_task,
  740. &nodes[i].index_node);
  741. }
  742. }
  743. }
  744. /**
  745. * The main function to obtain statistics in GNUnet.
  746. *
  747. * @param argc number of arguments from the command line
  748. * @param argv command line arguments
  749. * @return 0 ok, 1 on error
  750. */
  751. int
  752. main (int argc, char *const *argv)
  753. {
  754. struct GNUNET_GETOPT_CommandLineOption options[] = {
  755. GNUNET_GETOPT_option_string ('n',
  756. "name",
  757. "NAME",
  758. gettext_noop ("limit output to statistics for the given NAME"),
  759. &name),
  760. GNUNET_GETOPT_option_flag ('p',
  761. "persistent",
  762. gettext_noop ("make the value being set persistent"),
  763. &persistent),
  764. GNUNET_GETOPT_option_string ('s',
  765. "subsystem",
  766. "SUBSYSTEM",
  767. gettext_noop ("limit output to the given SUBSYSTEM"),
  768. &subsystem),
  769. GNUNET_GETOPT_option_string ('S',
  770. "csv-separator",
  771. "CSV_SEPARATOR",
  772. gettext_noop ("use as csv separator"),
  773. &csv_separator),
  774. GNUNET_GETOPT_option_filename ('t',
  775. "testbed",
  776. "TESTBED",
  777. gettext_noop ("path to the folder containing the testbed data"),
  778. &path_testbed),
  779. GNUNET_GETOPT_option_flag ('q',
  780. "quiet",
  781. gettext_noop ("just print the statistics value"),
  782. &quiet),
  783. GNUNET_GETOPT_option_flag ('w',
  784. "watch",
  785. gettext_noop ("watch value continuously"),
  786. &watch),
  787. GNUNET_GETOPT_option_string ('r',
  788. "remote",
  789. "REMOTE",
  790. gettext_noop ("connect to remote host"),
  791. &remote_host),
  792. GNUNET_GETOPT_option_ulong ('o',
  793. "port",
  794. "PORT",
  795. gettext_noop ("port for remote host"),
  796. &remote_port),
  797. GNUNET_GETOPT_OPTION_END
  798. };
  799. remote_port = 0;
  800. remote_host = NULL;
  801. if (GNUNET_OK !=
  802. GNUNET_STRINGS_get_utf8_args (argc, argv,
  803. &argc, &argv))
  804. return 2;
  805. ret = (GNUNET_OK ==
  806. GNUNET_PROGRAM_run (argc,
  807. argv,
  808. "gnunet-statistics [options [value]]",
  809. gettext_noop
  810. ("Print statistics about GNUnet operations."),
  811. options,
  812. &run,
  813. NULL)) ? ret : 1;
  814. GNUNET_free_non_null (remote_host);
  815. GNUNET_free ((void*) argv);
  816. return ret;
  817. }
  818. /* end of gnunet-statistics.c */