uncrustify as demanded.
[oweals/gnunet.git] / src / topology / gnunet-daemon-topology.c
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 three functions:
27  * - suggesting to ATS which peers we might want to connect to
28  * - enforcing the F2F restrictions (by blacklisting)
29  * - gossping HELLOs
30  *
31  * All three require similar information (who are our friends
32  * impacts connectivity suggestions; connectivity suggestions
33  * should consider blacklisting; connectivity suggestions
34  * should consider available/known HELLOs; gossip requires
35  * connectivity data; connectivity suggestions require
36  * connectivity data), which is why they are combined in this
37  * program.
38  */
39 #include "platform.h"
40 #include "gnunet_util_lib.h"
41 #include "gnunet_friends_lib.h"
42 #include "gnunet_constants.h"
43 #include "gnunet_core_service.h"
44 #include "gnunet_protocols.h"
45 #include "gnunet_peerinfo_service.h"
46 #include "gnunet_statistics_service.h"
47 #include "gnunet_transport_service.h"
48 #include "gnunet_ats_service.h"
49
50
51 /**
52  * At what frequency do we sent HELLOs to a peer?
53  */
54 #define HELLO_ADVERTISEMENT_MIN_FREQUENCY \
55   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
56
57 /**
58  * After what time period do we expire the HELLO Bloom filter?
59  */
60 #define HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY \
61   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_HOURS, 4)
62
63
64 /**
65  * Record for neighbours, friends and blacklisted peers.
66  */
67 struct Peer {
68   /**
69    * Which peer is this entry about?
70    */
71   struct GNUNET_PeerIdentity pid;
72
73   /**
74    * Our handle for transmitting to this peer; NULL
75    * if peer is not connected.
76    */
77   struct GNUNET_MQ_Handle *mq;
78
79   /**
80    * Pointer to the HELLO message of this peer; can be NULL.
81    */
82   struct GNUNET_HELLO_Message *hello;
83
84   /**
85    * Bloom filter used to mark which peers already got the HELLO
86    * from this peer.
87    */
88   struct GNUNET_CONTAINER_BloomFilter *filter;
89
90   /**
91    * Next time we are allowed to transmit a HELLO to this peer?
92    */
93   struct GNUNET_TIME_Absolute next_hello_allowed;
94
95   /**
96    * When should we reset the bloom filter of this entry?
97    */
98   struct GNUNET_TIME_Absolute filter_expiration;
99
100   /**
101    * ID of task we use to wait for the time to send the next HELLO
102    * to this peer.
103    */
104   struct GNUNET_SCHEDULER_Task *hello_delay_task;
105
106   /**
107    * Handle for our connectivity suggestion for this peer.
108    */
109   struct GNUNET_ATS_ConnectivitySuggestHandle *sh;
110
111   /**
112    * How much would we like to connect to this peer?
113    */
114   uint32_t strength;
115
116   /**
117    * Is this peer listed here because it is a friend?
118    */
119   int is_friend;
120 };
121
122
123 /**
124  * Our peerinfo notification context.  We use notification
125  * to instantly learn about new peers as they are discovered.
126  */
127 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify;
128
129 /**
130  * Our configuration.
131  */
132 static const struct GNUNET_CONFIGURATION_Handle *cfg;
133
134 /**
135  * Handle to the CORE service.
136  */
137 static struct GNUNET_CORE_Handle *handle;
138
139 /**
140  * Handle to the PEERINFO service.
141  */
142 static struct GNUNET_PEERINFO_Handle *pi;
143
144 /**
145  * Handle to the ATS service.
146  */
147 static struct GNUNET_ATS_ConnectivityHandle *ats;
148
149 /**
150  * Identity of this peer.
151  */
152 static struct GNUNET_PeerIdentity my_identity;
153
154 /**
155  * All of our friends, all of our current neighbours and all peers for
156  * which we have HELLOs.  So pretty much everyone.  Maps peer identities
157  * to `struct Peer *` values.
158  */
159 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
160
161 /**
162  * Handle for reporting statistics.
163  */
164 static struct GNUNET_STATISTICS_Handle *stats;
165
166 /**
167  * Blacklist (NULL if we have none).
168  */
169 static struct GNUNET_TRANSPORT_Blacklist *blacklist;
170
171 /**
172  * Task scheduled to asynchronously reconsider adding/removing
173  * peer connectivity suggestions.
174  */
175 static struct GNUNET_SCHEDULER_Task *add_task;
176
177 /**
178  * Active HELLO offering to transport service.
179  */
180 static struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
181
182 /**
183  * Flag to disallow non-friend connections (pure F2F mode).
184  */
185 static int friends_only;
186
187 /**
188  * Minimum number of friends to have in the
189  * connection set before we allow non-friends.
190  */
191 static unsigned int minimum_friend_count;
192
193 /**
194  * Number of peers (friends and others) that we are currently connected to.
195  */
196 static unsigned int connection_count;
197
198 /**
199  * Target number of connections.
200  */
201 static unsigned int target_connection_count;
202
203 /**
204  * Number of friends that we are currently connected to.
205  */
206 static unsigned int friend_count;
207
208
209 /**
210  * Function that decides if a connection is acceptable or not.
211  * If we have a blacklist, only friends are allowed, so the check
212  * is rather simple.
213  *
214  * @param cls closure
215  * @param pid peer to approve or disapprove
216  * @return #GNUNET_OK if the connection is allowed
217  */
218 static int
219 blacklist_check(void *cls, const struct GNUNET_PeerIdentity *pid)
220 {
221   struct Peer *pos;
222
223   pos = GNUNET_CONTAINER_multipeermap_get(peers, pid);
224   if ((NULL != pos) && (GNUNET_YES == pos->is_friend))
225     return GNUNET_OK;
226   GNUNET_STATISTICS_update(stats,
227                            gettext_noop("# peers blacklisted"),
228                            1,
229                            GNUNET_NO);
230   return GNUNET_SYSERR;
231 }
232
233
234 /**
235  * Whitelist all peers that we blacklisted; we've passed
236  * the minimum number of friends.
237  */
238 static void
239 whitelist_peers()
240 {
241   if (NULL != blacklist)
242     {
243       GNUNET_TRANSPORT_blacklist_cancel(blacklist);
244       blacklist = NULL;
245     }
246 }
247
248
249 /**
250  * Free all resources associated with the given peer.
251  *
252  * @param cls closure (not used)
253  * @param pid identity of the peer
254  * @param value peer to free
255  * @return #GNUNET_YES (always: continue to iterate)
256  */
257 static int
258 free_peer(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
259 {
260   struct Peer *pos = value;
261
262   GNUNET_break(NULL == pos->mq);
263   GNUNET_break(GNUNET_OK ==
264                GNUNET_CONTAINER_multipeermap_remove(peers, pid, pos));
265   if (NULL != pos->hello_delay_task)
266     {
267       GNUNET_SCHEDULER_cancel(pos->hello_delay_task);
268       pos->hello_delay_task = NULL;
269     }
270   if (NULL != pos->sh)
271     {
272       GNUNET_ATS_connectivity_suggest_cancel(pos->sh);
273       pos->sh = NULL;
274     }
275   if (NULL != pos->hello)
276     {
277       GNUNET_free_non_null(pos->hello);
278       pos->hello = NULL;
279     }
280   if (NULL != pos->filter)
281     {
282       GNUNET_CONTAINER_bloomfilter_free(pos->filter);
283       pos->filter = NULL;
284     }
285   GNUNET_free(pos);
286   return GNUNET_YES;
287 }
288
289
290 /**
291  * Recalculate how much we want to be connected to the specified peer
292  * and let ATS know about the result.
293  *
294  * @param pos peer to consider connecting to
295  */
296 static void
297 attempt_connect(struct Peer *pos)
298 {
299   uint32_t strength;
300
301   if (0 == GNUNET_memcmp(&my_identity, &pos->pid))
302     return; /* This is myself, nothing to do. */
303   if (connection_count < target_connection_count)
304     strength = 1;
305   else
306     strength = 0;
307   if ((friend_count < minimum_friend_count) || (GNUNET_YES == friends_only))
308     {
309       if (pos->is_friend)
310         strength += 10; /* urgently needed */
311       else
312         strength = 0; /* disallowed */
313     }
314   if (pos->is_friend)
315     strength *= 2; /* friends always count more */
316   if (NULL != pos->mq)
317     strength *= 2; /* existing connections preferred */
318   if (strength == pos->strength)
319     return; /* nothing to do */
320   if (NULL != pos->sh)
321     {
322       GNUNET_ATS_connectivity_suggest_cancel(pos->sh);
323       pos->sh = NULL;
324     }
325   pos->strength = strength;
326   if (0 != strength)
327     {
328       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
329                  "Asking to connect to `%s' with strength %u\n",
330                  GNUNET_i2s(&pos->pid),
331                  (unsigned int)strength);
332       GNUNET_STATISTICS_update(stats,
333                                gettext_noop("# connect requests issued to ATS"),
334                                1,
335                                GNUNET_NO);
336       pos->sh = GNUNET_ATS_connectivity_suggest(ats, &pos->pid, strength);
337     }
338 }
339
340
341 /**
342  * Create a new entry in the peer list.
343  *
344  * @param peer identity of the new entry
345  * @param hello hello message, can be NULL
346  * @param is_friend is the new entry for a friend?
347  * @return the new entry
348  */
349 static struct Peer *
350 make_peer(const struct GNUNET_PeerIdentity *peer,
351           const struct GNUNET_HELLO_Message *hello,
352           int is_friend)
353 {
354   struct Peer *ret;
355
356   ret = GNUNET_new(struct Peer);
357   ret->pid = *peer;
358   ret->is_friend = is_friend;
359   if (NULL != hello)
360     {
361       ret->hello = GNUNET_malloc(GNUNET_HELLO_size(hello));
362       GNUNET_memcpy(ret->hello, hello, GNUNET_HELLO_size(hello));
363     }
364   GNUNET_break(GNUNET_OK ==
365                GNUNET_CONTAINER_multipeermap_put(
366                  peers,
367                  peer,
368                  ret,
369                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
370   return ret;
371 }
372
373
374 /**
375  * Setup bloom filter for the given peer entry.
376  *
377  * @param peer entry to initialize
378  */
379 static void
380 setup_filter(struct Peer *peer)
381 {
382   struct GNUNET_HashCode hc;
383
384   /* 2^{-5} chance of not sending a HELLO to a peer is
385    * acceptably small (if the filter is 50% full);
386    * 64 bytes of memory are small compared to the rest
387    * of the data structure and would only really become
388    * "useless" once a HELLO has been passed on to ~100
389    * other peers, which is likely more than enough in
390    * any case; hence 64, 5 as bloomfilter parameters. */
391   peer->filter = GNUNET_CONTAINER_bloomfilter_init(NULL, 64, 5);
392   peer->filter_expiration =
393     GNUNET_TIME_relative_to_absolute(HELLO_ADVERTISEMENT_MIN_REPEAT_FREQUENCY);
394   /* never send a peer its own HELLO */
395   GNUNET_CRYPTO_hash(&peer->pid, sizeof(struct GNUNET_PeerIdentity), &hc);
396   GNUNET_CONTAINER_bloomfilter_add(peer->filter, &hc);
397 }
398
399
400 /**
401  * Closure for #find_advertisable_hello().
402  */
403 struct FindAdvHelloContext {
404   /**
405    * Peer we want to advertise to.
406    */
407   struct Peer *peer;
408
409   /**
410    * Where to store the result (peer selected for advertising).
411    */
412   struct Peer *result;
413
414   /**
415    * Maximum HELLO size we can use right now.
416    */
417   size_t max_size;
418
419   struct GNUNET_TIME_Relative next_adv;
420 };
421
422
423 /**
424  * Find a peer that would be reasonable for advertising.
425  *
426  * @param cls closure
427  * @param pid identity of a peer
428  * @param value 'struct Peer*' for the peer we are considering
429  * @return #GNUNET_YES (continue iteration)
430  */
431 static int
432 find_advertisable_hello(void *cls,
433                         const struct GNUNET_PeerIdentity *pid,
434                         void *value)
435 {
436   struct FindAdvHelloContext *fah = cls;
437   struct Peer *pos = value;
438   struct GNUNET_TIME_Relative rst_time;
439   struct GNUNET_HashCode hc;
440   size_t hs;
441
442   if (pos == fah->peer)
443     return GNUNET_YES;
444   if (pos->hello == NULL)
445     return GNUNET_YES;
446   rst_time = GNUNET_TIME_absolute_get_remaining(pos->filter_expiration);
447   if (0 == rst_time.rel_value_us)
448     {
449       /* time to discard... */
450       GNUNET_CONTAINER_bloomfilter_free(pos->filter);
451       setup_filter(pos);
452     }
453   fah->next_adv = GNUNET_TIME_relative_min(rst_time, fah->next_adv);
454   hs = GNUNET_HELLO_size(pos->hello);
455   if (hs > fah->max_size)
456     return GNUNET_YES;
457   GNUNET_CRYPTO_hash(&fah->peer->pid,
458                      sizeof(struct GNUNET_PeerIdentity),
459                      &hc);
460   if (GNUNET_NO == GNUNET_CONTAINER_bloomfilter_test(pos->filter, &hc))
461     fah->result = pos;
462   return GNUNET_YES;
463 }
464
465
466 /**
467  * Calculate when we would like to send the next HELLO to this
468  * peer and ask for it.
469  *
470  * @param cls for which peer to schedule the HELLO
471  */
472 static void
473 schedule_next_hello(void *cls)
474 {
475   struct Peer *pl = cls;
476   struct FindAdvHelloContext fah;
477   struct GNUNET_MQ_Envelope *env;
478   size_t want;
479   struct GNUNET_TIME_Relative delay;
480   struct GNUNET_HashCode hc;
481
482   pl->hello_delay_task = NULL;
483   GNUNET_assert(NULL != pl->mq);
484   /* find applicable HELLOs */
485   fah.peer = pl;
486   fah.result = NULL;
487   fah.max_size = GNUNET_MAX_MESSAGE_SIZE - 1;
488   fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
489   GNUNET_CONTAINER_multipeermap_iterate(peers, &find_advertisable_hello, &fah);
490   pl->hello_delay_task =
491     GNUNET_SCHEDULER_add_delayed(fah.next_adv, &schedule_next_hello, pl);
492   if (NULL == fah.result)
493     return;
494   delay = GNUNET_TIME_absolute_get_remaining(pl->next_hello_allowed);
495   if (0 != delay.rel_value_us)
496     return;
497
498   want = GNUNET_HELLO_size(fah.result->hello);
499   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
500              "Sending HELLO with %u bytes",
501              (unsigned int)want);
502   env = GNUNET_MQ_msg_copy(&fah.result->hello->header);
503   GNUNET_MQ_send(pl->mq, env);
504
505   /* avoid sending this one again soon */
506   GNUNET_CRYPTO_hash(&pl->pid, sizeof(struct GNUNET_PeerIdentity), &hc);
507   GNUNET_CONTAINER_bloomfilter_add(fah.result->filter, &hc);
508
509   GNUNET_STATISTICS_update(stats,
510                            gettext_noop("# HELLO messages gossipped"),
511                            1,
512                            GNUNET_NO);
513   /* prepare to send the next one */
514   pl->next_hello_allowed =
515     GNUNET_TIME_relative_to_absolute(HELLO_ADVERTISEMENT_MIN_FREQUENCY);
516   if (NULL != pl->hello_delay_task)
517     GNUNET_SCHEDULER_cancel(pl->hello_delay_task);
518   pl->hello_delay_task = GNUNET_SCHEDULER_add_now(&schedule_next_hello, pl);
519 }
520
521
522 /**
523  * Cancel existing requests for sending HELLOs to this peer
524  * and recalculate when we should send HELLOs to it based
525  * on our current state (something changed!).
526  *
527  * @param cls closure `struct Peer` to skip, or NULL
528  * @param pid identity of a peer
529  * @param value `struct Peer *` for the peer
530  * @return #GNUNET_YES (always)
531  */
532 static int
533 reschedule_hellos(void *cls,
534                   const struct GNUNET_PeerIdentity *pid,
535                   void *value)
536 {
537   struct Peer *peer = value;
538   struct Peer *skip = cls;
539
540   if (skip == peer)
541     return GNUNET_YES;
542   if (NULL == peer->mq)
543     return GNUNET_YES;
544   if (NULL != peer->hello_delay_task)
545     {
546       GNUNET_SCHEDULER_cancel(peer->hello_delay_task);
547       peer->hello_delay_task = NULL;
548     }
549   peer->hello_delay_task =
550     GNUNET_SCHEDULER_add_now(&schedule_next_hello, peer);
551   return GNUNET_YES;
552 }
553
554
555 /**
556  * Method called whenever a peer connects.
557  *
558  * @param cls closure
559  * @param peer peer identity this notification is about
560  * @param mq message queue for communicating with @a peer
561  * @return our `struct Peer` for @a peer
562  */
563 static void *
564 connect_notify(void *cls,
565                const struct GNUNET_PeerIdentity *peer,
566                struct GNUNET_MQ_Handle *mq)
567 {
568   struct Peer *pos;
569
570   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
571              "Core told us that we are connecting to `%s'\n",
572              GNUNET_i2s(peer));
573   if (0 == GNUNET_memcmp(&my_identity, peer))
574     return NULL;
575   GNUNET_MQ_set_options(mq, GNUNET_MQ_PRIO_BEST_EFFORT);
576   connection_count++;
577   GNUNET_STATISTICS_set(stats,
578                         gettext_noop("# peers connected"),
579                         connection_count,
580                         GNUNET_NO);
581   pos = GNUNET_CONTAINER_multipeermap_get(peers, peer);
582   if (NULL == pos)
583     {
584       pos = make_peer(peer, NULL, GNUNET_NO);
585     }
586   else
587     {
588       GNUNET_assert(NULL == pos->mq);
589     }
590   pos->mq = mq;
591   if (pos->is_friend)
592     {
593       friend_count++;
594       if ((friend_count == minimum_friend_count) && (GNUNET_YES != friends_only))
595         whitelist_peers();
596       GNUNET_STATISTICS_set(stats,
597                             gettext_noop("# friends connected"),
598                             friend_count,
599                             GNUNET_NO);
600     }
601   reschedule_hellos(NULL, peer, pos);
602   return pos;
603 }
604
605
606 /**
607  * Try to add more peers to our connection set.
608  *
609  * @param cls closure, not used
610  * @param pid identity of a peer
611  * @param value `struct Peer *` for the peer
612  * @return #GNUNET_YES (continue to iterate)
613  */
614 static int
615 try_add_peers(void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
616 {
617   struct Peer *pos = value;
618
619   attempt_connect(pos);
620   return GNUNET_YES;
621 }
622
623
624 /**
625  * Add peers and schedule connection attempt
626  *
627  * @param cls unused, NULL
628  */
629 static void
630 add_peer_task(void *cls)
631 {
632   add_task = NULL;
633
634   GNUNET_CONTAINER_multipeermap_iterate(peers, &try_add_peers, NULL);
635 }
636
637
638 /**
639  * Method called whenever a peer disconnects.
640  *
641  * @param cls closure
642  * @param peer peer identity this notification is about
643  * @param internal_cls the `struct Peer` for this peer
644  */
645 static void
646 disconnect_notify(void *cls,
647                   const struct GNUNET_PeerIdentity *peer,
648                   void *internal_cls)
649 {
650   struct Peer *pos = internal_cls;
651
652   if (NULL == pos)
653     return; /* myself, we're shutting down */
654   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
655              "Core told us that we disconnected from `%s'\n",
656              GNUNET_i2s(peer));
657   if (NULL == pos->mq)
658     {
659       GNUNET_break(0);
660       return;
661     }
662   pos->mq = NULL;
663   connection_count--;
664   if (NULL != pos->hello_delay_task)
665     {
666       GNUNET_SCHEDULER_cancel(pos->hello_delay_task);
667       pos->hello_delay_task = NULL;
668     }
669   GNUNET_STATISTICS_set(stats,
670                         gettext_noop("# peers connected"),
671                         connection_count,
672                         GNUNET_NO);
673   if (pos->is_friend)
674     {
675       friend_count--;
676       GNUNET_STATISTICS_set(stats,
677                             gettext_noop("# friends connected"),
678                             friend_count,
679                             GNUNET_NO);
680     }
681   if (((connection_count < target_connection_count) ||
682        (friend_count < minimum_friend_count)) &&
683       (NULL == add_task))
684     add_task = GNUNET_SCHEDULER_add_now(&add_peer_task, NULL);
685   if ((friend_count < minimum_friend_count) && (NULL == blacklist))
686     blacklist = GNUNET_TRANSPORT_blacklist(cfg, &blacklist_check, NULL);
687 }
688
689
690 /**
691  * Iterator called on each address.
692  *
693  * @param cls flag that we will set if we see any addresses
694  * @param address the address of the peer
695  * @param expiration when will the given address expire
696  * @return #GNUNET_SYSERR always, to terminate iteration
697  */
698 static int
699 address_iterator(void *cls,
700                  const struct GNUNET_HELLO_Address *address,
701                  struct GNUNET_TIME_Absolute expiration)
702 {
703   int *flag = cls;
704
705   *flag = GNUNET_YES;
706   return GNUNET_SYSERR;
707 }
708
709
710 /**
711  * We've gotten a HELLO from another peer.  Consider it for
712  * advertising.
713  *
714  * @param hello the HELLO we got
715  */
716 static void
717 consider_for_advertising(const struct GNUNET_HELLO_Message *hello)
718 {
719   int have_address;
720   struct GNUNET_PeerIdentity pid;
721   struct GNUNET_TIME_Absolute dt;
722   struct GNUNET_HELLO_Message *nh;
723   struct Peer *peer;
724   uint16_t size;
725
726   if (GNUNET_OK != GNUNET_HELLO_get_id(hello, &pid))
727     {
728       GNUNET_break(0);
729       return;
730     }
731   if (0 == GNUNET_memcmp(&pid, &my_identity))
732     return; /* that's me! */
733   have_address = GNUNET_NO;
734   GNUNET_HELLO_iterate_addresses(hello,
735                                  GNUNET_NO,
736                                  &address_iterator,
737                                  &have_address);
738   if (GNUNET_NO == have_address)
739     return; /* no point in advertising this one... */
740   peer = GNUNET_CONTAINER_multipeermap_get(peers, &pid);
741   if (NULL == peer)
742     {
743       peer = make_peer(&pid, hello, GNUNET_NO);
744     }
745   else if (NULL != peer->hello)
746     {
747       dt = GNUNET_HELLO_equals(peer->hello, hello, GNUNET_TIME_absolute_get());
748       if (dt.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
749         return; /* nothing new here */
750     }
751   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
752              "Found HELLO from peer `%s' for advertising\n",
753              GNUNET_i2s(&pid));
754   if (NULL != peer->hello)
755     {
756       nh = GNUNET_HELLO_merge(peer->hello, hello);
757       GNUNET_free(peer->hello);
758       peer->hello = nh;
759     }
760   else
761     {
762       size = GNUNET_HELLO_size(hello);
763       peer->hello = GNUNET_malloc(size);
764       GNUNET_memcpy(peer->hello, hello, size);
765     }
766   if (NULL != peer->filter)
767     {
768       GNUNET_CONTAINER_bloomfilter_free(peer->filter);
769       peer->filter = NULL;
770     }
771   setup_filter(peer);
772   /* since we have a new HELLO to pick from, re-schedule all
773    * HELLO requests that are not bound by the HELLO send rate! */
774   GNUNET_CONTAINER_multipeermap_iterate(peers, &reschedule_hellos, peer);
775 }
776
777
778 /**
779  * PEERINFO calls this function to let us know about a possible peer
780  * that we might want to connect to.
781  *
782  * @param cls closure (not used)
783  * @param peer potential peer to connect to
784  * @param hello HELLO for this peer (or NULL)
785  * @param err_msg NULL if successful, otherwise contains error message
786  */
787 static void
788 process_peer(void *cls,
789              const struct GNUNET_PeerIdentity *peer,
790              const struct GNUNET_HELLO_Message *hello,
791              const char *err_msg)
792 {
793   struct Peer *pos;
794
795   if (NULL != err_msg)
796     {
797       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
798                  _("Error in communication with PEERINFO service: %s\n"),
799                  err_msg);
800       GNUNET_PEERINFO_notify_cancel(peerinfo_notify);
801       peerinfo_notify =
802         GNUNET_PEERINFO_notify(cfg, GNUNET_NO, &process_peer, NULL);
803       return;
804     }
805   GNUNET_assert(NULL != peer);
806   if (0 == GNUNET_memcmp(&my_identity, peer))
807     return; /* that's me! */
808   if (NULL == hello)
809     {
810       /* free existing HELLO, if any */
811       pos = GNUNET_CONTAINER_multipeermap_get(peers, peer);
812       if (NULL != pos)
813         {
814           GNUNET_free_non_null(pos->hello);
815           pos->hello = NULL;
816           if (NULL != pos->filter)
817             {
818               GNUNET_CONTAINER_bloomfilter_free(pos->filter);
819               pos->filter = NULL;
820             }
821           if ((NULL == pos->mq) && (GNUNET_NO == pos->is_friend))
822             free_peer(NULL, &pos->pid, pos);
823         }
824       return;
825     }
826   consider_for_advertising(hello);
827   pos = GNUNET_CONTAINER_multipeermap_get(peers, peer);
828   if (NULL == pos)
829     pos = make_peer(peer, hello, GNUNET_NO);
830   attempt_connect(pos);
831 }
832
833
834 /**
835  * Function called after #GNUNET_CORE_connect has succeeded
836  * (or failed for good).
837  *
838  * @param cls closure
839  * @param my_id ID of this peer, NULL if we failed
840  */
841 static void
842 core_init(void *cls, const struct GNUNET_PeerIdentity *my_id)
843 {
844   if (NULL == my_id)
845     {
846       GNUNET_log(
847         GNUNET_ERROR_TYPE_ERROR,
848         _("Failed to connect to core service, can not manage topology!\n"));
849       GNUNET_SCHEDULER_shutdown();
850       return;
851     }
852   my_identity = *my_id;
853   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "I am peer `%s'\n", GNUNET_i2s(my_id));
854   peerinfo_notify =
855     GNUNET_PEERINFO_notify(cfg, GNUNET_NO, &process_peer, NULL);
856 }
857
858
859 /**
860  * Process friend found in FRIENDS file.
861  *
862  * @param cls pointer to an `unsigned int` to be incremented per friend found
863  * @param pid identity of the friend
864  */
865 static void
866 handle_friend(void *cls, const struct GNUNET_PeerIdentity *pid)
867 {
868   unsigned int *entries_found = cls;
869   struct Peer *fl;
870
871   if (0 == GNUNET_memcmp(pid, &my_identity))
872     {
873       GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
874                  _("Found myself `%s' in friend list (useless, ignored)\n"),
875                  GNUNET_i2s(pid));
876       return;
877     }
878   (*entries_found)++;
879   fl = make_peer(pid, NULL, GNUNET_YES);
880   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
881              _("Found friend `%s' in configuration\n"),
882              GNUNET_i2s(&fl->pid));
883 }
884
885
886 /**
887  * Read the friends file.
888  */
889 static void
890 read_friends_file(const struct GNUNET_CONFIGURATION_Handle *cfg)
891 {
892   unsigned int entries_found;
893
894   entries_found = 0;
895   if (GNUNET_OK != GNUNET_FRIENDS_parse(cfg, &handle_friend, &entries_found))
896     {
897       if ((GNUNET_YES == friends_only) || (minimum_friend_count > 0))
898         GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
899                    _("Encountered errors parsing friends list!\n"));
900     }
901   GNUNET_STATISTICS_update(stats,
902                            gettext_noop("# friends in configuration"),
903                            entries_found,
904                            GNUNET_NO);
905   if ((minimum_friend_count > entries_found) && (GNUNET_NO == friends_only))
906     {
907       GNUNET_log(
908         GNUNET_ERROR_TYPE_WARNING,
909         _(
910           "Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
911     }
912   if ((minimum_friend_count > target_connection_count) &&
913       (GNUNET_NO == friends_only))
914     {
915       GNUNET_log(
916         GNUNET_ERROR_TYPE_WARNING,
917         _(
918           "More friendly connections required than target total number of connections.\n"));
919     }
920 }
921
922
923 /**
924  * This function is called whenever an encrypted HELLO message is
925  * received.
926  *
927  * @param cls closure with the peer identity of the sender
928  * @param message the actual HELLO message
929  * @return #GNUNET_OK if @a message is well-formed
930  *         #GNUNET_SYSERR if @a message is invalid
931  */
932 static int
933 check_hello(void *cls, const struct GNUNET_HELLO_Message *message)
934 {
935   struct GNUNET_PeerIdentity pid;
936
937   if (GNUNET_OK != GNUNET_HELLO_get_id(message, &pid))
938     {
939       GNUNET_break_op(0);
940       return GNUNET_SYSERR;
941     }
942   return GNUNET_OK;
943 }
944
945
946 /**
947  * This function is called whenever an encrypted HELLO message is
948  * received.
949  *
950  * @param cls closure with the peer identity of the sender
951  * @param message the actual HELLO message
952  */
953 static void
954 handle_hello(void *cls, const struct GNUNET_HELLO_Message *message)
955 {
956   const struct GNUNET_PeerIdentity *other = cls;
957   struct Peer *peer;
958   struct GNUNET_PeerIdentity pid;
959
960   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
961              "Received encrypted HELLO from peer `%s'",
962              GNUNET_i2s(other));
963   GNUNET_assert(GNUNET_OK == GNUNET_HELLO_get_id(message, &pid));
964   GNUNET_STATISTICS_update(stats,
965                            gettext_noop("# HELLO messages received"),
966                            1,
967                            GNUNET_NO);
968   peer = GNUNET_CONTAINER_multipeermap_get(peers, &pid);
969   if (NULL == peer)
970     {
971       if ((GNUNET_YES == friends_only) || (friend_count < minimum_friend_count))
972         return;
973     }
974   else
975     {
976       if ((GNUNET_YES != peer->is_friend) && (GNUNET_YES == friends_only))
977         return;
978       if ((GNUNET_YES != peer->is_friend) &&
979           (friend_count < minimum_friend_count))
980         return;
981     }
982   (void)GNUNET_PEERINFO_add_peer(pi, message, NULL, NULL);
983 }
984
985
986 /**
987  * Last task run during shutdown.  Disconnects us from
988  * the transport and core.
989  *
990  * @param cls unused, NULL
991  */
992 static void
993 cleaning_task(void *cls)
994 {
995   if (NULL != peerinfo_notify)
996     {
997       GNUNET_PEERINFO_notify_cancel(peerinfo_notify);
998       peerinfo_notify = NULL;
999     }
1000   if (NULL != handle)
1001     {
1002       GNUNET_CORE_disconnect(handle);
1003       handle = NULL;
1004     }
1005   whitelist_peers();
1006   if (NULL != add_task)
1007     {
1008       GNUNET_SCHEDULER_cancel(add_task);
1009       add_task = NULL;
1010     }
1011   if (NULL != oh)
1012     {
1013       GNUNET_TRANSPORT_offer_hello_cancel(oh);
1014       oh = NULL;
1015     }
1016   GNUNET_CONTAINER_multipeermap_iterate(peers, &free_peer, NULL);
1017   GNUNET_CONTAINER_multipeermap_destroy(peers);
1018   peers = NULL;
1019   if (NULL != ats)
1020     {
1021       GNUNET_ATS_connectivity_done(ats);
1022       ats = NULL;
1023     }
1024   if (NULL != pi)
1025     {
1026       GNUNET_PEERINFO_disconnect(pi);
1027       pi = NULL;
1028     }
1029   if (NULL != stats)
1030     {
1031       GNUNET_STATISTICS_destroy(stats, GNUNET_NO);
1032       stats = NULL;
1033     }
1034 }
1035
1036
1037 /**
1038  * Main function that will be run.
1039  *
1040  * @param cls closure
1041  * @param args remaining command-line arguments
1042  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1043  * @param c configuration
1044  */
1045 static void
1046 run(void *cls,
1047     char *const *args,
1048     const char *cfgfile,
1049     const struct GNUNET_CONFIGURATION_Handle *c)
1050 {
1051   struct GNUNET_MQ_MessageHandler handlers[] =
1052   { GNUNET_MQ_hd_var_size(hello,
1053                           GNUNET_MESSAGE_TYPE_HELLO,
1054                           struct GNUNET_HELLO_Message,
1055                           NULL),
1056     GNUNET_MQ_handler_end() };
1057   unsigned long long opt;
1058
1059   cfg = c;
1060   stats = GNUNET_STATISTICS_create("topology", cfg);
1061   friends_only =
1062     GNUNET_CONFIGURATION_get_value_yesno(cfg, "TOPOLOGY", "FRIENDS-ONLY");
1063   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg,
1064                                                          "TOPOLOGY",
1065                                                          "MINIMUM-FRIENDS",
1066                                                          &opt))
1067     opt = 0;
1068   minimum_friend_count = (unsigned int)opt;
1069   if (GNUNET_OK !=
1070       GNUNET_CONFIGURATION_get_value_number(cfg,
1071                                             "TOPOLOGY",
1072                                             "TARGET-CONNECTION-COUNT",
1073                                             &opt))
1074     opt = 16;
1075   target_connection_count = (unsigned int)opt;
1076   peers = GNUNET_CONTAINER_multipeermap_create(target_connection_count * 2,
1077                                                GNUNET_NO);
1078   read_friends_file(cfg);
1079   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1080              "Topology would like %u connections with at least %u friends\n",
1081              target_connection_count,
1082              minimum_friend_count);
1083   if ((GNUNET_YES == friends_only) || (minimum_friend_count > 0))
1084     blacklist = GNUNET_TRANSPORT_blacklist(cfg, &blacklist_check, NULL);
1085   ats = GNUNET_ATS_connectivity_init(cfg);
1086   pi = GNUNET_PEERINFO_connect(cfg);
1087   handle = GNUNET_CORE_connect(cfg,
1088                                NULL,
1089                                &core_init,
1090                                &connect_notify,
1091                                &disconnect_notify,
1092                                handlers);
1093   GNUNET_SCHEDULER_add_shutdown(&cleaning_task, NULL);
1094   if (NULL == handle)
1095     {
1096       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1097                  _("Failed to connect to `%s' service.\n"),
1098                  "core");
1099       GNUNET_SCHEDULER_shutdown();
1100       return;
1101     }
1102 }
1103
1104
1105 /**
1106  * The main function for the topology daemon.
1107  *
1108  * @param argc number of arguments from the command line
1109  * @param argv command line arguments
1110  * @return 0 ok, 1 on error
1111  */
1112 int
1113 main(int argc, char *const *argv)
1114 {
1115   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1116     GNUNET_GETOPT_OPTION_END
1117   };
1118   int ret;
1119
1120   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args(argc, argv, &argc, &argv))
1121     return 2;
1122
1123   ret = (GNUNET_OK == GNUNET_PROGRAM_run(argc,
1124                                          argv,
1125                                          "gnunet-daemon-topology",
1126                                          _("GNUnet topology control"),
1127                                          options,
1128                                          &run,
1129                                          NULL))
1130         ? 0
1131         : 1;
1132   GNUNET_free((void *)argv);
1133   return ret;
1134 }
1135
1136
1137 #if defined(LINUX) && defined(__GLIBC__)
1138 #include <malloc.h>
1139
1140 /**
1141  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1142  */
1143 void __attribute__ ((constructor)) GNUNET_ARM_memory_init()
1144 {
1145   mallopt(M_TRIM_THRESHOLD, 4 * 1024);
1146   mallopt(M_TOP_PAD, 1 * 1024);
1147   malloc_trim(0);
1148 }
1149 #endif
1150
1151 /* end of gnunet-daemon-topology.c */