diff options
Diffstat (limited to 'src/testbed/testbed_api_topology.c')
-rw-r--r-- | src/testbed/testbed_api_topology.c | 1000 |
1 files changed, 974 insertions, 26 deletions
diff --git a/src/testbed/testbed_api_topology.c b/src/testbed/testbed_api_topology.c index c0e9f72..9618f98 100644 --- a/src/testbed/testbed_api_topology.c +++ b/src/testbed/testbed_api_topology.c @@ -25,6 +25,768 @@ */ #include "platform.h" #include "gnunet_testbed_service.h" +#include "testbed_api.h" +#include "testbed_api_peers.h" +#include "testbed_api_operations.h" +#include "testbed_api_topology.h" + +/** + * Generic loggins shorthand + */ +#define LOG(kind,...) \ + GNUNET_log_from (kind, "testbed-api-topology", __VA_ARGS__) + + +/** + * Default number of retires + */ +#define DEFAULT_RETRY_CNT 3 + + +/** + * Context information for topology operations + */ +struct TopologyContext; + + +/** + * Representation of an overlay link + */ +struct OverlayLink +{ + + /** + * An operation corresponding to this link + */ + struct GNUNET_TESTBED_Operation *op; + + /** + * The topology context this link is a part of + */ + struct TopologyContext *tc; + + /** + * position of peer A's handle in peers array + */ + uint32_t A; + + /** + * position of peer B's handle in peers array + */ + uint32_t B; + +}; + + +struct RetryListEntry +{ + /** + * the next pointer for the DLL + */ + struct RetryListEntry *next; + + /** + * the prev pointer for the DLL + */ + struct RetryListEntry *prev; + + /** + * The link to be retired + */ + struct OverlayLink *link; +}; + + +/** + * Context information for topology operations + */ +struct TopologyContext +{ + /** + * The array of peers + */ + struct GNUNET_TESTBED_Peer **peers; + + /** + * An array of links; this array is of size link_array_size + */ + struct OverlayLink *link_array; + + /** + * The operation closure + */ + void *op_cls; + + /** + * topology generation completion callback + */ + GNUNET_TESTBED_TopologyCompletionCallback comp_cb; + + /** + * The closure for the above callback + */ + void *comp_cb_cls; + + /** + * DLL head for retry list + */ + struct RetryListEntry *rl_head; + + /** + * DLL tail for retry list + */ + struct RetryListEntry *rl_tail; + + /** + * The number of peers + */ + unsigned int num_peers; + + /** + * The size of the link array + */ + unsigned int link_array_size; + + /** + * How many retries to do before we give up + */ + unsigned int retry_cnt; + + /** + * Number of links to try + */ + unsigned int nlinks; + + /** + * How many links have been completed + */ + unsigned int ncompleted; + + /** + * Total successfully established overlay connections + */ + unsigned int nsuccess; + + /** + * Total failed overlay connections + */ + unsigned int nfailures; +}; + + +/** + * A array of names representing topologies. Should be in sync with enum + * GNUNET_TESTBED_TopologyOption + */ +const char *topology_strings[] = { + + /** + * A clique (everyone connected to everyone else). No options. If there are N + * peers this topology results in (N * (N -1)) connections. + */ + "CLIQUE", + + /** + * Small-world network (2d torus plus random links). Followed + * by the number of random links to add (unsigned int). + */ + "SMALL_WORLD", + + /** + * Small-world network (ring plus random links). Followed + * by the number of random links to add (unsigned int). + */ + "SMALL_WORLD_RING", + + /** + * Ring topology. No options. + */ + "RING", + + /** + * 2-d torus. No options. + */ + "2D_TORUS", + + /** + * Random graph. Followed by the number of random links to be established + * (unsigned int) + */ + "RANDOM", // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI + + /** + * Certain percentage of peers are unable to communicate directly + * replicating NAT conditions. Followed by the fraction of + * NAT'ed peers (float). + */ + "INTERNAT", + + /** + * Scale free topology. No options. + */ + "SCALE_FREE", + + /** + * Straight line topology. No options. + */ + "LINE", + + /** + * Read a topology from a given file. Followed by the name of the file (const char *). + */ + "FROM_FILE", + + /** + * All peers are disconnected. No options. + */ + "NONE", + + /** + * End of strings + */ + NULL +}; + + +/** + * Callback to be called when an overlay_link operation complete + * + * @param cls element of the link_op array which points to the corresponding operation + * @param op the operation that has been finished + * @param emsg error message in case the operation has failed; will be NULL if + * operation has executed successfully. + */ +static void +overlay_link_completed (void *cls, struct GNUNET_TESTBED_Operation *op, + const char *emsg) +{ + struct OverlayLink *link = cls; + struct TopologyContext *tc; + struct RetryListEntry *retry_entry; + + GNUNET_assert (op == link->op); + GNUNET_TESTBED_operation_done (op); + link->op = NULL; + tc = link->tc; + if (NULL != emsg) + { + tc->nfailures++; + if (0 != tc->retry_cnt) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Error while establishing a link: %s -- Retrying\n", emsg); + retry_entry = GNUNET_malloc (sizeof (struct RetryListEntry)); + retry_entry->link = link; + GNUNET_CONTAINER_DLL_insert_tail (tc->rl_head, tc->rl_tail, retry_entry); + } + } + else + tc->nsuccess++; + tc->ncompleted++; + if (tc->ncompleted < tc->nlinks) + return; + if ((0 != tc->retry_cnt) && (NULL != tc->rl_head)) + { + tc->retry_cnt--; + tc->ncompleted = 0; + tc->nlinks = 0; + while (NULL != (retry_entry = tc->rl_head)) + { + link = retry_entry->link; + link->op = + GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed, + link, tc->peers[link->A], + tc->peers[link->B]); + tc->nlinks++; + GNUNET_CONTAINER_DLL_remove (tc->rl_head, tc->rl_tail, retry_entry); + GNUNET_free (retry_entry); + } + return; + } + if (NULL != tc->comp_cb) + { + tc->comp_cb (tc->comp_cb_cls, tc->nsuccess, tc->nfailures); + } +} + + + +/** + * Function called when a overlay connect operation is ready + * + * @param cls the Topology context + */ +static void +opstart_overlay_configure_topology (void *cls) +{ + struct TopologyContext *tc = cls; + unsigned int p; + + tc->nlinks = tc->link_array_size; + for (p = 0; p < tc->link_array_size; p++) + { + tc->link_array[p].op = + GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed, + &tc->link_array[p], + tc->peers[tc->link_array[p].A], + tc->peers[tc->link_array[p].B]); + } +} + + +/** + * Callback which will be called when overlay connect operation is released + * + * @param cls the Topology context + */ +static void +oprelease_overlay_configure_topology (void *cls) +{ + struct TopologyContext *tc = cls; + struct RetryListEntry *retry_entry; + unsigned int p; + + while (NULL != (retry_entry = tc->rl_head)) + { + GNUNET_CONTAINER_DLL_remove (tc->rl_head, tc->rl_tail, retry_entry); + GNUNET_free (retry_entry); + } + if (NULL != tc->link_array) + { + for (p = 0; p < tc->link_array_size; p++) + if (NULL != tc->link_array[p].op) + GNUNET_TESTBED_operation_done (tc->link_array[p].op); + GNUNET_free (tc->link_array); + } + GNUNET_free (tc); +} + + +/** + * Populates the OverlayLink structure. + * + * @param link the OverlayLink + * @param A the peer A. Should be different from B + * @param B the peer B. Should be different from A + * @param tc the TopologyContext + * @return + */ +static void +make_link (struct OverlayLink *link, uint32_t A, uint32_t B, + struct TopologyContext *tc) +{ + GNUNET_assert (A != B); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A); + link->A = A; + link->B = B; + link->op = NULL; + link->tc = tc; +} + + +/** + * Generates line topology + * + * @param tc the topology context + */ +static void +gen_topo_line (struct TopologyContext *tc) +{ + unsigned int cnt; + + tc->link_array_size = tc->num_peers - 1; + tc->link_array = + GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size); + for (cnt = 0; cnt < (tc->num_peers - 1); cnt++) + make_link (&tc->link_array[cnt], cnt, cnt + 1, tc); +} + + +/** + * Generates ring topology + * + * @param tc the topology context + */ +static void +gen_topo_ring (struct TopologyContext *tc) +{ + gen_topo_line (tc); + tc->link_array_size++; + tc->link_array = + GNUNET_realloc (tc->link_array, + sizeof (struct OverlayLink) * tc->link_array_size); + make_link (&tc->link_array[tc->link_array_size - 1], tc->num_peers - 1, 0, + tc); +} + + +/** + * Returns the number of links that are required to generate a 2d torus for the + * given number of peers. Also returns the arrangment (number of rows and the + * length of each row) + * + * @param num_peers number of peers + * @param rows number of rows in the 2d torus. Can be NULL + * @param rows_len the length of each row. This array will be allocated + * fresh. The caller should free it. Can be NULL + */ +unsigned int +GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows, + unsigned int **rows_len) +{ + double sq; + unsigned int sq_floor; + unsigned int _rows; + unsigned int *_rows_len; + unsigned int x; + unsigned int y; + unsigned int _num_peers; + unsigned int cnt; + + sq = sqrt (num_peers); + sq = floor (sq); + sq_floor = (unsigned int) sq; + _rows = (sq_floor + 1); + _rows_len = GNUNET_malloc (sizeof (unsigned int) * _rows); + for (y = 0; y < _rows - 1; y++) + _rows_len[y] = sq_floor; + _num_peers = sq_floor * sq_floor; + cnt = 2 * _num_peers; + x = 0; + y = 0; + while (_num_peers < num_peers) + { + if (x < y) + _rows_len[_rows - 1] = ++x; + else + _rows_len[y++]++; + _num_peers++; + } + cnt += (x < 2) ? x : 2 * x; + cnt += (y < 2) ? y : 2 * y; + if (0 == _rows_len[_rows - 1]) + _rows--; + if (NULL != rows) + *rows = _rows; + if (NULL != rows_len) + *rows_len = _rows_len; + else + GNUNET_free (_rows_len); + return cnt; +} + + +/** + * Generates ring topology + * + * @param tc the topology context + */ +static void +gen_topo_2dtorus (struct TopologyContext *tc) +{ + unsigned int rows; + unsigned int *rows_len; + unsigned int x; + unsigned int y; + unsigned int cnt; + unsigned int offset; + + tc->link_array_size = + GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len); + tc->link_array = + GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size); + cnt = 0; + offset = 0; + for (y = 0; y < rows; y++) + { + for (x = 0; x < rows_len[y] - 1; x++) + { + make_link (&tc->link_array[cnt], offset + x, offset + x + 1, tc); + cnt++; + } + if (0 == x) + break; + make_link (&tc->link_array[cnt], offset + x, offset, tc); + cnt++; + offset += rows_len[y]; + } + for (x = 0; x < rows_len[0]; x++) + { + offset = 0; + for (y = 0; y < rows - 1; y++) + { + if (x >= rows_len[y + 1]) + break; + GNUNET_assert (x < rows_len[y + 1]); + make_link (&tc->link_array[cnt], offset + x, offset + rows_len[y] + x, + tc); + offset += rows_len[y]; + cnt++; + } + if (0 == offset) + break; + make_link (&tc->link_array[cnt], offset + x, x, tc); + cnt++; + } + GNUNET_assert (cnt == tc->link_array_size); + GNUNET_free (rows_len); +} + + +/** + * Generates ring topology + * + * @param tc the topology context + * @param links the number of random links to establish + * @param append GNUNET_YES to add links to existing link array; GNUNET_NO to + * create a new link array + */ +static void +gen_topo_random (struct TopologyContext *tc, unsigned int links, int append) +{ + unsigned int cnt; + unsigned int index; + uint32_t A_rand; + uint32_t B_rand; + + if (GNUNET_YES == append) + { + GNUNET_assert ((0 < tc->link_array_size) && (NULL != tc->link_array)); + index = tc->link_array_size; + tc->link_array_size += links; + tc->link_array = + GNUNET_realloc (tc->link_array, + sizeof (struct OverlayLink) * tc->link_array_size); + } + else + { + GNUNET_assert ((0 == tc->link_array_size) && (NULL == tc->link_array)); + index = 0; + tc->link_array_size = links; + tc->link_array = + GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size); + } + for (cnt = 0; cnt < links; cnt++) + { + do + { + A_rand = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers); + B_rand = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers); + } + while (A_rand == B_rand); + make_link (&tc->link_array[index + cnt], A_rand, B_rand, tc); + } +} + + +/** + * Generates scale free network. Its construction is described in: + * + * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. + * + * @param tc the topology context + */ +static void +gen_scale_free (struct TopologyContext *tc) +{ + double random; + double probability; + unsigned int cnt; + unsigned int previous_connections; + unsigned int i; + uint16_t *popularity; + + popularity = GNUNET_malloc (sizeof (uint16_t) * tc->num_peers); + /* Initially connect peer 1 to peer 0 */ + tc->link_array_size = 1; + tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink)); + make_link (&tc->link_array[0], 0, 1, tc); + popularity[0]++; /* increase popularity of 0 as 1 connected to it */ + for (cnt = 1; cnt < tc->num_peers; cnt++) + { + previous_connections = tc->link_array_size; + for (i = 0; i < cnt; i++) + { + probability = ((double) popularity[i]) / ((double) previous_connections); + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + if (random < probability) + { + tc->link_array_size++; + tc->link_array = + GNUNET_realloc (tc->link_array, + (sizeof (struct OverlayLink) * + tc->link_array_size)); + make_link (&tc->link_array[tc->link_array_size - 1], cnt, i, tc); + popularity[cnt]++; + } + } + } + GNUNET_free (popularity); +} + + +/** + * Generates topology from the given file + * + * @param tc the topology context + * @param filename the filename of the file containing topology data + */ +static void +gen_topo_from_file (struct TopologyContext *tc, const char *filename) +{ + char *data; + char *end; + char *buf; + uint64_t fs; + uint64_t offset; + unsigned long int peer_id; + unsigned long int other_peer_id; + enum ParseState + { + + /** + * We read the peer index + */ + PEER_INDEX, + + /** + * We read the other peer indices + */ + OTHER_PEER_INDEX, + + } state; + int status; + + status = GNUNET_SYSERR; + if (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s not found\n"), filename); + return; + } + if (GNUNET_OK != + GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s has no data\n"), + filename); + return; + } + data = GNUNET_malloc (fs); + if (fs != GNUNET_DISK_fn_read (filename, data, fs)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s cannot be read\n"), + filename); + goto _exit; + } + + offset = 0; + peer_id = 0; + state = PEER_INDEX; + buf = data; + while (offset < fs) + { + if (0 != isspace (data[offset])) + { + offset++; + continue; + } + switch (state) + { + case PEER_INDEX: + buf = strchr (&data[offset], ':'); + if (NULL == buf) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read peer index from toology file: %s"), filename); + goto _exit; + } + *buf = '\0'; + errno = 0; + peer_id = (unsigned int) strtoul (&data[offset], &end, 10); + if (0 != errno) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Value in given topology file: %s out of range\n"), filename); + goto _exit; + } + if (&data[offset] == end) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read peer index from topology file: %s"), filename); + goto _exit; + } + if (tc->num_peers <= peer_id) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Topology file needs more peers than given ones\n"), filename); + goto _exit; + } + state = OTHER_PEER_INDEX; + offset += ((unsigned int) (buf - &data[offset])) + 1; + break; + case OTHER_PEER_INDEX: + errno = 0; + other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10); + if (0 != errno) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Value in given topology file: %s out of range\n"), filename); + goto _exit; + } + if (&data[offset] == end) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read peer index from topology file: %s"), filename); + goto _exit; + } + if (tc->num_peers <= other_peer_id) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Topology file needs more peers than given ones\n"), filename); + goto _exit; + } + if (peer_id != other_peer_id) + { + tc->link_array_size++; + tc->link_array = + GNUNET_realloc (tc->link_array, + sizeof (struct OverlayLink) * tc->link_array_size); + offset += end - &data[offset]; + make_link (&tc->link_array[tc->link_array_size - 1], peer_id, + other_peer_id, tc); + } + else + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Ignoring to connect peer %u to peer %u\n"), peer_id, + other_peer_id); + while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs)) + offset++; + if ('\n' == data[offset]) + state = PEER_INDEX; + else if ('|' == data[offset]) + { + state = OTHER_PEER_INDEX; + offset++; + } + break; + } + } + status = GNUNET_OK; + +_exit: + GNUNET_free (data); + if (GNUNET_OK != status) + { + LOG (GNUNET_ERROR_TYPE_WARNING, "Removing link data read from the file\n"); + tc->link_array_size = 0; + GNUNET_free_non_null (tc->link_array); + tc->link_array = NULL; + } +} /** @@ -40,10 +802,12 @@ */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **peers, - enum GNUNET_TESTBED_TopologyOption topo, - va_list ap) + unsigned int num_peers, + struct GNUNET_TESTBED_Peer + **peers, + enum + GNUNET_TESTBED_TopologyOption + topo, va_list ap) { GNUNET_break (0); return NULL; @@ -63,10 +827,10 @@ GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls, */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_underlay_configure_topology (void *op_cls, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer **peers, - enum GNUNET_TESTBED_TopologyOption topo, - ...) + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **peers, + enum GNUNET_TESTBED_TopologyOption + topo, ...) { GNUNET_break (0); return NULL; @@ -78,24 +842,144 @@ GNUNET_TESTBED_underlay_configure_topology (void *op_cls, * This function then connects the given peers in the P2P overlay * using the given topology. * - * @param op_cls closure argument to give with the operation event + * @param op_cls closure argument to give with the peer connect operation events + * generated through this function * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure + * @param max_connections the maximums number of overlay connections that will + * be made to achieve the given topology + * @param comp_cb the completion callback to call when the topology generation + * is completed + * @param comp_cb_cls closure for the above completion callback * @param topo desired underlay topology to use * @param va topology-specific options - * @return handle to the operation, NULL if connecting these + * @return handle to the operation, NULL if connecting these * peers is fundamentally not possible at this time (peers - * not running or underlay disallows) + * not running or underlay disallows) or if num_peers is less than 2 */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer *peers, - enum GNUNET_TESTBED_TopologyOption topo, - va_list va) + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **peers, + unsigned int *max_connections, + GNUNET_TESTBED_TopologyCompletionCallback + comp_cb, + void *comp_cb_cls, + enum GNUNET_TESTBED_TopologyOption topo, + va_list va) { - GNUNET_break (0); - return NULL; + struct TopologyContext *tc; + struct GNUNET_TESTBED_Operation *op; + struct GNUNET_TESTBED_Controller *c; + enum GNUNET_TESTBED_TopologyOption secondary_option; + unsigned int cnt; + + if (num_peers < 2) + return NULL; + c = peers[0]->controller; + tc = GNUNET_malloc (sizeof (struct TopologyContext)); + tc->peers = peers; + tc->num_peers = num_peers; + tc->op_cls = op_cls; + tc->retry_cnt = DEFAULT_RETRY_CNT; + switch (topo) + { + case GNUNET_TESTBED_TOPOLOGY_LINE: + gen_topo_line (tc); + break; + case GNUNET_TESTBED_TOPOLOGY_RING: + gen_topo_ring (tc); + break; + case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI: + gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO); + + break; + case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING: + gen_topo_ring (tc); + gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES); + + break; + case GNUNET_TESTBED_TOPOLOGY_CLIQUE: + tc->link_array_size = num_peers * (num_peers - 1); + tc->link_array = + GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size); + { + unsigned int offset; + + offset = 0; + for (cnt = 0; cnt < num_peers; cnt++) + { + unsigned int neighbour; + + for (neighbour = 0; neighbour < num_peers; neighbour++) + { + if (neighbour == cnt) + continue; + tc->link_array[offset].A = cnt; + tc->link_array[offset].B = neighbour; + tc->link_array[offset].tc = tc; + offset++; + } + } + } + break; + case GNUNET_TESTBED_TOPOLOGY_2D_TORUS: + gen_topo_2dtorus (tc); + break; + case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD: + gen_topo_2dtorus (tc); + gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES); + + break; + case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE: + gen_scale_free (tc); + break; + case GNUNET_TESTBED_TOPOLOGY_FROM_FILE: + { + const char *filename; + + filename = va_arg (va, const char *); + + GNUNET_assert (NULL != filename); + gen_topo_from_file (tc, filename); + } + break; + default: + GNUNET_break (0); + GNUNET_free (tc); + return NULL; + } + do + { + secondary_option = va_arg (va, enum GNUNET_TESTBED_TopologyOption); + + switch (secondary_option) + { + case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT: + tc->retry_cnt = va_arg (va, unsigned int); + break; + case GNUNET_TESTBED_TOPOLOGY_OPTION_END: + break; + default: + GNUNET_break (0); /* Should not use any other option apart from + * the ones handled here */ + GNUNET_free_non_null (tc->link_array); + GNUNET_free (tc); + return NULL; + } + } + while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option); + op = GNUNET_TESTBED_operation_create_ (tc, + &opstart_overlay_configure_topology, + &oprelease_overlay_configure_topology); + GNUNET_TESTBED_operation_queue_insert_ + (c->opq_parallel_topology_config_operations, op); + GNUNET_TESTBED_operation_begin_wait_ (op); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Generated %u connections\n", + tc->link_array_size); + if (NULL != max_connections) + *max_connections = tc->link_array_size; + return op; } @@ -104,24 +988,88 @@ GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls, * This function then connects the given peers in the P2P overlay * using the given topology. * - * @param op_cls closure argument to give with the operation event + * @param op_cls closure argument to give with the peer connect operation events + * generated through this function * @param num_peers number of peers in 'peers' * @param peers array of 'num_peers' with the peers to configure + * @param max_connections the maximums number of overlay connections that will + * be made to achieve the given topology + * @param comp_cb the completion callback to call when the topology generation + * is completed + * @param comp_cb_cls closure for the above completion callback * @param topo desired underlay topology to use * @param ... topology-specific options - * @return handle to the operation, NULL if connecting these + * @return handle to the operation, NULL if connecting these * peers is fundamentally not possible at this time (peers - * not running or underlay disallows) + * not running or underlay disallows) or if num_peers is less than 2 */ struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_overlay_configure_topology (void *op_cls, - unsigned int num_peers, - struct GNUNET_TESTBED_Peer *peers, - enum GNUNET_TESTBED_TopologyOption topo, - ...) + unsigned int num_peers, + struct GNUNET_TESTBED_Peer **peers, + unsigned int *max_connections, + GNUNET_TESTBED_TopologyCompletionCallback + comp_cb, + void *comp_cb_cls, + enum GNUNET_TESTBED_TopologyOption topo, + ...) { - GNUNET_break (0); - return NULL; + struct GNUNET_TESTBED_Operation *op; + va_list vargs; + + GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END); + va_start (vargs, topo); + op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers, + max_connections, + comp_cb, comp_cb_cls, + topo, + vargs); + va_end (vargs); + return op; +} + + +/** + * Get a topology from a string input. + * + * @param topology where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if topology string matched a + * known topology, GNUNET_NO if not + */ +int +GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology, + const char *topology_string) +{ + unsigned int cnt; + + for (cnt = 0; NULL != topology_strings[cnt]; cnt++) + { + if (0 == strcasecmp (topology_string, topology_strings[cnt])) + { + if (NULL != topology) + *topology = (enum GNUNET_TESTBED_TopologyOption) cnt; + return GNUNET_YES; + } + } + return GNUNET_NO; +} + + +/** + * Returns the string corresponding to the given topology + * + * @param topology the topology + * @return the string (freshly allocated) of given topology; NULL if topology cannot be + * expressed as a string + */ +char * +GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology) +{ + if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology) + return NULL; + return GNUNET_strdup (topology_strings[topology]); } /* end of testbed_api_topology.c */ |