GNUnet  0.10.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, ...) \
34  GNUNET_log (type, __VA_ARGS__)
35 
36 
37 #define LOG_ERROR(...) \
38  LOG (GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
39 
45 #define LOG_SQLITE(db, msg, level, cmd) \
46  do { \
47  GNUNET_log_from (level, "sqlite", _("`%s' failed at %s:%d with error: %s\n"), \
48  cmd, __FILE__,__LINE__, sqlite3_errmsg(db)); \
49  if (msg != NULL) \
50  GNUNET_asprintf(msg, _("`%s' failed at %s:%u with error: %s"), cmd, \
51  __FILE__, __LINE__, sqlite3_errmsg(db)); \
52  } while(0)
53 
54 
58 static struct sqlite3 *db;
59 
63 struct sqlite3_stmt *stmt_insert;
64 
69 
73 static unsigned int num_peers;
74 
78 static int exit_result;
79 
80 
92 static int
93 link_processor (void *cls,
94  unsigned int A,
95  unsigned int B,
96  unsigned int bandwidth,
97  unsigned int latency,
98  unsigned int loss)
99 {
100  if ( (SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, A)) ||
101  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, B)) ||
102  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 3, bandwidth)) ||
103  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 4, latency)) ||
104  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 5, loss)) )
105  {
106  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
107  return GNUNET_SYSERR;
108  }
109  if (SQLITE_DONE != sqlite3_step (stmt_insert))
110  {
111  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
112  return GNUNET_SYSERR;
113  }
114  FPRINTF (stdout, "%u -> %u\n", A, B);
115  GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
116  //GNUNET_break (SQLITE_OK == sqlite3_clear_bindings (stmt_insert));
117  if ( (SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, B)) ||
118  (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, A)) )
119  {
120  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
121  return GNUNET_SYSERR;
122  }
123  if (SQLITE_DONE != sqlite3_step (stmt_insert))
124  {
125  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
126  return GNUNET_SYSERR;
127  }
128  FPRINTF (stdout, "%u -> %u\n", B, A);
129  GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
130  return GNUNET_OK;
131 }
132 
133 
142 static int
143 setup_db (const char *dbfile)
144 {
145  const char *query_create =
146  "CREATE TABLE whitelist ("
147  "id INTEGER,"
148  "oid INTEGER,"
149  "bandwidth INTEGER DEFAULT NULL,"
150  "latency INTEGER DEFAULT NULL,"
151  "loss INTEGER DEFAULT NULL,"
152  " UNIQUE ("
153  " id,"
154  " oid"
155  " ) ON CONFLICT IGNORE"
156  ");";
157  const char *query_insert =
158  "INSERT INTO whitelist("
159  " id,"
160  " oid,"
161  " bandwidth,"
162  " latency,"
163  " loss"
164  ") VALUES ("
165  " ?1,"
166  " ?2,"
167  " ?3,"
168  " ?4,"
169  " ?5);";
170  int ret;
171 
172  ret = GNUNET_SYSERR;
173  if (SQLITE_OK != sqlite3_open (dbfile, &db))
174  {
175  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_open");
176  goto err_ret;
177  }
178  if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
179  {
180  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
181  FPRINTF (stderr, "Error: %d. Perhaps the database `%s' already exits.\n",
182  sqlite3_errcode (db),
183  dbfile);
184  goto err_ret;
185  }
186  GNUNET_break (0 == sqlite3_exec (db, "PRAGMA synchronous = 0;", NULL, NULL, NULL));
187  if (SQLITE_OK != sqlite3_prepare_v2 (db, query_insert, -1,
188  &stmt_insert, NULL))
189  {
190  LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
191  goto err_ret;
192  }
193  ret = GNUNET_OK;
194 
195  err_ret:
196  return ret;
197 }
198 
199 
208 static void
209 run (void *cls, char *const *args, const char *cfgfile,
210  const struct GNUNET_CONFIGURATION_Handle *config)
211 {
212  const char *dbfile;
213  const char *topology_string;
214  unsigned int arg_uint1;
215  unsigned int arg_uint2;
216  const char *arg_str1;
217  const char *value;
218  unsigned int argc;
219 
220  argc = 0;
221  arg_uint1 = 0; /* make compilers happy */
222  arg_uint2 = 0; /* make compilers happy */
223  if (NULL == args)
224  {
225  LOG_ERROR (_("Need at least 2 arguments\n"));
226  return;
227  }
228  if (NULL == (dbfile = args[argc++]))
229  {
230  LOG_ERROR (_("Database filename missing\n"));
231  return;
232  }
233  if (GNUNET_OK != setup_db (dbfile))
234  return;
235  if (NULL == (topology_string = args[argc++]))
236  {
237  LOG_ERROR (_("Topology string missing\n"));
238  return;
239  }
240  if (GNUNET_YES != GNUNET_TESTBED_topology_get_ (&topology, topology_string))
241  {
242  LOG_ERROR (_("Invalid topology: %s\n"), topology_string);
243  return;
244  }
245  arg_str1 = NULL;
246  /* parse for first TOPOOPT. This can either be arg_uint1 or arg_str1 */
247  switch (topology)
248  {
253  if (NULL == (value = args[argc++]))
254  {
255  LOG_ERROR (_("An argument is missing for given topology `%s'\n"),
256  topology_string);
257  return;
258  }
259  if (-1 == SSCANF (value, "%u", &arg_uint1))
260  {
261  LOG_ERROR (_("Invalid argument `%s' given as topology argument\n"),
262  value);
263  return;
264  }
265  break;
267  if (NULL == (arg_str1 = args[argc++]))
268  {
269  LOG_ERROR (_("Filename argument missing for topology `%s'\n"),
270  topology_string);
271  return;
272  }
273  break;
274  default:
275  break;
276  }
277  /* parse for second TOPOOPT. Only required for SCALE_FREE topology */
278  switch (topology)
279  {
281  if (NULL == (value = args[argc++]))
282  {
283  LOG_ERROR (_("Second argument for topology `%s' is missing\n"),
284  topology_string);
285  return;
286  }
287  if (-1 == SSCANF (value, "%u", &arg_uint2))
288  {
289  LOG_ERROR (_("Invalid argument `%s'; expecting unsigned int\n"), value);
290  return;
291  }
292  break;
293  default:
294  break;
295  }
296  /* contruct topologies */
297  switch (topology)
298  {
305  topology);
306  break;
311  topology,
312  arg_uint1);
313  break;
316  topology,
317  arg_str1);
318  break;
321  topology,
322  arg_uint1,
323  arg_uint2);
324  break;
325  default:
326  GNUNET_assert (0);
327  }
328 }
329 
330 
334 int
335 main (int argc, char *const argv[])
336 {
337  struct GNUNET_GETOPT_CommandLineOption option[] = {
338 
340  "num-peers",
341  "COUNT",
342  gettext_noop ("create COUNT number of peers"),
343  &num_peers),
345  };
346 
347  int ret;
348 
350  ret =
351  GNUNET_PROGRAM_run (argc, argv, "gnunet-underlay-topology",
352  _("Generates SQLite3 database representing a given underlay topology.\n"
353  "Usage: gnunet-underlay-topology [OPTIONS] db-filename TOPO [TOPOOPTS]\n"
354  "The following options are available for TOPO followed by TOPOOPTS if applicable:\n"
355  "\t LINE\n"
356  "\t RING\n"
357  "\t RANDOM <num_rnd_links>\n"
358  "\t SMALL_WORLD <num_rnd_links>\n"
359  "\t SMALL_WORLD_RING <num_rnd_links>\n"
360  "\t CLIQUE\n"
361  "\t 2D_TORUS\n"
362  "\t SCALE_FREE <cap> <m>\n"
363  "\t FROM_FILE <filename>\n"
364  "TOPOOPTS:\n"
365  "\t num_rnd_links: The number of random links\n"
366  "\t cap: the maximum number of links a node can have\n"
367  "\t m: the number of links a node should have while joining the network\n"
368  "\t filename: the path of the file which contains topology information\n"
369  "NOTE: the format of the above file is descibed here: https://www.gnunet.org/content/topology-file-format\n"),
370  option, &run, NULL);
371  if (NULL != stmt_insert)
372  sqlite3_finalize (stmt_insert);
373  if (NULL != db)
374  GNUNET_break (SQLITE_OK == sqlite3_close (db));
375  if ((GNUNET_OK != ret) || (GNUNET_OK != exit_result))
376  return 1;
377  return 0;
378 }
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 FPRINTF
Definition: plibc.h:683
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static int exit_result
program result
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
enum GNUNET_TESTBED_TopologyOption topology
The topology to generate.
Definition of a command line option.
static int ret
Final status code.
Definition: gnunet-arm.c:89
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:208
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:79
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...
#define SSCANF
Definition: plibc.h:691
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:361
static unsigned int num_peers
The number of peers to include in the topology.
#define GNUNET_YES
Definition: gnunet_common.h:80
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).