generate-underlay-topology.c 12 KB

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