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