tighten formatting rules
[oweals/gnunet.git] / src / testbed / testbed_api_topology.c
1 /*
2       This file is part of GNUnet
3       Copyright (C) 2008--2013 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
21 /**
22  * @file testbed/testbed_api_topology.c
23  * @brief topology-generation functions
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
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"
32
33 /**
34  * Generic loggins shorthand
35  */
36 #define LOG(kind, ...)                                           \
37   GNUNET_log_from (kind, "testbed-api-topology", __VA_ARGS__)
38
39
40 /**
41  * Default number of retires
42  */
43 #define DEFAULT_RETRY_CNT 3
44
45
46 /**
47  * Context information for topology operations
48  */
49 struct TopologyContext;
50
51
52 /**
53  * Representation of an overlay link
54  */
55 struct OverlayLink
56 {
57   /**
58    * An operation corresponding to this link
59    */
60   struct GNUNET_TESTBED_Operation *op;
61
62   /**
63    * The topology context this link is a part of
64    */
65   struct TopologyContext *tc;
66
67   /**
68    * position of peer A's handle in peers array
69    */
70   uint32_t A;
71
72   /**
73    * position of peer B's handle in peers array
74    */
75   uint32_t B;
76 };
77
78
79 /**
80  * Representation of an underlay link
81  */
82 struct UnderlayLink
83 {
84   /**
85    * position of peer A's handle in peers array
86    */
87   uint32_t A;
88
89   /**
90    * position of peer B's handle in peers array
91    */
92   uint32_t B;
93
94   /**
95    * Bandwidth of the link in bytes per second
96    */
97   uint32_t bandwidth;
98
99   /**
100    * Latency of the link in milliseconds
101    */
102   uint32_t latency;
103
104   /**
105    * Loss in the link in percentage of message dropped
106    */
107   uint32_t loss;
108 };
109
110
111 struct RetryListEntry
112 {
113   /**
114    * the next pointer for the DLL
115    */
116   struct RetryListEntry *next;
117
118   /**
119    * the prev pointer for the DLL
120    */
121   struct RetryListEntry *prev;
122
123   /**
124    * The link to be retired
125    */
126   struct OverlayLink *link;
127 };
128
129
130 /**
131  * Context information for overlay topologies
132  */
133 struct TopologyContextOverlay
134 {
135   /**
136    * The array of peers
137    */
138   struct GNUNET_TESTBED_Peer **peers;
139
140   /**
141    * An array of links; this array is of size link_array_size
142    */
143   struct OverlayLink *link_array;
144
145   /**
146    * The operation closure
147    */
148   void *op_cls;
149
150   /**
151    * topology generation completion callback
152    */
153   GNUNET_TESTBED_TopologyCompletionCallback comp_cb;
154
155   /**
156    * The closure for the above callback
157    */
158   void *comp_cb_cls;
159
160   /**
161    * DLL head for retry list
162    */
163   struct RetryListEntry *rl_head;
164
165   /**
166    * DLL tail for retry list
167    */
168   struct RetryListEntry *rl_tail;
169
170   /**
171    * How many retries to do before we give up
172    */
173   unsigned int retry_cnt;
174
175   /**
176    * Number of links to try
177    */
178   unsigned int nlinks;
179
180   /**
181    * How many links have been completed
182    */
183   unsigned int ncompleted;
184
185   /**
186    * Total successfully established overlay connections
187    */
188   unsigned int nsuccess;
189
190   /**
191    * Total failed overlay connections
192    */
193   unsigned int nfailures;
194 };
195
196
197 /**
198  * Topology context information for underlay topologies
199  */
200 struct TopologyContextUnderlay
201 {
202   /**
203    * The link array
204    */
205   struct UnderlayLink *link_array;
206 };
207
208
209 /**
210  * Context information for topology operations
211  */
212 struct TopologyContext
213 {
214   /**
215    * The type of this context
216    */
217   enum
218   {
219     /**
220      * Type for underlay topology
221      */
222     TOPOLOGYCONTEXT_TYPE_UNDERLAY = 0,
223
224     /**
225      * Type for overlay topology
226      */
227     TOPOLOGYCONTEXT_TYPE_OVERLAY
228   } type;
229
230   union
231   {
232     /**
233      * Topology context information for overlay topology
234      */
235     struct TopologyContextOverlay overlay;
236
237     /**
238      * Topology context information for underlay topology
239      */
240     struct TopologyContextUnderlay underlay;
241   } u;
242
243   /**
244    * The number of peers
245    */
246   unsigned int num_peers;
247
248   /**
249    * The size of the link array
250    */
251   unsigned int link_array_size;
252 };
253
254
255 /**
256  * A array of names representing topologies. Should be in sync with enum
257  * GNUNET_TESTBED_TopologyOption
258  */
259 static const char *topology_strings[] = {
260   /**
261    * A clique (everyone connected to everyone else).  No options. If there are N
262    * peers this topology results in (N * (N -1)) connections.
263    */
264   "CLIQUE",
265
266   /*
267    * Small-world network (2d torus plus random links).  Followed
268    * by the number of random links to add (unsigned int).
269    */
270   "SMALL_WORLD",
271
272   /**
273    * Small-world network (ring plus random links).  Followed
274    * by the number of random links to add (unsigned int).
275    */
276   "SMALL_WORLD_RING",
277
278   /**
279    * Ring topology.  No options.
280    */
281   "RING",
282
283   /**
284    * Star topology.  No options.
285    */
286   "STAR",
287
288   /**
289    * 2-d torus.  No options.
290    */
291   "2D_TORUS",
292
293   /**
294    * Random graph.  Followed by the number of random links to be established
295    * (unsigned int)
296    */
297   "RANDOM",                     // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
298
299   /**
300    * Certain percentage of peers are unable to communicate directly
301    * replicating NAT conditions.  Followed by the fraction of
302    * NAT'ed peers (float).
303    */
304   "INTERNAT",
305
306   /**
307    * Scale free topology. Followed by the maximum number of links a node can
308    * have (unsigned int); and the number of links a new node should have when
309    * it is added to the network (unsigned int)
310    */
311   "SCALE_FREE",
312
313   /**
314    * Straight line topology.  No options.
315    */
316   "LINE",
317
318   /**
319    * Read a topology from a given file.  Followed by the name of the file (const char *).
320    */
321   "FROM_FILE",
322
323   /**
324    * All peers are disconnected.  No options.
325    */
326   "NONE",
327
328   /**
329    * End of strings
330    */
331   NULL
332 };
333
334
335 /**
336  * Callback to be called when an overlay_link operation complete
337  *
338  * @param cls element of the link_op array which points to the corresponding operation
339  * @param op the operation that has been finished
340  * @param emsg error message in case the operation has failed; will be NULL if
341  *          operation has executed successfully.
342  */
343 static void
344 overlay_link_completed (void *cls,
345                         struct GNUNET_TESTBED_Operation *op,
346                         const char *emsg)
347 {
348   struct OverlayLink *link = cls;
349   struct TopologyContext *tc;
350   struct TopologyContextOverlay *overlay;
351   struct RetryListEntry *retry_entry;
352
353   GNUNET_assert (op == link->op);
354   GNUNET_TESTBED_operation_done (op);
355   link->op = NULL;
356   tc = link->tc;
357   GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
358   overlay = &tc->u.overlay;
359   if (NULL != emsg)
360   {
361     overlay->nfailures++;
362     if (0 != overlay->retry_cnt)
363     {
364       LOG (GNUNET_ERROR_TYPE_WARNING,
365            "Error while establishing a link: %s -- Retrying\n",
366            emsg);
367       retry_entry = GNUNET_new (struct RetryListEntry);
368       retry_entry->link = link;
369       GNUNET_CONTAINER_DLL_insert_tail (overlay->rl_head,
370                                         overlay->rl_tail,
371                                         retry_entry);
372     }
373   }
374   else
375     overlay->nsuccess++;
376   overlay->ncompleted++;
377   if (overlay->ncompleted < overlay->nlinks)
378     return;
379   if ((0 != overlay->retry_cnt) && (NULL != overlay->rl_head))
380   {
381     overlay->retry_cnt--;
382     overlay->ncompleted = 0;
383     overlay->nlinks = 0;
384     while (NULL != (retry_entry = overlay->rl_head))
385     {
386       link = retry_entry->link;
387       link->op =
388         GNUNET_TESTBED_overlay_connect (overlay->op_cls,
389                                         &overlay_link_completed,
390                                         link,
391                                         overlay->peers[link->A],
392                                         overlay->peers[link->B]);
393       overlay->nlinks++;
394       GNUNET_CONTAINER_DLL_remove (overlay->rl_head,
395                                    overlay->rl_tail,
396                                    retry_entry);
397       GNUNET_free (retry_entry);
398     }
399     return;
400   }
401   if (NULL != overlay->comp_cb)
402   {
403     overlay->comp_cb (overlay->comp_cb_cls,
404                       overlay->nsuccess,
405                       overlay->nfailures);
406   }
407 }
408
409
410 /**
411  * Function called when a overlay connect operation is ready
412  *
413  * @param cls the Topology context
414  */
415 static void
416 opstart_overlay_configure_topology (void *cls)
417 {
418   struct TopologyContext *tc = cls;
419   struct TopologyContextOverlay *overlay;
420   unsigned int p;
421
422   GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
423   overlay = &tc->u.overlay;
424   overlay->nlinks = tc->link_array_size;
425   for (p = 0; p < tc->link_array_size; p++)
426   {
427     overlay->link_array[p].op =
428       GNUNET_TESTBED_overlay_connect (overlay->op_cls,
429                                       &overlay_link_completed,
430                                       &overlay->link_array[p],
431                                       overlay->peers[overlay->link_array[p].A],
432                                       overlay->peers[overlay->link_array[p].B]);
433   }
434 }
435
436
437 /**
438  * Callback which will be called when overlay connect operation is released
439  *
440  * @param cls the Topology context
441  */
442 static void
443 oprelease_overlay_configure_topology (void *cls)
444 {
445   struct TopologyContext *tc = cls;
446   struct TopologyContextOverlay *overlay;
447   struct RetryListEntry *retry_entry;
448   unsigned int p;
449
450   GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
451   overlay = &tc->u.overlay;
452   while (NULL != (retry_entry = overlay->rl_head))
453   {
454     GNUNET_CONTAINER_DLL_remove (overlay->rl_head, overlay->rl_tail,
455                                  retry_entry);
456     GNUNET_free (retry_entry);
457   }
458   if (NULL != overlay->link_array)
459   {
460     for (p = 0; p < tc->link_array_size; p++)
461       if (NULL != overlay->link_array[p].op)
462         GNUNET_TESTBED_operation_done (overlay->link_array[p].op);
463     GNUNET_free (overlay->link_array);
464   }
465   GNUNET_free (tc);
466 }
467
468
469 /**
470  * Populates the OverlayLink structure.
471  *
472  * @param offset the offset of the link array to use
473  * @param A the peer A. Should be different from B
474  * @param B the peer B. Should be different from A
475  * @param tc the TopologyContext
476  * @return
477  */
478 static void
479 make_link (unsigned int offset,
480            uint32_t A,
481            uint32_t B,
482            struct TopologyContext *tc)
483 {
484   GNUNET_assert (A != B);
485   switch (tc->type)
486   {
487   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
488     {
489       struct TopologyContextOverlay *overlay;
490       struct OverlayLink *olink;
491
492       overlay = &tc->u.overlay;
493       GNUNET_assert (offset < tc->link_array_size);
494       olink = &overlay->link_array[offset];
495       LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A);
496       olink->A = A;
497       olink->B = B;
498       olink->op = NULL;
499       olink->tc = tc;
500     }
501     break;
502
503   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
504     {
505       struct TopologyContextUnderlay *underlay;
506       struct UnderlayLink *ulink;
507
508       underlay = &tc->u.underlay;
509       GNUNET_assert (offset < tc->link_array_size);
510       ulink = &underlay->link_array[offset];
511       ulink->A = A;
512       ulink->B = B;
513     }
514     break;
515   }
516 }
517
518
519 /**
520  * Generates line topology
521  *
522  * @param tc the topology context
523  */
524 static void
525 gen_topo_line (struct TopologyContext *tc)
526 {
527   unsigned int cnt;
528
529   tc->link_array_size = tc->num_peers - 1;
530   switch (tc->type)
531   {
532   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
533     {
534       struct TopologyContextOverlay *overlay;
535
536       overlay = &tc->u.overlay;
537       overlay->link_array =
538         GNUNET_new_array (tc->link_array_size,
539                           struct OverlayLink);
540     }
541     break;
542
543   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
544     {
545       struct TopologyContextUnderlay *underlay;
546
547       underlay = &tc->u.underlay;
548       underlay->link_array =
549         GNUNET_new_array (tc->link_array_size,
550                           struct UnderlayLink);
551     }
552     break;
553   }
554   for (cnt = 0; cnt < (tc->link_array_size); cnt++)
555     make_link (cnt, cnt, cnt + 1, tc);
556 }
557
558
559 /**
560  * Generates star topology
561  *
562  * @param tc the topology context
563  */
564 static void
565 gen_topo_star (struct TopologyContext *tc)
566 {
567   unsigned int cnt;
568
569   tc->link_array_size = tc->num_peers - 1;
570   switch (tc->type)
571   {
572   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
573     {
574       struct TopologyContextOverlay *overlay;
575
576       overlay = &tc->u.overlay;
577       overlay->link_array =
578         GNUNET_new_array (tc->link_array_size,
579                           struct OverlayLink);
580     }
581     break;
582
583   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
584     {
585       struct TopologyContextUnderlay *underlay;
586
587       underlay = &tc->u.underlay;
588       underlay->link_array =
589         GNUNET_new_array (tc->link_array_size,
590                           struct UnderlayLink);
591     }
592     break;
593   }
594   for (cnt = tc->link_array_size; cnt; cnt--)
595     make_link (cnt - 1,
596                0,
597                cnt,
598                tc);
599 }
600
601
602 /**
603  * Generates ring topology
604  *
605  * @param tc the topology context
606  */
607 static void
608 gen_topo_ring (struct TopologyContext *tc)
609 {
610   gen_topo_line (tc);
611   tc->link_array_size++;
612   switch (tc->type)
613   {
614   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
615     {
616       struct TopologyContextOverlay *overlay;
617
618       overlay = &tc->u.overlay;
619       overlay->link_array =
620         GNUNET_realloc (overlay->link_array, sizeof(struct OverlayLink)
621                         * tc->link_array_size);
622     }
623     break;
624
625   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
626     {
627       struct TopologyContextUnderlay *underlay;
628
629       underlay = &tc->u.underlay;
630       underlay->link_array =
631         GNUNET_realloc (underlay->link_array, sizeof(struct UnderlayLink)
632                         * tc->link_array_size);
633     }
634     break;
635   }
636   make_link (tc->link_array_size - 1, tc->num_peers - 1, 0, tc);
637 }
638
639
640 /**
641  * Returns the number of links that are required to generate a 2d torus for the
642  * given number of peers. Also returns the arrangment (number of rows and the
643  * length of each row)
644  *
645  * @param num_peers number of peers
646  * @param rows number of rows in the 2d torus. Can be NULL
647  * @param rows_len the length of each row. This array will be allocated
648  *          fresh. The caller should free it. Can be NULL
649  * @return the number of links that are required to generate a 2d torus for the
650  *           given number of peers
651  */
652 unsigned int
653 GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
654                                    unsigned int **rows_len)
655 {
656   double sq;
657   unsigned int sq_floor;
658   unsigned int _rows;
659   unsigned int *_rows_len;
660   unsigned int x;
661   unsigned int y;
662   unsigned int _num_peers;
663   unsigned int cnt;
664
665   sq = sqrt (num_peers);
666   sq = floor (sq);
667   sq_floor = (unsigned int) sq;
668   _rows = (sq_floor + 1);
669   _rows_len = GNUNET_malloc (sizeof(unsigned int) * _rows);
670   for (y = 0; y < _rows - 1; y++)
671     _rows_len[y] = sq_floor;
672   _num_peers = sq_floor * sq_floor;
673   cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers;
674   x = 0;
675   y = 0;
676   while (_num_peers < num_peers)
677   {
678     if (x < y)
679       _rows_len[_rows - 1] = ++x;
680     else
681       _rows_len[y++]++;
682     _num_peers++;
683   }
684   cnt += (x < 2) ? x : 2 * x;
685   cnt += (y < 2) ? y : 2 * y;
686   if (0 == _rows_len[_rows - 1])
687     _rows--;
688   if (NULL != rows)
689     *rows = _rows;
690   if (NULL != rows_len)
691     *rows_len = _rows_len;
692   else
693     GNUNET_free (_rows_len);
694   return cnt;
695 }
696
697
698 /**
699  * Generates ring topology
700  *
701  * @param tc the topology context
702  */
703 static void
704 gen_topo_2dtorus (struct TopologyContext *tc)
705 {
706   unsigned int rows;
707   unsigned int *rows_len;
708   unsigned int x;
709   unsigned int y;
710   unsigned int cnt;
711   unsigned int offset;
712
713   tc->link_array_size =
714     GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len);
715   switch (tc->type)
716   {
717   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
718     {
719       struct TopologyContextOverlay *overlay;
720
721       overlay = &tc->u.overlay;
722       overlay->link_array =
723         GNUNET_malloc (sizeof(struct OverlayLink) * tc->link_array_size);
724     }
725     break;
726
727   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
728     {
729       struct TopologyContextUnderlay *underlay;
730
731       underlay = &tc->u.underlay;
732       underlay->link_array =
733         GNUNET_malloc (sizeof(struct UnderlayLink) * tc->link_array_size);
734       break;
735     }
736   }
737   cnt = 0;
738   offset = 0;
739   for (y = 0; y < rows; y++)
740   {
741     for (x = 0; x < rows_len[y] - 1; x++)
742     {
743       make_link (cnt, offset + x, offset + x + 1, tc);
744       cnt++;
745     }
746     if (0 == x)
747       break;
748     make_link (cnt, offset + x, offset, tc);
749     cnt++;
750     offset += rows_len[y];
751   }
752   for (x = 0; x < rows_len[0]; x++)
753   {
754     offset = 0;
755     for (y = 0; y < rows - 1; y++)
756     {
757       if (x >= rows_len[y + 1])
758         break;
759       GNUNET_assert (x < rows_len[y + 1]);
760       make_link (cnt, offset + x, offset + rows_len[y] + x, tc);
761       offset += rows_len[y];
762       cnt++;
763     }
764     if (0 == offset)
765       break;
766     make_link (cnt, offset + x, x, tc);
767     cnt++;
768   }
769   GNUNET_assert (cnt == tc->link_array_size);
770   GNUNET_free (rows_len);
771 }
772
773
774 /**
775  * Generates ring topology
776  *
777  * @param tc the topology context
778  * @param links the number of random links to establish
779  * @param append #GNUNET_YES to add links to existing link array; #GNUNET_NO to
780  *          create a new link array
781  */
782 static void
783 gen_topo_random (struct TopologyContext *tc,
784                  unsigned int links,
785                  int append)
786 {
787   unsigned int cnt;
788   unsigned int index;
789   uint32_t A_rand;
790   uint32_t B_rand;
791
792   if (1 == tc->num_peers)
793     return;
794   if (GNUNET_YES == append)
795   {
796     index = tc->link_array_size;
797     tc->link_array_size += links;
798   }
799   else
800   {
801     index = 0;
802     tc->link_array_size = links;
803   }
804   switch (tc->type)
805   {
806   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
807     {
808       struct TopologyContextOverlay *overlay;
809
810       overlay = &tc->u.overlay;
811       if (GNUNET_YES != append)
812       {
813         GNUNET_assert (NULL == overlay->link_array);
814         overlay->link_array =
815           GNUNET_malloc (sizeof(struct OverlayLink) * tc->link_array_size);
816         break;
817       }
818       GNUNET_assert ((0 < tc->link_array_size) && (NULL !=
819                                                    overlay->link_array));
820       overlay->link_array =
821         GNUNET_realloc (overlay->link_array,
822                         sizeof(struct OverlayLink) * tc->link_array_size);
823       break;
824     }
825
826   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
827     {
828       struct TopologyContextUnderlay *underlay;
829
830       underlay = &tc->u.underlay;
831       if (GNUNET_YES != append)
832       {
833         GNUNET_assert (NULL == underlay->link_array);
834         underlay->link_array =
835           GNUNET_malloc (sizeof(struct UnderlayLink) * tc->link_array_size);
836         break;
837       }
838       GNUNET_assert ((0 < tc->link_array_size) && (NULL !=
839                                                    underlay->link_array));
840       underlay->link_array =
841         GNUNET_realloc (underlay->link_array,
842                         sizeof(struct UnderlayLink) * tc->link_array_size);
843       break;
844     }
845   }
846   for (cnt = 0; cnt < links; cnt++)
847   {
848     do
849     {
850       A_rand =
851         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
852       B_rand =
853         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
854     }
855     while (A_rand == B_rand);
856     make_link (index + cnt, A_rand, B_rand, tc);
857   }
858 }
859
860
861 /**
862  * Generates scale free network. Its construction is described in:
863  *
864  * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
865  *
866  * @param tc the topology context
867  * @param cap maximum allowed node degree
868  * @param m number of edges to establish for a new node when it is added to the
869  *   network
870  */
871 static void
872 gen_topo_scale_free (struct TopologyContext *tc,
873                      uint16_t cap,
874                      uint8_t m)
875 {
876   unsigned int *deg;
877   unsigned int *etab;
878   unsigned int *used;
879   unsigned int etaboff;
880   unsigned int cnt;
881   unsigned int cnt2;
882   unsigned int peer;
883   unsigned int random_peer;
884   unsigned int links;
885   unsigned int off;
886   unsigned int redo_threshold;
887
888   etaboff = 0;
889   tc->link_array_size = tc->num_peers * m;
890   switch (tc->type)
891   {
892   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
893     {
894       struct TopologyContextOverlay *overlay;
895
896       overlay = &tc->u.overlay;
897       overlay->link_array = GNUNET_malloc_large (sizeof(struct OverlayLink)
898                                                  * tc->link_array_size);
899     }
900     break;
901
902   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
903     {
904       struct TopologyContextUnderlay *underlay;
905
906       underlay = &tc->u.underlay;
907       underlay->link_array = GNUNET_malloc_large (sizeof(struct UnderlayLink)
908                                                   * tc->link_array_size);
909     }
910     break;
911   }
912   etab = GNUNET_malloc_large (sizeof(unsigned int) * 2 * tc->link_array_size);
913   deg = GNUNET_malloc (sizeof(unsigned int) * tc->num_peers);
914   used = GNUNET_malloc (sizeof(unsigned int) * m);
915   /* start by connecting peer 1 to peer 0 */
916   make_link (0, 0, 1, tc);
917   deg[0]++;
918   deg[1]++;
919   etab[etaboff++] = 0;
920   etab[etaboff++] = 1;
921   links = 1;
922   for (peer = 2; peer < tc->num_peers; peer++)
923   {
924     if (cap < deg[peer])
925       continue;
926     for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
927     {
928       redo_threshold = 0;
929 redo:
930       off = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, etaboff);
931       random_peer = etab[off];
932       if (cap < deg[random_peer])
933       {
934         if (++redo_threshold > GNUNET_MAX (1, cap / 2))
935         {
936           redo_threshold = 0;
937           off = 0;
938           for (cnt2 = 0; cnt2 < etaboff; cnt2++)
939           {
940             if (random_peer == etab[cnt2])
941             {
942               off++;
943               continue;
944             }
945             etab[cnt2 - off] = etab[cnt2];
946           }
947           etaboff -= off;
948         }
949         goto redo;
950       }
951       for (cnt2 = 0; cnt2 < cnt; cnt2++)
952         if (random_peer == used[cnt2])
953           goto redo;
954       make_link (links + cnt, random_peer, peer, tc);
955       deg[random_peer]++;
956       deg[peer]++;
957       used[cnt] = random_peer;
958     }
959     for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
960     {
961       etab[etaboff++] = used[cnt];
962       etab[etaboff++] = peer;
963     }
964     links += GNUNET_MIN (peer, m);
965   }
966   GNUNET_free (etab);
967   GNUNET_free (used);
968   GNUNET_free (deg);
969   GNUNET_assert (links <= tc->link_array_size);
970   tc->link_array_size = links;
971   switch (tc->type)
972   {
973   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
974     {
975       struct TopologyContextOverlay *overlay;
976
977       overlay = &tc->u.overlay;
978       overlay->link_array =
979         GNUNET_realloc (overlay->link_array, sizeof(struct OverlayLink)
980                         * tc->link_array_size);
981     }
982     break;
983
984   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
985     {
986       struct TopologyContextUnderlay *underlay;
987
988       underlay = &tc->u.underlay;
989       underlay->link_array =
990         GNUNET_realloc (underlay->link_array, sizeof(struct UnderlayLink)
991                         * tc->link_array_size);
992     }
993     break;
994   }
995 }
996
997
998 /**
999  * Generates topology from the given file
1000  *
1001  * @param tc the topology context
1002  * @param filename the filename of the file containing topology data
1003  */
1004 static void
1005 gen_topo_from_file (struct TopologyContext *tc,
1006                     const char *filename)
1007 {
1008   char *data;
1009   char *end;
1010   char *buf;
1011   uint64_t fs;
1012   uint64_t offset;
1013   unsigned long int peer_id;
1014   unsigned long int other_peer_id;
1015   enum ParseState
1016   {
1017     /**
1018      * We read the peer index
1019      */
1020     PEER_INDEX,
1021
1022     /**
1023      * We read the other peer indices
1024      */
1025     OTHER_PEER_INDEX,
1026   } state;
1027   int status;
1028
1029   status = GNUNET_SYSERR;
1030   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
1031   {
1032     LOG (GNUNET_ERROR_TYPE_ERROR,
1033          _ ("Topology file %s not found\n"),
1034          filename);
1035     return;
1036   }
1037   if (GNUNET_OK !=
1038       GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
1039   {
1040     LOG (GNUNET_ERROR_TYPE_ERROR,
1041          _ ("Topology file %s has no data\n"),
1042          filename);
1043     return;
1044   }
1045   data = GNUNET_malloc (fs);
1046   if (fs != GNUNET_DISK_fn_read (filename, data, fs))
1047   {
1048     LOG (GNUNET_ERROR_TYPE_ERROR,
1049          _ ("Topology file %s cannot be read\n"),
1050          filename);
1051     goto _exit;
1052   }
1053
1054   offset = 0;
1055   peer_id = 0;
1056   state = PEER_INDEX;
1057   while (offset < fs)
1058   {
1059     if (0 != isspace ((unsigned char) data[offset]))
1060     {
1061       offset++;
1062       continue;
1063     }
1064     switch (state)
1065     {
1066     case PEER_INDEX:
1067       buf = strchr (&data[offset], ':');
1068       if (NULL == buf)
1069       {
1070         LOG (GNUNET_ERROR_TYPE_ERROR,
1071              _ ("Failed to read peer index from toology file: %s"), filename);
1072         goto _exit;
1073       }
1074       *buf = '\0';
1075       errno = 0;
1076       peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
1077       if (0 != errno)
1078       {
1079         LOG (GNUNET_ERROR_TYPE_ERROR,
1080              _ ("Value in given topology file: %s out of range\n"), filename);
1081         goto _exit;
1082       }
1083       if (&data[offset] == end)
1084       {
1085         LOG (GNUNET_ERROR_TYPE_ERROR,
1086              _ ("Failed to read peer index from topology file: %s"), filename);
1087         goto _exit;
1088       }
1089       if (tc->num_peers <= peer_id)
1090       {
1091         LOG (GNUNET_ERROR_TYPE_ERROR,
1092              _ ("Topology file needs more peers than given ones\n"), filename);
1093         goto _exit;
1094       }
1095       state = OTHER_PEER_INDEX;
1096       offset += ((unsigned int) (buf - &data[offset])) + 1;
1097       break;
1098
1099     case OTHER_PEER_INDEX:
1100       errno = 0;
1101       other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
1102       if (0 != errno)
1103       {
1104         LOG (GNUNET_ERROR_TYPE_ERROR,
1105              _ ("Value in given topology file: %s out of range\n"), filename);
1106         goto _exit;
1107       }
1108       if (&data[offset] == end)
1109       {
1110         LOG (GNUNET_ERROR_TYPE_ERROR,
1111              _ ("Failed to read peer index from topology file: %s"), filename);
1112         goto _exit;
1113       }
1114       if (tc->num_peers <= other_peer_id)
1115       {
1116         LOG (GNUNET_ERROR_TYPE_ERROR,
1117              _ ("Topology file needs more peers than given ones\n"), filename);
1118         goto _exit;
1119       }
1120       if (peer_id != other_peer_id)
1121       {
1122         tc->link_array_size++;
1123         switch (tc->type)
1124         {
1125         case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1126           {
1127             struct TopologyContextOverlay *overlay;
1128
1129             overlay = &tc->u.overlay;
1130             overlay->link_array =
1131               GNUNET_realloc (overlay->link_array,
1132                               sizeof(struct OverlayLink) * tc->link_array_size);
1133           }
1134           break;
1135
1136         case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1137           {
1138             struct TopologyContextUnderlay *underlay;
1139
1140             underlay = &tc->u.underlay;
1141             underlay->link_array =
1142               GNUNET_realloc (underlay->link_array,
1143                               sizeof(struct UnderlayLink)
1144                               * tc->link_array_size);
1145           }
1146           break;
1147         }
1148         offset += end - &data[offset];
1149         make_link (tc->link_array_size - 1, peer_id, other_peer_id, tc);
1150       }
1151       else
1152         LOG (GNUNET_ERROR_TYPE_WARNING,
1153              _ ("Ignoring to connect peer %u to peer %u\n"),
1154              peer_id,
1155              other_peer_id);
1156       while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
1157         offset++;
1158       if ((offset < fs) &&
1159           ('\n' == data[offset]))
1160         state = PEER_INDEX;
1161       else if ((offset < fs) &&
1162                ('|' == data[offset]))
1163       {
1164         state = OTHER_PEER_INDEX;
1165         offset++;
1166       }
1167       break;
1168     }
1169   }
1170   status = GNUNET_OK;
1171
1172 _exit:
1173   GNUNET_free (data);
1174   if (GNUNET_OK != status)
1175   {
1176     LOG (GNUNET_ERROR_TYPE_WARNING,
1177          "Removing link data read from the file\n");
1178     tc->link_array_size = 0;
1179     switch (tc->type)
1180     {
1181     case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1182       {
1183         struct TopologyContextOverlay *overlay;
1184
1185         overlay = &tc->u.overlay;
1186         GNUNET_free_non_null (overlay->link_array);
1187         overlay->link_array = NULL;
1188       }
1189       break;
1190
1191     case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1192       {
1193         struct TopologyContextUnderlay *underlay;
1194
1195         underlay = &tc->u.underlay;
1196         GNUNET_free_non_null (underlay->link_array);
1197         underlay->link_array = NULL;
1198       }
1199       break;
1200     }
1201   }
1202 }
1203
1204
1205 /**
1206  * Generates clique topology
1207  *
1208  * @param tc the topology context
1209  */
1210 static void
1211 gen_topo_clique (struct TopologyContext *tc)
1212 {
1213   unsigned int cnt;
1214   unsigned int offset;
1215   unsigned int neighbour;
1216
1217   tc->link_array_size = tc->num_peers * (tc->num_peers - 1);
1218   switch (tc->type)
1219   {
1220   case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1221     {
1222       struct TopologyContextOverlay *overlay;
1223
1224       overlay = &tc->u.overlay;
1225       overlay->link_array = GNUNET_new_array (tc->link_array_size,
1226                                               struct OverlayLink);
1227     }
1228     break;
1229
1230   case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1231     {
1232       struct TopologyContextUnderlay *underlay;
1233
1234       underlay = &tc->u.underlay;
1235       underlay->link_array = GNUNET_new_array (tc->link_array_size,
1236                                                struct UnderlayLink);
1237     }
1238   }
1239   offset = 0;
1240   for (cnt = 0; cnt < tc->num_peers; cnt++)
1241   {
1242     for (neighbour = 0; neighbour < tc->num_peers; neighbour++)
1243     {
1244       if (neighbour == cnt)
1245         continue;
1246       make_link (offset, cnt, neighbour, tc);
1247       offset++;
1248     }
1249   }
1250 }
1251
1252
1253 /**
1254  * Configure overall network topology to have a particular shape.
1255  *
1256  * @param op_cls closure argument to give with the operation event
1257  * @param num_peers number of peers in @a peers
1258  * @param peers array of @a num_peers with the peers to configure
1259  * @param topo desired underlay topology to use
1260  * @param ap topology-specific options
1261  * @return handle to the operation, NULL if configuring the topology
1262  *         is not allowed at this time
1263  */
1264 struct GNUNET_TESTBED_Operation *
1265 GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
1266                                                unsigned int num_peers,
1267                                                struct GNUNET_TESTBED_Peer
1268                                                **peers,
1269                                                enum
1270                                                GNUNET_TESTBED_TopologyOption
1271                                                topo, va_list ap)
1272 {
1273   GNUNET_break (0);
1274   return NULL;
1275 }
1276
1277
1278 /**
1279  * Configure overall network topology to have a particular shape.
1280  *
1281  * @param op_cls closure argument to give with the operation event
1282  * @param num_peers number of peers in @a peers
1283  * @param peers array of @a num_peers with the peers to configure
1284  * @param topo desired underlay topology to use
1285  * @param ... topology-specific options
1286  * @return handle to the operation, NULL if configuring the topology
1287  *         is not allowed at this time
1288  */
1289 struct GNUNET_TESTBED_Operation *
1290 GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
1291                                             unsigned int num_peers,
1292                                             struct GNUNET_TESTBED_Peer **peers,
1293                                             enum GNUNET_TESTBED_TopologyOption
1294                                             topo, ...)
1295 {
1296   GNUNET_break (0);
1297   return NULL;
1298 }
1299
1300
1301 /**
1302  * All peers must have been started before calling this function.
1303  * This function then connects the given peers in the P2P overlay
1304  * using the given topology.
1305  *
1306  * @param op_cls closure argument to give with the peer connect operation events
1307  *          generated through this function
1308  * @param num_peers number of peers in @a peers
1309  * @param peers array of @a num_peers with the peers to configure
1310  * @param max_connections the maximums number of overlay connections that will
1311  *          be made to achieve the given topology
1312  * @param comp_cb the completion callback to call when the topology generation
1313  *          is completed
1314  * @param comp_cb_cls closure for the above completion callback
1315  * @param topo desired underlay topology to use
1316  * @param va topology-specific options
1317  * @return handle to the operation, NULL if connecting these
1318  *         peers is fundamentally not possible at this time (peers
1319  *         not running or underlay disallows) or if num_peers is less than 2
1320  */
1321 struct GNUNET_TESTBED_Operation *
1322 GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
1323                                               unsigned int num_peers,
1324                                               struct GNUNET_TESTBED_Peer **peers,
1325                                               unsigned int *max_connections,
1326                                               GNUNET_TESTBED_TopologyCompletionCallback
1327                                               comp_cb,
1328                                               void *comp_cb_cls,
1329                                               enum GNUNET_TESTBED_TopologyOption
1330                                               topo,
1331                                               va_list va)
1332 {
1333   struct TopologyContext *tc;
1334   struct TopologyContextOverlay *overlay;
1335   struct GNUNET_TESTBED_Operation *op;
1336   struct GNUNET_TESTBED_Controller *c;
1337   enum GNUNET_TESTBED_TopologyOption secondary_option;
1338
1339   if (num_peers < 2)
1340     return NULL;
1341   c = peers[0]->controller;
1342   tc = GNUNET_new (struct TopologyContext);
1343   tc->type = TOPOLOGYCONTEXT_TYPE_OVERLAY;
1344   overlay = &tc->u.overlay;
1345   overlay->peers = peers;
1346   tc->num_peers = num_peers;
1347   overlay->op_cls = op_cls;
1348   overlay->retry_cnt = DEFAULT_RETRY_CNT;
1349   overlay->comp_cb = comp_cb;
1350   overlay->comp_cb_cls = comp_cb_cls;
1351   switch (topo)
1352   {
1353   case GNUNET_TESTBED_TOPOLOGY_LINE:
1354     gen_topo_line (tc);
1355     break;
1356
1357   case GNUNET_TESTBED_TOPOLOGY_STAR:
1358     gen_topo_star (tc);
1359     break;
1360
1361   case GNUNET_TESTBED_TOPOLOGY_RING:
1362     gen_topo_ring (tc);
1363     break;
1364
1365   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1366     gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO);
1367     break;
1368
1369   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1370     gen_topo_ring (tc);
1371     gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
1372     break;
1373
1374   case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
1375     gen_topo_clique (tc);
1376     break;
1377
1378   case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
1379     gen_topo_2dtorus (tc);
1380     break;
1381
1382   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1383     gen_topo_2dtorus (tc);
1384     gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
1385
1386     break;
1387
1388   case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1389     {
1390       uint16_t cap;
1391       uint8_t m;
1392
1393       cap = (uint16_t) va_arg (va, unsigned int);
1394       m = (uint8_t) va_arg (va, unsigned int);
1395       gen_topo_scale_free (tc, cap, m);
1396     }
1397     break;
1398
1399   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1400     {
1401       const char *filename;
1402
1403       filename = va_arg (va, const char *);
1404
1405       GNUNET_assert (NULL != filename);
1406       gen_topo_from_file (tc, filename);
1407     }
1408     break;
1409
1410   default:
1411     GNUNET_break (0);
1412     GNUNET_free (tc);
1413     return NULL;
1414   }
1415   do
1416   {
1417     secondary_option = GNUNET_VA_ARG_ENUM (va, GNUNET_TESTBED_TopologyOption);
1418
1419     switch (secondary_option)
1420     {
1421     case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT:
1422       overlay->retry_cnt = va_arg (va, unsigned int);
1423       break;
1424
1425     case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
1426       break;
1427
1428     default:
1429       GNUNET_break (0);         /* Should not use any other option apart from
1430                                  * the ones handled here */
1431       GNUNET_free_non_null (overlay->link_array);
1432       GNUNET_free (tc);
1433       return NULL;
1434     }
1435   }
1436   while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
1437   op = GNUNET_TESTBED_operation_create_ (tc,
1438                                          &opstart_overlay_configure_topology,
1439                                          &oprelease_overlay_configure_topology);
1440   GNUNET_TESTBED_operation_queue_insert_
1441     (c->opq_parallel_topology_config_operations, op);
1442   GNUNET_TESTBED_operation_begin_wait_ (op);
1443   LOG (GNUNET_ERROR_TYPE_DEBUG,
1444        "Generated %u connections\n",
1445        tc->link_array_size);
1446   if (NULL != max_connections)
1447     *max_connections = tc->link_array_size;
1448   return op;
1449 }
1450
1451
1452 /**
1453  * All peers must have been started before calling this function.
1454  * This function then connects the given peers in the P2P overlay
1455  * using the given topology.
1456  *
1457  * @param op_cls closure argument to give with the peer connect operation events
1458  *          generated through this function
1459  * @param num_peers number of peers in 'peers'
1460  * @param peers array of 'num_peers' with the peers to configure
1461  * @param max_connections the maximums number of overlay connections that will
1462  *          be made to achieve the given topology
1463  * @param comp_cb the completion callback to call when the topology generation
1464  *          is completed
1465  * @param comp_cb_cls closure for the above completion callback
1466  * @param topo desired underlay topology to use
1467  * @param ... topology-specific options
1468  * @return handle to the operation, NULL if connecting these
1469  *         peers is fundamentally not possible at this time (peers
1470  *         not running or underlay disallows) or if num_peers is less than 2
1471  */
1472 struct GNUNET_TESTBED_Operation *
1473 GNUNET_TESTBED_overlay_configure_topology (void *op_cls,
1474                                            unsigned int num_peers,
1475                                            struct GNUNET_TESTBED_Peer **peers,
1476                                            unsigned int *max_connections,
1477                                            GNUNET_TESTBED_TopologyCompletionCallback
1478                                            comp_cb,
1479                                            void *comp_cb_cls,
1480                                            enum GNUNET_TESTBED_TopologyOption
1481                                            topo,
1482                                            ...)
1483 {
1484   struct GNUNET_TESTBED_Operation *op;
1485   va_list vargs;
1486
1487   GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
1488   va_start (vargs, topo);
1489   op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
1490                                                      max_connections,
1491                                                      comp_cb, comp_cb_cls,
1492                                                      topo,
1493                                                      vargs);
1494   va_end (vargs);
1495   return op;
1496 }
1497
1498
1499 /**
1500  * Get a topology from a string input.
1501  *
1502  * @param topology where to write the retrieved topology
1503  * @param topology_string The string to attempt to
1504  *        get a configuration value from
1505  * @return #GNUNET_YES if topology string matched a
1506  *         known topology, #GNUNET_NO if not
1507  */
1508 int
1509 GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
1510                               const char *topology_string)
1511 {
1512   unsigned int cnt;
1513
1514   for (cnt = 0; NULL != topology_strings[cnt]; cnt++)
1515   {
1516     if (0 == strcasecmp (topology_string, topology_strings[cnt]))
1517     {
1518       if (NULL != topology)
1519         *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
1520       GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END !=
1521                      (enum GNUNET_TESTBED_TopologyOption) cnt);
1522       return GNUNET_YES;
1523     }
1524   }
1525   return GNUNET_NO;
1526 }
1527
1528
1529 /**
1530  * Returns the string corresponding to the given topology
1531  *
1532  * @param topology the topology
1533  * @return the string (freshly allocated) of given topology; NULL if topology cannot be
1534  *           expressed as a string
1535  */
1536 char *
1537 GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology)
1538 {
1539   if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology)
1540     return NULL;
1541   return GNUNET_strdup (topology_strings[topology]);
1542 }
1543
1544
1545 /**
1546  * Function to construct an underlay topology
1547  *
1548  * @param num_peers the number of peers for which the topology should be
1549  *          generated
1550  * @param proc the underlay link processor callback.  Will be called for each
1551  *          underlay link generated unless a previous call to this callback
1552  *          returned #GNUNET_SYSERR.  Cannot be NULL.
1553  * @param cls closure for @a proc
1554  * @param ... variable arguments denoting the topology and its parameters.  They
1555  *          should start with the type of topology to generate followed by their
1556  *          options.
1557  * @return #GNUNET_OK if underlay link generation is successful; #GNUNET_SYSERR
1558  *          upon error in generating the underlay or if any calls to the
1559  *          underlay link processor returned #GNUNET_SYSERR
1560  */
1561 int
1562 GNUNET_TESTBED_underlay_construct_ (int num_peers,
1563                                     underlay_link_processor proc,
1564                                     void *cls,
1565                                     ...)
1566 {
1567   struct TopologyContext tc;
1568   struct TopologyContextUnderlay *underlay;
1569   struct UnderlayLink *ulink;
1570   va_list vargs;
1571   enum GNUNET_TESTBED_TopologyOption topology;
1572   unsigned int cnt;
1573   int ret;
1574
1575   GNUNET_assert (NULL != proc);
1576   ret = GNUNET_OK;
1577   memset (&tc, 0, sizeof(tc));
1578   tc.num_peers = num_peers;
1579   tc.type = TOPOLOGYCONTEXT_TYPE_UNDERLAY;
1580   underlay = &tc.u.underlay;
1581   va_start (vargs, cls);
1582   topology = GNUNET_VA_ARG_ENUM (vargs, GNUNET_TESTBED_TopologyOption);
1583   switch (topology)
1584   {
1585   case GNUNET_TESTBED_TOPOLOGY_LINE:
1586     gen_topo_line (&tc);
1587     break;
1588
1589   case GNUNET_TESTBED_TOPOLOGY_STAR:
1590     gen_topo_star (&tc);
1591     break;
1592
1593   case GNUNET_TESTBED_TOPOLOGY_RING:
1594     gen_topo_ring (&tc);
1595     break;
1596
1597   case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
1598     gen_topo_clique (&tc);
1599     break;
1600
1601   case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
1602     gen_topo_2dtorus (&tc);
1603     break;
1604
1605   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1606     gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_NO);
1607     break;
1608
1609   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1610     gen_topo_ring (&tc);
1611     gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
1612     break;
1613
1614   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1615     gen_topo_2dtorus (&tc);
1616     gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
1617     break;
1618
1619   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1620     {
1621       const char *filename;
1622       filename = va_arg (vargs, char *);
1623       GNUNET_assert (NULL != filename);
1624       gen_topo_from_file (&tc, filename);
1625     }
1626     break;
1627
1628   case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1629     {
1630       uint16_t cap;
1631       uint8_t m;
1632       cap = (uint16_t) va_arg (vargs, unsigned int);
1633       m = (uint8_t) va_arg (vargs, unsigned int);
1634       gen_topo_scale_free (&tc, cap, m);
1635     }
1636     break;
1637
1638   default:
1639     GNUNET_assert (0);
1640   }
1641   va_end (vargs);
1642   for (cnt = 0; cnt < tc.link_array_size; cnt++)
1643   {
1644     ulink = &underlay->link_array[cnt];
1645     if (GNUNET_SYSERR == proc (cls,
1646                                ulink->A,
1647                                ulink->B,
1648                                ulink->bandwidth,
1649                                ulink->latency,
1650                                ulink->loss))
1651     {
1652       ret = GNUNET_SYSERR;
1653       break;
1654     }
1655   }
1656   GNUNET_free_non_null (underlay->link_array);
1657   return ret;
1658 }
1659
1660
1661 /* end of testbed_api_topology.c */