GNUnet  0.11.x
generate-underlay-topology.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2008--2014 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_testbed_service.h"
30 #include "testbed_api_topology.h"
31 #include "sqlite3.h"
32 
33 #define LOG(type, ...) GNUNET_log (type, __VA_ARGS__)
34 
35 
36 #define LOG_ERROR(...) LOG (GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
37 
43 #define LOG_SQLITE(db, msg, level, cmd) \
44  do \
45  { \
46  GNUNET_log_from (level, \
47  "sqlite", \
48  _ ("`%s' failed at %s:%d with error: %s\n"), \
49  cmd, \
50  __FILE__, \
51  __LINE__, \
52  sqlite3_errmsg (db)); \
53  if (msg != NULL) \
54  GNUNET_asprintf (msg, \
55  _ ("`%s' failed at %s:%u with error: %s"), \
56  cmd, \
57  __FILE__, \
58  __LINE__, \
59  sqlite3_errmsg (db)); \
60  } while (0)
61 
62 
66 static struct sqlite3 *db;
67 
71 struct sqlite3_stmt *stmt_insert;
72 
77 
81 static unsigned int num_peers;
82 
86 static int exit_result;
87 
88 
100 static int
101 link_processor (void *cls,
102  unsigned int A,
103  unsigned int B,
104  unsigned int bandwidth,
105  unsigned int latency,
106  unsigned int loss)
107 {
108  if ((SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, A)) ||
109  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, B)) ||
110  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 3, bandwidth)) ||
111  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 4, latency)) ||
112  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 5, loss)))
113  {
114  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
115  return GNUNET_SYSERR;
116  }
117  if (SQLITE_DONE != sqlite3_step (stmt_insert))
118  {
119  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
120  return GNUNET_SYSERR;
121  }
122  fprintf (stdout, "%u -> %u\n", A, B);
123  GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
124  // GNUNET_break (SQLITE_OK == sqlite3_clear_bindings (stmt_insert));
125  if ((SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, B)) ||
126  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, A)))
127  {
128  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
129  return GNUNET_SYSERR;
130  }
131  if (SQLITE_DONE != sqlite3_step (stmt_insert))
132  {
133  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
134  return GNUNET_SYSERR;
135  }
136  fprintf (stdout, "%u -> %u\n", B, A);
137  GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
138  return GNUNET_OK;
139 }
140 
141 
150 static int
151 setup_db (const char *dbfile)
152 {
153  const char *query_create = "CREATE TABLE whitelist ("
154  "id INTEGER,"
155  "oid INTEGER,"
156  "bandwidth INTEGER DEFAULT NULL,"
157  "latency INTEGER DEFAULT NULL,"
158  "loss INTEGER DEFAULT NULL,"
159  " UNIQUE ("
160  " id,"
161  " oid"
162  " ) ON CONFLICT IGNORE"
163  ");";
164  const char *query_insert = "INSERT INTO whitelist("
165  " id,"
166  " oid,"
167  " bandwidth,"
168  " latency,"
169  " loss"
170  ") VALUES ("
171  " ?1,"
172  " ?2,"
173  " ?3,"
174  " ?4,"
175  " ?5);";
176  int ret;
177 
178  ret = GNUNET_SYSERR;
179  if (SQLITE_OK != sqlite3_open (dbfile, &db))
180  {
181  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_open");
182  goto err_ret;
183  }
184  if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
185  {
186  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
187  fprintf (stderr,
188  "Error: %d. Perhaps the database `%s' already exits.\n",
189  sqlite3_errcode (db),
190  dbfile);
191  goto err_ret;
192  }
193  GNUNET_break (0 ==
194  sqlite3_exec (db, "PRAGMA synchronous = 0;", NULL, NULL, NULL));
195  if (SQLITE_OK !=
196  sqlite3_prepare_v2 (db, query_insert, -1, &stmt_insert, NULL))
197  {
198  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
199  goto err_ret;
200  }
201  ret = GNUNET_OK;
202 
203 err_ret:
204  return ret;
205 }
206 
207 
216 static void
217 run (void *cls,
218  char *const *args,
219  const char *cfgfile,
220  const struct GNUNET_CONFIGURATION_Handle *config)
221 {
222  const char *dbfile;
223  const char *topology_string;
224  unsigned int arg_uint1;
225  unsigned int arg_uint2;
226  const char *arg_str1;
227  const char *value;
228  unsigned int argc;
229 
230  argc = 0;
231  arg_uint1 = 0; /* make compilers happy */
232  arg_uint2 = 0; /* make compilers happy */
233  if (NULL == args)
234  {
235  LOG_ERROR (_ ("Need at least 2 arguments\n"));
236  return;
237  }
238  if (NULL == (dbfile = args[argc++]))
239  {
240  LOG_ERROR (_ ("Database filename missing\n"));
241  return;
242  }
243  if (GNUNET_OK != setup_db (dbfile))
244  return;
245  if (NULL == (topology_string = args[argc++]))
246  {
247  LOG_ERROR (_ ("Topology string missing\n"));
248  return;
249  }
250  if (GNUNET_YES != GNUNET_TESTBED_topology_get_ (&topology, topology_string))
251  {
252  LOG_ERROR (_ ("Invalid topology: %s\n"), topology_string);
253  return;
254  }
255  arg_str1 = NULL;
256  /* parse for first TOPOOPT. This can either be arg_uint1 or arg_str1 */
257  switch (topology)
258  {
263  if (NULL == (value = args[argc++]))
264  {
265  LOG_ERROR (_ ("An argument is missing for given topology `%s'\n"),
266  topology_string);
267  return;
268  }
269  if (-1 == sscanf (value, "%u", &arg_uint1))
270  {
271  LOG_ERROR (_ ("Invalid argument `%s' given as topology argument\n"),
272  value);
273  return;
274  }
275  break;
276 
278  if (NULL == (arg_str1 = args[argc++]))
279  {
280  LOG_ERROR (_ ("Filename argument missing for topology `%s'\n"),
281  topology_string);
282  return;
283  }
284  break;
285 
286  default:
287  break;
288  }
289  /* parse for second TOPOOPT. Only required for SCALE_FREE topology */
290  switch (topology)
291  {
293  if (NULL == (value = args[argc++]))
294  {
295  LOG_ERROR (_ ("Second argument for topology `%s' is missing\n"),
296  topology_string);
297  return;
298  }
299  if (-1 == sscanf (value, "%u", &arg_uint2))
300  {
301  LOG_ERROR (_ ("Invalid argument `%s'; expecting unsigned int\n"), value);
302  return;
303  }
304  break;
305 
306  default:
307  break;
308  }
309  /* contruct topologies */
310  switch (topology)
311  {
319  NULL,
320  topology);
321  break;
322 
328  NULL,
329  topology,
330  arg_uint1);
331  break;
332 
336  NULL,
337  topology,
338  arg_str1);
339  break;
340 
344  NULL,
345  topology,
346  arg_uint1,
347  arg_uint2);
348  break;
349 
350  default:
351  GNUNET_assert (0);
352  }
353 }
354 
355 
359 int
360 main (int argc, char *const argv[])
361 {
362  struct GNUNET_GETOPT_CommandLineOption option[] = {
364  "num-peers",
365  "COUNT",
366  gettext_noop ("create COUNT number of peers"),
367  &num_peers),
369  };
370 
371  int ret;
372 
374  ret = GNUNET_PROGRAM_run (
375  argc,
376  argv,
377  "gnunet-underlay-topology",
378  _ (
379  "Generates SQLite3 database representing a given underlay topology.\n"
380  "Usage: gnunet-underlay-topology [OPTIONS] db-filename TOPO [TOPOOPTS]\n"
381  "The following options are available for TOPO followed by TOPOOPTS if applicable:\n"
382  "\t LINE\n"
383  "\t RING\n"
384  "\t RANDOM <num_rnd_links>\n"
385  "\t SMALL_WORLD <num_rnd_links>\n"
386  "\t SMALL_WORLD_RING <num_rnd_links>\n"
387  "\t CLIQUE\n"
388  "\t 2D_TORUS\n"
389  "\t SCALE_FREE <cap> <m>\n"
390  "\t FROM_FILE <filename>\n"
391  "TOPOOPTS:\n"
392  "\t num_rnd_links: The number of random links\n"
393  "\t cap: the maximum number of links a node can have\n"
394  "\t m: the number of links a node should have while joining the network\n"
395  "\t filename: the path of the file which contains topology information\n"
396  "NOTE: the format of the above file is descibed here: https://www.gnunet.org/content/topology-file-format\n"),
397  option,
398  &run,
399  NULL);
400  if (NULL != stmt_insert)
401  sqlite3_finalize (stmt_insert);
402  if (NULL != db)
403  GNUNET_break (SQLITE_OK == sqlite3_close (db));
404  if ((GNUNET_OK != ret) || (GNUNET_OK != exit_result))
405  return 1;
406  return 0;
407 }
A clique (everyone connected to everyone else).
int GNUNET_TESTBED_underlay_construct_(int num_peers, underlay_link_processor proc, void *cls,...)
Function to construct an underlay topology.
GNUNET_TESTBED_TopologyOption
Topologies and topology options supported for testbeds.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static int exit_result
program result
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
enum GNUNET_TESTBED_TopologyOption topology
The topology to generate.
Definition of a command line option.
static int setup_db(const char *dbfile)
Open the database file, creating a new database if not existing and setup the whitelist table...
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
Read a topology from a given file.
static char * value
Value of the record to add/remove.
static struct sqlite3 * db
Handle to the sqlite3 database.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *config)
Main run function.
#define LOG_ERROR(...)
struct sqlite3_stmt * stmt_insert
Prepared statement for inserting link values into db.
static const struct GNUNET_CONFIGURATION_Handle * config
static int link_processor(void *cls, unsigned int A, unsigned int B, unsigned int bandwidth, unsigned int latency, unsigned int loss)
Functions of this type are called to process underlay link.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
Small-world network (2d torus plus random links).
int main(int argc, char *const argv[])
Main.
#define LOG_SQLITE(db, msg, level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; on file &#39;file...
configuration data
Definition: configuration.c:85
int GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:367
static unsigned int num_peers
The number of peers to include in the topology.
#define GNUNET_YES
Definition: gnunet_common.h:77
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint(char shortName, const char *name, const char *argumentHelp, const char *description, unsigned int *val)
Allow user to specify an unsigned int.
header for intra library exported functions
int GNUNET_TESTBED_topology_get_(enum GNUNET_TESTBED_TopologyOption *topology, const char *topology_string)
Get a topology from a string input.
#define gettext_noop(String)
Definition: gettext.h:69
Small-world network (ring plus random links).