+
+/**
+ * Function to construct an underlay topology
+ *
+ * @param num_peers the number of peers for which the topology should be
+ * generated
+ * @param proc the underlay link processor callback. Will be called for each
+ * underlay link generated unless a previous call to this callback
+ * returned #GNUNET_SYSERR. Cannot be NULL.
+ * @param cls closure for @a proc
+ * @param ... variable arguments denoting the topology and its parameters. They
+ * should start with the type of topology to generate followed by their
+ * options.
+ * @return #GNUNET_OK if underlay link generation is successful; #GNUNET_SYSERR
+ * upon error in generating the underlay or if any calls to the
+ * underlay link processor returned #GNUNET_SYSERR
+ */
+int
+GNUNET_TESTBED_underlay_construct_ (int num_peers,
+ underlay_link_processor proc,
+ void *cls,
+ ...)
+{
+ struct TopologyContext tc;
+ struct TopologyContextUnderlay *underlay;
+ struct UnderlayLink *ulink;
+ va_list vargs;
+ enum GNUNET_TESTBED_TopologyOption topology;
+ unsigned int cnt;
+ int ret;
+
+ GNUNET_assert (NULL != proc);
+ ret = GNUNET_OK;
+ memset (&tc, 0, sizeof (tc));
+ tc.num_peers = num_peers;
+ tc.type = TOPOLOGYCONTEXT_TYPE_UNDERLAY;
+ underlay = &tc.u.underlay;
+ va_start (vargs, cls);
+ topology = va_arg (vargs, enum GNUNET_TESTBED_TopologyOption);
+ switch (topology)
+ {
+ case GNUNET_TESTBED_TOPOLOGY_LINE:
+ gen_topo_line (&tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_RING:
+ gen_topo_ring (&tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
+ gen_topo_clique (&tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
+ gen_topo_2dtorus (&tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
+ gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_NO);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
+ gen_topo_ring (&tc);
+ gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
+ gen_topo_2dtorus (&tc);
+ gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
+ {
+ const char *filename;
+ filename = va_arg (vargs, char *);
+ GNUNET_assert (NULL != filename);
+ gen_topo_from_file (&tc, filename);
+ }
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
+ {
+ uint16_t cap;
+ uint8_t m;
+ cap = (uint16_t) va_arg (vargs, unsigned int);
+ m = (uint8_t) va_arg (vargs, unsigned int);
+ gen_topo_scale_free (&tc, cap, m);
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ va_end (vargs);
+ for (cnt = 0; cnt < tc.link_array_size; cnt++)
+ {
+ ulink = &underlay->link_array[cnt];
+ if (GNUNET_SYSERR == proc (cls,
+ ulink->A,
+ ulink->B,
+ ulink->bandwidth,
+ ulink->latency,
+ ulink->loss))
+ {
+ ret = GNUNET_SYSERR;
+ break;
+ }
+ }
+ GNUNET_free_non_null (underlay->link_array);
+ return ret;
+}
+