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