fixing remaining network-connection naming confusion in API
[oweals/gnunet.git] / src / topology / gnunet-daemon-topology.c
1 /*
2      This file is part of GNUnet.
3      (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
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 2, 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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file topology/gnunet-daemon-topology.c
23  * @brief code for bootstrapping via topology servers
24  * @author Christian Grothoff
25  */
26
27 #include <stdlib.h>
28 #include "platform.h"
29 #include "gnunet_core_service.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_util_lib.h"
34
35
36 #define DEBUG_TOPOLOGY GNUNET_NO
37
38 /**
39  * For how long do we blacklist a peer after a failed
40  * connection attempt?
41  */
42 #define BLACKLIST_AFTER_ATTEMPT GNUNET_TIME_UNIT_HOURS
43
44 /**
45  * For how long do we blacklist a friend after a failed
46  * connection attempt?
47  */
48 #define BLACKLIST_AFTER_ATTEMPT_FRIEND GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
49
50 /**
51  * How frequently are we allowed to ask PEERINFO for more
52  * HELLO's to advertise (at most)?
53  */
54 #define MIN_HELLO_GATHER_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 27)
55
56 /**
57  * How often do we at most advertise the same HELLO to the same peer?
58  * Also used to remove HELLOs of peers that PEERINFO no longer lists
59  * from our cache.
60  */
61 #define HELLO_ADVERTISEMENT_MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
62
63
64 /**
65  * List of neighbours, friends and blacklisted peers.
66  */
67 struct PeerList
68 {
69
70   /**
71    * This is a linked list.
72    */
73   struct PeerList *next;
74
75   /**
76    * Is this peer listed here because he is a friend?
77    */
78   int is_friend;
79
80   /**
81    * Are we connected to this peer right now?
82    */
83   int is_connected;
84
85   /**
86    * Until what time should we not try to connect again
87    * to this peer?
88    */
89   struct GNUNET_TIME_Absolute blacklisted_until;
90
91   /**
92    * Last time we transmitted a HELLO to this peer?
93    */
94   struct GNUNET_TIME_Absolute last_hello_sent;
95
96   /**
97    * ID of the peer.
98    */
99   struct GNUNET_PeerIdentity id;
100
101 };
102
103
104 /**
105  * List of HELLOs we may consider for advertising.
106  */
107 struct HelloList
108 {
109   /**
110    * This is a linked list.
111    */
112   struct HelloList *next;
113
114   /**
115    * Pointer to the HELLO message.  Memory allocated as part
116    * of the "struct HelloList" --- do not free!
117    */
118   struct GNUNET_HELLO_Message *msg;
119
120   /**
121    * Bloom filter used to mark which peers already got
122    * this HELLO.
123    */
124   struct GNUNET_CONTAINER_BloomFilter *filter;
125
126   /**
127    * What peer is this HELLO for?
128    */
129   struct GNUNET_PeerIdentity id;
130
131   /**
132    * When should we remove this entry from the linked list (either
133    * resetting the filter or possibly eliminating it for good because
134    * we no longer consider the peer to be participating in the
135    * network)?
136    */
137   struct GNUNET_TIME_Absolute expiration;
138 };
139
140
141 /**
142  * Linked list of HELLOs for advertising.
143  */
144 static struct HelloList *hellos;
145
146 /**
147  * Our scheduler.
148  */
149 static struct GNUNET_SCHEDULER_Handle * sched;
150
151 /**
152  * Our configuration.
153  */
154 static const struct GNUNET_CONFIGURATION_Handle * cfg;
155
156 /**
157  * Handle to the core API.
158  */
159 static struct GNUNET_CORE_Handle *handle;
160
161 /**
162  * Handle to the transport API.
163  */
164 static struct GNUNET_TRANSPORT_Handle *transport;
165
166 /**
167  * Identity of this peer.
168  */
169 static struct GNUNET_PeerIdentity my_identity;
170
171 /**
172  * Linked list of all of our friends and all of our current
173  * neighbours.
174  */
175 static struct PeerList *friends;
176
177 /**
178  * Timestamp from the last time we tried to gather HELLOs.
179  */
180 static struct GNUNET_TIME_Absolute last_hello_gather_time;
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  * Should the topology daemon try to establish connections?
210  */
211 static int autoconnect;
212
213 /**
214  * Are we currently having a request pending with
215  * PEERINFO asking for HELLOs for advertising?
216  */
217 static int hello_gathering_active;
218
219
220
221 /**
222  * Force a disconnect from the specified peer.
223  */
224 static void
225 force_disconnect (const struct GNUNET_PeerIdentity *peer)
226 {
227   GNUNET_CORE_peer_configure (handle,
228                               peer,
229                               GNUNET_TIME_UNIT_FOREVER_REL,
230                               0,
231                               0,
232                               0,
233                               NULL,
234                               NULL);
235 }
236
237
238 /**
239  * Function called by core when our attempt to connect
240  * succeeded.  Does nothing.
241  */
242 static size_t
243 ready_callback (void *cls,
244                 size_t size, void *buf)
245 {
246   return 0;
247 }
248
249
250 /**
251  * Try to connect to the specified peer.
252  *
253  * @param pos NULL if not in friend list yet
254  */
255 static void
256 attempt_connect (const struct GNUNET_PeerIdentity *peer,
257                  struct PeerList *pos)
258 {
259   if (pos == NULL)
260     {
261       pos = friends;
262       while (pos != NULL)
263         {
264           if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
265             break;
266         }
267     }
268   if (pos == NULL)
269     {
270       pos = GNUNET_malloc (sizeof(struct PeerList));
271       pos->id = *peer;
272       pos->next = friends;
273       friends = pos;
274     }
275   if (GNUNET_YES == pos->is_friend)
276     pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT_FRIEND);
277   else
278     pos->blacklisted_until = GNUNET_TIME_relative_to_absolute (BLACKLIST_AFTER_ATTEMPT);
279   GNUNET_CORE_notify_transmit_ready (handle,
280                                      0 /* priority */,
281                                      GNUNET_TIME_UNIT_MINUTES,
282                                      peer,
283                                      sizeof(struct GNUNET_MessageHeader),
284                                      &ready_callback,
285                                      NULL);
286 }
287
288
289 /**
290  * Is this peer one of our friends?
291  */
292 static int
293 is_friend (const struct GNUNET_PeerIdentity * peer)
294 {
295   struct PeerList *pos;
296
297   pos = friends;
298   while (pos != NULL)
299     {
300       if ( (GNUNET_YES == pos->is_friend) &&
301            (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
302         return GNUNET_YES;
303       pos = pos->next;
304     }
305   return GNUNET_NO;
306 }
307
308
309 /**
310  * Check if an additional connection from the given peer is allowed.
311  */
312 static int
313 is_connection_allowed (const struct GNUNET_PeerIdentity * peer)
314 {
315   if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
316     return GNUNET_SYSERR;       /* disallow connections to self */
317   if (is_friend (peer))
318     return GNUNET_OK;
319   if (GNUNET_YES == friends_only)
320     return GNUNET_SYSERR;
321   if (friend_count >= minimum_friend_count)
322     return GNUNET_OK;
323   return GNUNET_SYSERR;
324 }
325
326
327 /**
328  * Method called whenever a peer connects.
329  *
330  * @param cls closure
331  * @param peer peer identity this notification is about
332  */
333 static void connect_notify (void *cls,
334                             const struct
335                             GNUNET_PeerIdentity * peer)
336 {
337   struct PeerList *pos;
338
339   connection_count++;
340   pos = friends;
341   while (pos != NULL)
342     {
343       if ( (GNUNET_YES == pos->is_friend) &&
344            (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity))) )
345         {
346           GNUNET_assert (GNUNET_NO == pos->is_connected);
347           pos->is_connected = GNUNET_YES;
348           pos->blacklisted_until.value = 0; /* remove blacklisting */
349           friend_count++;
350           return;
351         }
352       pos = pos->next;
353     }
354   pos = GNUNET_malloc (sizeof(struct PeerList));
355   pos->id = *peer;
356   pos->is_connected = GNUNET_YES;
357   pos->next = friends;
358   friends = pos;
359   if (GNUNET_OK != is_connection_allowed (peer))
360     force_disconnect (peer);
361 }
362
363
364 /**
365  * Disconnect from all non-friends (we're below quota).
366  */
367 static void
368 drop_non_friends ()
369 {
370   struct PeerList *pos;
371
372   pos = friends;
373   while (pos != NULL)
374     {
375       if (GNUNET_NO == pos->is_friend)
376         {
377           GNUNET_assert (GNUNET_YES == pos->is_connected);
378           force_disconnect (&pos->id);
379         }
380       pos = pos->next;
381     }
382 }
383
384
385 /**
386  * Method called whenever a peer disconnects.
387  *
388  * @param cls closure
389  * @param peer peer identity this notification is about
390  */
391 static void disconnect_notify (void *cls,
392                                const struct
393                                GNUNET_PeerIdentity * peer)
394 {
395   struct PeerList *pos;
396   struct PeerList *prev;
397
398   connection_count--;
399   pos = friends;
400   prev = NULL;
401   while (pos != NULL)
402     {
403       if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
404         {
405           GNUNET_assert (GNUNET_YES == pos->is_connected);
406           pos->is_connected = GNUNET_NO;
407           if (GNUNET_YES == pos->is_friend)
408             {
409               friend_count--;
410               if (friend_count < minimum_friend_count)
411                 {
412                   /* disconnect from all non-friends */
413                   drop_non_friends ();
414                   attempt_connect (peer, pos);
415                 }
416             }
417           else
418             {
419               /* free entry */
420               if (prev == NULL)
421                 friends = pos->next;
422               else
423                 prev->next = pos->next;
424               GNUNET_free (pos);
425             }
426           return;
427         }
428       prev = pos;
429       pos = pos->next;
430     }
431   GNUNET_break (0);
432 }
433
434
435 /**
436  * Find more peers that we should connect to and ask the
437  * core to establish connections.
438  */
439 static void
440 find_more_peers (void *cls,
441                  const struct GNUNET_SCHEDULER_TaskContext *tc);
442
443
444 /**
445  * Determine when we should try again to find more peers and
446  * schedule the task.
447  */
448 static void
449 schedule_peer_search ()
450 {
451   struct GNUNET_TIME_Relative delay;
452
453   /* Typically, we try again every 15 minutes; the minimum period is
454      15s; if we are above the connection target, we reduce re-trying
455      by the square of how much we are above; so for example, with 200%
456      of the connection target we would only look for more peers once
457      every hour (after all, we're quite busy processing twice as many
458      connections as we intended to have); similarly, if we are at only
459      25% of our connectivity goal, we will try 16x as hard to connect
460      (so roughly once a minute, plus the 15s minimum delay */
461   delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
462                                          15 + 15 * 60 * connection_count * connection_count / target_connection_count / target_connection_count);
463   GNUNET_SCHEDULER_add_delayed (sched,
464                                 GNUNET_NO,
465                                 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
466                                 GNUNET_SCHEDULER_NO_TASK,
467                                 delay,
468                                 &find_more_peers,
469                                 NULL);
470 }
471
472
473
474
475 /**
476  * Iterator called on each address.
477  *
478  * @param cls flag that we will set if we see any addresses.
479  */
480 static int
481 address_iterator (void *cls,
482                   const char *tname,
483                   struct GNUNET_TIME_Absolute expiration,
484                   const void *addr, size_t addrlen)
485 {
486   int *flag = cls;
487   *flag = GNUNET_YES;
488   return GNUNET_SYSERR;
489 }
490
491
492 /**
493  * We've gotten a HELLO from another peer.
494  * Consider it for advertising.
495  */
496 static void
497 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
498 {
499   int have_address;
500   struct GNUNET_PeerIdentity pid;
501   struct HelloList *pos;
502   uint16_t size;
503
504   have_address = GNUNET_NO;
505   GNUNET_HELLO_iterate_addresses (hello,
506                                   GNUNET_NO,
507                                   &address_iterator,
508                                   &have_address);
509   if (GNUNET_NO == have_address)
510     return; /* no point in advertising this one... */
511   GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
512   pos = hellos;
513   while (pos != NULL)
514     {
515       if (0 == memcmp (&pos->id,
516                        &pid,
517                        sizeof(struct GNUNET_PeerIdentity)))
518         return; /* duplicate, at least "mostly" */
519       pos = pos->next;
520     }
521   size = GNUNET_HELLO_size (hello);
522   pos = GNUNET_malloc (sizeof(struct HelloList) + size);
523   pos->msg = (struct GNUNET_HELLO_Message*) &pos[1];
524   memcpy (&pos->msg, hello, size);
525   pos->id = pid;
526   pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
527   /* 2^{-5} chance of not sending a HELLO to a peer is
528      acceptably small (if the filter is 50% full);
529      64 bytes of memory are small compared to the rest
530      of the data structure and would only really become
531      "useless" once a HELLO has been passed on to ~100
532      other peers, which is likely more than enough in
533      any case; hence 64, 5 as bloomfilter parameters. */
534   pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
535   /* never send a peer its own HELLO */
536   GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey);
537   pos->next = hellos;
538   hellos = pos;
539 }
540
541
542 /**
543  * Peerinfo calls this function to let us know about a
544  * possible peer that we might want to connect to.
545  */
546 static void
547 process_peer (void *cls,
548               const struct GNUNET_PeerIdentity *peer,
549               const struct GNUNET_HELLO_Message *hello,
550               uint32_t trust)
551 {
552   struct PeerList *pos;
553
554   if (peer == NULL)
555     {
556       /* last call, schedule 'find_more_peers' again... */
557       schedule_peer_search ();
558       return;
559     }
560   if (hello == NULL)
561     {
562       /* no HELLO known; can not connect, ignore! */
563       return;
564     }
565   if (0 == memcmp (&my_identity,
566                    peer, sizeof (struct GNUNET_PeerIdentity)))
567     return;  /* that's me! */
568
569   consider_for_advertising (hello);
570   pos = friends;
571   while (pos != NULL)
572     {
573       if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
574         {
575           if (GNUNET_YES == pos->is_connected)
576             return;
577           if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
578             return; /* peer still blacklisted */
579           if (GNUNET_YES == pos->is_friend)
580             {
581               attempt_connect (peer, pos);
582               return;
583             }
584         }
585       pos = pos->next;
586     }
587   if (GNUNET_YES == friends_only)
588     return;
589   if (friend_count < minimum_friend_count)
590     return;
591   attempt_connect (peer, NULL);
592 }
593
594
595 /**
596  * Try to add more friends to our connection set.
597  */
598 static void
599 try_add_friends ()
600 {
601   struct PeerList *pos;
602
603   pos = friends;
604   while (pos != NULL)
605     {
606       if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
607            (GNUNET_YES == pos->is_friend) &&
608            (GNUNET_YES != pos->is_connected) )
609         attempt_connect (&pos->id, pos);
610       pos = pos->next;
611     }
612 }
613
614
615 /**
616  * Discard peer entries for blacklisted peers
617  * where the blacklisting has expired.
618  */
619 static void
620 discard_old_blacklist_entries ()
621 {
622   struct PeerList *pos;
623   struct PeerList *next;
624   struct PeerList *prev;
625
626   next = friends;
627   prev = NULL;
628   while (NULL != (pos = next))
629     {
630       next = pos->next;
631       if ( (GNUNET_NO == pos->is_friend) &&
632            (GNUNET_NO == pos->is_connected) &&
633            (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
634         {
635           /* delete 'pos' from list */
636           if (prev == NULL)
637             friends = next;
638           else
639             prev->next = next;
640           GNUNET_free (pos);
641         }
642       else
643         {
644           prev = pos;
645         }
646     }
647 }
648
649
650 /**
651  * Find more peers that we should connect to and ask the
652  * core to establish connections.
653  */
654 static void
655 find_more_peers (void *cls,
656                  const struct GNUNET_SCHEDULER_TaskContext *tc)
657 {
658   discard_old_blacklist_entries ();
659   if (target_connection_count <= connection_count)
660     {
661       schedule_peer_search ();
662       return;
663     }
664   if ( (GNUNET_YES == friends_only) ||
665        (friend_count < minimum_friend_count) )
666     {
667       try_add_friends ();
668       schedule_peer_search ();
669       return;
670     }
671   GNUNET_PEERINFO_for_all (cfg,
672                            sched,
673                            NULL,
674                            0, GNUNET_TIME_UNIT_FOREVER_REL,
675                            &process_peer, NULL);
676 }
677
678
679 /**
680  * Function called after GNUNET_CORE_connect has succeeded
681  * (or failed for good).
682  *
683  * @param cls closure
684  * @param server handle to the server, NULL if we failed
685  * @param my_id ID of this peer, NULL if we failed
686  * @param publicKey public key of this peer, NULL if we failed
687  */
688 static void
689 core_init (void *cls,
690            struct GNUNET_CORE_Handle * server,
691            const struct GNUNET_PeerIdentity *
692            my_id,
693            const struct
694            GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
695            publicKey)
696 {
697   if (server == NULL)
698     {
699       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
700                   _("Failed to connect to core service, can not manage topology!\n"));
701       return;
702     }
703   handle = server;
704   my_identity = *my_id;
705   if (autoconnect)
706     GNUNET_SCHEDULER_add_delayed (sched,
707                                   GNUNET_NO,
708                                   GNUNET_SCHEDULER_PRIORITY_DEFAULT,
709                                   GNUNET_SCHEDULER_NO_TASK,
710                                   GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */,
711                                   &find_more_peers,
712                                   NULL);
713 }
714
715
716 /**
717  * gnunet-daemon-topology command line options.
718  */
719 static struct GNUNET_GETOPT_CommandLineOption options[] = {
720   GNUNET_GETOPT_OPTION_END
721 };
722
723
724 /**
725  * Read the friends file.
726  */
727 static void
728 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
729 {
730   char *fn;
731   char *data;
732   size_t pos;
733   GNUNET_HashCode hc;
734   struct stat frstat;
735   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
736   unsigned int entries_found;
737   struct PeerList *fl;
738
739   if (GNUNET_OK !=
740       GNUNET_CONFIGURATION_get_value_filename (cfg,
741                                                "TOPOLOGY",
742                                                "FRIENDS",
743                                                &fn))
744     {
745       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
746                   _("Option `%s' in section `%s' not specified!\n"),
747                   "FRIENDS",
748                   "TOPOLOGY");
749       return;
750     }
751   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
752     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
753         | GNUNET_DISK_PERM_USER_WRITE);
754   if (0 != STAT (fn, &frstat))
755     {
756       if ((friends_only) || (minimum_friend_count > 0))
757         {
758           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
759                       _("Could not read friends list `%s'\n"), fn);
760           GNUNET_free (fn);
761           return;
762         }
763     }
764   if (frstat.st_size == 0)
765     {
766       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
767                   _("Friends file `%s' is empty.\n"),
768                   fn);
769       GNUNET_free (fn);
770       return;
771     }
772   data = GNUNET_malloc_large (frstat.st_size);
773   if (frstat.st_size !=
774       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
775     {
776       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
777                   _("Failed to read friends list from `%s'\n"), fn);
778       GNUNET_free (fn);
779       GNUNET_free (data);
780       return;
781     }
782   entries_found = 0;
783   pos = 0;
784   while ((pos < frstat.st_size) && isspace (data[pos]))
785     pos++;
786   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
787          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
788     {
789       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
790       if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
791         {
792           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
793                       _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
794                       (unsigned long long) pos);
795           pos++;
796           while ((pos < frstat.st_size) && (!isspace (data[pos])))
797             pos++;
798           continue;
799         }
800       enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
801       if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc))
802         {
803           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
804                       _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
805                       (unsigned long long) pos,
806                       &enc);
807         }
808       else
809         {
810           entries_found++;
811           fl = GNUNET_malloc (sizeof(struct PeerList));
812           fl->is_friend = GNUNET_YES;
813           fl->id.hashPubKey = hc;
814           fl->next = friends;
815           friends = fl;
816         }
817       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
818       while ((pos < frstat.st_size) && isspace (data[pos]))
819         pos++;
820     }
821   GNUNET_free (data);
822   GNUNET_free (fn);
823   if ( (minimum_friend_count > entries_found) &&
824        (friends_only == GNUNET_NO) )
825     {
826       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
827                   _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
828     }
829   if ( (minimum_friend_count > target_connection_count) &&
830        (friends_only == GNUNET_NO) )
831     {
832       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
833                   _("More friendly connections required than target total number of connections.\n"));
834     }
835 }
836
837
838 /**
839  * This function is called whenever an encrypted HELLO message is
840  * received.
841  *
842  * @param cls closure
843  * @param peer the other peer involved (sender or receiver, NULL
844  *        for loopback messages where we are both sender and receiver)
845  * @param message the actual HELLO message
846  * @return GNUNET_OK to keep the connection open,
847  *         GNUNET_SYSERR to close it (signal serious error)
848  */
849 static int
850 handle_encrypted_hello (void *cls,
851                         const struct GNUNET_PeerIdentity * other,
852                         const struct GNUNET_MessageHeader *
853                         message)
854 {
855   if (transport != NULL)
856     GNUNET_TRANSPORT_offer_hello (transport,
857                                   message);
858   return GNUNET_OK;
859 }
860
861
862 /**
863  * Peerinfo calls this function to let us know about a
864  * possible peer that we might want to connect to.
865  */
866 static void
867 gather_hello_callback (void *cls,
868                        const struct GNUNET_PeerIdentity *peer,
869                        const struct GNUNET_HELLO_Message *hello,
870                        uint32_t trust)
871 {
872   if (peer == NULL)
873     {
874       hello_gathering_active = GNUNET_NO;
875       return;
876     }
877   if (hello != NULL)
878     consider_for_advertising (hello);
879 }
880
881
882 /**
883  * Function to fill send buffer with HELLO.
884  *
885  * @param receiver the receiver of the message
886  * @param position is the reference to the
887  *        first unused position in the buffer where GNUnet is building
888  *        the message
889  * @param padding is the number of bytes left in that buffer.
890  * @return the number of bytes written to
891  *   that buffer (must be a positive number).
892  */
893 static unsigned int
894 hello_advertising (void *cls,
895                    const struct GNUNET_PeerIdentity *
896                    receiver,
897                    void *position, unsigned int padding)
898 {
899   struct PeerList *pl;
900   struct HelloList *pos;
901   struct HelloList *prev;
902   struct HelloList *next;
903   uint16_t size;
904
905   pl = friends;
906   while (pl != NULL)
907     {
908       if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
909         break;
910       pl = pl->next;
911     }
912   if (pl == NULL)
913     {
914       GNUNET_break (0);
915       return 0;
916     }
917   /* find applicable HELLOs */
918   prev = NULL;
919   next = hellos;
920   while (NULL != (pos = next))
921     {
922       next = pos->next;
923       if (GNUNET_NO ==
924           GNUNET_CONTAINER_bloomfilter_test (pos->filter,
925                                              &receiver->hashPubKey))
926         break;
927       if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
928         {
929           /* time to discard... */
930           if (prev != NULL)
931             prev->next = next;
932           else
933             hellos = next;
934           GNUNET_CONTAINER_bloomfilter_free (pos->filter);
935           GNUNET_free (pos);
936         }
937       else
938         {
939           prev = pos;
940         }
941     }
942   if (pos != NULL)
943     {
944       size = GNUNET_HELLO_size (pos->msg);
945       if (size < padding)
946         {
947           memcpy (position, pos->msg, size);
948           GNUNET_CONTAINER_bloomfilter_add (pos->filter,
949                                             &receiver->hashPubKey);
950         }
951       else
952         {
953           size = 0;
954         }
955       return size;
956     }
957   if ( (GNUNET_NO == hello_gathering_active) &&
958        (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
959         MIN_HELLO_GATHER_DELAY.value) )
960     {
961       hello_gathering_active = GNUNET_YES;
962       last_hello_gather_time = GNUNET_TIME_absolute_get();
963       GNUNET_PEERINFO_for_all (cfg,
964                                sched,
965                                NULL,
966                                0, GNUNET_TIME_UNIT_FOREVER_REL,
967                                &gather_hello_callback, NULL);
968     }
969   return 0;
970 }
971
972
973 /**
974  * Last task run during shutdown.  Disconnects us from
975  * the transport and core.
976  */
977 static void
978 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
979 {
980   struct PeerList *pl;
981
982   GNUNET_TRANSPORT_disconnect (transport);
983   transport = NULL;
984   GNUNET_CORE_disconnect (handle);
985   handle = NULL;
986   while (NULL != (pl = friends))
987     {
988       friends = pl->next;
989       GNUNET_free (pl);
990     }
991 }
992
993
994 /**
995  * Main function that will be run.
996  *
997  * @param cls closure
998  * @param s the scheduler to use
999  * @param args remaining command-line arguments
1000  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1001  * @param c configuration
1002  */
1003 static void
1004 run (void *cls,
1005      struct GNUNET_SCHEDULER_Handle * s,
1006      char *const *args,
1007      const char *cfgfile,
1008      const struct GNUNET_CONFIGURATION_Handle * c)
1009 {
1010   struct GNUNET_CORE_MessageHandler handlers[] =
1011     {
1012       { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
1013       { NULL, 0, 0 }
1014     };
1015   unsigned long long opt;
1016
1017   sched = s;
1018   cfg = c;
1019   autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1020                                                       "TOPOLOGY",
1021                                                       "AUTOCONNECT");
1022   friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1023                                                        "TOPOLOGY",
1024                                                        "FRIENDS-ONLY");
1025   if (GNUNET_OK !=
1026       GNUNET_CONFIGURATION_get_value_number (cfg,
1027                                              "TOPOLOGY",
1028                                              "MINIMUM-FRIENDS",
1029                                              &opt))
1030     opt = 0;
1031   minimum_friend_count = (unsigned int) opt;
1032   if (GNUNET_OK !=
1033       GNUNET_CONFIGURATION_get_value_number (cfg,
1034                                              "TOPOLOGY",
1035                                              "TARGET-CONNECTION-COUNT",
1036                                              &opt))
1037     opt = 16;
1038   target_connection_count = (unsigned int) opt;
1039
1040   if ( (friends_only == GNUNET_YES) ||
1041        (minimum_friend_count > 0) )
1042     read_friends_file (cfg);
1043
1044   transport = GNUNET_TRANSPORT_connect (sched,
1045                                         cfg,
1046                                         NULL,
1047                                         NULL,
1048                                         NULL,
1049                                         NULL);
1050   GNUNET_CORE_connect (sched,
1051                        cfg,
1052                        GNUNET_TIME_UNIT_FOREVER_REL,
1053                        NULL,
1054                        &core_init,
1055                        &connect_notify,
1056                        &disconnect_notify,
1057                        &hello_advertising,
1058                        NULL, GNUNET_NO,
1059                        NULL, GNUNET_NO,
1060                        handlers);
1061
1062   GNUNET_SCHEDULER_add_delayed (sched,
1063                                 GNUNET_YES,
1064                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
1065                                 GNUNET_SCHEDULER_NO_TASK,
1066                                 GNUNET_TIME_UNIT_FOREVER_REL,
1067                                 &cleaning_task, NULL);
1068 }
1069
1070
1071 /**
1072  * The main function for the topology daemon.
1073  *
1074  * @param argc number of arguments from the command line
1075  * @param argv command line arguments
1076  * @return 0 ok, 1 on error
1077  */
1078 int
1079 main (int argc, char *const *argv)
1080 {
1081   int ret;
1082
1083   ret = (GNUNET_OK ==
1084          GNUNET_PROGRAM_run (argc,
1085                              argv,
1086                              "topology",
1087                              _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
1088                              options,
1089                              &run, NULL)) ? 0 : 1;
1090   return ret;
1091 }
1092
1093 /* end of gnunet-daemon-topology.c */