gnunet-daemon-latency-logger.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2008--2014 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. 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. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file testbed/gnunet-daemon-latency-logger.c
  19. * @brief log latency values from neighbour connections into an SQLite database
  20. * @author Sree Harsha Totakura <sreeharsha@totakura.in>
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_ats_service.h"
  25. #include <sqlite3.h>
  26. /**
  27. * Logging shorthand
  28. */
  29. #define LOG(type,...) \
  30. GNUNET_log (type, __VA_ARGS__)
  31. /**
  32. * Debug logging shorthand
  33. */
  34. #define DEBUG(...) \
  35. LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
  36. /**
  37. * Log an error message at log-level 'level' that indicates
  38. * a failure of the command 'cmd' on file 'filename'
  39. * with the message given by strerror(errno).
  40. */
  41. #define LOG_SQLITE(db, msg, level, cmd) \
  42. do { \
  43. GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), \
  44. cmd, __FILE__,__LINE__, sqlite3_errmsg(db)); \
  45. if (msg != NULL) \
  46. GNUNET_asprintf(msg, _("`%s' failed at %s:%u with error: %s"), cmd, \
  47. __FILE__, __LINE__, sqlite3_errmsg(db)); \
  48. } while(0)
  49. /**
  50. * Entry type to be used in the map to store old latency values
  51. */
  52. struct Entry
  53. {
  54. /**
  55. * The peer's identity
  56. */
  57. struct GNUNET_PeerIdentity id;
  58. /**
  59. * The last known value for latency.
  60. * FIXME: type!
  61. */
  62. unsigned int latency;
  63. };
  64. /**
  65. * Handle to the map used to store old latency values for peers
  66. */
  67. static struct GNUNET_CONTAINER_MultiPeerMap *map;
  68. /**
  69. * The SQLite database handle
  70. */
  71. static struct sqlite3 *db;
  72. /**
  73. * Handle to the ATS performance subsystem
  74. */
  75. struct GNUNET_ATS_PerformanceHandle *ats;
  76. /**
  77. * Prepared statement for inserting values into the database table
  78. */
  79. struct sqlite3_stmt *stmt_insert;
  80. /**
  81. * Shutdown task identifier
  82. */
  83. struct GNUNET_SCHEDULER_Task * shutdown_task;
  84. /**
  85. * @ingroup hashmap
  86. * Iterator over hash map entries.
  87. *
  88. * @param cls closure
  89. * @param key current public key
  90. * @param value value in the hash map
  91. * @return #GNUNET_YES if we should continue to
  92. * iterate,
  93. * #GNUNET_NO if not.
  94. */
  95. static int
  96. free_iterator (void *cls,
  97. const struct GNUNET_PeerIdentity *key,
  98. void *value)
  99. {
  100. struct Entry *e = cls;
  101. GNUNET_assert (GNUNET_YES ==
  102. GNUNET_CONTAINER_multipeermap_remove (map, key, e));
  103. GNUNET_free (e);
  104. return GNUNET_YES;
  105. }
  106. /**
  107. * Shutdown
  108. *
  109. * @param cls NULL
  110. * @param tc task context from scheduler
  111. * @return
  112. */
  113. static void
  114. do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  115. {
  116. shutdown_task = NULL;
  117. GNUNET_ATS_performance_done (ats);
  118. ats = NULL;
  119. if (NULL != stmt_insert)
  120. {
  121. sqlite3_finalize (stmt_insert);
  122. stmt_insert = NULL;
  123. }
  124. GNUNET_break (SQLITE_OK == sqlite3_close (db));
  125. db = NULL;
  126. if (NULL != map)
  127. {
  128. GNUNET_assert (GNUNET_SYSERR !=
  129. GNUNET_CONTAINER_multipeermap_iterate (map, free_iterator, NULL));
  130. GNUNET_CONTAINER_multipeermap_destroy (map);
  131. map = NULL;
  132. }
  133. }
  134. /**
  135. * Signature of a function that is called with QoS information about an address.
  136. *
  137. * @param cls closure
  138. * @param address the address
  139. * @param address_active #GNUNET_YES if this address is actively used
  140. * to maintain a connection to a peer;
  141. * #GNUNET_NO if the address is not actively used;
  142. * #GNUNET_SYSERR if this address is no longer available for ATS
  143. * @param bandwidth_out assigned outbound bandwidth for the connection
  144. * @param bandwidth_in assigned inbound bandwidth for the connection
  145. * @param prop performance data for the address (as far as known)
  146. */
  147. static void
  148. addr_info_cb (void *cls,
  149. const struct GNUNET_HELLO_Address *address,
  150. int address_active,
  151. struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
  152. struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
  153. const struct GNUNET_ATS_Properties *prop)
  154. {
  155. static const char *query_insert =
  156. "INSERT INTO ats_info("
  157. " id,"
  158. " val,"
  159. " timestamp"
  160. ") VALUES ("
  161. " ?1,"
  162. " ?2,"
  163. " datetime('now')"
  164. ");";
  165. struct Entry *entry;
  166. int latency; /* FIXME: type!? */
  167. if (NULL == address)
  168. {
  169. /* ATS service temporarily disconnected */
  170. return;
  171. }
  172. GNUNET_assert (NULL != db);
  173. if (GNUNET_YES != address_active)
  174. return;
  175. latency = (int) prop->delay.rel_value_us;
  176. entry = NULL;
  177. if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (map,
  178. &address->peer))
  179. {
  180. entry = GNUNET_CONTAINER_multipeermap_get (map, &address->peer);
  181. GNUNET_assert (NULL != entry);
  182. if (latency == entry->latency)
  183. return;
  184. }
  185. if (NULL == stmt_insert)
  186. {
  187. if (SQLITE_OK != sqlite3_prepare_v2 (db, query_insert, -1, &stmt_insert,
  188. NULL))
  189. {
  190. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
  191. goto err_shutdown;
  192. }
  193. }
  194. if ( (SQLITE_OK != sqlite3_bind_text (stmt_insert, 1,
  195. GNUNET_i2s (&address->peer), -1,
  196. SQLITE_STATIC)) ||
  197. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, latency)) )
  198. {
  199. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_text");
  200. goto err_shutdown;
  201. }
  202. if (SQLITE_DONE != sqlite3_step (stmt_insert))
  203. {
  204. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
  205. goto err_shutdown;
  206. }
  207. if (SQLITE_OK != sqlite3_reset (stmt_insert))
  208. {
  209. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_insert");
  210. goto err_shutdown;
  211. }
  212. if (NULL == entry)
  213. {
  214. entry = GNUNET_new (struct Entry);
  215. entry->id = address->peer;
  216. GNUNET_CONTAINER_multipeermap_put (map,
  217. &entry->id, entry,
  218. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  219. }
  220. entry->latency = latency;
  221. return;
  222. err_shutdown:
  223. GNUNET_SCHEDULER_shutdown ();
  224. }
  225. /**
  226. * Main function that will be run.
  227. *
  228. * @param cls closure
  229. * @param args remaining command-line arguments
  230. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  231. * @param c configuration
  232. */
  233. static void
  234. run (void *cls, char *const *args, const char *cfgfile,
  235. const struct GNUNET_CONFIGURATION_Handle *c)
  236. {
  237. const char *query_create =
  238. "CREATE TABLE ats_info ("
  239. "id TEXT,"
  240. "val INTEGER,"
  241. "timestamp NUMERIC"
  242. ");";
  243. char *dbfile;
  244. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "LATENCY-LOGGER",
  245. "DBFILE",
  246. &dbfile))
  247. {
  248. GNUNET_break (0);
  249. return;
  250. }
  251. if (SQLITE_OK != sqlite3_open (dbfile, &db))
  252. {
  253. if (NULL != db)
  254. {
  255. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_open_v2");
  256. GNUNET_break (SQLITE_OK == sqlite3_close (db));
  257. }
  258. else
  259. LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot open sqlite file %s\n", dbfile);
  260. GNUNET_free (dbfile);
  261. return;
  262. }
  263. if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
  264. DEBUG ("SQLite Error: %d. Perhaps the database `%s' already exits.\n",
  265. sqlite3_errcode (db), dbfile);
  266. DEBUG ("Opened database %s\n", dbfile);
  267. GNUNET_free (dbfile);
  268. dbfile = NULL;
  269. ats = GNUNET_ATS_performance_init (c, &addr_info_cb, NULL);
  270. map = GNUNET_CONTAINER_multipeermap_create (30, GNUNET_YES);
  271. shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
  272. &do_shutdown, NULL);
  273. }
  274. /**
  275. * Execution entry point
  276. */
  277. int
  278. main (int argc, char * const *argv)
  279. {
  280. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  281. GNUNET_GETOPT_OPTION_END
  282. };
  283. int ret;
  284. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  285. return 2;
  286. ret =
  287. (GNUNET_OK ==
  288. GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-latency-logger",
  289. _("Daemon to log latency values of connections to neighbours"),
  290. options, &run, NULL)) ? 0 : 1;
  291. GNUNET_free ((void*) argv);
  292. return ret;
  293. }