diff options
Diffstat (limited to 'src/testbed/testbed_api_topology.c')
-rw-r--r-- | src/testbed/testbed_api_topology.c | 1598 |
1 files changed, 0 insertions, 1598 deletions
diff --git a/src/testbed/testbed_api_topology.c b/src/testbed/testbed_api_topology.c deleted file mode 100644 index f73be378e..000000000 --- a/src/testbed/testbed_api_topology.c +++ /dev/null | |||
@@ -1,1598 +0,0 @@ | |||
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 | unsigned int | ||
641 | GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows, | ||
642 | unsigned int **rows_len) | ||
643 | { | ||
644 | double sq; | ||
645 | unsigned int sq_floor; | ||
646 | unsigned int _rows; | ||
647 | unsigned int *_rows_len; | ||
648 | unsigned int x; | ||
649 | unsigned int y; | ||
650 | unsigned int _num_peers; | ||
651 | unsigned int cnt; | ||
652 | |||
653 | sq = sqrt (num_peers); | ||
654 | sq = floor (sq); | ||
655 | sq_floor = (unsigned int) sq; | ||
656 | _rows = (sq_floor + 1); | ||
657 | _rows_len = GNUNET_malloc (sizeof(unsigned int) * _rows); | ||
658 | for (y = 0; y < _rows - 1; y++) | ||
659 | _rows_len[y] = sq_floor; | ||
660 | _num_peers = sq_floor * sq_floor; | ||
661 | cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers; | ||
662 | x = 0; | ||
663 | y = 0; | ||
664 | while (_num_peers < num_peers) | ||
665 | { | ||
666 | if (x < y) | ||
667 | _rows_len[_rows - 1] = ++x; | ||
668 | else | ||
669 | _rows_len[y++]++; | ||
670 | _num_peers++; | ||
671 | } | ||
672 | cnt += (x < 2) ? x : 2 * x; | ||
673 | cnt += (y < 2) ? y : 2 * y; | ||
674 | if (0 == _rows_len[_rows - 1]) | ||
675 | _rows--; | ||
676 | if (NULL != rows) | ||
677 | *rows = _rows; | ||
678 | if (NULL != rows_len) | ||
679 | *rows_len = _rows_len; | ||
680 | else | ||
681 | GNUNET_free (_rows_len); | ||
682 | return cnt; | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Generates ring topology | ||
688 | * | ||
689 | * @param tc the topology context | ||
690 | */ | ||
691 | static void | ||
692 | gen_topo_2dtorus (struct TopologyContext *tc) | ||
693 | { | ||
694 | unsigned int rows; | ||
695 | unsigned int *rows_len; | ||
696 | unsigned int x; | ||
697 | unsigned int y; | ||
698 | unsigned int cnt; | ||
699 | unsigned int offset; | ||
700 | |||
701 | tc->link_array_size = | ||
702 | GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len); | ||
703 | switch (tc->type) | ||
704 | { | ||
705 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
706 | { | ||
707 | struct TopologyContextOverlay *overlay; | ||
708 | |||
709 | overlay = &tc->u.overlay; | ||
710 | overlay->link_array = | ||
711 | GNUNET_malloc (sizeof(struct OverlayLink) * tc->link_array_size); | ||
712 | } | ||
713 | break; | ||
714 | |||
715 | case TOPOLOGYCONTEXT_TYPE_UNDERLAY: | ||
716 | { | ||
717 | struct TopologyContextUnderlay *underlay; | ||
718 | |||
719 | underlay = &tc->u.underlay; | ||
720 | underlay->link_array = | ||
721 | GNUNET_malloc (sizeof(struct UnderlayLink) * tc->link_array_size); | ||
722 | break; | ||
723 | } | ||
724 | } | ||
725 | cnt = 0; | ||
726 | offset = 0; | ||
727 | for (y = 0; y < rows; y++) | ||
728 | { | ||
729 | for (x = 0; x < rows_len[y] - 1; x++) | ||
730 | { | ||
731 | make_link (cnt, offset + x, offset + x + 1, tc); | ||
732 | cnt++; | ||
733 | } | ||
734 | if (0 == x) | ||
735 | break; | ||
736 | make_link (cnt, offset + x, offset, tc); | ||
737 | cnt++; | ||
738 | offset += rows_len[y]; | ||
739 | } | ||
740 | for (x = 0; x < rows_len[0]; x++) | ||
741 | { | ||
742 | offset = 0; | ||
743 | for (y = 0; y < rows - 1; y++) | ||
744 | { | ||
745 | if (x >= rows_len[y + 1]) | ||
746 | break; | ||
747 | GNUNET_assert (x < rows_len[y + 1]); | ||
748 | make_link (cnt, offset + x, offset + rows_len[y] + x, tc); | ||
749 | offset += rows_len[y]; | ||
750 | cnt++; | ||
751 | } | ||
752 | if (0 == offset) | ||
753 | break; | ||
754 | make_link (cnt, offset + x, x, tc); | ||
755 | cnt++; | ||
756 | } | ||
757 | GNUNET_assert (cnt == tc->link_array_size); | ||
758 | GNUNET_free (rows_len); | ||
759 | } | ||
760 | |||
761 | |||
762 | /** | ||
763 | * Generates ring topology | ||
764 | * | ||
765 | * @param tc the topology context | ||
766 | * @param links the number of random links to establish | ||
767 | * @param append #GNUNET_YES to add links to existing link array; #GNUNET_NO to | ||
768 | * create a new link array | ||
769 | */ | ||
770 | static void | ||
771 | gen_topo_random (struct TopologyContext *tc, | ||
772 | unsigned int links, | ||
773 | int append) | ||
774 | { | ||
775 | unsigned int cnt; | ||
776 | unsigned int index; | ||
777 | uint32_t A_rand; | ||
778 | uint32_t B_rand; | ||
779 | |||
780 | if (1 == tc->num_peers) | ||
781 | return; | ||
782 | if (GNUNET_YES == append) | ||
783 | { | ||
784 | index = tc->link_array_size; | ||
785 | tc->link_array_size += links; | ||
786 | } | ||
787 | else | ||
788 | { | ||
789 | index = 0; | ||
790 | tc->link_array_size = links; | ||
791 | } | ||
792 | switch (tc->type) | ||
793 | { | ||
794 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
795 | { | ||
796 | struct TopologyContextOverlay *overlay; | ||
797 | |||
798 | overlay = &tc->u.overlay; | ||
799 | if (GNUNET_YES != append) | ||
800 | { | ||
801 | GNUNET_assert (NULL == overlay->link_array); | ||
802 | overlay->link_array = | ||
803 | GNUNET_malloc (sizeof(struct OverlayLink) * tc->link_array_size); | ||
804 | break; | ||
805 | } | ||
806 | GNUNET_assert ((0 < tc->link_array_size) && (NULL != | ||
807 | overlay->link_array)); | ||
808 | overlay->link_array = | ||
809 | GNUNET_realloc (overlay->link_array, | ||
810 | sizeof(struct OverlayLink) * tc->link_array_size); | ||
811 | break; | ||
812 | } | ||
813 | |||
814 | case TOPOLOGYCONTEXT_TYPE_UNDERLAY: | ||
815 | { | ||
816 | struct TopologyContextUnderlay *underlay; | ||
817 | |||
818 | underlay = &tc->u.underlay; | ||
819 | if (GNUNET_YES != append) | ||
820 | { | ||
821 | GNUNET_assert (NULL == underlay->link_array); | ||
822 | underlay->link_array = | ||
823 | GNUNET_malloc (sizeof(struct UnderlayLink) * tc->link_array_size); | ||
824 | break; | ||
825 | } | ||
826 | GNUNET_assert ((0 < tc->link_array_size) && (NULL != | ||
827 | underlay->link_array)); | ||
828 | underlay->link_array = | ||
829 | GNUNET_realloc (underlay->link_array, | ||
830 | sizeof(struct UnderlayLink) * tc->link_array_size); | ||
831 | break; | ||
832 | } | ||
833 | } | ||
834 | for (cnt = 0; cnt < links; cnt++) | ||
835 | { | ||
836 | do | ||
837 | { | ||
838 | A_rand = | ||
839 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers); | ||
840 | B_rand = | ||
841 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers); | ||
842 | } | ||
843 | while (A_rand == B_rand); | ||
844 | make_link (index + cnt, A_rand, B_rand, tc); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | |||
849 | /** | ||
850 | * Generates scale free network. Its construction is described in: | ||
851 | * | ||
852 | * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. | ||
853 | * | ||
854 | * @param tc the topology context | ||
855 | * @param cap maximum allowed node degree | ||
856 | * @param m number of edges to establish for a new node when it is added to the | ||
857 | * network | ||
858 | */ | ||
859 | static void | ||
860 | gen_topo_scale_free (struct TopologyContext *tc, | ||
861 | uint16_t cap, | ||
862 | uint8_t m) | ||
863 | { | ||
864 | unsigned int *deg; | ||
865 | unsigned int *etab; | ||
866 | unsigned int *used; | ||
867 | unsigned int etaboff; | ||
868 | unsigned int cnt; | ||
869 | unsigned int cnt2; | ||
870 | unsigned int peer; | ||
871 | unsigned int random_peer; | ||
872 | unsigned int links; | ||
873 | unsigned int off; | ||
874 | unsigned int redo_threshold; | ||
875 | |||
876 | etaboff = 0; | ||
877 | tc->link_array_size = tc->num_peers * m; | ||
878 | switch (tc->type) | ||
879 | { | ||
880 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
881 | { | ||
882 | struct TopologyContextOverlay *overlay; | ||
883 | |||
884 | overlay = &tc->u.overlay; | ||
885 | overlay->link_array = GNUNET_malloc_large (sizeof(struct OverlayLink) | ||
886 | * tc->link_array_size); | ||
887 | } | ||
888 | break; | ||
889 | |||
890 | case TOPOLOGYCONTEXT_TYPE_UNDERLAY: | ||
891 | { | ||
892 | struct TopologyContextUnderlay *underlay; | ||
893 | |||
894 | underlay = &tc->u.underlay; | ||
895 | underlay->link_array = GNUNET_malloc_large (sizeof(struct UnderlayLink) | ||
896 | * tc->link_array_size); | ||
897 | } | ||
898 | break; | ||
899 | } | ||
900 | etab = GNUNET_malloc_large (sizeof(unsigned int) * 2 * tc->link_array_size); | ||
901 | deg = GNUNET_malloc (sizeof(unsigned int) * tc->num_peers); | ||
902 | used = GNUNET_malloc (sizeof(unsigned int) * m); | ||
903 | /* start by connecting peer 1 to peer 0 */ | ||
904 | make_link (0, 0, 1, tc); | ||
905 | deg[0]++; | ||
906 | deg[1]++; | ||
907 | etab[etaboff++] = 0; | ||
908 | etab[etaboff++] = 1; | ||
909 | links = 1; | ||
910 | for (peer = 2; peer < tc->num_peers; peer++) | ||
911 | { | ||
912 | if (cap < deg[peer]) | ||
913 | continue; | ||
914 | for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++) | ||
915 | { | ||
916 | redo_threshold = 0; | ||
917 | redo: | ||
918 | off = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, etaboff); | ||
919 | random_peer = etab[off]; | ||
920 | if (cap < deg[random_peer]) | ||
921 | { | ||
922 | if (++redo_threshold > GNUNET_MAX (1, cap / 2)) | ||
923 | { | ||
924 | redo_threshold = 0; | ||
925 | off = 0; | ||
926 | for (cnt2 = 0; cnt2 < etaboff; cnt2++) | ||
927 | { | ||
928 | if (random_peer == etab[cnt2]) | ||
929 | { | ||
930 | off++; | ||
931 | continue; | ||
932 | } | ||
933 | etab[cnt2 - off] = etab[cnt2]; | ||
934 | } | ||
935 | etaboff -= off; | ||
936 | } | ||
937 | goto redo; | ||
938 | } | ||
939 | for (cnt2 = 0; cnt2 < cnt; cnt2++) | ||
940 | if (random_peer == used[cnt2]) | ||
941 | goto redo; | ||
942 | make_link (links + cnt, random_peer, peer, tc); | ||
943 | deg[random_peer]++; | ||
944 | deg[peer]++; | ||
945 | used[cnt] = random_peer; | ||
946 | } | ||
947 | for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++) | ||
948 | { | ||
949 | etab[etaboff++] = used[cnt]; | ||
950 | etab[etaboff++] = peer; | ||
951 | } | ||
952 | links += GNUNET_MIN (peer, m); | ||
953 | } | ||
954 | GNUNET_free (etab); | ||
955 | GNUNET_free (used); | ||
956 | GNUNET_free (deg); | ||
957 | GNUNET_assert (links <= tc->link_array_size); | ||
958 | tc->link_array_size = links; | ||
959 | switch (tc->type) | ||
960 | { | ||
961 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
962 | { | ||
963 | struct TopologyContextOverlay *overlay; | ||
964 | |||
965 | overlay = &tc->u.overlay; | ||
966 | overlay->link_array = | ||
967 | GNUNET_realloc (overlay->link_array, sizeof(struct OverlayLink) | ||
968 | * tc->link_array_size); | ||
969 | } | ||
970 | break; | ||
971 | |||
972 | case TOPOLOGYCONTEXT_TYPE_UNDERLAY: | ||
973 | { | ||
974 | struct TopologyContextUnderlay *underlay; | ||
975 | |||
976 | underlay = &tc->u.underlay; | ||
977 | underlay->link_array = | ||
978 | GNUNET_realloc (underlay->link_array, sizeof(struct UnderlayLink) | ||
979 | * 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 | * We read the peer index | ||
1007 | */ | ||
1008 | PEER_INDEX, | ||
1009 | |||
1010 | /** | ||
1011 | * We read the other peer indices | ||
1012 | */ | ||
1013 | OTHER_PEER_INDEX, | ||
1014 | } state; | ||
1015 | int status; | ||
1016 | |||
1017 | status = GNUNET_SYSERR; | ||
1018 | if (GNUNET_YES != GNUNET_DISK_file_test (filename)) | ||
1019 | { | ||
1020 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1021 | _ ("Topology file %s not found\n"), | ||
1022 | filename); | ||
1023 | return; | ||
1024 | } | ||
1025 | if (GNUNET_OK != | ||
1026 | GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) | ||
1027 | { | ||
1028 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1029 | _ ("Topology file %s has no data\n"), | ||
1030 | filename); | ||
1031 | return; | ||
1032 | } | ||
1033 | data = GNUNET_malloc (fs); | ||
1034 | if (fs != GNUNET_DISK_fn_read (filename, data, fs)) | ||
1035 | { | ||
1036 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1037 | _ ("Topology file %s cannot be read\n"), | ||
1038 | filename); | ||
1039 | goto _exit; | ||
1040 | } | ||
1041 | |||
1042 | offset = 0; | ||
1043 | peer_id = 0; | ||
1044 | state = PEER_INDEX; | ||
1045 | while (offset < fs) | ||
1046 | { | ||
1047 | if (0 != isspace ((unsigned char) data[offset])) | ||
1048 | { | ||
1049 | offset++; | ||
1050 | continue; | ||
1051 | } | ||
1052 | switch (state) | ||
1053 | { | ||
1054 | case PEER_INDEX: | ||
1055 | buf = strchr (&data[offset], ':'); | ||
1056 | if (NULL == buf) | ||
1057 | { | ||
1058 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1059 | _ ("Failed to read peer index from toology file: %s"), filename); | ||
1060 | goto _exit; | ||
1061 | } | ||
1062 | *buf = '\0'; | ||
1063 | errno = 0; | ||
1064 | peer_id = (unsigned int) strtoul (&data[offset], &end, 10); | ||
1065 | if (0 != errno) | ||
1066 | { | ||
1067 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1068 | _ ("Value in given topology file: %s out of range\n"), filename); | ||
1069 | goto _exit; | ||
1070 | } | ||
1071 | if (&data[offset] == end) | ||
1072 | { | ||
1073 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1074 | _ ("Failed to read peer index from topology file: %s"), filename); | ||
1075 | goto _exit; | ||
1076 | } | ||
1077 | if (tc->num_peers <= peer_id) | ||
1078 | { | ||
1079 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1080 | _ ("Topology file needs more peers than given ones\n")); | ||
1081 | goto _exit; | ||
1082 | } | ||
1083 | state = OTHER_PEER_INDEX; | ||
1084 | offset += ((unsigned int) (buf - &data[offset])) + 1; | ||
1085 | break; | ||
1086 | |||
1087 | case OTHER_PEER_INDEX: | ||
1088 | errno = 0; | ||
1089 | other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10); | ||
1090 | if (0 != errno) | ||
1091 | { | ||
1092 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1093 | _ ("Value in given topology file: %s out of range\n"), filename); | ||
1094 | goto _exit; | ||
1095 | } | ||
1096 | if (&data[offset] == end) | ||
1097 | { | ||
1098 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1099 | _ ("Failed to read peer index from topology file: %s"), filename); | ||
1100 | goto _exit; | ||
1101 | } | ||
1102 | if (tc->num_peers <= other_peer_id) | ||
1103 | { | ||
1104 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1105 | _ ("Topology file needs more peers than given ones\n")); | ||
1106 | goto _exit; | ||
1107 | } | ||
1108 | if (peer_id != other_peer_id) | ||
1109 | { | ||
1110 | tc->link_array_size++; | ||
1111 | switch (tc->type) | ||
1112 | { | ||
1113 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
1114 | { | ||
1115 | struct TopologyContextOverlay *overlay; | ||
1116 | |||
1117 | overlay = &tc->u.overlay; | ||
1118 | overlay->link_array = | ||
1119 | GNUNET_realloc (overlay->link_array, | ||
1120 | sizeof(struct OverlayLink) * tc->link_array_size); | ||
1121 | } | ||
1122 | break; | ||
1123 | |||
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) | ||
1132 | * tc->link_array_size); | ||
1133 | } | ||
1134 | break; | ||
1135 | } | ||
1136 | offset += end - &data[offset]; | ||
1137 | make_link (tc->link_array_size - 1, peer_id, other_peer_id, tc); | ||
1138 | } | ||
1139 | else | ||
1140 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1141 | _ ("Ignoring to connect peer %lu to peer %lu\n"), | ||
1142 | peer_id, | ||
1143 | other_peer_id); | ||
1144 | while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs)) | ||
1145 | offset++; | ||
1146 | if ((offset < fs) && | ||
1147 | ('\n' == data[offset])) | ||
1148 | state = PEER_INDEX; | ||
1149 | else if ((offset < fs) && | ||
1150 | ('|' == data[offset])) | ||
1151 | { | ||
1152 | state = OTHER_PEER_INDEX; | ||
1153 | offset++; | ||
1154 | } | ||
1155 | break; | ||
1156 | } | ||
1157 | } | ||
1158 | status = GNUNET_OK; | ||
1159 | |||
1160 | _exit: | ||
1161 | GNUNET_free (data); | ||
1162 | if (GNUNET_OK != status) | ||
1163 | { | ||
1164 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1165 | "Removing link data read from the file\n"); | ||
1166 | tc->link_array_size = 0; | ||
1167 | switch (tc->type) | ||
1168 | { | ||
1169 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
1170 | { | ||
1171 | struct TopologyContextOverlay *overlay; | ||
1172 | |||
1173 | overlay = &tc->u.overlay; | ||
1174 | GNUNET_free (overlay->link_array); | ||
1175 | overlay->link_array = NULL; | ||
1176 | } | ||
1177 | break; | ||
1178 | |||
1179 | case TOPOLOGYCONTEXT_TYPE_UNDERLAY: | ||
1180 | { | ||
1181 | struct TopologyContextUnderlay *underlay; | ||
1182 | |||
1183 | underlay = &tc->u.underlay; | ||
1184 | GNUNET_free (underlay->link_array); | ||
1185 | underlay->link_array = NULL; | ||
1186 | } | ||
1187 | break; | ||
1188 | } | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | |||
1193 | /** | ||
1194 | * Generates clique topology | ||
1195 | * | ||
1196 | * @param tc the topology context | ||
1197 | */ | ||
1198 | static void | ||
1199 | gen_topo_clique (struct TopologyContext *tc) | ||
1200 | { | ||
1201 | unsigned int cnt; | ||
1202 | unsigned int offset; | ||
1203 | unsigned int neighbour; | ||
1204 | |||
1205 | tc->link_array_size = tc->num_peers * (tc->num_peers - 1); | ||
1206 | switch (tc->type) | ||
1207 | { | ||
1208 | case TOPOLOGYCONTEXT_TYPE_OVERLAY: | ||
1209 | { | ||
1210 | struct TopologyContextOverlay *overlay; | ||
1211 | |||
1212 | overlay = &tc->u.overlay; | ||
1213 | overlay->link_array = GNUNET_new_array (tc->link_array_size, | ||
1214 | struct OverlayLink); | ||
1215 | } | ||
1216 | break; | ||
1217 | |||
1218 | case TOPOLOGYCONTEXT_TYPE_UNDERLAY: | ||
1219 | { | ||
1220 | struct TopologyContextUnderlay *underlay; | ||
1221 | |||
1222 | underlay = &tc->u.underlay; | ||
1223 | underlay->link_array = GNUNET_new_array (tc->link_array_size, | ||
1224 | struct UnderlayLink); | ||
1225 | } | ||
1226 | } | ||
1227 | offset = 0; | ||
1228 | for (cnt = 0; cnt < tc->num_peers; cnt++) | ||
1229 | { | ||
1230 | for (neighbour = 0; neighbour < tc->num_peers; neighbour++) | ||
1231 | { | ||
1232 | if (neighbour == cnt) | ||
1233 | continue; | ||
1234 | make_link (offset, cnt, neighbour, tc); | ||
1235 | offset++; | ||
1236 | } | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | |||
1241 | struct GNUNET_TESTBED_Operation * | ||
1242 | GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls, | ||
1243 | unsigned int num_peers, | ||
1244 | struct GNUNET_TESTBED_Peer | ||
1245 | **peers, | ||
1246 | enum | ||
1247 | GNUNET_TESTBED_TopologyOption | ||
1248 | topo, va_list ap) | ||
1249 | { | ||
1250 | GNUNET_break (0); | ||
1251 | return NULL; | ||
1252 | } | ||
1253 | |||
1254 | |||
1255 | struct GNUNET_TESTBED_Operation * | ||
1256 | GNUNET_TESTBED_underlay_configure_topology (void *op_cls, | ||
1257 | unsigned int num_peers, | ||
1258 | struct GNUNET_TESTBED_Peer **peers, | ||
1259 | enum GNUNET_TESTBED_TopologyOption | ||
1260 | topo, ...) | ||
1261 | { | ||
1262 | GNUNET_break (0); | ||
1263 | return NULL; | ||
1264 | } | ||
1265 | |||
1266 | |||
1267 | struct GNUNET_TESTBED_Operation * | ||
1268 | GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls, | ||
1269 | unsigned int num_peers, | ||
1270 | struct GNUNET_TESTBED_Peer **peers, | ||
1271 | unsigned int *max_connections, | ||
1272 | GNUNET_TESTBED_TopologyCompletionCallback | ||
1273 | comp_cb, | ||
1274 | void *comp_cb_cls, | ||
1275 | enum GNUNET_TESTBED_TopologyOption | ||
1276 | topo, | ||
1277 | va_list va) | ||
1278 | { | ||
1279 | struct TopologyContext *tc; | ||
1280 | struct TopologyContextOverlay *overlay; | ||
1281 | struct GNUNET_TESTBED_Operation *op; | ||
1282 | struct GNUNET_TESTBED_Controller *c; | ||
1283 | enum GNUNET_TESTBED_TopologyOption secondary_option; | ||
1284 | |||
1285 | if (num_peers < 2) | ||
1286 | return NULL; | ||
1287 | c = peers[0]->controller; | ||
1288 | tc = GNUNET_new (struct TopologyContext); | ||
1289 | tc->type = TOPOLOGYCONTEXT_TYPE_OVERLAY; | ||
1290 | overlay = &tc->u.overlay; | ||
1291 | overlay->peers = peers; | ||
1292 | tc->num_peers = num_peers; | ||
1293 | overlay->op_cls = op_cls; | ||
1294 | overlay->retry_cnt = DEFAULT_RETRY_CNT; | ||
1295 | overlay->comp_cb = comp_cb; | ||
1296 | overlay->comp_cb_cls = comp_cb_cls; | ||
1297 | switch (topo) | ||
1298 | { | ||
1299 | case GNUNET_TESTBED_TOPOLOGY_LINE: | ||
1300 | gen_topo_line (tc); | ||
1301 | break; | ||
1302 | |||
1303 | case GNUNET_TESTBED_TOPOLOGY_STAR: | ||
1304 | gen_topo_star (tc); | ||
1305 | break; | ||
1306 | |||
1307 | case GNUNET_TESTBED_TOPOLOGY_RING: | ||
1308 | gen_topo_ring (tc); | ||
1309 | break; | ||
1310 | |||
1311 | case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI: | ||
1312 | gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO); | ||
1313 | break; | ||
1314 | |||
1315 | case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING: | ||
1316 | gen_topo_ring (tc); | ||
1317 | gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES); | ||
1318 | break; | ||
1319 | |||
1320 | case GNUNET_TESTBED_TOPOLOGY_CLIQUE: | ||
1321 | gen_topo_clique (tc); | ||
1322 | break; | ||
1323 | |||
1324 | case GNUNET_TESTBED_TOPOLOGY_2D_TORUS: | ||
1325 | gen_topo_2dtorus (tc); | ||
1326 | break; | ||
1327 | |||
1328 | case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD: | ||
1329 | gen_topo_2dtorus (tc); | ||
1330 | gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES); | ||
1331 | |||
1332 | break; | ||
1333 | |||
1334 | case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE: | ||
1335 | { | ||
1336 | uint16_t cap; | ||
1337 | uint8_t m; | ||
1338 | |||
1339 | cap = (uint16_t) va_arg (va, unsigned int); | ||
1340 | m = (uint8_t) va_arg (va, unsigned int); | ||
1341 | gen_topo_scale_free (tc, cap, m); | ||
1342 | } | ||
1343 | break; | ||
1344 | |||
1345 | case GNUNET_TESTBED_TOPOLOGY_FROM_FILE: | ||
1346 | { | ||
1347 | const char *filename; | ||
1348 | |||
1349 | filename = va_arg (va, const char *); | ||
1350 | |||
1351 | GNUNET_assert (NULL != filename); | ||
1352 | gen_topo_from_file (tc, filename); | ||
1353 | } | ||
1354 | break; | ||
1355 | |||
1356 | default: | ||
1357 | GNUNET_break (0); | ||
1358 | GNUNET_free (tc); | ||
1359 | return NULL; | ||
1360 | } | ||
1361 | do | ||
1362 | { | ||
1363 | secondary_option = GNUNET_VA_ARG_ENUM (va, GNUNET_TESTBED_TopologyOption); | ||
1364 | |||
1365 | switch (secondary_option) | ||
1366 | { | ||
1367 | case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT: | ||
1368 | overlay->retry_cnt = va_arg (va, unsigned int); | ||
1369 | break; | ||
1370 | |||
1371 | case GNUNET_TESTBED_TOPOLOGY_OPTION_END: | ||
1372 | break; | ||
1373 | |||
1374 | default: | ||
1375 | GNUNET_break (0); /* Should not use any other option apart from | ||
1376 | * the ones handled here */ | ||
1377 | GNUNET_free (overlay->link_array); | ||
1378 | GNUNET_free (tc); | ||
1379 | return NULL; | ||
1380 | } | ||
1381 | } | ||
1382 | while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option); | ||
1383 | op = GNUNET_TESTBED_operation_create_ (tc, | ||
1384 | &opstart_overlay_configure_topology, | ||
1385 | &oprelease_overlay_configure_topology); | ||
1386 | GNUNET_TESTBED_operation_queue_insert_ | ||
1387 | (c->opq_parallel_topology_config_operations, op); | ||
1388 | GNUNET_TESTBED_operation_begin_wait_ (op); | ||
1389 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1390 | "Generated topology with %u connections\n", | ||
1391 | tc->link_array_size); | ||
1392 | if (NULL != max_connections) | ||
1393 | *max_connections = tc->link_array_size; | ||
1394 | return op; | ||
1395 | } | ||
1396 | |||
1397 | |||
1398 | /** | ||
1399 | * All peers must have been started before calling this function. | ||
1400 | * This function then connects the given peers in the P2P overlay | ||
1401 | * using the given topology. | ||
1402 | * | ||
1403 | * @param op_cls closure argument to give with the peer connect operation events | ||
1404 | * generated through this function | ||
1405 | * @param num_peers number of peers in 'peers' | ||
1406 | * @param peers array of 'num_peers' with the peers to configure | ||
1407 | * @param max_connections the maximums number of overlay connections that will | ||
1408 | * be made to achieve the given topology | ||
1409 | * @param comp_cb the completion callback to call when the topology generation | ||
1410 | * is completed | ||
1411 | * @param comp_cb_cls closure for the above completion callback | ||
1412 | * @param topo desired underlay topology to use | ||
1413 | * @param ... topology-specific options | ||
1414 | * @return handle to the operation, NULL if connecting these | ||
1415 | * peers is fundamentally not possible at this time (peers | ||
1416 | * not running or underlay disallows) or if num_peers is less than 2 | ||
1417 | */ | ||
1418 | struct GNUNET_TESTBED_Operation * | ||
1419 | GNUNET_TESTBED_overlay_configure_topology (void *op_cls, | ||
1420 | unsigned int num_peers, | ||
1421 | struct GNUNET_TESTBED_Peer **peers, | ||
1422 | unsigned int *max_connections, | ||
1423 | GNUNET_TESTBED_TopologyCompletionCallback | ||
1424 | comp_cb, | ||
1425 | void *comp_cb_cls, | ||
1426 | enum GNUNET_TESTBED_TopologyOption | ||
1427 | topo, | ||
1428 | ...) | ||
1429 | { | ||
1430 | struct GNUNET_TESTBED_Operation *op; | ||
1431 | va_list vargs; | ||
1432 | |||
1433 | GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END); | ||
1434 | va_start (vargs, topo); | ||
1435 | op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers, | ||
1436 | max_connections, | ||
1437 | comp_cb, comp_cb_cls, | ||
1438 | topo, | ||
1439 | vargs); | ||
1440 | va_end (vargs); | ||
1441 | return op; | ||
1442 | } | ||
1443 | |||
1444 | |||
1445 | int | ||
1446 | GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology, | ||
1447 | const char *topology_string) | ||
1448 | { | ||
1449 | unsigned int cnt; | ||
1450 | |||
1451 | for (cnt = 0; NULL != topology_strings[cnt]; cnt++) | ||
1452 | { | ||
1453 | if (0 == strcasecmp (topology_string, topology_strings[cnt])) | ||
1454 | { | ||
1455 | if (NULL != topology) | ||
1456 | *topology = (enum GNUNET_TESTBED_TopologyOption) cnt; | ||
1457 | GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END != | ||
1458 | (enum GNUNET_TESTBED_TopologyOption) cnt); | ||
1459 | return GNUNET_YES; | ||
1460 | } | ||
1461 | } | ||
1462 | return GNUNET_NO; | ||
1463 | } | ||
1464 | |||
1465 | |||
1466 | /** | ||
1467 | * Returns the string corresponding to the given topology | ||
1468 | * | ||
1469 | * @param topology the topology | ||
1470 | * @return the string (freshly allocated) of given topology; NULL if topology cannot be | ||
1471 | * expressed as a string | ||
1472 | */ | ||
1473 | char * | ||
1474 | GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology) | ||
1475 | { | ||
1476 | if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology) | ||
1477 | return NULL; | ||
1478 | return GNUNET_strdup (topology_strings[topology]); | ||
1479 | } | ||
1480 | |||
1481 | |||
1482 | /** | ||
1483 | * Function to construct an underlay topology | ||
1484 | * | ||
1485 | * @param num_peers the number of peers for which the topology should be | ||
1486 | * generated | ||
1487 | * @param proc the underlay link processor callback. Will be called for each | ||
1488 | * underlay link generated unless a previous call to this callback | ||
1489 | * returned #GNUNET_SYSERR. Cannot be NULL. | ||
1490 | * @param cls closure for @a proc | ||
1491 | * @param ... variable arguments denoting the topology and its parameters. They | ||
1492 | * should start with the type of topology to generate followed by their | ||
1493 | * options. | ||
1494 | * @return #GNUNET_OK if underlay link generation is successful; #GNUNET_SYSERR | ||
1495 | * upon error in generating the underlay or if any calls to the | ||
1496 | * underlay link processor returned #GNUNET_SYSERR | ||
1497 | */ | ||
1498 | int | ||
1499 | GNUNET_TESTBED_underlay_construct_ (int num_peers, | ||
1500 | underlay_link_processor proc, | ||
1501 | void *cls, | ||
1502 | ...) | ||
1503 | { | ||
1504 | struct TopologyContext tc; | ||
1505 | struct TopologyContextUnderlay *underlay; | ||
1506 | struct UnderlayLink *ulink; | ||
1507 | va_list vargs; | ||
1508 | enum GNUNET_TESTBED_TopologyOption topology; | ||
1509 | unsigned int cnt; | ||
1510 | int ret; | ||
1511 | |||
1512 | GNUNET_assert (NULL != proc); | ||
1513 | ret = GNUNET_OK; | ||
1514 | memset (&tc, 0, sizeof(tc)); | ||
1515 | tc.num_peers = num_peers; | ||
1516 | tc.type = TOPOLOGYCONTEXT_TYPE_UNDERLAY; | ||
1517 | underlay = &tc.u.underlay; | ||
1518 | va_start (vargs, cls); | ||
1519 | topology = GNUNET_VA_ARG_ENUM (vargs, GNUNET_TESTBED_TopologyOption); | ||
1520 | switch (topology) | ||
1521 | { | ||
1522 | case GNUNET_TESTBED_TOPOLOGY_LINE: | ||
1523 | gen_topo_line (&tc); | ||
1524 | break; | ||
1525 | |||
1526 | case GNUNET_TESTBED_TOPOLOGY_STAR: | ||
1527 | gen_topo_star (&tc); | ||
1528 | break; | ||
1529 | |||
1530 | case GNUNET_TESTBED_TOPOLOGY_RING: | ||
1531 | gen_topo_ring (&tc); | ||
1532 | break; | ||
1533 | |||
1534 | case GNUNET_TESTBED_TOPOLOGY_CLIQUE: | ||
1535 | gen_topo_clique (&tc); | ||
1536 | break; | ||
1537 | |||
1538 | case GNUNET_TESTBED_TOPOLOGY_2D_TORUS: | ||
1539 | gen_topo_2dtorus (&tc); | ||
1540 | break; | ||
1541 | |||
1542 | case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI: | ||
1543 | gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_NO); | ||
1544 | break; | ||
1545 | |||
1546 | case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING: | ||
1547 | gen_topo_ring (&tc); | ||
1548 | gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES); | ||
1549 | break; | ||
1550 | |||
1551 | case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD: | ||
1552 | gen_topo_2dtorus (&tc); | ||
1553 | gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES); | ||
1554 | break; | ||
1555 | |||
1556 | case GNUNET_TESTBED_TOPOLOGY_FROM_FILE: | ||
1557 | { | ||
1558 | const char *filename; | ||
1559 | filename = va_arg (vargs, char *); | ||
1560 | GNUNET_assert (NULL != filename); | ||
1561 | gen_topo_from_file (&tc, filename); | ||
1562 | } | ||
1563 | break; | ||
1564 | |||
1565 | case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE: | ||
1566 | { | ||
1567 | uint16_t cap; | ||
1568 | uint8_t m; | ||
1569 | cap = (uint16_t) va_arg (vargs, unsigned int); | ||
1570 | m = (uint8_t) va_arg (vargs, unsigned int); | ||
1571 | gen_topo_scale_free (&tc, cap, m); | ||
1572 | } | ||
1573 | break; | ||
1574 | |||
1575 | default: | ||
1576 | GNUNET_assert (0); | ||
1577 | } | ||
1578 | va_end (vargs); | ||
1579 | for (cnt = 0; cnt < tc.link_array_size; cnt++) | ||
1580 | { | ||
1581 | ulink = &underlay->link_array[cnt]; | ||
1582 | if (GNUNET_SYSERR == proc (cls, | ||
1583 | ulink->A, | ||
1584 | ulink->B, | ||
1585 | ulink->bandwidth, | ||
1586 | ulink->latency, | ||
1587 | ulink->loss)) | ||
1588 | { | ||
1589 | ret = GNUNET_SYSERR; | ||
1590 | break; | ||
1591 | } | ||
1592 | } | ||
1593 | GNUNET_free (underlay->link_array); | ||
1594 | return ret; | ||
1595 | } | ||
1596 | |||
1597 | |||
1598 | /* end of testbed_api_topology.c */ | ||