testbed_api_topology.c 42 KB

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