aboutsummaryrefslogtreecommitdiff
path: root/src/service/topology
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/topology')
-rw-r--r--src/service/topology/.gitignore2
-rw-r--r--src/service/topology/Makefile.am47
-rw-r--r--src/service/topology/gnunet-daemon-topology.c1119
-rw-r--r--src/service/topology/meson.build29
-rw-r--r--src/service/topology/test_gnunet_daemon_topology.c300
-rw-r--r--src/service/topology/test_gnunet_daemon_topology_data.conf34
-rw-r--r--src/service/topology/topology.conf5
7 files changed, 1536 insertions, 0 deletions
diff --git a/src/service/topology/.gitignore b/src/service/topology/.gitignore
new file mode 100644
index 000000000..cfa95ec7e
--- /dev/null
+++ b/src/service/topology/.gitignore
@@ -0,0 +1,2 @@
1gnunet-daemon-topology
2test_gnunet_daemon_topology
diff --git a/src/service/topology/Makefile.am b/src/service/topology/Makefile.am
new file mode 100644
index 000000000..559e55174
--- /dev/null
+++ b/src/service/topology/Makefile.am
@@ -0,0 +1,47 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6endif
7
8pkgcfgdir= $(pkgdatadir)/config.d/
9
10libexecdir= $(pkglibdir)/libexec/
11
12dist_pkgcfg_DATA = \
13 topology.conf
14
15
16libexec_PROGRAMS = \
17 gnunet-daemon-topology
18
19gnunet_daemon_topology_SOURCES = \
20 gnunet-daemon-topology.c
21gnunet_daemon_topology_LDADD = \
22 $(top_builddir)/src/service/core/libgnunetcore.la \
23 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
24 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
25 $(top_builddir)/src/service/transport/libgnunettransportapplication.la \
26 $(top_builddir)/src/lib/hello/libgnunethello.la \
27 $(top_builddir)/src/lib/util/libgnunetutil.la \
28 $(GN_LIBINTL)
29
30
31#check_PROGRAMS = \
32# test_gnunet_daemon_topology
33
34# if ENABLE_TEST_RUN
35# AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
36# TESTS = $(check_PROGRAMS)
37# endif
38
39test_gnunet_daemon_topology_SOURCES = \
40 test_gnunet_daemon_topology.c
41test_gnunet_daemon_topology_LDADD = \
42 $(top_builddir)/src/testbed/libgnunettestbed.la \
43 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
44 $(top_builddir)/src/lib/util/libgnunetutil.la
45
46EXTRA_DIST = \
47 test_gnunet_daemon_topology_data.conf
diff --git a/src/service/topology/gnunet-daemon-topology.c b/src/service/topology/gnunet-daemon-topology.c
new file mode 100644
index 000000000..a95b67908
--- /dev/null
+++ b/src/service/topology/gnunet-daemon-topology.c
@@ -0,0 +1,1119 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2007-2016 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 topology/gnunet-daemon-topology.c
23 * @brief code for maintaining the overlay topology
24 * @author Christian Grothoff
25 *
26 * This daemon combines one Function:
27 * - gossping HELLOs
28 *
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_hello_uri_lib.h"
33#include "gnunet_constants.h"
34#include "gnunet_core_service.h"
35#include "gnunet_protocols.h"
36#include "gnunet_peerstore_service.h"
37#include "gnunet_statistics_service.h"
38#include "gnunet_transport_application_service.h"
39#include <assert.h>
40
41
42/**
43 * At what frequency do we sent HELLOs to a peer?
44 */
45#define HELLO_ADVERTISEMENT_MIN_FREQUENCY \
46 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
47
48/**
49 * After what time period do we expire the HELLO Bloom filter?
50 */
51#define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY \
52 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
53
54
55/**
56 * Record for neighbours and blacklisted peers.
57 */
58struct Peer
59{
60 /**
61 * Which peer is this entry about?
62 */
63 struct GNUNET_PeerIdentity pid;
64
65 /**
66 * Our handle for transmitting to this peer; NULL
67 * if peer is not connected.
68 */
69 struct GNUNET_MQ_Handle *mq;
70
71 /**
72 * Pointer to the hello uri of this peer; can be NULL.
73 */
74 struct GNUNET_MessageHeader *hello;
75
76 /**
77 * Bloom filter used to mark which peers already got the HELLO
78 * from this peer.
79 */
80 struct GNUNET_CONTAINER_BloomFilter *filter;
81
82 /**
83 * Next time we are allowed to transmit a HELLO to this peer?
84 */
85 struct GNUNET_TIME_Absolute next_hello_allowed;
86
87 /**
88 * When should we reset the bloom filter of this entry?
89 */
90 struct GNUNET_TIME_Absolute filter_expiration;
91
92 /**
93 * ID of task we use to wait for the time to send the next HELLO
94 * to this peer.
95 */
96 struct GNUNET_SCHEDULER_Task *hello_delay_task;
97
98 /**
99 * Transport suggest handle.
100 */
101 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *ash;
102
103 /**
104 * How much would we like to connect to this peer?
105 */
106 uint32_t strength;
107
108};
109
110/**
111* Context for a add hello uri request.
112*/
113struct StoreHelloEntry
114{
115 /**
116 * Kept (also) in a DLL.
117 */
118 struct StoreHelloEntry *prev;
119
120 /**
121 * Kept (also) in a DLL.
122 */
123 struct StoreHelloEntry *next;
124
125 /**
126 * Store hello ctx
127 */
128 struct GNUNET_PEERSTORE_StoreHelloContext *sc;
129};
130
131/**
132 * The task to delayed start the notification process intially.
133 * We like to give transport some time to give us our hello to distribute it.
134 */
135struct GNUNET_SCHEDULER_Task *peerstore_notify_task;
136
137
138/**
139 * Our peerstore notification context. We use notification
140 * to instantly learn about new peers as they are discovered.
141 */
142static struct GNUNET_PEERSTORE_Monitor *peerstore_notify;
143
144/**
145 * Our configuration.
146 */
147static const struct GNUNET_CONFIGURATION_Handle *cfg;
148
149/**
150 * Handle to the CORE service.
151 */
152static struct GNUNET_CORE_Handle *handle;
153
154/**
155 * Handle to the PEERSTORE service.
156 */
157static struct GNUNET_PEERSTORE_Handle *ps;
158
159/**
160 * Handle to Transport service.
161 */
162struct GNUNET_TRANSPORT_ApplicationHandle *transport;
163
164/**
165 * Identity of this peer.
166 */
167static struct GNUNET_PeerIdentity my_identity;
168
169/**
170 * Our private key.
171 */
172static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
173
174/**
175 * All of our current neighbours and all peers for
176 * which we have HELLOs. So pretty much everyone. Maps peer identities
177 * to `struct Peer *` values.
178 */
179static struct GNUNET_CONTAINER_MultiPeerMap *peers;
180
181/**
182 * Handle for reporting statistics.
183 */
184static struct GNUNET_STATISTICS_Handle *stats;
185
186/**
187 * Task scheduled to asynchronously reconsider adding/removing
188 * peer connectivity suggestions.
189 */
190static struct GNUNET_SCHEDULER_Task *add_task;
191
192/**
193 * Number of peers that we are currently connected to.
194 */
195static unsigned int connection_count;
196
197/**
198 * Target number of connections.
199 */
200static unsigned int target_connection_count;
201
202/**
203 * Head of the linkd list to store the store context for hellos.
204 */
205static struct StoreHelloEntry *she_head;
206
207/**
208 * Tail of the linkd list to store the store context for hellos.
209 */
210static struct StoreHelloEntry *she_tail;
211
212/**
213 * Free all resources associated with the given peer.
214 *
215 * @param cls closure (not used)
216 * @param pid identity of the peer
217 * @param value peer to free
218 * @return #GNUNET_YES (always: continue to iterate)
219 */
220static int
221free_peer (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
222{
223 struct Peer *pos = value;
224
225 GNUNET_break (NULL == pos->mq);
226 GNUNET_break (GNUNET_OK ==
227 GNUNET_CONTAINER_multipeermap_remove (peers, pid, pos));
228 if (NULL != pos->hello_delay_task)
229 {
230 GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
231 pos->hello_delay_task = NULL;
232 }
233 if (NULL != pos->ash)
234 {
235 GNUNET_TRANSPORT_application_suggest_cancel (pos->ash);
236 pos->ash = NULL;
237 }
238 if (NULL != pos->hello)
239 {
240 GNUNET_free (pos->hello);
241 pos->hello = NULL;
242 }
243 if (NULL != pos->filter)
244 {
245 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
246 pos->filter = NULL;
247 }
248 GNUNET_free (pos);
249 return GNUNET_YES;
250}
251
252
253/**
254 * Recalculate how much we want to be connected to the specified peer
255 * and let ATS know about the result.
256 *
257 * @param pos peer to consider connecting to
258 */
259static void
260attempt_connect (struct Peer *pos)
261{
262 uint32_t strength;
263 struct GNUNET_BANDWIDTH_Value32NBO bw;
264
265 if (0 == GNUNET_memcmp (&my_identity, &pos->pid))
266 return; /* This is myself, nothing to do. */
267 if (connection_count < target_connection_count)
268 strength = 1;
269 else
270 strength = 0;
271 if (NULL != pos->mq)
272 strength *= 2; /* existing connections preferred */
273 if (NULL != pos->ash)
274 {
275 GNUNET_TRANSPORT_application_suggest_cancel (pos->ash);
276 pos->ash = NULL;
277 }
278 pos->strength = strength;
279 if (0 != strength)
280 {
281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282 "Asking to connect to `%s' with strength %u\n",
283 GNUNET_i2s (&pos->pid),
284 (unsigned int) strength);
285 GNUNET_STATISTICS_update (stats,
286 gettext_noop ("# connect requests issued to ATS"),
287 1,
288 GNUNET_NO);
289 // TODO Use strength somehow.
290 bw.value__ = 0;
291 pos->ash = GNUNET_TRANSPORT_application_suggest (transport,
292 &pos->pid,
293 GNUNET_MQ_PRIO_BEST_EFFORT,
294 bw);
295 }
296}
297
298
299/**
300 * Create a new entry in the peer list.
301 *
302 * @param peer identity of the new entry
303 * @param hello hello message, can be NULL
304 * @return the new entry
305 */
306static struct Peer *
307make_peer (const struct GNUNET_PeerIdentity *peer,
308 const struct GNUNET_MessageHeader *hello)
309{
310 struct Peer *ret;
311
312 ret = GNUNET_new (struct Peer);
313 ret->pid = *peer;
314 if (NULL != hello)
315 {
316 ret->hello = GNUNET_malloc (ntohs (hello->size));
317 GNUNET_memcpy (ret->hello, hello, ntohs (hello->size));
318 }
319 GNUNET_break (GNUNET_OK ==
320 GNUNET_CONTAINER_multipeermap_put (
321 peers,
322 peer,
323 ret,
324 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
325 return ret;
326}
327
328
329/**
330 * Setup bloom filter for the given peer entry.
331 *
332 * @param peer entry to initialize
333 */
334static void
335setup_filter (struct Peer *peer)
336{
337 struct GNUNET_HashCode hc;
338
339 /* 2^{-5} chance of not sending a HELLO to a peer is
340 * acceptably small (if the filter is 50% full);
341 * 64 bytes of memory are small compared to the rest
342 * of the data structure and would only really become
343 * "useless" once a HELLO has been passed on to ~100
344 * other peers, which is likely more than enough in
345 * any case; hence 64, 5 as bloomfilter parameters. */peer->filter = GNUNET_CONTAINER_bloomfilter_init (NULL, 64, 5);
346 peer->filter_expiration =
347 GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
348 /* never send a peer its own HELLO */
349 GNUNET_CRYPTO_hash (&peer->pid, sizeof(struct GNUNET_PeerIdentity), &hc);
350 GNUNET_CONTAINER_bloomfilter_add (peer->filter, &hc);
351}
352
353
354/**
355 * Closure for #find_advertisable_hello().
356 */
357struct FindAdvHelloContext
358{
359 /**
360 * Peer we want to advertise to.
361 */
362 struct Peer *peer;
363
364 /**
365 * Where to store the result (peer selected for advertising).
366 */
367 struct Peer *result;
368
369 /**
370 * Maximum HELLO size we can use right now.
371 */
372 size_t max_size;
373
374 struct GNUNET_TIME_Relative next_adv;
375};
376
377
378/**
379 * Find a peer that would be reasonable for advertising.
380 *
381 * @param cls closure
382 * @param pid identity of a peer
383 * @param value 'struct Peer*' for the peer we are considering
384 * @return #GNUNET_YES (continue iteration)
385 */
386static int
387find_advertisable_hello (void *cls,
388 const struct GNUNET_PeerIdentity *pid,
389 void *value)
390{
391 struct FindAdvHelloContext *fah = cls;
392 struct Peer *pos = value;
393 struct GNUNET_TIME_Relative rst_time;
394 struct GNUNET_HashCode hc;
395 size_t hs;
396
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "find_advertisable_hello\n");
399 if (pos == fah->peer)
400 return GNUNET_YES;
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "find_advertisable_hello 2\n");
403 if (pos->hello == NULL)
404 return GNUNET_YES;
405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406 "find_advertisable_hello 3\n");
407 rst_time = GNUNET_TIME_absolute_get_remaining (pos->filter_expiration);
408 if (0 == rst_time.rel_value_us)
409 {
410 /* time to discard... */
411 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
412 setup_filter (pos);
413 }
414 fah->next_adv = GNUNET_TIME_relative_min (rst_time, fah->next_adv);
415 hs = pos->hello->size;
416 if (hs > fah->max_size)
417 return GNUNET_YES;
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419 "find_advertisable_hello 4\n");
420 GNUNET_CRYPTO_hash (&fah->peer->pid,
421 sizeof(struct GNUNET_PeerIdentity),
422 &hc);
423 if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test (pos->filter, &hc))
424 fah->result = pos;
425 return GNUNET_YES;
426}
427
428
429/**
430 * Calculate when we would like to send the next HELLO to this
431 * peer and ask for it.
432 *
433 * @param cls for which peer to schedule the HELLO
434 */
435static void
436schedule_next_hello (void *cls)
437{
438 struct Peer *pl = cls;
439 struct FindAdvHelloContext fah;
440 struct GNUNET_MQ_Envelope *env;
441 size_t want;
442 struct GNUNET_TIME_Relative delay;
443 struct GNUNET_HashCode hc;
444
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446 "schedule_next_hello\n");
447 pl->hello_delay_task = NULL;
448 GNUNET_assert (NULL != pl->mq);
449 /* find applicable HELLOs */
450 fah.peer = pl;
451 fah.result = NULL;
452 fah.max_size = GNUNET_MAX_MESSAGE_SIZE - 1;
453 fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
454 GNUNET_CONTAINER_multipeermap_iterate (peers, &find_advertisable_hello, &fah);
455 if (NULL == fah.result)
456 {
457 pl->hello_delay_task =
458 GNUNET_SCHEDULER_add_delayed (fah.next_adv, &schedule_next_hello, pl);
459
460 return;
461 }
462 want = ntohs (fah.result->hello->size);
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464 "Sending HELLO with %u bytes for peer %s\n",
465 (unsigned int) want,
466 GNUNET_i2s (&pl->pid));
467 env = GNUNET_MQ_msg_copy (fah.result->hello);
468 GNUNET_MQ_send (pl->mq, env);
469
470 /* avoid sending this one again soon */
471 GNUNET_CRYPTO_hash (&pl->pid, sizeof(struct GNUNET_PeerIdentity), &hc);
472 GNUNET_CONTAINER_bloomfilter_add (fah.result->filter, &hc);
473
474 GNUNET_STATISTICS_update (stats,
475 gettext_noop ("# HELLO messages gossipped"),
476 1,
477 GNUNET_NO);
478 /* prepare to send the next one */
479 pl->next_hello_allowed =
480 GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
481 delay = GNUNET_TIME_absolute_get_remaining (pl->next_hello_allowed);
482 pl->hello_delay_task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_next_hello, pl);
483}
484
485
486/**
487 * Cancel existing requests for sending HELLOs to this peer
488 * and recalculate when we should send HELLOs to it based
489 * on our current state (something changed!).
490 *
491 * @param cls closure `struct Peer` to skip, or NULL
492 * @param pid identity of a peer
493 * @param value `struct Peer *` for the peer
494 * @return #GNUNET_YES (always)
495 */
496static int
497reschedule_hellos (void *cls,
498 const struct GNUNET_PeerIdentity *pid,
499 void *value)
500{
501 (void) cls;
502 struct Peer *peer = value;
503
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
505 "Reschedule for `%s'\n",
506 GNUNET_i2s (&peer->pid));
507 if (NULL == peer->mq)
508 return GNUNET_YES;
509 if (NULL != peer->hello_delay_task)
510 {
511 GNUNET_SCHEDULER_cancel (peer->hello_delay_task);
512 peer->hello_delay_task = NULL;
513 }
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 "Schedule_next_hello\n");
516 peer->hello_delay_task =
517 GNUNET_SCHEDULER_add_now (&schedule_next_hello, peer);
518 return GNUNET_YES;
519}
520
521
522/**
523 * Method called whenever a peer connects.
524 *
525 * @param cls closure
526 * @param peer peer identity this notification is about
527 * @param mq message queue for communicating with @a peer
528 * @return our `struct Peer` for @a peer
529 */
530static void *
531connect_notify (void *cls,
532 const struct GNUNET_PeerIdentity *peer,
533 struct GNUNET_MQ_Handle *mq)
534{
535 struct Peer *pos;
536
537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
538 "Core told us that we are connecting to `%s'\n",
539 GNUNET_i2s (peer));
540 if (0 == GNUNET_memcmp (&my_identity, peer))
541 return NULL;
542 GNUNET_MQ_set_options (mq, GNUNET_MQ_PRIO_BEST_EFFORT);
543 connection_count++;
544 GNUNET_STATISTICS_set (stats,
545 gettext_noop ("# peers connected"),
546 connection_count,
547 GNUNET_NO);
548 pos = GNUNET_CONTAINER_multipeermap_get (peers, peer);
549 if (NULL == pos)
550 {
551 pos = make_peer (peer, NULL);
552 }
553 else
554 {
555 GNUNET_assert (NULL == pos->mq);
556 }
557 pos->mq = mq;
558 reschedule_hellos (NULL, peer, pos);
559 return pos;
560}
561
562
563/**
564 * Try to add more peers to our connection set.
565 *
566 * @param cls closure, not used
567 * @param pid identity of a peer
568 * @param value `struct Peer *` for the peer
569 * @return #GNUNET_YES (continue to iterate)
570 */
571static int
572try_add_peers (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
573{
574 struct Peer *pos = value;
575
576 attempt_connect (pos);
577 return GNUNET_YES;
578}
579
580
581/**
582 * Add peers and schedule connection attempt
583 *
584 * @param cls unused, NULL
585 */
586static void
587add_peer_task (void *cls)
588{
589 add_task = NULL;
590
591 GNUNET_CONTAINER_multipeermap_iterate (peers, &try_add_peers, NULL);
592}
593
594
595/**
596 * Method called whenever a peer disconnects.
597 *
598 * @param cls closure
599 * @param peer peer identity this notification is about
600 * @param internal_cls the `struct Peer` for this peer
601 */
602static void
603disconnect_notify (void *cls,
604 const struct GNUNET_PeerIdentity *peer,
605 void *internal_cls)
606{
607 struct Peer *pos = internal_cls;
608
609 if (NULL == pos)
610 return; /* myself, we're shutting down */
611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
612 "Core told us that we disconnected from `%s'\n",
613 GNUNET_i2s (peer));
614 if (NULL == pos->mq)
615 {
616 GNUNET_break (0);
617 return;
618 }
619 pos->mq = NULL;
620 connection_count--;
621 if (NULL != pos->hello_delay_task)
622 {
623 GNUNET_SCHEDULER_cancel (pos->hello_delay_task);
624 pos->hello_delay_task = NULL;
625 }
626 GNUNET_STATISTICS_set (stats,
627 gettext_noop ("# peers connected"),
628 connection_count,
629 GNUNET_NO);
630 if ((connection_count < target_connection_count) &&
631 (NULL == add_task))
632 add_task = GNUNET_SCHEDULER_add_now (&add_peer_task, NULL);
633
634}
635
636
637/**
638 * Iterator called on each address.
639 *
640 * @param cls flag that we will set if we see any addresses
641 * @param address the address of the peer
642 * @return #GNUNET_SYSERR always, to terminate iteration
643 */
644static void
645address_iterator (void *cls,
646 const struct GNUNET_PeerIdentity *pid,
647 const char *uri)
648{
649 (void) pid;
650 int *flag = cls;
651
652 *flag = *flag + 1;
653 // *flag = GNUNET_YES;
654}
655
656
657/**
658 * We've gotten a HELLO from another peer. Consider it for
659 * advertising.
660 *
661 * @param hello the HELLO we got
662 */
663static void
664consider_for_advertising (const struct GNUNET_MessageHeader *hello)
665{
666 int num_addresses_old = 0;
667 int num_addresses_new = 0;
668 struct GNUNET_HELLO_Builder *builder = GNUNET_HELLO_builder_from_msg (hello);
669 const struct GNUNET_PeerIdentity *pid;
670 struct Peer *peer;
671 uint16_t size;
672
673 pid = GNUNET_HELLO_builder_iterate (builder,
674 &address_iterator,
675 &num_addresses_new);
676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
677 "consider 0 for %s\n",
678 GNUNET_i2s (pid));
679 if (0 == num_addresses_new)
680 {
681 GNUNET_HELLO_builder_free (builder);
682 return; /* no point in advertising this one... */
683 }
684 peer = GNUNET_CONTAINER_multipeermap_get (peers, pid);
685 if (NULL == peer)
686 {
687 peer = make_peer (pid, hello);
688 }
689 else if (NULL != peer->hello)
690 {
691 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
692 struct GNUNET_TIME_Absolute new_hello_exp =
693 GNUNET_HELLO_builder_get_expiration_time (hello);
694 struct GNUNET_TIME_Absolute old_hello_exp =
695 GNUNET_HELLO_builder_get_expiration_time (peer->hello);
696 struct GNUNET_HELLO_Builder *builder_old = GNUNET_HELLO_builder_from_msg (
697 peer->hello);
698
699 GNUNET_HELLO_builder_iterate (builder_old,
700 &address_iterator,
701 &num_addresses_old);
702 GNUNET_HELLO_builder_free (builder_old);
703 if (GNUNET_TIME_absolute_cmp (new_hello_exp, >, now) &&
704 (GNUNET_TIME_absolute_cmp (new_hello_exp, >, old_hello_exp) ||
705 num_addresses_old < num_addresses_new))
706 {
707 GNUNET_free (peer->hello);
708 size = ntohs (hello->size);
709 peer->hello = GNUNET_malloc (size);
710 GNUNET_memcpy (peer->hello, hello, size);
711 }
712 else
713 {
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "consider 3\n");
716 GNUNET_HELLO_builder_free (builder);
717 return;
718 }
719 }
720 else
721 {
722 size = ntohs (hello->size);
723 peer->hello = GNUNET_malloc (size);
724 GNUNET_memcpy (peer->hello, hello, size);
725 }
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 "Found HELLO from peer `%s' for advertising\n",
728 GNUNET_i2s (pid));
729 if (NULL != peer->filter)
730 {
731 GNUNET_CONTAINER_bloomfilter_free (peer->filter);
732 peer->filter = NULL;
733 }
734 setup_filter (peer);
735 /* since we have a new HELLO to pick from, re-schedule all
736 * HELLO requests that are not bound by the HELLO send rate! */
737 GNUNET_CONTAINER_multipeermap_iterate (peers, &reschedule_hellos, NULL);
738 GNUNET_HELLO_builder_free (builder);
739}
740
741
742static void
743error_cb (void *cls)
744{
745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
746 _ (
747 "Error in communication with PEERSTORE service to monitor.\n"));
748 return;
749}
750
751
752static void
753sync_cb (void *cls)
754{
755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
756 _ ("Finished initial PEERSTORE iteration in monitor.\n"));
757 return;
758}
759
760
761/**
762 * PEERSTORE calls this function to let us know about a possible peer
763 * that we might want to connect to.
764 *
765 * @param cls closure (not used)
766 * @param peer potential peer to connect to
767 * @param hello HELLO for this peer (or NULL)
768 * @param err_msg NULL if successful, otherwise contains error message
769 */
770static void
771process_peer (void *cls,
772 const struct GNUNET_PEERSTORE_Record *record,
773 const char *err_msg)
774{
775 struct Peer *pos;
776 struct GNUNET_MessageHeader *hello;
777
778 if (NULL != err_msg)
779 {
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 _ ("Error in communication with PEERSTORE service: %s\n"),
782 err_msg);
783 GNUNET_PEERSTORE_monitor_stop (peerstore_notify);
784 peerstore_notify =
785 GNUNET_PEERSTORE_monitor_start (cfg,
786 GNUNET_YES,
787 "peerstore",
788 NULL,
789 GNUNET_PEERSTORE_HELLO_KEY,
790 error_cb,
791 NULL,
792 sync_cb,
793 NULL,
794 &process_peer,
795 NULL);
796 return;
797 }
798 GNUNET_assert (NULL != record);
799 hello = record->value;
800 if (NULL == hello)
801 {
802 /* free existing HELLO, if any */
803 pos = GNUNET_CONTAINER_multipeermap_get (peers, &record->peer);
804 if (NULL != pos)
805 {
806 GNUNET_free (pos->hello);
807 pos->hello = NULL;
808 if (NULL != pos->filter)
809 {
810 GNUNET_CONTAINER_bloomfilter_free (pos->filter);
811 pos->filter = NULL;
812 }
813 if (NULL == pos->mq)
814 free_peer (NULL, &pos->pid, pos);
815 }
816 GNUNET_PEERSTORE_monitor_next (peerstore_notify, 1);
817 return;
818 }
819 consider_for_advertising (hello);
820 pos = GNUNET_CONTAINER_multipeermap_get (peers, &record->peer);
821 if (NULL == pos)
822 pos = make_peer (&record->peer, hello);
823 attempt_connect (pos);
824 GNUNET_PEERSTORE_monitor_next (peerstore_notify, 1);
825}
826
827
828static void
829start_notify (void *cls)
830{
831 (void) cls;
832
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834 "Starting to process new hellos for gossiping.\n");
835 peerstore_notify =
836 GNUNET_PEERSTORE_monitor_start (cfg,
837 GNUNET_YES,
838 "peerstore",
839 NULL,
840 GNUNET_PEERSTORE_HELLO_KEY,
841 &error_cb,
842 NULL,
843 &sync_cb,
844 NULL,
845 &process_peer,
846 NULL);
847}
848
849
850/**
851 * Function called after #GNUNET_CORE_connect has succeeded
852 * (or failed for good).
853 *
854 * @param cls closure
855 * @param my_id ID of this peer, NULL if we failed
856 */
857static void
858core_init (void *cls, const struct GNUNET_PeerIdentity *my_id)
859{
860 if (NULL == my_id)
861 {
862 GNUNET_log (
863 GNUNET_ERROR_TYPE_ERROR,
864 _ ("Failed to connect to core service, can not manage topology!\n"));
865 GNUNET_SCHEDULER_shutdown ();
866 return;
867 }
868 my_identity = *my_id;
869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am peer `%s'\n", GNUNET_i2s (my_id));
870 peerstore_notify_task = GNUNET_SCHEDULER_add_delayed (
871 GNUNET_TIME_UNIT_MINUTES,
872 start_notify,
873 NULL);
874}
875
876
877/**
878 * This function is called whenever an encrypted HELLO message is
879 * received.
880 *
881 * @param cls closure with the peer identity of the sender
882 * @param message the actual HELLO message
883 * @return #GNUNET_OK if @a message is well-formed
884 * #GNUNET_SYSERR if @a message is invalid
885 */
886static int
887check_hello (void *cls, const struct GNUNET_MessageHeader *message)
888{
889 struct GNUNET_HELLO_Builder *builder = GNUNET_HELLO_builder_from_msg (
890 message);
891 const struct GNUNET_PeerIdentity *pid = GNUNET_HELLO_builder_get_id (builder);
892
893 if (NULL == pid)
894 {
895 GNUNET_break_op (0);
896 return GNUNET_SYSERR;
897 }
898 return GNUNET_OK;
899}
900
901
902static void
903shc_cont (void *cls, int success)
904{
905 struct StoreHelloEntry *she = cls;
906
907 she->sc = NULL;
908 if (GNUNET_YES == success)
909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
910 "Hello stored successfully!\n");
911 else
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913 "Error storing hello!\n");
914 GNUNET_CONTAINER_DLL_remove (she_head, she_tail, she);
915 GNUNET_free (she);
916}
917
918
919/**
920 * This function is called whenever an encrypted HELLO message is
921 * received.
922 *
923 * @param cls closure with the peer identity of the sender
924 * @param message the actual HELLO message
925 */
926static void
927handle_hello (void *cls, const struct GNUNET_MessageHeader *message)
928{
929 struct StoreHelloEntry *she;
930 const struct GNUNET_PeerIdentity *other = cls;
931 struct GNUNET_HELLO_Builder *builder = GNUNET_HELLO_builder_from_msg (
932 message);
933
934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
935 "Received encrypted HELLO from peer `%s'\n",
936 GNUNET_i2s (other));
937 GNUNET_STATISTICS_update (stats,
938 gettext_noop ("# HELLO messages received"),
939 1,
940 GNUNET_NO);
941 GNUNET_HELLO_builder_from_msg (message);
942 she = GNUNET_new (struct StoreHelloEntry);
943 she->sc = GNUNET_PEERSTORE_hello_add (ps, message, &shc_cont, she);
944 if (NULL != she->sc)
945 {
946 GNUNET_CONTAINER_DLL_insert (she_head, she_tail, she);
947 }
948 else
949 GNUNET_free (she);
950 GNUNET_HELLO_builder_free (builder);
951}
952
953
954/**
955 * Last task run during shutdown. Disconnects us from
956 * the transport and core.
957 *
958 * @param cls unused, NULL
959 */
960static void
961cleaning_task (void *cls)
962{
963 struct StoreHelloEntry *pos;
964
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Topology shutdown\n");
966 while (NULL != (pos = she_head))
967 {
968 GNUNET_CONTAINER_DLL_remove (she_head, she_tail, pos);
969 if (NULL != pos->sc)
970 GNUNET_PEERSTORE_hello_add_cancel (pos->sc);
971 GNUNET_free (pos);
972 }
973 if (NULL != peerstore_notify)
974 {
975 GNUNET_PEERSTORE_monitor_stop (peerstore_notify);
976 peerstore_notify = NULL;
977 }
978 else if (NULL != peerstore_notify_task)
979 {
980 GNUNET_SCHEDULER_cancel (peerstore_notify_task);
981 }
982 if (NULL != handle)
983 {
984 GNUNET_CORE_disconnect (handle);
985 handle = NULL;
986 }
987 if (NULL != add_task)
988 {
989 GNUNET_SCHEDULER_cancel (add_task);
990 add_task = NULL;
991 }
992 GNUNET_CONTAINER_multipeermap_iterate (peers, &free_peer, NULL);
993 GNUNET_CONTAINER_multipeermap_destroy (peers);
994 peers = NULL;
995 if (NULL != transport)
996 {
997 GNUNET_TRANSPORT_application_done (transport);
998 transport = NULL;
999 }
1000 if (NULL != ps)
1001 {
1002 GNUNET_PEERSTORE_disconnect (ps);
1003 ps = NULL;
1004 }
1005 if (NULL != stats)
1006 {
1007 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1008 stats = NULL;
1009 }
1010 GNUNET_free (my_private_key);
1011}
1012
1013
1014/**
1015 * Main function that will be run.
1016 *
1017 * @param cls closure
1018 * @param args remaining command-line arguments
1019 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1020 * @param c configuration
1021 */
1022static void
1023run (void *cls,
1024 char *const *args,
1025 const char *cfgfile,
1026 const struct GNUNET_CONFIGURATION_Handle *c)
1027{
1028 struct GNUNET_MQ_MessageHandler handlers[] =
1029 { GNUNET_MQ_hd_var_size (hello,
1030 GNUNET_MESSAGE_TYPE_HELLO_URI,
1031 struct GNUNET_MessageHeader,
1032 NULL),
1033 GNUNET_MQ_handler_end () };
1034 unsigned long long opt;
1035
1036 cfg = c;
1037 my_private_key =
1038 GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1039 stats = GNUNET_STATISTICS_create ("topology", cfg);
1040
1041 if (GNUNET_OK !=
1042 GNUNET_CONFIGURATION_get_value_number (cfg,
1043 "TOPOLOGY",
1044 "TARGET-CONNECTION-COUNT",
1045 &opt))
1046 opt = 16;
1047 target_connection_count = (unsigned int) opt;
1048 peers = GNUNET_CONTAINER_multipeermap_create (target_connection_count * 2,
1049 GNUNET_NO);
1050 transport = GNUNET_TRANSPORT_application_init (cfg);
1051 ps = GNUNET_PEERSTORE_connect (cfg);
1052 handle = GNUNET_CORE_connect (cfg,
1053 NULL,
1054 &core_init,
1055 &connect_notify,
1056 &disconnect_notify,
1057 handlers);
1058 GNUNET_SCHEDULER_add_shutdown (&cleaning_task, NULL);
1059 if (NULL == handle)
1060 {
1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1062 _ ("Failed to connect to `%s' service.\n"),
1063 "core");
1064 GNUNET_SCHEDULER_shutdown ();
1065 return;
1066 }
1067}
1068
1069
1070/**
1071 * The main function for the topology daemon.
1072 *
1073 * @param argc number of arguments from the command line
1074 * @param argv command line arguments
1075 * @return 0 ok, 1 on error
1076 */
1077int
1078main (int argc, char *const *argv)
1079{
1080 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1081 GNUNET_GETOPT_OPTION_END
1082 };
1083 int ret;
1084
1085 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1086 return 2;
1087
1088 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
1089 argv,
1090 "gnunet-daemon-topology",
1091 _ ("GNUnet topology control"),
1092 options,
1093 &run,
1094 NULL))
1095 ? 0
1096 : 1;
1097 GNUNET_free_nz ((void *) argv);
1098 return ret;
1099}
1100
1101
1102#if defined(__linux__) && defined(__GLIBC__)
1103#include <malloc.h>
1104
1105/**
1106 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1107 */
1108void __attribute__ ((constructor))
1109GNUNET_TOPOLOGY_memory_init ()
1110{
1111 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1112 mallopt (M_TOP_PAD, 1 * 1024);
1113 malloc_trim (0);
1114}
1115
1116
1117#endif
1118
1119/* end of gnunet-daemon-topology.c */
diff --git a/src/service/topology/meson.build b/src/service/topology/meson.build
new file mode 100644
index 000000000..ca3cc6935
--- /dev/null
+++ b/src/service/topology/meson.build
@@ -0,0 +1,29 @@
1gnunetdaemontopology_src = ['gnunet-daemon-topology.c']
2
3configure_file(input : 'topology.conf',
4 output : 'topology.conf',
5 configuration : cdata,
6 install: true,
7 install_dir: pkgcfgdir)
8
9
10if get_option('monolith')
11 # FIXME add daemon when new daemon macro is ported/ready for it.
12 #foreach p : libgnunetfriends_src
13 # gnunet_src += 'topology/' + p
14 #endforeach
15endif
16
17executable ('gnunet-daemon-topology',
18 gnunetdaemontopology_src,
19 dependencies: [
20 libgnunetutil_dep,
21 libgnunetcore_dep,
22 libgnunetpeerstore_dep,
23 libgnunetstatistics_dep,
24 libgnunettransportapplication_dep,
25 libgnunethello_dep],
26 include_directories: [incdir, configuration_inc],
27 install: true,
28 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
29
diff --git a/src/service/topology/test_gnunet_daemon_topology.c b/src/service/topology/test_gnunet_daemon_topology.c
new file mode 100644
index 000000000..6f9758b09
--- /dev/null
+++ b/src/service/topology/test_gnunet_daemon_topology.c
@@ -0,0 +1,300 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 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 * @file topology/test_gnunet_daemon_topology.c
22 * @brief testcase for topology maintenance code
23 * @author Christian Grothoff
24 * @author xrs
25 */
26#include "platform.h"
27#include "gnunet_testbed_service.h"
28#include "gnunet_statistics_service.h"
29
30
31#define NUM_PEERS 8
32
33/*
34 * The threshold defines the number of connection that are needed
35 * for one peer to pass the test. Be aware that setting NUM_PEERS
36 * too high can cause bandwidth problems for the testing peers.
37 * Normal should be 5KB/s per peer. See gnunet-config -s ats.
38 * schanzen 12/2019: This _only_ makes sense if we connect to the
39 * actual network as in the test we do not connect to more than 1 peer.
40 * => reducing to 1 for now, was NUM_PEERS / 2
41 */
42#define THRESHOLD 1
43
44/**
45 * How long until we give up on connecting the peers?
46 */
47#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
48
49/*
50 * Store manual connections.
51 */
52static unsigned int connect_left;
53
54/*
55 * Result of the testcase.
56 */
57static int result;
58
59/*
60 * Peers that reached the threshold of connections.
61 */
62static int checked_peers;
63
64/*
65 * Testbed operations.
66 */
67struct GNUNET_TESTBED_Operation *op[NUM_PEERS];
68
69/*
70 * Timeout for testcase.
71 */
72static struct GNUNET_SCHEDULER_Task *timeout_tid;
73
74/*
75 * Peer context for every testbed peer.
76 */
77struct peerctx
78{
79 int index;
80 struct GNUNET_STATISTICS_Handle *statistics;
81 int connections;
82 int reported; /* GNUNET_NO | GNUNET_YES */
83};
84
85
86static void
87shutdown_task (void *cls)
88{
89 unsigned int i;
90
91 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
92 "Shutting down testcase\n");
93
94 for (i = 0; i < NUM_PEERS; i++)
95 {
96 if (NULL != op[i])
97 GNUNET_TESTBED_operation_done (op[i]);
98 }
99
100 if (NULL != timeout_tid)
101 GNUNET_SCHEDULER_cancel (timeout_tid);
102}
103
104
105static void
106timeout_task (void *cls)
107{
108 timeout_tid = NULL;
109 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
110 "Testcase timeout\n");
111
112 result = GNUNET_SYSERR;
113 GNUNET_SCHEDULER_shutdown ();
114}
115
116
117/*
118 * The function is called every time the topology of connected
119 * peers to a peer changes.
120 */
121int
122statistics_iterator (void *cls,
123 const char *subsystem,
124 const char *name,
125 uint64_t value,
126 int is_persistent)
127{
128 struct peerctx *p_ctx = (struct peerctx*) cls;
129
130 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
131 "Peer %d: %s = %llu\n",
132 p_ctx->index,
133 name,
134 (unsigned long long) value);
135
136 if (p_ctx->connections < value)
137 p_ctx->connections = value;
138
139 if ((THRESHOLD <= value) && (GNUNET_NO == p_ctx->reported))
140 {
141 p_ctx->reported = GNUNET_YES;
142 checked_peers++;
143 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
144 "Peer %d successfully connected to at least %d peers once.\n",
145 p_ctx->index,
146 THRESHOLD);
147
148 if (checked_peers == NUM_PEERS)
149 {
150 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
151 "Test OK: All peers have connected to %d peers once.\n",
152 THRESHOLD);
153 result = GNUNET_YES;
154 GNUNET_SCHEDULER_shutdown ();
155 }
156 }
157
158 return GNUNET_YES;
159}
160
161
162static void *
163ca_statistics (void *cls,
164 const struct GNUNET_CONFIGURATION_Handle *cfg)
165{
166 return GNUNET_STATISTICS_create ("topology", cfg);
167}
168
169
170void
171da_statistics (void *cls,
172 void *op_result)
173{
174 struct peerctx *p_ctx = (struct peerctx *) cls;
175
176 GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
177 (p_ctx->statistics, "topology", "# peers connected",
178 statistics_iterator, p_ctx));
179
180 GNUNET_STATISTICS_destroy (p_ctx->statistics, GNUNET_NO);
181 p_ctx->statistics = NULL;
182
183 GNUNET_free (p_ctx);
184}
185
186
187static void
188service_connect_complete (void *cls,
189 struct GNUNET_TESTBED_Operation *op,
190 void *ca_result,
191 const char *emsg)
192{
193 int ret;
194 struct peerctx *p_ctx = (struct peerctx*) cls;
195
196 if (NULL == ca_result)
197 GNUNET_SCHEDULER_shutdown ();
198
199 p_ctx->statistics = ca_result;
200
201 ret = GNUNET_STATISTICS_watch (ca_result,
202 "topology",
203 "# peers connected",
204 statistics_iterator,
205 p_ctx);
206
207 if (GNUNET_NO == ret)
208 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
209 "call to GNUNET_STATISTICS_watch() failed\n");
210}
211
212
213static void
214notify_connect_complete (void *cls,
215 struct GNUNET_TESTBED_Operation *op,
216 const char *emsg)
217{
218 GNUNET_TESTBED_operation_done (op);
219 if (NULL != emsg)
220 {
221 fprintf (stderr, "Failed to connect two peers: %s\n", emsg);
222 result = GNUNET_SYSERR;
223 GNUNET_SCHEDULER_shutdown ();
224 return;
225 }
226 connect_left--;
227}
228
229
230static void
231do_connect (void *cls,
232 struct GNUNET_TESTBED_RunHandle *h,
233 unsigned int num_peers,
234 struct GNUNET_TESTBED_Peer **peers,
235 unsigned int links_succeeded,
236 unsigned int links_failed)
237{
238 unsigned int i;
239 struct peerctx *p_ctx;
240
241 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
242 "Threshold is set to %d.\n",
243 THRESHOLD);
244
245 GNUNET_assert (NUM_PEERS == num_peers);
246
247 for (i = 0; i < NUM_PEERS; i++)
248 {
249 p_ctx = GNUNET_new (struct peerctx);
250 p_ctx->index = i;
251 p_ctx->connections = 0;
252 p_ctx->reported = GNUNET_NO;
253
254 if (i < NUM_PEERS - 1)
255 {
256 connect_left++;
257 GNUNET_TESTBED_overlay_connect (NULL,
258 &notify_connect_complete, NULL,
259 peers[i], peers[i + 1]);
260 }
261
262 op[i] =
263 GNUNET_TESTBED_service_connect (cls,
264 peers[i],
265 "statistics",
266 service_connect_complete,
267 p_ctx, /* cls of completion cb */
268 ca_statistics, /* connect adapter */
269 da_statistics, /* disconnect adapter */
270 p_ctx);
271 }
272
273 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
274 timeout_tid =
275 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
276 &timeout_task,
277 NULL);
278}
279
280
281int
282main (int argc, char *argv[])
283{
284 result = GNUNET_SYSERR;
285 checked_peers = 0;
286
287 (void) GNUNET_TESTBED_test_run ("test-gnunet-daemon-topology",
288 "test_gnunet_daemon_topology_data.conf",
289 NUM_PEERS,
290 0, NULL, NULL,
291 &do_connect, NULL);
292 GNUNET_DISK_purge_cfg_dir
293 ("test_gnunet_daemon_topology_data.conf",
294 "GNUNET_TEST_HOME");
295
296 return (GNUNET_OK != result) ? 1 : 0;
297}
298
299
300/* end of test_gnunet_daemon_topology.c */
diff --git a/src/service/topology/test_gnunet_daemon_topology_data.conf b/src/service/topology/test_gnunet_daemon_topology_data.conf
new file mode 100644
index 000000000..b1b3e9b88
--- /dev/null
+++ b/src/service/topology/test_gnunet_daemon_topology_data.conf
@@ -0,0 +1,34 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-topology/
3
4[transport]
5PLUGINS = tcp
6#PREFIX = xterm -e xterm -T transport -e gdb -x cmd --args
7#PREFIX = valgrind --tool=memcheck --log-file=logs%p
8
9[testbed]
10OVERLAY_TOPOLOGY=LINE
11
12[transport-tcp]
13BINDTO = 127.0.0.1
14
15# Do not try to connect to external network
16[hostlist]
17OPTIONS =
18
19[nat]
20DISABLEV6 = YES
21ENABLE_UPNP = NO
22BEHIND_NAT = NO
23ALLOW_NAT = NO
24INTERNAL_ADDRESS = 127.0.0.1
25EXTERNAL_ADDRESS = 127.0.0.1
26USE_LOCALADDR = NO
27USE_HOSTNAME = NO
28
29[nse]
30WORKBITS = 0
31
32[rps]
33START_ON_DEMAND = NO
34IMMEDIATE_START = NO
diff --git a/src/service/topology/topology.conf b/src/service/topology/topology.conf
new file mode 100644
index 000000000..9bcfb479c
--- /dev/null
+++ b/src/service/topology/topology.conf
@@ -0,0 +1,5 @@
1[topology]
2IMMEDIATE_START = YES
3NOARMBIND = YES
4TARGET-CONNECTION-COUNT = 16
5BINARY = gnunet-daemon-topology