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