generate-underlay-topology.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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/generate-underlay-topology.c
  19. * @brief Program to generate a database file containing given underlay topology
  20. * @author Sree Harsha Totakura <sreeharsha@totakura.in>
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_testbed_service.h"
  25. #include "testbed_api_topology.h"
  26. #include "sqlite3.h"
  27. #define LOG(type, ...) \
  28. GNUNET_log (type, __VA_ARGS__)
  29. #define LOG_ERROR(...) \
  30. LOG (GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
  31. /**
  32. * Log an error message at log-level 'level' that indicates
  33. * a failure of the command 'cmd' on file 'filename'
  34. * with the message given by strerror(errno).
  35. */
  36. #define LOG_SQLITE(db, msg, level, cmd) \
  37. do { \
  38. GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), \
  39. cmd, __FILE__,__LINE__, sqlite3_errmsg(db)); \
  40. if (msg != NULL) \
  41. GNUNET_asprintf(msg, _("`%s' failed at %s:%u with error: %s"), cmd, \
  42. __FILE__, __LINE__, sqlite3_errmsg(db)); \
  43. } while(0)
  44. /**
  45. * Handle to the sqlite3 database
  46. */
  47. static struct sqlite3 *db;
  48. /**
  49. * Prepared statement for inserting link values into db
  50. */
  51. struct sqlite3_stmt *stmt_insert;
  52. /**
  53. * The topology to generate
  54. */
  55. enum GNUNET_TESTBED_TopologyOption topology;
  56. /**
  57. * The number of peers to include in the topology
  58. */
  59. static int num_peers;
  60. /**
  61. * program result
  62. */
  63. static int exit_result;
  64. /**
  65. * Functions of this type are called to process underlay link
  66. *
  67. * @param cls closure
  68. * @param A offset of first peer
  69. * @param B offset of second peer
  70. * @param bandwidth the bandwidth of the link in bytes per second
  71. * @param latency the latency of link in milliseconds
  72. * @param loss the percentage of messages dropped on the link
  73. * @return GNUNET_OK to continue processing; GNUNET_SYSERR to abort
  74. */
  75. static int
  76. link_processor (void *cls,
  77. unsigned int A,
  78. unsigned int B,
  79. unsigned int bandwidth,
  80. unsigned int latency,
  81. unsigned int loss)
  82. {
  83. if ( (SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, A)) ||
  84. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, B)) ||
  85. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 3, bandwidth)) ||
  86. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 4, latency)) ||
  87. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 5, loss)) )
  88. {
  89. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
  90. return GNUNET_SYSERR;
  91. }
  92. if (SQLITE_DONE != sqlite3_step (stmt_insert))
  93. {
  94. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
  95. return GNUNET_SYSERR;
  96. }
  97. FPRINTF (stdout, "%u -> %u\n", A, B);
  98. GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
  99. //GNUNET_break (SQLITE_OK == sqlite3_clear_bindings (stmt_insert));
  100. if ( (SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, B)) ||
  101. (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, A)) )
  102. {
  103. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
  104. return GNUNET_SYSERR;
  105. }
  106. if (SQLITE_DONE != sqlite3_step (stmt_insert))
  107. {
  108. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
  109. return GNUNET_SYSERR;
  110. }
  111. FPRINTF (stdout, "%u -> %u\n", B, A);
  112. GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
  113. return GNUNET_OK;
  114. }
  115. /**
  116. * Open the database file, creating a new database if not existing and setup the
  117. * whitelist table
  118. *
  119. * @param dbfile the database filename
  120. * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure (error message has
  121. * to be printed)
  122. */
  123. static int
  124. setup_db (const char *dbfile)
  125. {
  126. const char *query_create =
  127. "CREATE TABLE whitelist ("
  128. "id INTEGER,"
  129. "oid INTEGER,"
  130. "bandwidth INTEGER DEFAULT NULL,"
  131. "latency INTEGER DEFAULT NULL,"
  132. "loss INTEGER DEFAULT NULL,"
  133. " UNIQUE ("
  134. " id,"
  135. " oid"
  136. " ) ON CONFLICT IGNORE"
  137. ");";
  138. const char *query_insert =
  139. "INSERT INTO whitelist("
  140. " id,"
  141. " oid,"
  142. " bandwidth,"
  143. " latency,"
  144. " loss"
  145. ") VALUES ("
  146. " ?1,"
  147. " ?2,"
  148. " ?3,"
  149. " ?4,"
  150. " ?5);";
  151. int ret;
  152. ret = GNUNET_SYSERR;
  153. if (SQLITE_OK != sqlite3_open (dbfile, &db))
  154. {
  155. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_open");
  156. goto err_ret;
  157. }
  158. if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
  159. {
  160. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
  161. FPRINTF (stderr, "Error: %d. Perhaps the database `%s' already exits.\n",
  162. sqlite3_errcode (db),
  163. dbfile);
  164. goto err_ret;
  165. }
  166. GNUNET_break (0 == sqlite3_exec (db, "PRAGMA synchronous = 0;", NULL, NULL, NULL));
  167. if (SQLITE_OK != sqlite3_prepare_v2 (db, query_insert, -1,
  168. &stmt_insert, NULL))
  169. {
  170. LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
  171. goto err_ret;
  172. }
  173. ret = GNUNET_OK;
  174. err_ret:
  175. return ret;
  176. }
  177. /**
  178. * Main run function.
  179. *
  180. * @param cls NULL
  181. * @param args arguments passed to GNUNET_PROGRAM_run
  182. * @param cfgfile the path to configuration file
  183. * @param cfg the configuration file handle
  184. */
  185. static void
  186. run (void *cls, char *const *args, const char *cfgfile,
  187. const struct GNUNET_CONFIGURATION_Handle *config)
  188. {
  189. const char *dbfile;
  190. const char *topology_string;
  191. unsigned int arg_uint1;
  192. unsigned int arg_uint2;
  193. const char *arg_str1;
  194. const char *value;
  195. unsigned int argc;
  196. argc = 0;
  197. if (NULL == args)
  198. {
  199. LOG_ERROR (_("Need atleast 2 arguments\n"));
  200. return;
  201. }
  202. if (NULL == (dbfile = args[argc++]))
  203. {
  204. LOG_ERROR (_("Database filename missing\n"));
  205. return;
  206. }
  207. if (GNUNET_OK != setup_db (dbfile))
  208. return;
  209. if (NULL == (topology_string = args[argc++]))
  210. {
  211. LOG_ERROR (_("Topology string missing\n"));
  212. return;
  213. }
  214. if (GNUNET_YES != GNUNET_TESTBED_topology_get_ (&topology, topology_string))
  215. {
  216. LOG_ERROR (_("Invalid topology: %s\n"), topology_string);
  217. return;
  218. }
  219. arg_str1 = NULL;
  220. /* parse for first TOPOOPT. This can either be arg_uint1 or arg_str1 */
  221. switch (topology)
  222. {
  223. case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
  224. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
  225. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
  226. case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
  227. if (NULL == (value = args[argc++]))
  228. {
  229. LOG_ERROR (_("An argument is missing for given topology `%s'\n"),
  230. topology_string);
  231. return;
  232. }
  233. if (-1 == SSCANF (value, "%u", &arg_uint1))
  234. {
  235. LOG_ERROR (_("Invalid argument `%s' given as topology argument\n"),
  236. value);
  237. return;
  238. }
  239. break;
  240. case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
  241. if (NULL == (arg_str1 = args[argc++]))
  242. {
  243. LOG_ERROR (_("Filename argument missing for topology `%s'\n"),
  244. topology_string);
  245. return;
  246. }
  247. break;
  248. default:
  249. break;
  250. }
  251. /* parse for second TOPOOPT. Only required for SCALE_FREE topology */
  252. switch (topology)
  253. {
  254. case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
  255. if (NULL == (value = args[argc++]))
  256. {
  257. LOG_ERROR (_("Second argument for topology `%s' is missing\n"),
  258. topology_string);
  259. return;
  260. }
  261. if (-1 == SSCANF (value, "%u", &arg_uint2))
  262. {
  263. LOG_ERROR (_("Invalid argument `%s'; expecting unsigned int\n"), value);
  264. return;
  265. }
  266. break;
  267. default:
  268. break;
  269. }
  270. /* contruct topologies */
  271. switch (topology)
  272. {
  273. case GNUNET_TESTBED_TOPOLOGY_LINE:
  274. case GNUNET_TESTBED_TOPOLOGY_RING:
  275. case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
  276. case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
  277. GNUNET_TESTBED_underlay_construct_ (num_peers, link_processor, NULL,
  278. topology);
  279. break;
  280. case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
  281. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
  282. case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
  283. GNUNET_TESTBED_underlay_construct_ (num_peers, link_processor, NULL,
  284. topology,
  285. arg_uint1);
  286. break;
  287. case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
  288. GNUNET_TESTBED_underlay_construct_ (num_peers, link_processor, NULL,
  289. topology,
  290. arg_str1);
  291. break;
  292. case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
  293. GNUNET_TESTBED_underlay_construct_ (num_peers, link_processor, NULL,
  294. topology,
  295. arg_uint1,
  296. arg_uint2);
  297. break;
  298. default:
  299. GNUNET_assert (0);
  300. }
  301. }
  302. /**
  303. * Main
  304. */
  305. int
  306. main (int argc, char *const argv[])
  307. {
  308. struct GNUNET_GETOPT_CommandLineOption option[] = {
  309. {'p', "num-peers", "COUNT",
  310. gettext_noop ("create COUNT number of peers"),
  311. GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers},
  312. GNUNET_GETOPT_OPTION_END
  313. };
  314. int ret;
  315. exit_result = GNUNET_SYSERR;
  316. ret =
  317. GNUNET_PROGRAM_run (argc, argv, "gnunet-underlay-topology",
  318. _("Generates SQLite3 database representing a given underlay topology.\n"
  319. "Usage: gnunet-underlay-topology [OPTIONS] db-filename TOPO [TOPOOPTS]\n"
  320. "The following options are available for TOPO followed by TOPOOPTS if applicable:\n"
  321. "\t LINE\n"
  322. "\t RING\n"
  323. "\t RANDOM <num_rnd_links>\n"
  324. "\t SMALL_WORLD <num_rnd_links>\n"
  325. "\t SMALL_WORLD_RING <num_rnd_links>\n"
  326. "\t CLIQUE\n"
  327. "\t 2D_TORUS\n"
  328. "\t SCALE_FREE <cap> <m>\n"
  329. "\t FROM_FILE <filename>\n"
  330. "TOPOOPTS:\n"
  331. "\t num_rnd_links: The number of random links\n"
  332. "\t cap: the maximum number of links a node can have\n"
  333. "\t m: the number of links a node should have while joining the network\n"
  334. "\t filename: the path of the file which contains topology information\n"
  335. "NOTE: the format of the above file is descibed here: https://www.gnunet.org/content/topology-file-format\n"),
  336. option, &run, NULL);
  337. if (NULL != stmt_insert)
  338. sqlite3_finalize (stmt_insert);
  339. if (NULL != db)
  340. sqlite3_close (db);
  341. if ((GNUNET_OK != ret) || (GNUNET_OK != exit_result))
  342. return 1;
  343. return 0;
  344. }