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