converting FS to new MQ-based core API
[oweals/gnunet.git] / src / fs / gnunet-service-fs.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2014, 2016 GNUnet e.V.
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 3, 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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file fs/gnunet-service-fs.c
23  * @brief gnunet anonymity protocol implementation
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include <float.h>
28 #include "gnunet_constants.h"
29 #include "gnunet_core_service.h"
30 #include "gnunet_dht_service.h"
31 #include "gnunet_datastore_service.h"
32 #include "gnunet_load_lib.h"
33 #include "gnunet_peer_lib.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_statistics_service.h"
37 #include "gnunet_transport_service.h"
38 #include "gnunet_util_lib.h"
39 #include "gnunet-service-fs_cp.h"
40 #include "gnunet-service-fs_indexing.h"
41 #include "gnunet-service-fs_lc.h"
42 #include "gnunet-service-fs_pe.h"
43 #include "gnunet-service-fs_pr.h"
44 #include "gnunet-service-fs_push.h"
45 #include "gnunet-service-fs_put.h"
46 #include "gnunet-service-fs_cadet.h"
47 #include "fs.h"
48 #include "fs_api.h"
49
50 /**
51  * Size for the hash map for DHT requests from the FS
52  * service.  Should be about the number of concurrent
53  * DHT requests we plan to make.
54  */
55 #define FS_DHT_HT_SIZE 1024
56
57
58 /**
59  * How quickly do we age cover traffic?  At the given
60  * time interval, remaining cover traffic counters are
61  * decremented by 1/16th.
62  */
63 #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
64
65 /**
66  * Collect an instane number of statistics?  May cause excessive IPC.
67  */
68 #define INSANE_STATISTICS GNUNET_NO
69
70
71 /* ****************************** globals ****************************** */
72
73 /**
74  * Our connection to the datastore.
75  */
76 struct GNUNET_DATASTORE_Handle *GSF_dsh;
77
78 /**
79  * Our configuration.
80  */
81 const struct GNUNET_CONFIGURATION_Handle *GSF_cfg;
82
83 /**
84  * Handle for reporting statistics.
85  */
86 struct GNUNET_STATISTICS_Handle *GSF_stats;
87
88 /**
89  * Handle for DHT operations.
90  */
91 struct GNUNET_DHT_Handle *GSF_dht;
92
93 /**
94  * How long do requests typically stay in the routing table?
95  */
96 struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime;
97
98 /**
99  * Running average of the observed latency to other peers (round trip).
100  * Initialized to 5s as the initial default.
101  */
102 struct GNUNET_TIME_Relative GSF_avg_latency = { 500 };
103
104 /**
105  * Handle to ATS service.
106  */
107 struct GNUNET_ATS_PerformanceHandle *GSF_ats;
108
109
110 /**
111  * Typical priorities we're seeing from other peers right now.  Since
112  * most priorities will be zero, this value is the weighted average of
113  * non-zero priorities seen "recently".  In order to ensure that new
114  * values do not dramatically change the ratio, values are first
115  * "capped" to a reasonable range (+N of the current value) and then
116  * averaged into the existing value by a ratio of 1:N.  Hence
117  * receiving the largest possible priority can still only raise our
118  * "current_priorities" by at most 1.
119  */
120 double GSF_current_priorities;
121
122 /**
123  * Size of the datastore queue we assume for common requests.
124  */
125 unsigned int GSF_datastore_queue_size;
126
127 /**
128  * How many query messages have we received 'recently' that
129  * have not yet been claimed as cover traffic?
130  */
131 unsigned int GSF_cover_query_count;
132
133 /**
134  * How many content messages have we received 'recently' that
135  * have not yet been claimed as cover traffic?
136  */
137 unsigned int GSF_cover_content_count;
138
139 /**
140  * Our block context.
141  */
142 struct GNUNET_BLOCK_Context *GSF_block_ctx;
143
144 /**
145  * Pointer to handle to the core service (points to NULL until we've
146  * connected to it).
147  */
148 struct GNUNET_CORE_Handle *GSF_core;
149
150 /**
151  * Are we introducing randomized delays for better anonymity?
152  */
153 int GSF_enable_randomized_delays;
154
155 /* ***************************** locals ******************************* */
156
157 /**
158  * Configuration for block library.
159  */
160 static struct GNUNET_CONFIGURATION_Handle *block_cfg;
161
162 /**
163  * Private key of this peer.  Used to sign LOC URI requests.
164  */
165 static struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
166
167 /**
168  * ID of our task that we use to age the cover counters.
169  */
170 static struct GNUNET_SCHEDULER_Task * cover_age_task;
171
172 /**
173  * Datastore 'GET' load tracking.
174  */
175 static struct GNUNET_LOAD_Value *datastore_get_load;
176
177 /**
178  * Identity of this peer.
179  */
180 struct GNUNET_PeerIdentity GSF_my_id;
181
182
183 /**
184  * Task that periodically ages our cover traffic statistics.
185  *
186  * @param cls unused closure
187  */
188 static void
189 age_cover_counters (void *cls)
190 {
191   GSF_cover_content_count = (GSF_cover_content_count * 15) / 16;
192   GSF_cover_query_count = (GSF_cover_query_count * 15) / 16;
193   cover_age_task =
194       GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
195                                     &age_cover_counters,
196                                     NULL);
197 }
198
199
200 /**
201  * We've just now completed a datastore request.  Update our
202  * datastore load calculations.
203  *
204  * @param start time when the datastore request was issued
205  */
206 void
207 GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start)
208 {
209   struct GNUNET_TIME_Relative delay;
210
211   delay = GNUNET_TIME_absolute_get_duration (start);
212   GNUNET_LOAD_update (datastore_get_load, delay.rel_value_us);
213 }
214
215
216 /**
217  * Test if the DATABASE (GET) load on this peer is too high
218  * to even consider processing the query at
219  * all.
220  *
221  * @param priority priority of the request (used as a reference point to compare with the load)
222  * @return #GNUNET_YES if the load is too high to do anything (load high)
223  *         #GNUNET_NO to process normally (load normal)
224  *         #GNUNET_SYSERR to process for free (load low)
225  */
226 int
227 GSF_test_get_load_too_high_ (uint32_t priority)
228 {
229   double ld;
230
231   ld = GNUNET_LOAD_get_load (datastore_get_load);
232   if (ld < 1)
233     return GNUNET_SYSERR;
234   if (ld <= priority)
235     return GNUNET_NO;
236   return GNUNET_YES;
237 }
238
239
240 /**
241  * We've received peer performance information. Update
242  * our running average for the P2P latency.
243  *
244  * @param cls closure
245  * @param address the address
246  * @param active is this address in active use
247  * @param bandwidth_out assigned outbound bandwidth for the connection
248  * @param bandwidth_in assigned inbound bandwidth for the connection
249  * @param prop performance data for the address (as far as known)
250  */
251 static void
252 update_latencies (void *cls,
253                   const struct GNUNET_HELLO_Address *address,
254                   int active,
255                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
256                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
257                   const struct GNUNET_ATS_Properties *prop)
258 {
259   if (NULL == address)
260   {
261     /* ATS service temporarily disconnected */
262     return;
263   }
264
265   if (GNUNET_YES != active)
266     return;
267   GSF_update_peer_latency_ (&address->peer,
268                             prop->delay);
269   GSF_avg_latency.rel_value_us =
270     (GSF_avg_latency.rel_value_us * 31 +
271      GNUNET_MIN (5000, prop->delay.rel_value_us)) / 32;
272   GNUNET_STATISTICS_set (GSF_stats,
273                          gettext_noop ("# running average P2P latency (ms)"),
274                          GSF_avg_latency.rel_value_us / 1000LL,
275                          GNUNET_NO);
276 }
277
278
279 /**
280  * Check P2P "PUT" message.
281  *
282  * @param cls closure with the `struct GSF_ConnectedPeer`
283  * @param message the actual message
284  * @return #GNUNET_OK to keep the connection open,
285  *         #GNUNET_SYSERR to close it (signal serious error)
286  */
287 static int
288 check_p2p_put (void *cls,
289                const struct PutMessage *put)
290 {
291   enum GNUNET_BLOCK_Type type;
292   
293   type = ntohl (put->type);
294   if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
295   {
296     GNUNET_break_op (0);
297     return GNUNET_SYSERR;
298   }
299   return GNUNET_OK;
300 }
301
302
303 /**
304  * We have a new request, consider forwarding it to the given
305  * peer.
306  *
307  * @param cls the `struct GSF_PendingRequest`
308  * @param peer identity of the peer
309  * @param cp handle to the connected peer record
310  * @param ppd peer performance data
311  */
312 static void
313 consider_request_for_forwarding (void *cls,
314                                  const struct GNUNET_PeerIdentity *peer,
315                                  struct GSF_ConnectedPeer *cp,
316                                  const struct GSF_PeerPerformanceData *ppd)
317 {
318   struct GSF_PendingRequest *pr = cls;
319
320   if (GNUNET_YES !=
321       GSF_pending_request_test_target_ (pr, peer))
322   {
323 #if INSANE_STATISTICS
324     GNUNET_STATISTICS_update (GSF_stats,
325                               gettext_noop ("# Loopback routes suppressed"), 1,
326                               GNUNET_NO);
327 #endif
328     return;
329   }
330   GSF_plan_add_ (cp,
331                  pr);
332 }
333
334
335 /**
336  * Function to be called after we're done processing
337  * replies from the local lookup.  If the result status
338  * code indicates that there may be more replies, plan
339  * forwarding the request.
340  *
341  * @param cls closure (NULL)
342  * @param pr the pending request we were processing
343  * @param result final datastore lookup result
344  */
345 void
346 GSF_consider_forwarding (void *cls,
347                          struct GSF_PendingRequest *pr,
348                          enum GNUNET_BLOCK_EvaluationResult result)
349 {
350   if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
351     return;                     /* we're done... */
352   if (GNUNET_YES !=
353       GSF_pending_request_test_active_ (pr))
354     return; /* request is not actually active, skip! */
355   GSF_iterate_connected_peers_ (&consider_request_for_forwarding,
356                                 pr);
357 }
358
359
360 /**
361  * Check P2P "GET" request.
362  *
363  * @param cls closure
364  * @param gm the actual message
365  * @return #GNUNET_OK to keep the connection open,
366  *         #GNUNET_SYSERR to close it (signal serious error)
367  */
368 static int
369 check_p2p_get (void *cls,
370                const struct GetMessage *gm)
371 {
372   size_t msize;
373   unsigned int bm;
374   unsigned int bits;
375   size_t bfsize;
376   
377   msize = ntohs (gm->header.size);
378   bm = ntohl (gm->hash_bitmap);
379   bits = 0;
380   while (bm > 0)
381   {
382     if (1 == (bm & 1))
383       bits++;
384     bm >>= 1;
385   }
386   if (msize < sizeof (struct GetMessage) + bits * sizeof (struct GNUNET_PeerIdentity))
387   {
388     GNUNET_break_op (0);
389     return GNUNET_SYSERR;
390   }
391   bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (struct GNUNET_PeerIdentity);
392   /* bfsize must be power of 2, check! */
393   if (0 != ((bfsize - 1) & bfsize))
394   {
395     GNUNET_break_op (0);
396     return GNUNET_SYSERR;
397   }  
398   return GNUNET_OK; 
399 }
400
401
402 /**
403  * We're done with the local lookup, now consider
404  * P2P processing (depending on request options and
405  * result status).  Also signal that we can now
406  * receive more request information from the client.
407  *
408  * @param cls the client doing the request (`struct GNUNET_SERVER_Client`)
409  * @param pr the pending request we were processing
410  * @param result final datastore lookup result
411  */
412 static void
413 start_p2p_processing (void *cls,
414                       struct GSF_PendingRequest *pr,
415                       enum GNUNET_BLOCK_EvaluationResult result)
416 {
417   struct GNUNET_SERVER_Client *client = cls;
418   struct GSF_PendingRequestData *prd;
419
420   GNUNET_SERVER_receive_done (client,
421                               GNUNET_OK);
422   if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
423     return;                     /* we're done, 'pr' was already destroyed... */
424   prd = GSF_pending_request_get_data_ (pr);
425   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426               "Finished database lookup for local request `%s' with result %d\n",
427               GNUNET_h2s (&prd->query),
428               result);
429   if (0 == prd->anonymity_level)
430   {
431     switch (prd->type)
432     {
433     case GNUNET_BLOCK_TYPE_FS_DBLOCK:
434     case GNUNET_BLOCK_TYPE_FS_IBLOCK:
435       /* the above block types MAY be available via 'cadet' */
436       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
437                   "Considering cadet-based download for block\n");
438       GSF_cadet_lookup_ (pr);
439       break;
440     case GNUNET_BLOCK_TYPE_FS_UBLOCK:
441       /* the above block types are in the DHT */
442       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443                   "Considering DHT-based search for block\n");
444       GSF_dht_lookup_ (pr);
445       break;
446     default:
447       GNUNET_break (0);
448       break;
449     }
450   }
451   GSF_consider_forwarding (NULL, pr, result);
452 }
453
454
455 /**
456  * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
457  * from client).
458  *
459  * @param cls closure
460  * @param client identification of the client
461  * @param message the actual message
462  */
463 static void
464 handle_start_search (void *cls,
465                      struct GNUNET_SERVER_Client *client,
466                      const struct GNUNET_MessageHeader *message)
467 {
468   struct GSF_PendingRequest *pr;
469   int ret;
470
471   pr = NULL;
472   ret = GSF_local_client_start_search_handler_ (client,
473                                                 message,
474                                                 &pr);
475   switch (ret)
476   {
477   case GNUNET_SYSERR:
478     GNUNET_SERVER_receive_done (client,
479                                 GNUNET_SYSERR);
480     break;
481   case GNUNET_NO:
482     GNUNET_SERVER_receive_done (client,
483                                 GNUNET_OK);
484     break;
485   case GNUNET_YES:
486     GSF_pending_request_get_data_ (pr)->has_started = GNUNET_YES;
487     GSF_local_lookup_ (pr,
488                        &start_p2p_processing,
489                        client);
490     break;
491   default:
492     GNUNET_assert (0);
493   }
494 }
495
496
497 /**
498  * Handle request to sign a LOC URI (from client).
499  *
500  * @param cls closure (NULL)
501  * @param client identification of the client
502  * @param message the actual message
503  */
504 static void
505 handle_loc_sign (void *cls,
506                  struct GNUNET_SERVER_Client *client,
507                  const struct GNUNET_MessageHeader *message)
508 {
509   const struct RequestLocSignatureMessage *msg;
510   struct GNUNET_FS_Uri base;
511   struct GNUNET_FS_Uri *loc;
512   struct ResponseLocSignatureMessage resp;
513   struct GSF_LocalClient *lc;
514
515   msg = (const struct RequestLocSignatureMessage *) message;
516   GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
517                 ntohl (msg->purpose));
518   base.type = GNUNET_FS_URI_CHK;
519   base.data.chk.chk = msg->chk;
520   base.data.chk.file_length = GNUNET_ntohll (msg->file_length);
521   loc = GNUNET_FS_uri_loc_create (&base,
522                                   pk,
523                                   GNUNET_TIME_absolute_ntoh (msg->expiration_time));
524   resp.header.size = htons (sizeof (struct ResponseLocSignatureMessage));
525   resp.header.type = htons (GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
526   resp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
527   resp.expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime);
528   resp.signature = loc->data.loc.contentSignature;
529   resp.peer = loc->data.loc.peer;
530   GNUNET_FS_uri_destroy (loc);
531   lc = GSF_local_client_lookup_ (client);
532   GSF_local_client_transmit_ (lc,
533                               &resp.header);
534   GNUNET_SERVER_receive_done (client, GNUNET_OK);
535 }
536
537
538 /**
539  * Task run during shutdown.
540  *
541  * @param cls unused
542  */
543 static void
544 shutdown_task (void *cls)
545 {
546   GSF_cadet_stop_client ();
547   GSF_cadet_stop_server ();
548   if (NULL != GSF_core)
549   {
550     GNUNET_CORE_disconnecT (GSF_core);
551     GSF_core = NULL;
552   }
553   if (NULL != GSF_ats)
554   {
555     GNUNET_ATS_performance_done (GSF_ats);
556     GSF_ats = NULL;
557   }
558   GSF_put_done_ ();
559   GSF_push_done_ ();
560   GSF_pending_request_done_ ();
561   GSF_plan_done ();
562   GSF_connected_peer_done_ ();
563   GNUNET_DATASTORE_disconnect (GSF_dsh, GNUNET_NO);
564   GSF_dsh = NULL;
565   GNUNET_DHT_disconnect (GSF_dht);
566   GSF_dht = NULL;
567   GNUNET_BLOCK_context_destroy (GSF_block_ctx);
568   GSF_block_ctx = NULL;
569   GNUNET_CONFIGURATION_destroy (block_cfg);
570   block_cfg = NULL;
571   GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO);
572   GSF_stats = NULL;
573   if (NULL != cover_age_task)
574   {
575     GNUNET_SCHEDULER_cancel (cover_age_task);
576     cover_age_task = NULL;
577   }
578   GNUNET_FS_indexing_done ();
579   GNUNET_LOAD_value_free (datastore_get_load);
580   datastore_get_load = NULL;
581   GNUNET_LOAD_value_free (GSF_rt_entry_lifetime);
582   GSF_rt_entry_lifetime = NULL;
583 }
584
585
586 /**
587  * Function called after GNUNET_CORE_connecT has succeeded
588  * (or failed for good).  Note that the private key of the
589  * peer is intentionally not exposed here; if you need it,
590  * your process should try to read the private key file
591  * directly (which should work if you are authorized...).
592  *
593  * @param cls closure
594  * @param my_identity ID of this peer, NULL if we failed
595  */
596 static void
597 peer_init_handler (void *cls,
598                    const struct GNUNET_PeerIdentity *my_identity)
599 {
600   if (0 != GNUNET_CRYPTO_cmp_peer_identity (&GSF_my_id,
601                                             my_identity))
602   {
603     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
604                 "Peer identity missmatch, refusing to start!\n");
605     GNUNET_SCHEDULER_shutdown ();
606   }
607 }
608
609
610 /**
611  * Process fs requests.
612  *
613  * @param server the initialized server
614  * @param c configuration to use
615  */
616 static int
617 main_init (struct GNUNET_SERVER_Handle *server,
618            const struct GNUNET_CONFIGURATION_Handle *c)
619 {
620   GNUNET_MQ_hd_var_size (p2p_get,
621                          GNUNET_MESSAGE_TYPE_FS_GET,
622                          struct GetMessage);
623   GNUNET_MQ_hd_var_size (p2p_put,
624                          GNUNET_MESSAGE_TYPE_FS_PUT,
625                          struct PutMessage);
626   GNUNET_MQ_hd_fixed_size (p2p_migration_stop,
627                            GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP,
628                            struct MigrationStopMessage);
629   struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = {
630     GNUNET_MQ_handler_end ()
631   };
632   struct GNUNET_MQ_MessageHandler p2p_handlers[] = {
633     make_p2p_get_handler (NULL),
634     make_p2p_put_handler (NULL),
635     make_p2p_migration_stop_handler (NULL),
636     GNUNET_MQ_handler_end ()
637   };
638   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
639     { &GNUNET_FS_handle_index_start, NULL,
640       GNUNET_MESSAGE_TYPE_FS_INDEX_START, 0 },
641     { &GNUNET_FS_handle_index_list_get, NULL,
642       GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
643       sizeof (struct GNUNET_MessageHeader) },
644     { &GNUNET_FS_handle_unindex, NULL,
645       GNUNET_MESSAGE_TYPE_FS_UNINDEX,
646       sizeof (struct UnindexMessage) },
647     { &handle_start_search, NULL,
648       GNUNET_MESSAGE_TYPE_FS_START_SEARCH, 0 },
649     { &handle_loc_sign, NULL,
650       GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
651       sizeof (struct RequestLocSignatureMessage) },
652     {NULL, NULL, 0, 0}
653   };
654   int anon_p2p_off;
655   char *keyfile;
656
657   /* this option is really only for testcases that need to disable
658      _anonymous_ file-sharing for some reason */
659   anon_p2p_off = (GNUNET_YES ==
660                   GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg,
661                                                         "fs",
662                                                         "DISABLE_ANON_TRANSFER"));
663
664   if (GNUNET_OK !=
665       GNUNET_CONFIGURATION_get_value_filename (GSF_cfg,
666                                                "PEER",
667                                                "PRIVATE_KEY",
668                                                &keyfile))
669   {
670     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
671                 _("FS service is lacking HOSTKEY configuration setting.  Exiting.\n"));
672     GNUNET_SCHEDULER_shutdown ();
673     return GNUNET_SYSERR;
674   }
675   pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
676   GNUNET_free (keyfile);
677   GNUNET_assert (NULL != pk);
678   GNUNET_CRYPTO_eddsa_key_get_public (pk,
679                                       &GSF_my_id.public_key);
680
681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682               "I am peer %s\n",
683               GNUNET_i2s (&GSF_my_id));
684   GSF_core
685     = GNUNET_CORE_connecT (GSF_cfg,
686                            NULL,
687                            &peer_init_handler,
688                            &GSF_peer_connect_handler,
689                            &GSF_peer_disconnect_handler,
690                            (GNUNET_YES == anon_p2p_off)
691                            ? no_p2p_handlers
692                            : p2p_handlers);
693   if (NULL == GSF_core)
694   {
695     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
696                 _("Failed to connect to `%s' service.\n"),
697                 "core");
698     return GNUNET_SYSERR;
699   }
700   GNUNET_SERVER_disconnect_notify (server,
701                                    &GSF_client_disconnect_handler_,
702                                    NULL);
703   GNUNET_SERVER_add_handlers (server, handlers);
704   cover_age_task =
705       GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
706                                     &age_cover_counters,
707                                     NULL);
708   datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE);
709   GSF_cadet_start_server ();
710   GSF_cadet_start_client ();
711   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
712                                  NULL);
713   return GNUNET_OK;
714 }
715
716
717 /**
718  * Process fs requests.
719  *
720  * @param cls closure
721  * @param server the initialized server
722  * @param cfg configuration to use
723  */
724 static void
725 run (void *cls, struct GNUNET_SERVER_Handle *server,
726      const struct GNUNET_CONFIGURATION_Handle *cfg)
727 {
728   unsigned long long dqs;
729
730   GSF_cfg = cfg;
731   if (GNUNET_OK !=
732       GNUNET_CONFIGURATION_get_value_size (GSF_cfg, "fs", "DATASTORE_QUEUE_SIZE",
733                                            &dqs))
734   {
735     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
736                                "fs", "DATASTORE_QUEUE_SIZE");
737     dqs = 1024;
738   }
739   GSF_datastore_queue_size = (unsigned int) dqs;
740   GSF_enable_randomized_delays =
741       GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY");
742   GSF_dsh = GNUNET_DATASTORE_connect (cfg);
743   if (NULL == GSF_dsh)
744   {
745     GNUNET_SCHEDULER_shutdown ();
746     return;
747   }
748   GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL);
749   GSF_stats = GNUNET_STATISTICS_create ("fs", cfg);
750   block_cfg = GNUNET_CONFIGURATION_create ();
751   GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg);
752   GNUNET_assert (NULL != GSF_block_ctx);
753   GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE);
754   GSF_plan_init ();
755   GSF_pending_request_init_ ();
756   GSF_connected_peer_init_ ();
757   GSF_ats = GNUNET_ATS_performance_init (GSF_cfg, &update_latencies, NULL);
758   GSF_push_init_ ();
759   GSF_put_init_ ();
760   if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg, GSF_dsh)) ||
761       (GNUNET_OK != main_init (server, cfg)))
762   {
763     GNUNET_SCHEDULER_shutdown ();
764     shutdown_task (NULL);
765     return;
766   }
767 }
768
769
770 /**
771  * The main function for the fs service.
772  *
773  * @param argc number of arguments from the command line
774  * @param argv command line arguments
775  * @return 0 ok, 1 on error
776  */
777 int
778 main (int argc, char *const *argv)
779 {
780   return (GNUNET_OK ==
781           GNUNET_SERVICE_run (argc, argv, "fs", GNUNET_SERVICE_OPTION_NONE,
782                               &run, NULL)) ? 0 : 1;
783 }
784
785 /* end of gnunet-service-fs.c */