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