2 This file is part of GNUnet
3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file testbed/testbed_api_topology.c
23 * @brief topology-generation functions
24 * @author Christian Grothoff
27 #include "gnunet_testbed_service.h"
28 #include "testbed_api.h"
29 #include "testbed_api_peers.h"
30 #include "testbed_api_operations.h"
31 #include "testbed_api_topology.h"
34 * Generic loggins shorthand
36 #define LOG(kind,...) \
37 GNUNET_log_from (kind, "testbed-api-topology", __VA_ARGS__)
41 * Default number of retires
43 #define DEFAULT_RETRY_CNT 3
47 * Context information for topology operations
49 struct TopologyContext;
53 * Representation of an overlay link
59 * An operation corresponding to this link
61 struct GNUNET_TESTBED_Operation *op;
64 * The topology context this link is a part of
66 struct TopologyContext *tc;
69 * position of peer A's handle in peers array
74 * position of peer B's handle in peers array
84 * the next pointer for the DLL
86 struct RetryListEntry *next;
89 * the prev pointer for the DLL
91 struct RetryListEntry *prev;
94 * The link to be retired
96 struct OverlayLink *link;
101 * Context information for topology operations
103 struct TopologyContext
108 struct GNUNET_TESTBED_Peer **peers;
111 * An array of links; this array is of size link_array_size
113 struct OverlayLink *link_array;
116 * The operation closure
121 * topology generation completion callback
123 GNUNET_TESTBED_TopologyCompletionCallback comp_cb;
126 * The closure for the above callback
131 * DLL head for retry list
133 struct RetryListEntry *rl_head;
136 * DLL tail for retry list
138 struct RetryListEntry *rl_tail;
141 * The number of peers
143 unsigned int num_peers;
146 * The size of the link array
148 unsigned int link_array_size;
151 * How many retries to do before we give up
153 unsigned int retry_cnt;
156 * Number of links to try
161 * How many links have been completed
163 unsigned int ncompleted;
166 * Total successfully established overlay connections
168 unsigned int nsuccess;
171 * Total failed overlay connections
173 unsigned int nfailures;
178 * A array of names representing topologies. Should be in sync with enum
179 * GNUNET_TESTBED_TopologyOption
181 const char *topology_strings[] = {
184 * A clique (everyone connected to everyone else). No options. If there are N
185 * peers this topology results in (N * (N -1)) connections.
190 * Small-world network (2d torus plus random links). Followed
191 * by the number of random links to add (unsigned int).
196 * Small-world network (ring plus random links). Followed
197 * by the number of random links to add (unsigned int).
202 * Ring topology. No options.
207 * 2-d torus. No options.
212 * Random graph. Followed by the number of random links to be established
215 "RANDOM", // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
218 * Certain percentage of peers are unable to communicate directly
219 * replicating NAT conditions. Followed by the fraction of
220 * NAT'ed peers (float).
225 * Scale free topology. No options.
230 * Straight line topology. No options.
235 * Read a topology from a given file. Followed by the name of the file (const char *).
240 * All peers are disconnected. No options.
252 * Callback to be called when an overlay_link operation complete
254 * @param cls element of the link_op array which points to the corresponding operation
255 * @param op the operation that has been finished
256 * @param emsg error message in case the operation has failed; will be NULL if
257 * operation has executed successfully.
260 overlay_link_completed (void *cls, struct GNUNET_TESTBED_Operation *op,
263 struct OverlayLink *link = cls;
264 struct TopologyContext *tc;
265 struct RetryListEntry *retry_entry;
267 GNUNET_assert (op == link->op);
268 GNUNET_TESTBED_operation_done (op);
274 if (0 != tc->retry_cnt)
276 LOG (GNUNET_ERROR_TYPE_WARNING,
277 "Error while establishing a link: %s -- Retrying\n", emsg);
278 retry_entry = GNUNET_malloc (sizeof (struct RetryListEntry));
279 retry_entry->link = link;
280 GNUNET_CONTAINER_DLL_insert_tail (tc->rl_head, tc->rl_tail, retry_entry);
286 if (tc->ncompleted < tc->nlinks)
288 if ((0 != tc->retry_cnt) && (NULL != tc->rl_head))
293 while (NULL != (retry_entry = tc->rl_head))
295 link = retry_entry->link;
297 GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
298 link, tc->peers[link->A],
301 GNUNET_CONTAINER_DLL_remove (tc->rl_head, tc->rl_tail, retry_entry);
302 GNUNET_free (retry_entry);
306 if (NULL != tc->comp_cb)
308 tc->comp_cb (tc->comp_cb_cls, tc->nsuccess, tc->nfailures);
315 * Function called when a overlay connect operation is ready
317 * @param cls the Topology context
320 opstart_overlay_configure_topology (void *cls)
322 struct TopologyContext *tc = cls;
325 tc->nlinks = tc->link_array_size;
326 for (p = 0; p < tc->link_array_size; p++)
328 tc->link_array[p].op =
329 GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
331 tc->peers[tc->link_array[p].A],
332 tc->peers[tc->link_array[p].B]);
338 * Callback which will be called when overlay connect operation is released
340 * @param cls the Topology context
343 oprelease_overlay_configure_topology (void *cls)
345 struct TopologyContext *tc = cls;
346 struct RetryListEntry *retry_entry;
349 while (NULL != (retry_entry = tc->rl_head))
351 GNUNET_CONTAINER_DLL_remove (tc->rl_head, tc->rl_tail, retry_entry);
352 GNUNET_free (retry_entry);
354 if (NULL != tc->link_array)
356 for (p = 0; p < tc->link_array_size; p++)
357 if (NULL != tc->link_array[p].op)
358 GNUNET_TESTBED_operation_done (tc->link_array[p].op);
359 GNUNET_free (tc->link_array);
366 * Populates the OverlayLink structure.
368 * @param link the OverlayLink
369 * @param A the peer A. Should be different from B
370 * @param B the peer B. Should be different from A
371 * @param tc the TopologyContext
375 make_link (struct OverlayLink *link, uint32_t A, uint32_t B,
376 struct TopologyContext *tc)
378 GNUNET_assert (A != B);
379 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A);
388 * Generates line topology
390 * @param tc the topology context
393 gen_topo_line (struct TopologyContext *tc)
397 tc->link_array_size = tc->num_peers - 1;
399 GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
400 for (cnt = 0; cnt < (tc->num_peers - 1); cnt++)
401 make_link (&tc->link_array[cnt], cnt, cnt + 1, tc);
406 * Generates ring topology
408 * @param tc the topology context
411 gen_topo_ring (struct TopologyContext *tc)
414 tc->link_array_size++;
416 GNUNET_realloc (tc->link_array,
417 sizeof (struct OverlayLink) * tc->link_array_size);
418 make_link (&tc->link_array[tc->link_array_size - 1], tc->num_peers - 1, 0,
424 * Returns the number of links that are required to generate a 2d torus for the
425 * given number of peers. Also returns the arrangment (number of rows and the
426 * length of each row)
428 * @param num_peers number of peers
429 * @param rows number of rows in the 2d torus. Can be NULL
430 * @param rows_len the length of each row. This array will be allocated
431 * fresh. The caller should free it. Can be NULL
432 * @return the number of links that are required to generate a 2d torus for the
433 * given number of peers
436 GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
437 unsigned int **rows_len)
440 unsigned int sq_floor;
442 unsigned int *_rows_len;
445 unsigned int _num_peers;
448 sq = sqrt (num_peers);
450 sq_floor = (unsigned int) sq;
451 _rows = (sq_floor + 1);
452 _rows_len = GNUNET_malloc (sizeof (unsigned int) * _rows);
453 for (y = 0; y < _rows - 1; y++)
454 _rows_len[y] = sq_floor;
455 _num_peers = sq_floor * sq_floor;
456 cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers;
459 while (_num_peers < num_peers)
462 _rows_len[_rows - 1] = ++x;
467 cnt += (x < 2) ? x : 2 * x;
468 cnt += (y < 2) ? y : 2 * y;
469 if (0 == _rows_len[_rows - 1])
473 if (NULL != rows_len)
474 *rows_len = _rows_len;
476 GNUNET_free (_rows_len);
482 * Generates ring topology
484 * @param tc the topology context
487 gen_topo_2dtorus (struct TopologyContext *tc)
490 unsigned int *rows_len;
496 tc->link_array_size =
497 GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len);
499 GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
502 for (y = 0; y < rows; y++)
504 for (x = 0; x < rows_len[y] - 1; x++)
506 make_link (&tc->link_array[cnt], offset + x, offset + x + 1, tc);
511 make_link (&tc->link_array[cnt], offset + x, offset, tc);
513 offset += rows_len[y];
515 for (x = 0; x < rows_len[0]; x++)
518 for (y = 0; y < rows - 1; y++)
520 if (x >= rows_len[y + 1])
522 GNUNET_assert (x < rows_len[y + 1]);
523 make_link (&tc->link_array[cnt], offset + x, offset + rows_len[y] + x,
525 offset += rows_len[y];
530 make_link (&tc->link_array[cnt], offset + x, x, tc);
533 GNUNET_assert (cnt == tc->link_array_size);
534 GNUNET_free (rows_len);
539 * Generates ring topology
541 * @param tc the topology context
542 * @param links the number of random links to establish
543 * @param append GNUNET_YES to add links to existing link array; GNUNET_NO to
544 * create a new link array
547 gen_topo_random (struct TopologyContext *tc, unsigned int links, int append)
554 if (GNUNET_YES == append)
556 GNUNET_assert ((0 < tc->link_array_size) && (NULL != tc->link_array));
557 index = tc->link_array_size;
558 tc->link_array_size += links;
560 GNUNET_realloc (tc->link_array,
561 sizeof (struct OverlayLink) * tc->link_array_size);
565 GNUNET_assert ((0 == tc->link_array_size) && (NULL == tc->link_array));
567 tc->link_array_size = links;
569 GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
571 for (cnt = 0; cnt < links; cnt++)
576 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
578 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
580 while (A_rand == B_rand);
581 make_link (&tc->link_array[index + cnt], A_rand, B_rand, tc);
587 * Generates scale free network. Its construction is described in:
589 * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
591 * @param tc the topology context
592 * @param cap maximum allowed node degree
593 * @param m number of edges to establish for a new node when it is added to the
597 gen_scale_free (struct TopologyContext *tc, uint16_t cap, uint8_t m)
602 unsigned int etaboff;
606 unsigned int random_peer;
609 unsigned int redo_threshold;
613 tc->link_array_size = tc->num_peers * m;
614 tc->link_array = GNUNET_malloc_large (sizeof (struct OverlayLink) *
615 tc->link_array_size);
616 etab = GNUNET_malloc_large (sizeof (unsigned int) * 2 * tc->link_array_size);
617 deg = GNUNET_malloc (sizeof (unsigned int) * tc->num_peers);
618 used = GNUNET_malloc (sizeof (unsigned int) * m);
619 /* start by connecting peer 1 to peer 0 */
620 make_link (&tc->link_array[0], 0, 1, tc);
626 for (peer = 2; peer < tc->num_peers; peer++)
630 for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
634 off = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, etaboff);
635 random_peer = etab[off];
636 if (cap < deg[random_peer])
638 if (++redo_threshold > GNUNET_MAX (1, cap / 2))
642 for (cnt2 = 0; cnt2 < etaboff; cnt2++)
644 if (random_peer == etab[cnt2])
649 etab[cnt2 - off] = etab[cnt2];
655 for (cnt2 = 0; cnt2 < cnt; cnt2++)
656 if (random_peer == used[cnt2])
658 make_link (&tc->link_array[links + cnt], random_peer, peer, tc);
661 used[cnt] = random_peer;
663 for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
665 etab[etaboff++] = used[cnt];
666 etab[etaboff++] = peer;
668 links += GNUNET_MIN (peer, m);
673 GNUNET_assert (links <= tc->link_array_size);
674 tc->link_array_size = links;
676 GNUNET_realloc (tc->link_array,
677 sizeof (struct OverlayLink) * tc->link_array_size);
682 * Generates topology from the given file
684 * @param tc the topology context
685 * @param filename the filename of the file containing topology data
688 gen_topo_from_file (struct TopologyContext *tc, const char *filename)
695 unsigned long int peer_id;
696 unsigned long int other_peer_id;
701 * We read the peer index
706 * We read the other peer indices
713 status = GNUNET_SYSERR;
714 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
716 LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s not found\n"), filename);
720 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
722 LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s has no data\n"),
726 data = GNUNET_malloc (fs);
727 if (fs != GNUNET_DISK_fn_read (filename, data, fs))
729 LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s cannot be read\n"),
739 if (0 != isspace (data[offset]))
747 buf = strchr (&data[offset], ':');
750 LOG (GNUNET_ERROR_TYPE_ERROR,
751 _("Failed to read peer index from toology file: %s"), filename);
756 peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
759 LOG (GNUNET_ERROR_TYPE_ERROR,
760 _("Value in given topology file: %s out of range\n"), filename);
763 if (&data[offset] == end)
765 LOG (GNUNET_ERROR_TYPE_ERROR,
766 _("Failed to read peer index from topology file: %s"), filename);
769 if (tc->num_peers <= peer_id)
771 LOG (GNUNET_ERROR_TYPE_ERROR,
772 _("Topology file needs more peers than given ones\n"), filename);
775 state = OTHER_PEER_INDEX;
776 offset += ((unsigned int) (buf - &data[offset])) + 1;
778 case OTHER_PEER_INDEX:
780 other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
783 LOG (GNUNET_ERROR_TYPE_ERROR,
784 _("Value in given topology file: %s out of range\n"), filename);
787 if (&data[offset] == end)
789 LOG (GNUNET_ERROR_TYPE_ERROR,
790 _("Failed to read peer index from topology file: %s"), filename);
793 if (tc->num_peers <= other_peer_id)
795 LOG (GNUNET_ERROR_TYPE_ERROR,
796 _("Topology file needs more peers than given ones\n"), filename);
799 if (peer_id != other_peer_id)
801 tc->link_array_size++;
803 GNUNET_realloc (tc->link_array,
804 sizeof (struct OverlayLink) * tc->link_array_size);
805 offset += end - &data[offset];
806 make_link (&tc->link_array[tc->link_array_size - 1], peer_id,
810 LOG (GNUNET_ERROR_TYPE_WARNING,
811 _("Ignoring to connect peer %u to peer %u\n"), peer_id,
813 while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
815 if ('\n' == data[offset])
817 else if ('|' == data[offset])
819 state = OTHER_PEER_INDEX;
829 if (GNUNET_OK != status)
831 LOG (GNUNET_ERROR_TYPE_WARNING, "Removing link data read from the file\n");
832 tc->link_array_size = 0;
833 GNUNET_free_non_null (tc->link_array);
834 tc->link_array = NULL;
840 * Configure overall network topology to have a particular shape.
842 * @param op_cls closure argument to give with the operation event
843 * @param num_peers number of peers in 'peers'
844 * @param peers array of 'num_peers' with the peers to configure
845 * @param topo desired underlay topology to use
846 * @param ap topology-specific options
847 * @return handle to the operation, NULL if configuring the topology
848 * is not allowed at this time
850 struct GNUNET_TESTBED_Operation *
851 GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
852 unsigned int num_peers,
853 struct GNUNET_TESTBED_Peer
856 GNUNET_TESTBED_TopologyOption
865 * Configure overall network topology to have a particular shape.
867 * @param op_cls closure argument to give with the operation event
868 * @param num_peers number of peers in 'peers'
869 * @param peers array of 'num_peers' with the peers to configure
870 * @param topo desired underlay topology to use
871 * @param ... topology-specific options
872 * @return handle to the operation, NULL if configuring the topology
873 * is not allowed at this time
875 struct GNUNET_TESTBED_Operation *
876 GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
877 unsigned int num_peers,
878 struct GNUNET_TESTBED_Peer **peers,
879 enum GNUNET_TESTBED_TopologyOption
888 * All peers must have been started before calling this function.
889 * This function then connects the given peers in the P2P overlay
890 * using the given topology.
892 * @param op_cls closure argument to give with the peer connect operation events
893 * generated through this function
894 * @param num_peers number of peers in 'peers'
895 * @param peers array of 'num_peers' with the peers to configure
896 * @param max_connections the maximums number of overlay connections that will
897 * be made to achieve the given topology
898 * @param comp_cb the completion callback to call when the topology generation
900 * @param comp_cb_cls closure for the above completion callback
901 * @param topo desired underlay topology to use
902 * @param va topology-specific options
903 * @return handle to the operation, NULL if connecting these
904 * peers is fundamentally not possible at this time (peers
905 * not running or underlay disallows) or if num_peers is less than 2
907 struct GNUNET_TESTBED_Operation *
908 GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
909 unsigned int num_peers,
910 struct GNUNET_TESTBED_Peer **peers,
911 unsigned int *max_connections,
912 GNUNET_TESTBED_TopologyCompletionCallback
915 enum GNUNET_TESTBED_TopologyOption topo,
918 struct TopologyContext *tc;
919 struct GNUNET_TESTBED_Operation *op;
920 struct GNUNET_TESTBED_Controller *c;
921 enum GNUNET_TESTBED_TopologyOption secondary_option;
926 c = peers[0]->controller;
927 tc = GNUNET_malloc (sizeof (struct TopologyContext));
929 tc->num_peers = num_peers;
931 tc->retry_cnt = DEFAULT_RETRY_CNT;
932 tc->comp_cb = comp_cb;
933 tc->comp_cb_cls = comp_cb_cls;
936 case GNUNET_TESTBED_TOPOLOGY_LINE:
939 case GNUNET_TESTBED_TOPOLOGY_RING:
942 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
943 gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO);
945 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
947 gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
949 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
950 tc->link_array_size = num_peers * (num_peers - 1);
952 GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
957 for (cnt = 0; cnt < num_peers; cnt++)
959 unsigned int neighbour;
961 for (neighbour = 0; neighbour < num_peers; neighbour++)
963 if (neighbour == cnt)
965 tc->link_array[offset].A = cnt;
966 tc->link_array[offset].B = neighbour;
967 tc->link_array[offset].tc = tc;
973 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
974 gen_topo_2dtorus (tc);
976 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
977 gen_topo_2dtorus (tc);
978 gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
981 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
986 cap = (uint16_t) va_arg (va, unsigned int);
987 m = (uint8_t) va_arg (va, unsigned int);
988 gen_scale_free (tc, cap, m);
991 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
993 const char *filename;
995 filename = va_arg (va, const char *);
997 GNUNET_assert (NULL != filename);
998 gen_topo_from_file (tc, filename);
1008 secondary_option = va_arg (va, enum GNUNET_TESTBED_TopologyOption);
1010 switch (secondary_option)
1012 case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT:
1013 tc->retry_cnt = va_arg (va, unsigned int);
1015 case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
1018 GNUNET_break (0); /* Should not use any other option apart from
1019 * the ones handled here */
1020 GNUNET_free_non_null (tc->link_array);
1025 while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
1026 op = GNUNET_TESTBED_operation_create_ (tc,
1027 &opstart_overlay_configure_topology,
1028 &oprelease_overlay_configure_topology);
1029 GNUNET_TESTBED_operation_queue_insert_
1030 (c->opq_parallel_topology_config_operations, op);
1031 GNUNET_TESTBED_operation_begin_wait_ (op);
1032 LOG (GNUNET_ERROR_TYPE_DEBUG, "Generated %u connections\n",
1033 tc->link_array_size);
1034 if (NULL != max_connections)
1035 *max_connections = tc->link_array_size;
1041 * All peers must have been started before calling this function.
1042 * This function then connects the given peers in the P2P overlay
1043 * using the given topology.
1045 * @param op_cls closure argument to give with the peer connect operation events
1046 * generated through this function
1047 * @param num_peers number of peers in 'peers'
1048 * @param peers array of 'num_peers' with the peers to configure
1049 * @param max_connections the maximums number of overlay connections that will
1050 * be made to achieve the given topology
1051 * @param comp_cb the completion callback to call when the topology generation
1053 * @param comp_cb_cls closure for the above completion callback
1054 * @param topo desired underlay topology to use
1055 * @param ... topology-specific options
1056 * @return handle to the operation, NULL if connecting these
1057 * peers is fundamentally not possible at this time (peers
1058 * not running or underlay disallows) or if num_peers is less than 2
1060 struct GNUNET_TESTBED_Operation *
1061 GNUNET_TESTBED_overlay_configure_topology (void *op_cls,
1062 unsigned int num_peers,
1063 struct GNUNET_TESTBED_Peer **peers,
1064 unsigned int *max_connections,
1065 GNUNET_TESTBED_TopologyCompletionCallback
1068 enum GNUNET_TESTBED_TopologyOption topo,
1071 struct GNUNET_TESTBED_Operation *op;
1074 GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
1075 va_start (vargs, topo);
1076 op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
1078 comp_cb, comp_cb_cls,
1087 * Get a topology from a string input.
1089 * @param topology where to write the retrieved topology
1090 * @param topology_string The string to attempt to
1091 * get a configuration value from
1092 * @return GNUNET_YES if topology string matched a
1093 * known topology, GNUNET_NO if not
1096 GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
1097 const char *topology_string)
1101 for (cnt = 0; NULL != topology_strings[cnt]; cnt++)
1103 if (0 == strcasecmp (topology_string, topology_strings[cnt]))
1105 if (NULL != topology)
1106 *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
1115 * Returns the string corresponding to the given topology
1117 * @param topology the topology
1118 * @return the string (freshly allocated) of given topology; NULL if topology cannot be
1119 * expressed as a string
1122 GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology)
1124 if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology)
1126 return GNUNET_strdup (topology_strings[topology]);
1129 /* end of testbed_api_topology.c */