gnunet-daemon-latency-logger.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. This file is part of GNUnet
  3. (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. */
  61. unsigned int latency;
  62. };
  63. /**
  64. * Handle to the map used to store old latency values for peers
  65. */
  66. static struct GNUNET_CONTAINER_MultiPeerMap *map;
  67. /**
  68. * The SQLite database handle
  69. */
  70. static struct sqlite3 *db;
  71. /**
  72. * Handle to the ATS performance subsystem
  73. */
  74. struct GNUNET_ATS_PerformanceHandle *ats;
  75. /**
  76. * Prepared statement for inserting values into the database table
  77. */
  78. struct sqlite3_stmt *stmt_insert;
  79. /**
  80. * Shutdown task identifier
  81. */
  82. GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
  83. /**
  84. * @ingroup hashmap
  85. * Iterator over hash map entries.
  86. *
  87. * @param cls closure
  88. * @param key current public key
  89. * @param value value in the hash map
  90. * @return #GNUNET_YES if we should continue to
  91. * iterate,
  92. * #GNUNET_NO if not.
  93. */
  94. static int
  95. free_iterator (void *cls,
  96. const struct GNUNET_PeerIdentity *key,
  97. void *value)
  98. {
  99. struct Entry *e = cls;
  100. GNUNET_assert (GNUNET_YES ==
  101. GNUNET_CONTAINER_multipeermap_remove (map, key, e));
  102. GNUNET_free (e);
  103. return GNUNET_YES;
  104. }
  105. /**
  106. * Shutdown
  107. *
  108. * @param cls NULL
  109. * @param tc task context from scheduler
  110. * @return
  111. */
  112. static void
  113. do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  114. {
  115. shutdown_task = GNUNET_SCHEDULER_NO_TASK;
  116. GNUNET_ATS_performance_done (ats);
  117. ats = NULL;
  118. if (NULL != stmt_insert)
  119. {
  120. sqlite3_finalize (stmt_insert);
  121. stmt_insert = NULL;
  122. }
  123. GNUNET_break (SQLITE_OK == sqlite3_close (db));
  124. db = NULL;
  125. if (NULL != map)
  126. {
  127. GNUNET_assert (GNUNET_SYSERR !=
  128. GNUNET_CONTAINER_multipeermap_iterate (map, free_iterator, NULL));
  129. GNUNET_CONTAINER_multipeermap_destroy (map);
  130. map = NULL;
  131. }
  132. }
  133. /**
  134. * Signature of a function that is called with QoS information about an address.
  135. *
  136. * @param cls closure
  137. * @param address the address
  138. * @param address_active #GNUNET_YES if this address is actively used
  139. * to maintain a connection to a peer;
  140. * #GNUNET_NO if the address is not actively used;
  141. * #GNUNET_SYSERR if this address is no longer available for ATS
  142. * @param bandwidth_out assigned outbound bandwidth for the connection
  143. * @param bandwidth_in assigned inbound bandwidth for the connection
  144. * @param ats performance data for the address (as far as known)
  145. * @param ats_count number of performance records in 'ats'
  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_Information *ats,
  154. uint32_t ats_count)
  155. {
  156. static const char *query_insert =
  157. "INSERT INTO ats_info("
  158. " id,"
  159. " val,"
  160. " timestamp"
  161. ") VALUES ("
  162. " ?1,"
  163. " ?2,"
  164. " datetime('now')"
  165. ");";
  166. struct Entry *entry;
  167. int latency;
  168. unsigned int cnt;
  169. if (NULL == address)
  170. {
  171. /* ATS service temporarily disconnected */
  172. return;
  173. }
  174. GNUNET_assert (NULL != db);
  175. if (GNUNET_YES != address_active)
  176. return;
  177. for (cnt = 0; cnt < ats_count; cnt++)
  178. {
  179. if (GNUNET_ATS_QUALITY_NET_DELAY == ntohl (ats[cnt].type))
  180. goto insert;
  181. }
  182. return;
  183. insert:
  184. latency = (int) ntohl (ats[cnt].value);
  185. entry = NULL;
  186. if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (map,
  187. &address->peer))
  188. {
  189. entry = GNUNET_CONTAINER_multipeermap_get (map, &address->peer);
  190. GNUNET_assert (NULL != entry);
  191. if (latency == entry->latency)
  192. return;
  193. }
  194. if (NULL == stmt_insert)
  195. {
  196. if (SQLITE_OK != sqlite3_prepare_v2 (db, query_insert, -1, &stmt_insert,
  197. NULL))
  198. {
  199. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
  200. goto err_shutdown;
  201. }
  202. }
  203. if ( (SQLITE_OK != sqlite3_bind_text (stmt_insert, 1,
  204. GNUNET_i2s (&address->peer), -1,
  205. SQLITE_STATIC)) ||
  206. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, latency)) )
  207. {
  208. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_text");
  209. goto err_shutdown;
  210. }
  211. if (SQLITE_DONE != sqlite3_step (stmt_insert))
  212. {
  213. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
  214. goto err_shutdown;
  215. }
  216. if (SQLITE_OK != sqlite3_reset (stmt_insert))
  217. {
  218. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_insert");
  219. goto err_shutdown;
  220. }
  221. if (NULL == entry)
  222. {
  223. entry = GNUNET_new (struct Entry);
  224. entry->id = address->peer;
  225. GNUNET_CONTAINER_multipeermap_put (map,
  226. &entry->id, entry,
  227. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
  228. }
  229. entry->latency = latency;
  230. return;
  231. err_shutdown:
  232. GNUNET_SCHEDULER_shutdown ();
  233. }
  234. /**
  235. * Main function that will be run.
  236. *
  237. * @param cls closure
  238. * @param args remaining command-line arguments
  239. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  240. * @param c configuration
  241. */
  242. static void
  243. run (void *cls, char *const *args, const char *cfgfile,
  244. const struct GNUNET_CONFIGURATION_Handle *c)
  245. {
  246. const char *query_create =
  247. "CREATE TABLE ats_info ("
  248. "id TEXT,"
  249. "val INTEGER,"
  250. "timestamp NUMERIC"
  251. ");";
  252. char *dbfile;
  253. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "LATENCY-LOGGER",
  254. "DBFILE",
  255. &dbfile))
  256. {
  257. GNUNET_break (0);
  258. return;
  259. }
  260. if (SQLITE_OK != sqlite3_open (dbfile, &db))
  261. {
  262. if (NULL != db)
  263. {
  264. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_open_v2");
  265. sqlite3_close (db);
  266. }
  267. else
  268. LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot open sqlite file %s\n", dbfile);
  269. GNUNET_free (dbfile);
  270. return;
  271. }
  272. if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
  273. DEBUG ("SQLite Error: %d. Perhaps the database `%s' already exits.\n",
  274. sqlite3_errcode (db), dbfile);
  275. DEBUG ("Opened database %s\n", dbfile);
  276. GNUNET_free (dbfile);
  277. dbfile = NULL;
  278. ats = GNUNET_ATS_performance_init (c, &addr_info_cb, NULL);
  279. map = GNUNET_CONTAINER_multipeermap_create (30, GNUNET_YES);
  280. shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
  281. &do_shutdown, NULL);
  282. }
  283. /**
  284. * Execution entry point
  285. */
  286. int
  287. main (int argc, char * const *argv)
  288. {
  289. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  290. GNUNET_GETOPT_OPTION_END
  291. };
  292. int ret;
  293. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  294. return 2;
  295. ret =
  296. (GNUNET_OK ==
  297. GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-latency-logger",
  298. _("Daemon to log latency values of connections to neighbours"),
  299. options, &run, NULL)) ? 0 : 1;
  300. GNUNET_free ((void*) argv);
  301. return ret;
  302. }