5b2b999d618d44bbb1193cf4fb893ed8d1d278a6
[oweals/gnunet.git] / src / peerinfo / gnunet-service-peerinfo.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2004, 2005, 2007, 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 peerinfo/gnunet-service-peerinfo.c
23  * @brief maintains list of known peers
24  *
25  * Code to maintain the list of currently known hosts (in memory
26  * structure of data/hosts/ and data/credit/).
27  *
28  * @author Christian Grothoff
29  *
30  * TODO:
31  * - HostEntries are never 'free'd (add expiration, upper bound?)
32  */
33
34 #include "platform.h"
35 #include "gnunet_crypto_lib.h"
36 #include "gnunet_disk_lib.h"
37 #include "gnunet_hello_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_service_lib.h"
40 #include "peerinfo.h"
41
42 /**
43  * How often do we scan the HOST_DIR for new entries?
44  */
45 #define DATA_HOST_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
46
47 /**
48  * How often do we flush trust values to disk?
49  */
50 #define TRUST_FLUSH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
51
52 /**
53  * How often do we discard old entries in data/hosts/?
54  */
55 #define DATA_HOST_CLEAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 60)
56
57 /**
58  * In-memory cache of known hosts.
59  */
60 struct HostEntry
61 {
62
63   /**
64    * This is a linked list.
65    */
66   struct HostEntry *next;
67
68   /**
69    * Identity of the peer.
70    */
71   struct GNUNET_PeerIdentity identity;
72
73   /**
74    * Hello for the peer (can be NULL)
75    */
76   struct GNUNET_HELLO_Message *hello;
77
78   /**
79    * Trust rating for this peer
80    */
81   uint32_t trust;
82
83   /**
84    * Trust rating for this peer on disk.
85    */
86   uint32_t disk_trust;
87
88 };
89
90
91 /**
92  * The in-memory list of known hosts.
93  */
94 static struct HostEntry *hosts;
95
96 /**
97  * Clients to immediately notify about all changes.
98  */
99 static struct GNUNET_SERVER_NotificationContext *notify_list;
100
101 /**
102  * Directory where the hellos are stored in (data/hosts)
103  */
104 static char *networkIdDirectory;
105
106 /**
107  * Where do we store trust information?
108  */
109 static char *trustDirectory;
110
111
112 /**
113  * Notify all clients in the notify list about the
114  * given host entry changing.
115  */
116 static struct InfoMessage *
117 make_info_message (const struct HostEntry *he)
118 {
119   struct InfoMessage *im;
120   size_t hs;
121
122   hs = (he->hello == NULL) ? 0 : GNUNET_HELLO_size (he->hello);
123   im = GNUNET_malloc (sizeof (struct InfoMessage) + hs);
124   im->header.size = htons (hs + sizeof (struct InfoMessage));
125   im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
126   im->trust = htonl (he->trust);
127   im->peer = he->identity;
128   memcpy (&im[1], he->hello, hs);
129   return im;
130 }
131
132
133 /**
134  * Address iterator that causes expired entries to be discarded.
135  *
136  * @param cls pointer to the current time
137  * @param tname name of the transport
138  * @param expiration expiration time for the address
139  * @param addr the address
140  * @param addrlen length of addr in bytes
141  * @return GNUNET_NO if expiration smaller than the current time
142  */
143 static int
144 discard_expired (void *cls,
145                  const char *tname,
146                  struct GNUNET_TIME_Absolute expiration,
147                  const void *addr, size_t addrlen)
148 {
149   const struct GNUNET_TIME_Absolute *now = cls;
150   if (now->value > expiration.value)
151     return GNUNET_NO;
152   return GNUNET_OK;
153 }
154
155
156 /**
157  * Get the filename under which we would store the GNUNET_HELLO_Message
158  * for the given host and protocol.
159  * @return filename of the form DIRECTORY/HOSTID
160  */
161 static char *
162 get_host_filename (const struct GNUNET_PeerIdentity *id)
163 {
164   struct GNUNET_CRYPTO_HashAsciiEncoded fil;
165   char *fn;
166
167   GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil);
168   GNUNET_asprintf (&fn,
169                    "%s%s%s", networkIdDirectory, DIR_SEPARATOR_STR, &fil);
170   return fn;
171 }
172
173
174 /**
175  * Get the filename under which we would store the GNUNET_HELLO_Message
176  * for the given host and protocol.
177  * @return filename of the form DIRECTORY/HOSTID
178  */
179 static char *
180 get_trust_filename (const struct GNUNET_PeerIdentity *id)
181 {
182   struct GNUNET_CRYPTO_HashAsciiEncoded fil;
183   char *fn;
184
185   GNUNET_CRYPTO_hash_to_enc (&id->hashPubKey, &fil);
186   GNUNET_asprintf (&fn, "%s%s%s", trustDirectory, DIR_SEPARATOR_STR, &fil);
187   return fn;
188 }
189
190
191 /**
192  * Find the host entry for the given peer.  Call
193  * only when synchronized!
194  * @return NULL if not found
195  */
196 static struct HostEntry *
197 lookup_host_entry (const struct GNUNET_PeerIdentity *id)
198 {
199   struct HostEntry *pos;
200
201   pos = hosts;
202   while ((pos != NULL) &&
203          (0 !=
204           memcmp (id, &pos->identity, sizeof (struct GNUNET_PeerIdentity))))
205     pos = pos->next;
206   return pos;
207 }
208
209
210 /**
211  * Broadcast information about the given entry to all 
212  * clients that care.
213  *
214  * @param entry entry to broadcast about
215  */
216 static void
217 notify_all (struct HostEntry *entry)
218 {
219   struct InfoMessage *msg;
220
221   msg = make_info_message (entry);
222   GNUNET_SERVER_notification_context_broadcast (notify_list,
223                                                 &msg->header,
224                                                 GNUNET_NO);
225   GNUNET_free (msg);
226 }
227
228
229 /**
230  * Add a host to the list.
231  *
232  * @param identity the identity of the host
233  */
234 static void
235 add_host_to_known_hosts (const struct GNUNET_PeerIdentity *identity)
236 {
237   struct HostEntry *entry;
238   char *fn;
239   uint32_t trust;
240   char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
241   const struct GNUNET_HELLO_Message *hello;
242   struct GNUNET_HELLO_Message *hello_clean;
243   int size;
244   struct GNUNET_TIME_Absolute now;
245
246   entry = lookup_host_entry (identity);
247   if (entry != NULL)
248     return;
249   entry = GNUNET_malloc (sizeof (struct HostEntry));
250   entry->identity = *identity;
251   fn = get_trust_filename (identity);
252   if ((GNUNET_DISK_file_test (fn) == GNUNET_YES) &&
253       (sizeof (trust) == GNUNET_DISK_fn_read (fn, &trust, sizeof (trust))))
254     entry->disk_trust = entry->trust = ntohl (trust);
255   GNUNET_free (fn);
256
257   fn = get_host_filename (identity);
258   if (GNUNET_DISK_file_test (fn) == GNUNET_YES)
259     {
260       size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
261       hello = (const struct GNUNET_HELLO_Message *) buffer;
262       if ( (size < sizeof (struct GNUNET_MessageHeader)) ||
263            (size != ntohs((((const struct GNUNET_MessageHeader*) hello)->size))) ||
264            (size != GNUNET_HELLO_size (hello)) )
265         {
266           GNUNET_break (0);
267           if (0 != UNLINK (fn))
268             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
269                                       "unlink",
270                                       fn);
271         }
272       else
273         {
274           now = GNUNET_TIME_absolute_get ();
275           hello_clean = GNUNET_HELLO_iterate_addresses (hello,
276                                                         GNUNET_YES,
277                                                         &discard_expired, &now);
278           entry->hello = hello_clean;
279         }
280     }
281   GNUNET_free (fn);
282   entry->next = hosts;
283   hosts = entry;
284   notify_all (entry);
285 }
286
287
288 /**
289  * Increase the host credit by a value.
290  *
291  * @param hostId is the identity of the host
292  * @param value is the int value by which the
293  *  host credit is to be increased or decreased
294  * @returns the actual change in trust (positive or negative)
295  */
296 static int
297 change_host_trust (const struct GNUNET_PeerIdentity *hostId, int value)
298 {
299   struct HostEntry *host;
300   unsigned int old_trust;
301
302   if (value == 0)
303     return 0;
304   host = lookup_host_entry (hostId);
305   if (host == NULL)
306     {
307       add_host_to_known_hosts (hostId);
308       host = lookup_host_entry (hostId);
309     }
310   GNUNET_assert (host != NULL);
311   old_trust = host->trust;
312   if (value > 0)
313     {
314       if (host->trust + value < host->trust)
315         {
316           value = ((uint32_t) - 1) - host->trust;
317           host->trust = (uint32_t) - 1; /* maximized */
318         }
319       else
320         host->trust += value;
321     }
322   else
323     {
324       if (host->trust < -value)
325         {
326           value = -host->trust;
327           host->trust = 0;
328         }
329       else
330         host->trust += value;
331     }
332   if (host->trust != old_trust)
333     notify_all (host);    
334   return value;
335 }
336
337
338 /**
339  * Remove a file that should not be there.  LOG
340  * success or failure.
341  */
342 static void
343 remove_garbage (const char *fullname)
344 {
345   if (0 == UNLINK (fullname))
346     GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
347                 _
348                 ("File `%s' in directory `%s' does not match naming convention. "
349                  "Removed.\n"), fullname, networkIdDirectory);
350   else
351     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR |
352                               GNUNET_ERROR_TYPE_BULK, "unlink", fullname);
353 }
354
355
356 static int
357 hosts_directory_scan_callback (void *cls, const char *fullname)
358 {
359   unsigned int *matched = cls;
360   struct GNUNET_PeerIdentity identity;
361   const char *filename;
362
363   if (GNUNET_DISK_file_test (fullname) != GNUNET_YES)
364     return GNUNET_OK;           /* ignore non-files */
365   if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))
366     {
367       remove_garbage (fullname);
368       return GNUNET_OK;
369     }
370   filename =
371     &fullname[strlen (fullname) -
372               sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1];
373   if (filename[-1] != DIR_SEPARATOR)
374     {
375       remove_garbage (fullname);
376       return GNUNET_OK;
377     }
378   if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (filename,
379                                                    &identity.hashPubKey))
380     {
381       remove_garbage (fullname);
382       return GNUNET_OK;
383     }
384   (*matched)++;
385   add_host_to_known_hosts (&identity);
386   return GNUNET_OK;
387 }
388
389
390 /**
391  * Call this method periodically to scan data/hosts for new hosts.
392  */
393 static void
394 cron_scan_directory_data_hosts (void *cls,
395                                 const struct GNUNET_SCHEDULER_TaskContext *tc)
396 {
397   static unsigned int retries;
398   unsigned int count;
399
400   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
401     return;
402   count = 0;
403   GNUNET_DISK_directory_create (networkIdDirectory);
404   GNUNET_DISK_directory_scan (networkIdDirectory,
405                               &hosts_directory_scan_callback, &count);
406   if ((0 == count) && (0 == (++retries & 31)))
407     GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
408                 GNUNET_ERROR_TYPE_BULK,
409                 _("Still no peers found in `%s'!\n"), networkIdDirectory);
410   GNUNET_SCHEDULER_add_delayed (tc->sched,
411                                 DATA_HOST_FREQ,
412                                 &cron_scan_directory_data_hosts, NULL);
413 }
414
415
416 /**
417  * Bind a host address (hello) to a hostId.
418  *
419  * @param peer the peer for which this is a hello
420  * @param hello the verified (!) hello message
421  */
422 static void
423 bind_address (const struct GNUNET_PeerIdentity *peer,
424               const struct GNUNET_HELLO_Message *hello)
425 {
426   char *fn;
427   struct HostEntry *host;
428   struct GNUNET_HELLO_Message *mrg;
429
430   add_host_to_known_hosts (peer);
431   host = lookup_host_entry (peer);
432   GNUNET_assert (host != NULL);
433   if (host->hello == NULL)
434     {
435       host->hello = GNUNET_malloc (GNUNET_HELLO_size (hello));
436       memcpy (host->hello, hello, GNUNET_HELLO_size (hello));
437     }
438   else
439     {
440       mrg = GNUNET_HELLO_merge (host->hello, hello);
441       /* FIXME: check if old and merged hello are equal,
442          and if so, bail out early... */
443       GNUNET_free (host->hello);
444       host->hello = mrg;
445     }
446   fn = get_host_filename (peer);
447   GNUNET_DISK_directory_create_for_file (fn);
448   GNUNET_DISK_fn_write (fn, 
449                         host->hello, 
450                         GNUNET_HELLO_size (host->hello),
451                         GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
452                         | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ);
453   GNUNET_free (fn);
454   notify_all (host);
455 }
456
457
458 /**
459  * Do transmit info either for only the host matching the given
460  * argument or for all known hosts and change their trust values by
461  * the given delta.
462  *
463  * @param only NULL to hit all hosts, otherwise specifies a particular target
464  * @param trust_change how much should the trust be changed
465  * @param client who is making the request (and will thus receive our confirmation)
466  */
467 static void
468 send_to_each_host (const struct GNUNET_PeerIdentity *only,
469                    int trust_change, struct GNUNET_SERVER_Client *client)
470 {
471   struct HostEntry *pos;
472   struct InfoMessage *im;
473   const struct GNUNET_MessageHeader *end;
474   uint16_t hs;
475   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
476   struct GNUNET_SERVER_TransmitContext *tc;
477
478   tc = GNUNET_SERVER_transmit_context_create (client);
479   pos = hosts;
480   while (pos != NULL)
481     {
482       if ((only == NULL) ||
483           (0 ==
484            memcmp (only, &pos->identity,
485                    sizeof (struct GNUNET_PeerIdentity))))
486         {
487           change_host_trust (&pos->identity, trust_change);
488           hs = 0;
489           im = (struct InfoMessage *) buf;
490           if (pos->hello != NULL)
491             {
492               hs = GNUNET_HELLO_size (pos->hello);
493               GNUNET_assert (hs <
494                              GNUNET_SERVER_MAX_MESSAGE_SIZE -
495                              sizeof (struct InfoMessage));
496               memcpy (&im[1], pos->hello, hs);
497             }
498           im->trust = htonl (pos->trust);
499           im->peer = pos->identity;
500           end = &im->header;
501           GNUNET_SERVER_transmit_context_append (tc,
502                                                  &end[1],
503                                                  hs +
504                                                  sizeof (struct InfoMessage) -
505                                                  sizeof (struct
506                                                          GNUNET_MessageHeader),
507                                                  GNUNET_MESSAGE_TYPE_PEERINFO_INFO);
508         }
509       pos = pos->next;
510     }
511   GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
512                                          GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END);
513   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
514 }
515
516
517 /**
518  * Write host-trust information to a file - flush the buffer entry!
519  * Assumes synchronized access.
520  */
521 static void
522 flush_trust (struct HostEntry *host)
523 {
524   char *fn;
525   uint32_t trust;
526
527   if (host->trust == host->disk_trust)
528     return;                     /* unchanged */
529   fn = get_trust_filename (&host->identity);
530   if (host->trust == 0)
531     {
532       if ((0 != UNLINK (fn)) && (errno != ENOENT))
533         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
534                                   GNUNET_ERROR_TYPE_BULK, "unlink", fn);
535     }
536   else
537     {
538       trust = htonl (host->trust);
539       if (sizeof(uint32_t) == GNUNET_DISK_fn_write (fn, &trust, 
540                                                     sizeof(uint32_t),
541                                                     GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
542                                                     | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ))
543         host->disk_trust = host->trust;
544     }
545   GNUNET_free (fn);
546 }
547
548 /**
549  * Call this method periodically to scan data/hosts for new hosts.
550  */
551 static void
552 cron_flush_trust (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
553 {
554   struct HostEntry *pos;
555
556   pos = hosts;
557   while (pos != NULL)
558     {
559       flush_trust (pos);
560       pos = pos->next;
561     }
562   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
563     return;
564   GNUNET_SCHEDULER_add_delayed (tc->sched,
565                                 TRUST_FLUSH_FREQ, &cron_flush_trust, NULL);
566 }
567
568
569 /**
570  * @brief delete expired HELLO entries in data/hosts/
571  */
572 static int
573 discard_hosts_helper (void *cls, const char *fn)
574 {
575   struct GNUNET_TIME_Absolute *now = cls;
576   char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE];
577   const struct GNUNET_HELLO_Message *hello;
578   struct GNUNET_HELLO_Message *new_hello;
579   int size;
580
581   size = GNUNET_DISK_fn_read (fn, buffer, sizeof (buffer));
582   if ((size < sizeof (struct GNUNET_MessageHeader)) && (0 != UNLINK (fn)))
583     {
584       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
585                                 GNUNET_ERROR_TYPE_BULK, "unlink", fn);
586       return GNUNET_OK;
587     }
588   hello = (const struct GNUNET_HELLO_Message *) buffer;
589   new_hello = GNUNET_HELLO_iterate_addresses (hello,
590                                               GNUNET_YES,
591                                               &discard_expired, now);
592   if ((new_hello == NULL) && (0 != UNLINK (fn)))
593     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING |
594                               GNUNET_ERROR_TYPE_BULK, "unlink", fn);
595   if (new_hello != NULL)
596     {
597       GNUNET_DISK_fn_write (fn, 
598                             new_hello,
599                             GNUNET_HELLO_size (new_hello),
600                             GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE
601                             | GNUNET_DISK_PERM_GROUP_READ | GNUNET_DISK_PERM_OTHER_READ);
602       GNUNET_free (new_hello);
603     }
604   return GNUNET_OK;
605 }
606
607
608 /**
609  * Call this method periodically to scan data/hosts for new hosts.
610  */
611 static void
612 cron_clean_data_hosts (void *cls,
613                        const struct GNUNET_SCHEDULER_TaskContext *tc)
614 {
615   struct GNUNET_TIME_Absolute now;
616
617   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
618     return;
619   now = GNUNET_TIME_absolute_get ();
620   GNUNET_DISK_directory_scan (networkIdDirectory,
621                               &discard_hosts_helper, &now);
622
623   GNUNET_SCHEDULER_add_delayed (tc->sched,
624                                 DATA_HOST_CLEAN_FREQ,
625                                 &cron_clean_data_hosts, NULL);
626 }
627
628
629 /**
630  * Handle ADD-message.
631  *
632  * @param cls closure
633  * @param client identification of the client
634  * @param message the actual message
635  */
636 static void
637 handle_add (void *cls,
638             struct GNUNET_SERVER_Client *client,
639             const struct GNUNET_MessageHeader *message)
640 {
641   const struct PeerAddMessage *pam;
642   const struct GNUNET_MessageHeader *hello;
643   uint16_t size;
644
645   size = ntohs (message->size);
646   if (size <
647       sizeof (struct PeerAddMessage) + sizeof (struct GNUNET_MessageHeader))
648     {
649       GNUNET_break (0);
650       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
651       return;
652     }
653   pam = (const struct PeerAddMessage *) message;
654   hello = (const struct GNUNET_MessageHeader *) &pam[1];
655   if (size != sizeof (struct PeerAddMessage) + ntohs (hello->size))
656     {
657       GNUNET_break (0);
658       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
659       return;
660     }
661   bind_address (&pam->peer, (const struct GNUNET_HELLO_Message *) hello);
662   GNUNET_SERVER_receive_done (client, GNUNET_OK);
663 }
664
665
666 /**
667  * Handle GET-message.
668  *
669  * @param cls closure
670  * @param client identification of the client
671  * @param message the actual message
672  */
673 static void
674 handle_get (void *cls,
675             struct GNUNET_SERVER_Client *client,
676             const struct GNUNET_MessageHeader *message)
677 {
678   const struct ListPeerMessage *lpm;
679
680   lpm = (const struct ListPeerMessage *) message;
681   send_to_each_host (&lpm->peer, ntohl (lpm->trust_change), client);
682 }
683
684
685 /**
686  * Handle GET-ALL-message.
687  *
688  * @param cls closure
689  * @param client identification of the client
690  * @param message the actual message
691  */
692 static void
693 handle_get_all (void *cls,
694                 struct GNUNET_SERVER_Client *client,
695                 const struct GNUNET_MessageHeader *message)
696 {
697   const struct ListAllPeersMessage *lpm;
698
699   lpm = (const struct ListAllPeersMessage *) message;
700   send_to_each_host (NULL, ntohl (lpm->trust_change), client);
701 }
702
703
704 /**
705  * Handle NOTIFY-message.
706  *
707  * @param cls closure
708  * @param client identification of the client
709  * @param message the actual message
710  */
711 static void
712 handle_notify (void *cls,
713             struct GNUNET_SERVER_Client *client,
714             const struct GNUNET_MessageHeader *message)
715 {
716   struct InfoMessage *msg;
717   struct HostEntry *pos;
718
719   GNUNET_SERVER_notification_context_add (notify_list,
720                                           client);
721   pos = hosts;
722   while (NULL != pos)
723     {
724       msg = make_info_message (pos);
725       GNUNET_SERVER_notification_context_unicast (notify_list,
726                                                   client,
727                                                   &msg->header,
728                                                   GNUNET_NO);
729       GNUNET_free (msg);
730       pos = pos->next;
731     }
732 }
733
734
735 /**
736  * List of handlers for the messages understood by this
737  * service.
738  */
739 static struct GNUNET_SERVER_MessageHandler handlers[] = {
740   {&handle_add, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_ADD, 0},
741   {&handle_get, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET,
742    sizeof (struct ListPeerMessage)},
743   {&handle_get_all, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL,
744    sizeof (struct ListAllPeersMessage)},
745   {&handle_notify, NULL, GNUNET_MESSAGE_TYPE_PEERINFO_NOTIFY,
746    sizeof (struct GNUNET_MessageHeader)},
747   {NULL, NULL, 0, 0}
748 };
749
750
751 /**
752  * Clean up our state.  Called during shutdown.
753  *
754  * @param cls unused
755  * @param tc scheduler task context, unused
756  */
757 static void
758 shutdown_task (void *cls,
759                const struct GNUNET_SCHEDULER_TaskContext *tc)
760 {
761   GNUNET_SERVER_notification_context_destroy (notify_list);
762   notify_list = NULL;
763 }
764
765
766 /**
767  * Process statistics requests.
768  *
769  * @param cls closure
770  * @param sched scheduler to use
771  * @param server the initialized server
772  * @param cfg configuration to use
773  */
774 static void
775 run (void *cls,
776      struct GNUNET_SCHEDULER_Handle *sched,
777      struct GNUNET_SERVER_Handle *server,
778      const struct GNUNET_CONFIGURATION_Handle *cfg)
779 {
780   notify_list = GNUNET_SERVER_notification_context_create (server, 0);
781   GNUNET_assert (GNUNET_OK ==
782                  GNUNET_CONFIGURATION_get_value_filename (cfg,
783                                                           "peerinfo",
784                                                           "HOSTS",
785                                                           &networkIdDirectory));
786   GNUNET_assert (GNUNET_OK ==
787                  GNUNET_CONFIGURATION_get_value_filename (cfg,
788                                                           "peerinfo",
789                                                           "TRUST",
790                                                           &trustDirectory));
791   GNUNET_DISK_directory_create (networkIdDirectory);
792   GNUNET_DISK_directory_create (trustDirectory);
793   GNUNET_SCHEDULER_add_with_priority (sched,
794                                       GNUNET_SCHEDULER_PRIORITY_IDLE,
795                                       &cron_scan_directory_data_hosts, NULL);
796   GNUNET_SCHEDULER_add_with_priority (sched,
797                                       GNUNET_SCHEDULER_PRIORITY_HIGH,
798                                       &cron_flush_trust, NULL);
799   GNUNET_SCHEDULER_add_with_priority (sched,
800                                       GNUNET_SCHEDULER_PRIORITY_IDLE,
801                                       &cron_clean_data_hosts, NULL);
802   GNUNET_SCHEDULER_add_delayed (sched,
803                                 GNUNET_TIME_UNIT_FOREVER_REL,
804                                 &shutdown_task, NULL);
805   GNUNET_SERVER_add_handlers (server, handlers);
806 }
807
808
809 /**
810  * The main function for the statistics service.
811  *
812  * @param argc number of arguments from the command line
813  * @param argv command line arguments
814  * @return 0 ok, 1 on error
815  */
816 int
817 main (int argc, char *const *argv)
818 {
819   int ret;
820
821   ret = (GNUNET_OK ==
822          GNUNET_SERVICE_run (argc,
823                              argv,
824                               "peerinfo",
825                              GNUNET_SERVICE_OPTION_NONE,
826                              &run, NULL)) ? 0 : 1;
827   GNUNET_free_non_null (networkIdDirectory);
828   GNUNET_free_non_null (trustDirectory);
829   return ret;
830 }
831
832
833 /* end of gnunet-service-peerinfo.c */