2f58ac126cc0e4199fca0b8361c5d030b3b2ad75
[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                                 GNUNET_NO,
527                                 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
528                                 GNUNET_SCHEDULER_NO_TASK,
529                                 delay,
530                                 &find_more_peers,
531                                 NULL);
532 }
533
534
535
536
537 /**
538  * Iterator called on each address.
539  *
540  * @param cls flag that we will set if we see any addresses
541  * @param tname name of the transport
542  * @param expiration when will the given address expire
543  * @param addr the address of the peer
544  * @param addrlen number of bytes in addr
545  * @return GNUNET_SYSERR always, to terminate iteration
546  */
547 static int
548 address_iterator (void *cls,
549                   const char *tname,
550                   struct GNUNET_TIME_Absolute expiration,
551                   const void *addr, size_t addrlen)
552 {
553   int *flag = cls;
554   *flag = GNUNET_YES;
555   return GNUNET_SYSERR;
556 }
557
558
559 /**
560  * We've gotten a HELLO from another peer.
561  * Consider it for advertising.
562  */
563 static void
564 consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
565 {
566   int have_address;
567   struct GNUNET_PeerIdentity pid;
568   struct HelloList *pos;
569   uint16_t size;
570
571   have_address = GNUNET_NO;
572   GNUNET_HELLO_iterate_addresses (hello,
573                                   GNUNET_NO,
574                                   &address_iterator,
575                                   &have_address);
576   if (GNUNET_NO == have_address)
577     return; /* no point in advertising this one... */
578   GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
579   pos = hellos;
580   while (pos != NULL)
581     {
582       if (0 == memcmp (&pos->id,
583                        &pid,
584                        sizeof(struct GNUNET_PeerIdentity)))
585         return; /* duplicate, at least "mostly" */
586       pos = pos->next;
587     }
588 #if DEBUG_TOPOLOGY
589   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590               "Found `%s' from peer `%s' for advertising\n",
591               "HELLO",
592               GNUNET_i2s (&pid));
593 #endif 
594   size = GNUNET_HELLO_size (hello);
595   pos = GNUNET_malloc (sizeof(struct HelloList) + size);
596   pos->msg = (struct GNUNET_HELLO_Message*) &pos[1];
597   memcpy (&pos->msg, hello, size);
598   pos->id = pid;
599   pos->expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADVERTISEMENT_MIN_FREQUENCY);
600   /* 2^{-5} chance of not sending a HELLO to a peer is
601      acceptably small (if the filter is 50% full);
602      64 bytes of memory are small compared to the rest
603      of the data structure and would only really become
604      "useless" once a HELLO has been passed on to ~100
605      other peers, which is likely more than enough in
606      any case; hence 64, 5 as bloomfilter parameters. */
607   pos->filter = GNUNET_CONTAINER_bloomfilter_load (NULL, 64, 5);
608   /* never send a peer its own HELLO */
609   GNUNET_CONTAINER_bloomfilter_add (pos->filter, &pos->id.hashPubKey);
610   pos->next = hellos;
611   hellos = pos;
612 }
613
614
615 /**
616  * Peerinfo calls this function to let us know about a
617  * possible peer that we might want to connect to.
618  */
619 static void
620 process_peer (void *cls,
621               const struct GNUNET_PeerIdentity *peer,
622               const struct GNUNET_HELLO_Message *hello,
623               uint32_t trust)
624 {
625   struct PeerList *pos;
626
627   if (peer == NULL)
628     {
629       /* last call, schedule 'find_more_peers' again... */
630       schedule_peer_search ();
631       return;
632     }
633   if (hello == NULL)
634     {
635       /* no HELLO known; can not connect, ignore! */
636       return;
637     }
638   if (0 == memcmp (&my_identity,
639                    peer, sizeof (struct GNUNET_PeerIdentity)))
640     return;  /* that's me! */
641
642   consider_for_advertising (hello);
643 #if DEBUG_TOPOLOGY
644   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645               "Considering connecting to peer `%s'\n",
646               GNUNET_i2s (peer));
647 #endif 
648   pos = friends;
649   while (pos != NULL)
650     {
651       if (0 == memcmp (&pos->id, peer, sizeof (struct GNUNET_PeerIdentity)))
652         {
653           if (GNUNET_YES == pos->is_connected)
654             {
655 #if DEBUG_TOPOLOGY
656               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657                           "Already connected to peer `%s'\n",
658                           GNUNET_i2s (peer));
659 #endif 
660               return;
661             }
662           if (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value > 0)
663             {
664 #if DEBUG_TOPOLOGY
665               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666                           "Already tried peer `%s' recently\n",
667                           GNUNET_i2s (peer));
668 #endif 
669               return; /* peer still blacklisted */
670             }
671           if (GNUNET_YES == pos->is_friend)
672             {
673               attempt_connect (peer, pos);
674               return;
675             }
676         }
677       pos = pos->next;
678     }
679   if ( (GNUNET_YES == friends_only) ||    
680        (friend_count < minimum_friend_count) )
681     {
682 #if DEBUG_TOPOLOGY
683       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
684                   "Peer `%s' is not a friend, and we currently only connect to friends\n",
685                   GNUNET_i2s (peer));
686 #endif 
687       return;
688     }
689   attempt_connect (peer, NULL);
690 }
691
692
693 /**
694  * Try to add more friends to our connection set.
695  */
696 static void
697 try_add_friends ()
698 {
699   struct PeerList *pos;
700
701 #if DEBUG_TOPOLOGY
702   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
703               "Considering all of our friends for new connections\n");
704 #endif 
705   pos = friends;
706   while (pos != NULL)
707     {
708       if ( (GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value == 0) &&
709            (GNUNET_YES == pos->is_friend) &&
710            (GNUNET_YES != pos->is_connected) )
711         attempt_connect (&pos->id, pos);
712       pos = pos->next;
713     }
714 }
715
716
717 /**
718  * Discard peer entries for blacklisted peers
719  * where the blacklisting has expired.
720  */
721 static void
722 discard_old_blacklist_entries ()
723 {
724   struct PeerList *pos;
725   struct PeerList *next;
726   struct PeerList *prev;
727
728   next = friends;
729   prev = NULL;
730   while (NULL != (pos = next))
731     {
732       next = pos->next;
733       if ( (GNUNET_NO == pos->is_friend) &&
734            (GNUNET_NO == pos->is_connected) &&
735            (0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
736         {
737           /* delete 'pos' from list */
738 #if DEBUG_TOPOLOGY
739           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740                       "Deleting peer `%s' from our list (not connected, not a friend and blacklist expired)\n",
741                       GNUNET_i2s (&pos->id));
742 #endif  
743           if (prev == NULL)
744             friends = next;
745           else
746             prev->next = next;
747           GNUNET_free (pos);
748         }
749       else
750         {
751           prev = pos;
752         }
753     }
754 }
755
756
757 /**
758  * Find more peers that we should connect to and ask the
759  * core to establish connections.
760  */
761 static void
762 find_more_peers (void *cls,
763                  const struct GNUNET_SCHEDULER_TaskContext *tc)
764 {
765   discard_old_blacklist_entries ();
766   if (target_connection_count <= connection_count)
767     {
768       schedule_peer_search ();
769       return;
770     }
771   if ( (GNUNET_YES == friends_only) ||
772        (friend_count < minimum_friend_count) )
773     {
774       try_add_friends ();
775       schedule_peer_search ();
776       return;
777     }
778 #if DEBUG_TOPOLOGY
779   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
780               "Got sufficient (%u/%u, %u friends) number of connections, won't try to create more.\n",
781               connection_count,
782               target_connection_count,
783               friend_count);
784 #endif  
785   GNUNET_PEERINFO_for_all (cfg,
786                            sched,
787                            NULL,
788                            0, GNUNET_TIME_UNIT_FOREVER_REL,
789                            &process_peer, NULL);
790 }
791
792
793 /**
794  * Function called after GNUNET_CORE_connect has succeeded
795  * (or failed for good).
796  *
797  * @param cls closure
798  * @param server handle to the server, NULL if we failed
799  * @param my_id ID of this peer, NULL if we failed
800  * @param publicKey public key of this peer, NULL if we failed
801  */
802 static void
803 core_init (void *cls,
804            struct GNUNET_CORE_Handle * server,
805            const struct GNUNET_PeerIdentity *
806            my_id,
807            const struct
808            GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *
809            publicKey)
810 {
811   if (server == NULL)
812     {
813       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
814                   _("Failed to connect to core service, can not manage topology!\n"));
815       return;
816     }
817   handle = server;
818   my_identity = *my_id;
819 #if DEBUG_TOPOLOGY
820   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821               "I am peer `%s'",
822               GNUNET_i2s (my_id));
823 #endif  
824   if (autoconnect)
825     GNUNET_SCHEDULER_add_delayed (sched,
826                                   GNUNET_NO,
827                                   GNUNET_SCHEDULER_PRIORITY_DEFAULT,
828                                   GNUNET_SCHEDULER_NO_TASK,
829                                   GNUNET_TIME_UNIT_SECONDS /* give core time to tell us about existing connections */,
830                                   &find_more_peers,
831                                   NULL);
832 }
833
834
835 /**
836  * gnunet-daemon-topology command line options.
837  */
838 static struct GNUNET_GETOPT_CommandLineOption options[] = {
839   GNUNET_GETOPT_OPTION_END
840 };
841
842
843 /**
844  * Read the friends file.
845  */
846 static void
847 read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
848 {
849   char *fn;
850   char *data;
851   size_t pos;
852   GNUNET_HashCode hc;
853   struct stat frstat;
854   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
855   unsigned int entries_found;
856   struct PeerList *fl;
857
858   if (GNUNET_OK !=
859       GNUNET_CONFIGURATION_get_value_filename (cfg,
860                                                "TOPOLOGY",
861                                                "FRIENDS",
862                                                &fn))
863     {
864       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
865                   _("Option `%s' in section `%s' not specified!\n"),
866                   "FRIENDS",
867                   "TOPOLOGY");
868       return;
869     }
870   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
871     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
872         | GNUNET_DISK_PERM_USER_WRITE);
873   if (0 != STAT (fn, &frstat))
874     {
875       if ((friends_only) || (minimum_friend_count > 0))
876         {
877           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
878                       _("Could not read friends list `%s'\n"), fn);
879           GNUNET_free (fn);
880           return;
881         }
882     }
883   if (frstat.st_size == 0)
884     {
885       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
886                   _("Friends file `%s' is empty.\n"),
887                   fn);
888       GNUNET_free (fn);
889       return;
890     }
891   data = GNUNET_malloc_large (frstat.st_size);
892   if (frstat.st_size !=
893       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
894     {
895       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
896                   _("Failed to read friends list from `%s'\n"), fn);
897       GNUNET_free (fn);
898       GNUNET_free (data);
899       return;
900     }
901   entries_found = 0;
902   pos = 0;
903   while ((pos < frstat.st_size) && isspace (data[pos]))
904     pos++;
905   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
906          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
907     {
908       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
909       if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
910         {
911           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
912                       _("Syntax error in topology specification at offset %llu, skipping bytes.\n"),
913                       (unsigned long long) pos);
914           pos++;
915           while ((pos < frstat.st_size) && (!isspace (data[pos])))
916             pos++;
917           continue;
918         }
919       enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
920       if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &hc))
921         {
922           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
923                       _("Syntax error in topology specification at offset %llu, skipping bytes `%s'.\n"),
924                       (unsigned long long) pos,
925                       &enc);
926         }
927       else
928         {
929           entries_found++;
930           fl = GNUNET_malloc (sizeof(struct PeerList));
931           fl->is_friend = GNUNET_YES;
932           fl->id.hashPubKey = hc;
933           fl->next = friends;
934           friends = fl;
935 #if DEBUG_TOPOLOGY
936           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937                       "Found friend `%s' in configuration\n",
938                       GNUNET_i2s (&fl->id));
939 #endif       
940         }
941       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
942       while ((pos < frstat.st_size) && isspace (data[pos]))
943         pos++;
944     }
945   GNUNET_free (data);
946   GNUNET_free (fn);
947   if ( (minimum_friend_count > entries_found) &&
948        (friends_only == GNUNET_NO) )
949     {
950       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
951                   _("Fewer friends specified than required by minimum friend count. Will only connect to friends.\n"));
952     }
953   if ( (minimum_friend_count > target_connection_count) &&
954        (friends_only == GNUNET_NO) )
955     {
956       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
957                   _("More friendly connections required than target total number of connections.\n"));
958     }
959 }
960
961
962 /**
963  * This function is called whenever an encrypted HELLO message is
964  * received.
965  *
966  * @param cls closure
967  * @param other the other peer involved (sender or receiver, NULL
968  *        for loopback messages where we are both sender and receiver)
969  * @param message the actual HELLO message
970  * @return GNUNET_OK to keep the connection open,
971  *         GNUNET_SYSERR to close it (signal serious error)
972  */
973 static int
974 handle_encrypted_hello (void *cls,
975                         const struct GNUNET_PeerIdentity * other,
976                         const struct GNUNET_MessageHeader *
977                         message)
978 {
979 #if DEBUG_TOPOLOGY
980   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
981               "Received encrypted `%s' from peer `%s'",
982               "HELLO",
983               GNUNET_i2s (other));
984 #endif  
985   if (transport != NULL)
986     GNUNET_TRANSPORT_offer_hello (transport,
987                                   message);
988   return GNUNET_OK;
989 }
990
991
992 /**
993  * Peerinfo calls this function to let us know about a
994  * possible peer that we might want to connect to.
995  *
996  * @param cls unused
997  * @param peer NULL for the end of the list, otherwise a peer identity
998  * @param hello a HELLO for a peer, or NULL
999  * @param trust how much do we trust the given peer?
1000  */
1001 static void
1002 gather_hello_callback (void *cls,
1003                        const struct GNUNET_PeerIdentity *peer,
1004                        const struct GNUNET_HELLO_Message *hello,
1005                        uint32_t trust)
1006 {
1007   if (peer == NULL)
1008     {
1009       hello_gathering_active = GNUNET_NO;
1010       return;
1011     }
1012 #if DEBUG_TOPOLOGY
1013   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014               "Received `%s' for peer `%s'",
1015               "HELLO",
1016               GNUNET_i2s (peer));
1017 #endif  
1018   if (hello != NULL)
1019     consider_for_advertising (hello);
1020 }
1021
1022
1023 /**
1024  * Function to fill send buffer with HELLO.
1025  *
1026  * @param cls unused
1027  * @param receiver the receiver of the message
1028  * @param position is the reference to the
1029  *        first unused position in the buffer where GNUnet is building
1030  *        the message
1031  * @param padding is the number of bytes left in that buffer.
1032  * @return the number of bytes written to
1033  *   that buffer (must be a positive number).
1034  */
1035 static unsigned int
1036 hello_advertising (void *cls,
1037                    const struct GNUNET_PeerIdentity *
1038                    receiver,
1039                    void *position, 
1040                    size_t padding)
1041 {
1042   struct PeerList *pl;
1043   struct HelloList *pos;
1044   struct HelloList *prev;
1045   struct HelloList *next;
1046   uint16_t size;
1047
1048 #if DEBUG_TOPOLOGY
1049   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1050               "Data solicited for `%s', considering sending `%s's",
1051               GNUNET_i2s (receiver),
1052               "HELLO");
1053 #endif  
1054   pl = friends;
1055   while (pl != NULL)
1056     {
1057       if (0 == memcmp (&pl->id, receiver, sizeof (struct GNUNET_PeerIdentity)))
1058         break;
1059       pl = pl->next;
1060     }
1061   if (pl == NULL)
1062     {
1063       GNUNET_break (0);
1064       return 0;
1065     }
1066   /* find applicable HELLOs */
1067   prev = NULL;
1068   next = hellos;
1069   while (NULL != (pos = next))
1070     {
1071       next = pos->next;
1072       if (GNUNET_NO ==
1073           GNUNET_CONTAINER_bloomfilter_test (pos->filter,
1074                                              &receiver->hashPubKey))
1075         break;
1076       if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
1077         {
1078           /* time to discard... */
1079           if (prev != NULL)
1080             prev->next = next;
1081           else
1082             hellos = next;
1083           GNUNET_CONTAINER_bloomfilter_free (pos->filter);
1084           GNUNET_free (pos);
1085         }
1086       else
1087         {
1088           prev = pos;
1089         }
1090     }
1091   if (pos != NULL)
1092     {
1093       size = GNUNET_HELLO_size (pos->msg);
1094       if (size < padding)
1095         {
1096           memcpy (position, pos->msg, size);
1097           GNUNET_CONTAINER_bloomfilter_add (pos->filter,
1098                                             &receiver->hashPubKey);
1099         }
1100       else
1101         {
1102           size = 0;
1103         }
1104 #if DEBUG_TOPOLOGY
1105       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1106                   "Sending %u bytes of  `%s's",
1107                   (unsigned int) size,
1108                   "HELLO");
1109 #endif  
1110       return size;
1111     }
1112   if ( (GNUNET_NO == hello_gathering_active) &&
1113        (GNUNET_TIME_absolute_get_duration (last_hello_gather_time).value >
1114         MIN_HELLO_GATHER_DELAY.value) )
1115     {
1116 #if DEBUG_TOPOLOGY
1117       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1118                   "Have no `%s's, trying to get some from `%s' for next time",
1119                   "HELLO",
1120                   "PEERINFO");
1121 #endif  
1122       hello_gathering_active = GNUNET_YES;
1123       last_hello_gather_time = GNUNET_TIME_absolute_get();
1124       GNUNET_PEERINFO_for_all (cfg,
1125                                sched,
1126                                NULL,
1127                                0, GNUNET_TIME_UNIT_FOREVER_REL,
1128                                &gather_hello_callback, NULL);
1129     }
1130   return 0;
1131 }
1132
1133
1134 /**
1135  * Last task run during shutdown.  Disconnects us from
1136  * the transport and core.
1137  */
1138 static void
1139 cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1140 {
1141   struct PeerList *pl;
1142
1143   GNUNET_TRANSPORT_disconnect (transport);
1144   transport = NULL;
1145   GNUNET_CORE_disconnect (handle);
1146   handle = NULL;
1147   while (NULL != (pl = friends))
1148     {
1149       friends = pl->next;
1150       GNUNET_free (pl);
1151     }
1152 }
1153
1154
1155 /**
1156  * Main function that will be run.
1157  *
1158  * @param cls closure
1159  * @param s the scheduler to use
1160  * @param args remaining command-line arguments
1161  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1162  * @param c configuration
1163  */
1164 static void
1165 run (void *cls,
1166      struct GNUNET_SCHEDULER_Handle * s,
1167      char *const *args,
1168      const char *cfgfile,
1169      const struct GNUNET_CONFIGURATION_Handle * c)
1170 {
1171   struct GNUNET_CORE_MessageHandler handlers[] =
1172     {
1173       { &handle_encrypted_hello, GNUNET_MESSAGE_TYPE_HELLO, 0},
1174       { NULL, 0, 0 }
1175     };
1176   unsigned long long opt;
1177
1178   sched = s;
1179   cfg = c;
1180   autoconnect = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1181                                                       "TOPOLOGY",
1182                                                       "AUTOCONNECT");
1183   friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1184                                                        "TOPOLOGY",
1185                                                        "FRIENDS-ONLY");
1186   if (GNUNET_OK !=
1187       GNUNET_CONFIGURATION_get_value_number (cfg,
1188                                              "TOPOLOGY",
1189                                              "MINIMUM-FRIENDS",
1190                                              &opt))
1191     opt = 0;
1192   minimum_friend_count = (unsigned int) opt;
1193   if (GNUNET_OK !=
1194       GNUNET_CONFIGURATION_get_value_number (cfg,
1195                                              "TOPOLOGY",
1196                                              "TARGET-CONNECTION-COUNT",
1197                                              &opt))
1198     opt = 16;
1199   target_connection_count = (unsigned int) opt;
1200
1201   if ( (friends_only == GNUNET_YES) ||
1202        (minimum_friend_count > 0) )
1203     read_friends_file (cfg);
1204 #if DEBUG_TOPOLOGY
1205   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1206               "Topology would like %u connections with at least %u friends (%s)\n",
1207               target_connection_count,
1208               minimum_friend_count,
1209               autoconnect ? "autoconnect enabled" : "autoconnect disabled");
1210 #endif       
1211   transport = GNUNET_TRANSPORT_connect (sched,
1212                                         cfg,
1213                                         NULL,
1214                                         NULL,
1215                                         NULL,
1216                                         NULL);
1217   GNUNET_CORE_connect (sched,
1218                        cfg,
1219                        GNUNET_TIME_UNIT_FOREVER_REL,
1220                        NULL,
1221                        &core_init,
1222                        &connect_notify,
1223                        &disconnect_notify,
1224                        &hello_advertising,
1225                        NULL, GNUNET_NO,
1226                        NULL, GNUNET_NO,
1227                        handlers);
1228
1229   GNUNET_SCHEDULER_add_delayed (sched,
1230                                 GNUNET_YES,
1231                                 GNUNET_SCHEDULER_PRIORITY_IDLE,
1232                                 GNUNET_SCHEDULER_NO_TASK,
1233                                 GNUNET_TIME_UNIT_FOREVER_REL,
1234                                 &cleaning_task, NULL);
1235 }
1236
1237
1238 /**
1239  * The main function for the topology daemon.
1240  *
1241  * @param argc number of arguments from the command line
1242  * @param argv command line arguments
1243  * @return 0 ok, 1 on error
1244  */
1245 int
1246 main (int argc, char *const *argv)
1247 {
1248   int ret;
1249
1250   ret = (GNUNET_OK ==
1251          GNUNET_PROGRAM_run (argc,
1252                              argv,
1253                              "topology",
1254                              _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"),
1255                              options,
1256                              &run, NULL)) ? 0 : 1;
1257   return ret;
1258 }
1259
1260 /* end of gnunet-daemon-topology.c */