error handling
[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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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_pe.h"
42 #include "gnunet-service-fs_pr.h"
43 #include "gnunet-service-fs_push.h"
44 #include "gnunet-service-fs_put.h"
45 #include "gnunet-service-fs_cadet.h"
46 #include "fs.h"
47 #include "fs_api.h"
48
49 /**
50  * Size for the hash map for DHT requests from the FS
51  * service.  Should be about the number of concurrent
52  * DHT requests we plan to make.
53  */
54 #define FS_DHT_HT_SIZE 1024
55
56
57 /**
58  * How quickly do we age cover traffic?  At the given
59  * time interval, remaining cover traffic counters are
60  * decremented by 1/16th.
61  */
62 #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply ( \
63     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 /**
72  * Doubly-linked list of requests we are performing
73  * on behalf of the same client.
74  */
75 struct ClientRequest
76 {
77   /**
78    * This is a doubly-linked list.
79    */
80   struct ClientRequest *next;
81
82   /**
83    * This is a doubly-linked list.
84    */
85   struct ClientRequest *prev;
86
87   /**
88    * Request this entry represents.
89    */
90   struct GSF_PendingRequest *pr;
91
92   /**
93    * Client list this request belongs to.
94    */
95   struct GSF_LocalClient *lc;
96
97   /**
98    * Task scheduled to destroy the request.
99    */
100   struct GNUNET_SCHEDULER_Task *kill_task;
101 };
102
103
104 /**
105  * Replies to be transmitted to the client.  The actual
106  * response message is allocated after this struct.
107  */
108 struct ClientResponse
109 {
110   /**
111    * This is a doubly-linked list.
112    */
113   struct ClientResponse *next;
114
115   /**
116    * This is a doubly-linked list.
117    */
118   struct ClientResponse *prev;
119
120   /**
121    * Client list entry this response belongs to.
122    */
123   struct GSF_LocalClient *lc;
124
125   /**
126    * Number of bytes in the response.
127    */
128   size_t msize;
129 };
130
131
132 /**
133  * Information we track while handling an index
134  * start request from a client.
135  */
136 struct IndexStartContext
137 {
138   /**
139    * This is a doubly linked list.
140    */
141   struct IndexStartContext *next;
142
143   /**
144    * This is a doubly linked list.
145    */
146   struct IndexStartContext *prev;
147
148   /**
149    * Name of the indexed file.
150    */
151   char *filename;
152
153   /**
154    * Context for transmitting confirmation to client.
155    */
156   struct GSF_LocalClient *lc;
157
158   /**
159    * Context for hashing of the file.
160    */
161   struct GNUNET_CRYPTO_FileHashContext *fhc;
162
163   /**
164    * Hash of the contents of the file.
165    */
166   struct GNUNET_HashCode file_id;
167 };
168
169
170 /**
171  * A local client.
172  */
173 struct GSF_LocalClient
174 {
175   /**
176    * ID of the client.
177    */
178   struct GNUNET_SERVICE_Client *client;
179
180   /**
181    * Queue for sending replies.
182    */
183   struct GNUNET_MQ_Handle *mq;
184
185   /**
186    * Head of list of requests performed on behalf
187    * of this client right now.
188    */
189   struct ClientRequest *cr_head;
190
191   /**
192    * Tail of list of requests performed on behalf
193    * of this client right now.
194    */
195   struct ClientRequest *cr_tail;
196
197   /**
198    * This is a doubly linked list.
199    */
200   struct IndexStartContext *isc_head;
201
202   /**
203    * This is a doubly linked list.
204    */
205   struct IndexStartContext *isc_tail;
206
207   /**
208    * Head of linked list of responses.
209    */
210   struct ClientResponse *res_head;
211
212   /**
213    * Tail of linked list of responses.
214    */
215   struct ClientResponse *res_tail;
216 };
217
218
219 /* ****************************** globals ****************************** */
220
221 /**
222  * Our connection to the datastore.
223  */
224 struct GNUNET_DATASTORE_Handle *GSF_dsh;
225
226 /**
227  * Our configuration.
228  */
229 const struct GNUNET_CONFIGURATION_Handle *GSF_cfg;
230
231 /**
232  * Handle for reporting statistics.
233  */
234 struct GNUNET_STATISTICS_Handle *GSF_stats;
235
236 /**
237  * Handle for DHT operations.
238  */
239 struct GNUNET_DHT_Handle *GSF_dht;
240
241 /**
242  * How long do requests typically stay in the routing table?
243  */
244 struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime;
245
246 /**
247  * Running average of the observed latency to other peers (round trip).
248  * Initialized to 5s as the initial default.
249  */
250 struct GNUNET_TIME_Relative GSF_avg_latency = { 500 };
251
252 /**
253  * Handle to ATS service.
254  */
255 struct GNUNET_ATS_PerformanceHandle *GSF_ats;
256
257
258 /**
259  * Typical priorities we're seeing from other peers right now.  Since
260  * most priorities will be zero, this value is the weighted average of
261  * non-zero priorities seen "recently".  In order to ensure that new
262  * values do not dramatically change the ratio, values are first
263  * "capped" to a reasonable range (+N of the current value) and then
264  * averaged into the existing value by a ratio of 1:N.  Hence
265  * receiving the largest possible priority can still only raise our
266  * "current_priorities" by at most 1.
267  */
268 double GSF_current_priorities;
269
270 /**
271  * Size of the datastore queue we assume for common requests.
272  */
273 unsigned int GSF_datastore_queue_size;
274
275 /**
276  * How many query messages have we received 'recently' that
277  * have not yet been claimed as cover traffic?
278  */
279 unsigned int GSF_cover_query_count;
280
281 /**
282  * How many content messages have we received 'recently' that
283  * have not yet been claimed as cover traffic?
284  */
285 unsigned int GSF_cover_content_count;
286
287 /**
288  * Our block context.
289  */
290 struct GNUNET_BLOCK_Context *GSF_block_ctx;
291
292 /**
293  * Pointer to handle to the core service (points to NULL until we've
294  * connected to it).
295  */
296 struct GNUNET_CORE_Handle *GSF_core;
297
298 /**
299  * Are we introducing randomized delays for better anonymity?
300  */
301 int GSF_enable_randomized_delays;
302
303 /**
304  * Identity of this peer.
305  */
306 struct GNUNET_PeerIdentity GSF_my_id;
307
308 /* ***************************** locals ******************************* */
309
310 /**
311  * Configuration for block library.
312  */
313 static struct GNUNET_CONFIGURATION_Handle *block_cfg;
314
315 /**
316  * Private key of this peer.  Used to sign LOC URI requests.
317  */
318 static struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
319
320 /**
321  * ID of our task that we use to age the cover counters.
322  */
323 static struct GNUNET_SCHEDULER_Task *cover_age_task;
324
325 /**
326  * Datastore 'GET' load tracking.
327  */
328 static struct GNUNET_LOAD_Value *datastore_get_load;
329
330
331 /**
332  * Creates a fresh local client handle.
333  *
334  * @param cls NULL
335  * @param client handle of the client
336  * @param mq message queue for @a client
337  * @return handle to local client entry
338  */
339 static void *
340 client_connect_cb (void *cls,
341                    struct GNUNET_SERVICE_Client *client,
342                    struct GNUNET_MQ_Handle *mq)
343 {
344   struct GSF_LocalClient *pos;
345
346   pos = GNUNET_new (struct GSF_LocalClient);
347   pos->client = client;
348   pos->mq = mq;
349   return pos;
350 }
351
352
353 /**
354  * Free the given client request.
355  *
356  * @param cls the client request to free
357  */
358 static void
359 client_request_destroy (void *cls)
360 {
361   struct ClientRequest *cr = cls;
362   struct GSF_LocalClient *lc = cr->lc;
363
364   cr->kill_task = NULL;
365   GNUNET_CONTAINER_DLL_remove (lc->cr_head,
366                                lc->cr_tail,
367                                cr);
368   GSF_pending_request_cancel_ (cr->pr,
369                                GNUNET_YES);
370   GNUNET_STATISTICS_update (GSF_stats,
371                             gettext_noop ("# client searches active"),
372                             -1,
373                             GNUNET_NO);
374   GNUNET_free (cr);
375 }
376
377
378 /**
379  * Handle a reply to a pending request.  Also called if a request
380  * expires (then with data == NULL).  The handler may be called
381  * many times (depending on the request type), but will not be
382  * called during or after a call to #GSF_pending_request_cancel()
383  * and will also not be called anymore after a call signalling
384  * expiration.
385  *
386  * @param cls user-specified closure
387  * @param eval evaluation of the result
388  * @param pr handle to the original pending request
389  * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
390  * @param expiration when does @a data expire?
391  * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
392  * @param type type of the block
393  * @param data response data, NULL on request expiration
394  * @param data_len number of bytes in @a data
395  */
396 static void
397 client_response_handler (void *cls,
398                          enum GNUNET_BLOCK_EvaluationResult eval,
399                          struct GSF_PendingRequest *pr,
400                          uint32_t reply_anonymity_level,
401                          struct GNUNET_TIME_Absolute expiration,
402                          struct GNUNET_TIME_Absolute last_transmission,
403                          enum GNUNET_BLOCK_Type type,
404                          const void *data,
405                          size_t data_len)
406 {
407   struct ClientRequest *cr = cls;
408   struct GSF_LocalClient *lc;
409   struct GNUNET_MQ_Envelope *env;
410   struct ClientPutMessage *pm;
411   const struct GSF_PendingRequestData *prd;
412
413   if (NULL == data)
414   {
415     /* local-only request, with no result, clean up. */
416     if (NULL == cr->kill_task)
417       cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
418                                                 cr);
419     return;
420   }
421   prd = GSF_pending_request_get_data_ (pr);
422   GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
423   if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
424   {
425     GNUNET_break (0);
426     return;
427   }
428   GNUNET_STATISTICS_update (GSF_stats,
429                             gettext_noop
430                               ("# replies received for local clients"), 1,
431                             GNUNET_NO);
432   GNUNET_assert (pr == cr->pr);
433   lc = cr->lc;
434   env = GNUNET_MQ_msg_extra (pm,
435                              data_len,
436                              GNUNET_MESSAGE_TYPE_FS_PUT);
437   pm->type = htonl (type);
438   pm->expiration = GNUNET_TIME_absolute_hton (expiration);
439   pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
440   pm->num_transmissions = htonl (prd->num_transmissions);
441   pm->respect_offered = htonl (prd->respect_offered);
442   GNUNET_memcpy (&pm[1],
443                  data,
444                  data_len);
445   GNUNET_MQ_send (lc->mq,
446                   env);
447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448               "Queued reply to query `%s' for local client\n",
449               GNUNET_h2s (&prd->query));
450   if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
451   {
452     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453                 "Evaluation %d - keeping query alive\n",
454                 (int) eval);
455     return;
456   }
457   if (NULL == cr->kill_task)
458     cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
459                                               cr);
460 }
461
462
463 /**
464  * A client disconnected from us.  Tear down the local client
465  * record.
466  *
467  * @param cls unused
468  * @param client handle of the client
469  * @param app_ctx the `struct GSF_LocalClient`
470  */
471 static void
472 client_disconnect_cb (void *cls,
473                       struct GNUNET_SERVICE_Client *client,
474                       void *app_ctx)
475 {
476   struct GSF_LocalClient *lc = app_ctx;
477   struct IndexStartContext *isc;
478   struct ClientRequest *cr;
479   struct ClientResponse *res;
480
481   while (NULL != (cr = lc->cr_head))
482   {
483     if (NULL != cr->kill_task)
484       GNUNET_SCHEDULER_cancel (cr->kill_task);
485     client_request_destroy (cr);
486   }
487   while (NULL != (res = lc->res_head))
488   {
489     GNUNET_CONTAINER_DLL_remove (lc->res_head,
490                                  lc->res_tail,
491                                  res);
492     GNUNET_free (res);
493   }
494   while (NULL != (isc = lc->isc_head))
495   {
496     GNUNET_CONTAINER_DLL_remove (lc->isc_head,
497                                  lc->isc_tail,
498                                  isc);
499     GNUNET_CRYPTO_hash_file_cancel (isc->fhc);
500     GNUNET_free (isc);
501   }
502   GNUNET_free (lc);
503 }
504
505
506 /**
507  * Task that periodically ages our cover traffic statistics.
508  *
509  * @param cls unused closure
510  */
511 static void
512 age_cover_counters (void *cls)
513 {
514   GSF_cover_content_count = (GSF_cover_content_count * 15) / 16;
515   GSF_cover_query_count = (GSF_cover_query_count * 15) / 16;
516   cover_age_task =
517     GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
518                                   &age_cover_counters,
519                                   NULL);
520 }
521
522
523 /**
524  * We've just now completed a datastore request.  Update our
525  * datastore load calculations.
526  *
527  * @param start time when the datastore request was issued
528  */
529 void
530 GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start)
531 {
532   struct GNUNET_TIME_Relative delay;
533
534   delay = GNUNET_TIME_absolute_get_duration (start);
535   GNUNET_LOAD_update (datastore_get_load, delay.rel_value_us);
536 }
537
538
539 /**
540  * Test if the DATABASE (GET) load on this peer is too high
541  * to even consider processing the query at
542  * all.
543  *
544  * @param priority priority of the request (used as a reference point to compare with the load)
545  * @return #GNUNET_YES if the load is too high to do anything (load high)
546  *         #GNUNET_NO to process normally (load normal)
547  *         #GNUNET_SYSERR to process for free (load low)
548  */
549 int
550 GSF_test_get_load_too_high_ (uint32_t priority)
551 {
552   double ld;
553
554   ld = GNUNET_LOAD_get_load (datastore_get_load);
555   if (ld < 1)
556     return GNUNET_SYSERR;
557   if (ld <= priority)
558     return GNUNET_NO;
559   return GNUNET_YES;
560 }
561
562
563 /**
564  * We've received peer performance information. Update
565  * our running average for the P2P latency.
566  *
567  * @param cls closure
568  * @param address the address
569  * @param active is this address in active use
570  * @param bandwidth_out assigned outbound bandwidth for the connection
571  * @param bandwidth_in assigned inbound bandwidth for the connection
572  * @param prop performance data for the address (as far as known)
573  */
574 static void
575 update_latencies (void *cls,
576                   const struct GNUNET_HELLO_Address *address,
577                   int active,
578                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
579                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
580                   const struct GNUNET_ATS_Properties *prop)
581 {
582   if (NULL == address)
583   {
584     /* ATS service temporarily disconnected */
585     return;
586   }
587
588   if (GNUNET_YES != active)
589     return;
590   GSF_update_peer_latency_ (&address->peer,
591                             prop->delay);
592   GSF_avg_latency.rel_value_us =
593     (GSF_avg_latency.rel_value_us * 31
594      + GNUNET_MIN (5000, prop->delay.rel_value_us)) / 32;
595   GNUNET_STATISTICS_set (GSF_stats,
596                          gettext_noop ("# running average P2P latency (ms)"),
597                          GSF_avg_latency.rel_value_us / 1000LL,
598                          GNUNET_NO);
599 }
600
601
602 /**
603  * Check P2P "PUT" message.
604  *
605  * @param cls closure with the `struct GSF_ConnectedPeer`
606  * @param message the actual message
607  * @return #GNUNET_OK to keep the connection open,
608  *         #GNUNET_SYSERR to close it (signal serious error)
609  */
610 static int
611 check_p2p_put (void *cls,
612                const struct PutMessage *put)
613 {
614   enum GNUNET_BLOCK_Type type;
615
616   type = ntohl (put->type);
617   if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
618   {
619     GNUNET_break_op (0);
620     return GNUNET_SYSERR;
621   }
622   return GNUNET_OK;
623 }
624
625
626 /**
627  * We have a new request, consider forwarding it to the given
628  * peer.
629  *
630  * @param cls the `struct GSF_PendingRequest`
631  * @param peer identity of the peer
632  * @param cp handle to the connected peer record
633  * @param ppd peer performance data
634  */
635 static void
636 consider_request_for_forwarding (void *cls,
637                                  const struct GNUNET_PeerIdentity *peer,
638                                  struct GSF_ConnectedPeer *cp,
639                                  const struct GSF_PeerPerformanceData *ppd)
640 {
641   struct GSF_PendingRequest *pr = cls;
642
643   if (GNUNET_YES !=
644       GSF_pending_request_test_target_ (pr, peer))
645   {
646 #if INSANE_STATISTICS
647     GNUNET_STATISTICS_update (GSF_stats,
648                               gettext_noop ("# Loopback routes suppressed"), 1,
649                               GNUNET_NO);
650 #endif
651     return;
652   }
653   GSF_plan_add_ (cp,
654                  pr);
655 }
656
657
658 /**
659  * Function to be called after we're done processing
660  * replies from the local lookup.  If the result status
661  * code indicates that there may be more replies, plan
662  * forwarding the request.
663  *
664  * @param cls closure (NULL)
665  * @param pr the pending request we were processing
666  * @param result final datastore lookup result
667  */
668 void
669 GSF_consider_forwarding (void *cls,
670                          struct GSF_PendingRequest *pr,
671                          enum GNUNET_BLOCK_EvaluationResult result)
672 {
673   if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
674     return;                     /* we're done... */
675   if (GNUNET_YES !=
676       GSF_pending_request_test_active_ (pr))
677     return; /* request is not actually active, skip! */
678   GSF_iterate_connected_peers_ (&consider_request_for_forwarding,
679                                 pr);
680 }
681
682
683 /**
684  * Check P2P "GET" request.
685  *
686  * @param cls closure
687  * @param gm the actual message
688  * @return #GNUNET_OK to keep the connection open,
689  *         #GNUNET_SYSERR to close it (signal serious error)
690  */
691 static int
692 check_p2p_get (void *cls,
693                const struct GetMessage *gm)
694 {
695   size_t msize;
696   unsigned int bm;
697   unsigned int bits;
698   size_t bfsize;
699
700   msize = ntohs (gm->header.size);
701   bm = ntohl (gm->hash_bitmap);
702   bits = 0;
703   while (bm > 0)
704   {
705     if (1 == (bm & 1))
706       bits++;
707     bm >>= 1;
708   }
709   if (msize < sizeof(struct GetMessage) + bits * sizeof(struct
710                                                         GNUNET_PeerIdentity))
711   {
712     GNUNET_break_op (0);
713     return GNUNET_SYSERR;
714   }
715   bfsize = msize - sizeof(struct GetMessage) - bits * sizeof(struct
716                                                              GNUNET_PeerIdentity);
717   /* bfsize must be power of 2, check! */
718   if (0 != ((bfsize - 1) & bfsize))
719   {
720     GNUNET_break_op (0);
721     return GNUNET_SYSERR;
722   }
723   return GNUNET_OK;
724 }
725
726
727 /**
728  * We're done with the local lookup, now consider
729  * P2P processing (depending on request options and
730  * result status).  Also signal that we can now
731  * receive more request information from the client.
732  *
733  * @param cls the client doing the request (`struct GSF_LocalClient`)
734  * @param pr the pending request we were processing
735  * @param result final datastore lookup result
736  */
737 static void
738 start_p2p_processing (void *cls,
739                       struct GSF_PendingRequest *pr,
740                       enum GNUNET_BLOCK_EvaluationResult result)
741 {
742   struct GSF_LocalClient *lc = cls;
743   struct GSF_PendingRequestData *prd;
744
745   GNUNET_SERVICE_client_continue (lc->client);
746   if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
747     return;                     /* we're done, 'pr' was already destroyed... */
748   prd = GSF_pending_request_get_data_ (pr);
749   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750               "Finished database lookup for local request `%s' with result %d\n",
751               GNUNET_h2s (&prd->query),
752               result);
753   if (0 == prd->anonymity_level)
754   {
755     switch (prd->type)
756     {
757     case GNUNET_BLOCK_TYPE_FS_DBLOCK:
758     case GNUNET_BLOCK_TYPE_FS_IBLOCK:
759       /* the above block types MAY be available via 'cadet' */
760       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761                   "Considering cadet-based download for block\n");
762       GSF_cadet_lookup_ (pr);
763       break;
764
765     case GNUNET_BLOCK_TYPE_FS_UBLOCK:
766       /* the above block types are in the DHT */
767       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768                   "Considering DHT-based search for block\n");
769       GSF_dht_lookup_ (pr);
770       break;
771
772     default:
773       GNUNET_break (0);
774       break;
775     }
776   }
777   GSF_consider_forwarding (NULL,
778                            pr,
779                            result);
780 }
781
782
783 /**
784  * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
785  * from client).
786  *
787  * @param cls identification of the client
788  * @param sm the actual message
789  * @return #GNUNET_OK if @a sm is well-formed
790  */
791 static int
792 check_client_start_search (void *cls,
793                            const struct SearchMessage *sm)
794 {
795   uint16_t msize;
796
797   msize = ntohs (sm->header.size) - sizeof(struct SearchMessage);
798   if (0 != msize % sizeof(struct GNUNET_HashCode))
799   {
800     GNUNET_break (0);
801     return GNUNET_SYSERR;
802   }
803   return GNUNET_OK;
804 }
805
806
807 /**
808  * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
809  * from client).
810  *
811  * Responsible for creating the request entry itself and setting
812  * up reply callback and cancellation on client disconnect.
813  *
814  * @param cls identification of the client
815  * @param sm the actual message
816  */
817 static void
818 handle_client_start_search (void *cls,
819                             const struct SearchMessage *sm)
820 {
821   static struct GNUNET_PeerIdentity all_zeros;
822   struct GSF_LocalClient *lc = cls;
823   struct ClientRequest *cr;
824   struct GSF_PendingRequestData *prd;
825   uint16_t msize;
826   unsigned int sc;
827   enum GNUNET_BLOCK_Type type;
828   enum GSF_PendingRequestOptions options;
829
830   GNUNET_STATISTICS_update (GSF_stats,
831                             gettext_noop ("# client searches received"),
832                             1,
833                             GNUNET_NO);
834   msize = ntohs (sm->header.size) - sizeof(struct SearchMessage);
835   sc = msize / sizeof(struct GNUNET_HashCode);
836   type = ntohl (sm->type);
837   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
838               "Received request for `%s' of type %u from local client\n",
839               GNUNET_h2s (&sm->query),
840               (unsigned int) type);
841   cr = NULL;
842   /* detect duplicate UBLOCK requests */
843   if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) ||
844       (type == GNUNET_BLOCK_TYPE_ANY))
845   {
846     cr = lc->cr_head;
847     while (NULL != cr)
848     {
849       prd = GSF_pending_request_get_data_ (cr->pr);
850       /* only unify with queries that hae not yet started local processing
851          (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a
852          matching query and type */
853       if ((GNUNET_YES != prd->has_started) &&
854           (0 != memcmp (&prd->query,
855                         &sm->query,
856                         sizeof(struct GNUNET_HashCode))) &&
857           (prd->type == type))
858         break;
859       cr = cr->next;
860     }
861   }
862   if (NULL != cr)
863   {
864     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865                 "Have existing request, merging content-seen lists.\n");
866     GSF_pending_request_update_ (cr->pr,
867                                  (const struct GNUNET_HashCode *) &sm[1],
868                                  sc);
869     GNUNET_STATISTICS_update (GSF_stats,
870                               gettext_noop (
871                                 "# client searches updated (merged content seen list)"),
872                               1,
873                               GNUNET_NO);
874   }
875   else
876   {
877     GNUNET_STATISTICS_update (GSF_stats,
878                               gettext_noop ("# client searches active"),
879                               1,
880                               GNUNET_NO);
881     cr = GNUNET_new (struct ClientRequest);
882     cr->lc = lc;
883     GNUNET_CONTAINER_DLL_insert (lc->cr_head,
884                                  lc->cr_tail,
885                                  cr);
886     options = GSF_PRO_LOCAL_REQUEST;
887     if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options)))
888       options |= GSF_PRO_LOCAL_ONLY;
889     cr->pr = GSF_pending_request_create_ (options, type,
890                                           &sm->query,
891                                           (0 !=
892                                            memcmp (&sm->target,
893                                                    &all_zeros,
894                                                    sizeof(struct
895                                                           GNUNET_PeerIdentity)))
896                                           ? &sm->target : NULL, NULL, 0,
897                                           0 /* bf */,
898                                           ntohl (sm->anonymity_level),
899                                           0 /* priority */,
900                                           0 /* ttl */,
901                                           0 /* sender PID */,
902                                           0 /* origin PID */,
903                                           (const struct
904                                            GNUNET_HashCode *) &sm[1], sc,
905                                           &client_response_handler,
906                                           cr);
907   }
908   if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options)))
909   {
910     GNUNET_SERVICE_client_continue (lc->client);
911     return;
912   }
913   GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES;
914   GSF_local_lookup_ (cr->pr,
915                      &start_p2p_processing,
916                      lc);
917 }
918
919
920 /**
921  * Handle request to sign a LOC URI (from client).
922  *
923  * @param cls identification of the client
924  * @param msg the actual message
925  */
926 static void
927 handle_client_loc_sign (void *cls,
928                         const struct RequestLocSignatureMessage *msg)
929 {
930   struct GSF_LocalClient *lc = cls;
931   struct GNUNET_FS_Uri base;
932   struct GNUNET_FS_Uri *loc;
933   struct GNUNET_MQ_Envelope *env;
934   struct ResponseLocSignatureMessage *resp;
935
936   GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
937                 ntohl (msg->purpose));
938   base.type = GNUNET_FS_URI_CHK;
939   base.data.chk.chk = msg->chk;
940   base.data.chk.file_length = GNUNET_ntohll (msg->file_length);
941   loc = GNUNET_FS_uri_loc_create (&base,
942                                   pk,
943                                   GNUNET_TIME_absolute_ntoh (
944                                     msg->expiration_time));
945   env = GNUNET_MQ_msg (resp,
946                        GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
947   resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
948   resp->expiration_time = GNUNET_TIME_absolute_hton (
949     loc->data.loc.expirationTime);
950   resp->signature = loc->data.loc.contentSignature;
951   resp->peer = loc->data.loc.peer;
952   GNUNET_FS_uri_destroy (loc);
953   GNUNET_MQ_send (lc->mq,
954                   env);
955   GNUNET_SERVICE_client_continue (lc->client);
956 }
957
958
959 /**
960  * Check INDEX_START-message.
961  *
962  * @param cls identification of the client
963  * @param ism the actual message
964  * @return #GNUNET_OK if @a ism is well-formed
965  */
966 static int
967 check_client_index_start (void *cls,
968                           const struct IndexStartMessage *ism)
969 {
970   char *fn;
971
972   GNUNET_MQ_check_zero_termination (ism);
973   if (0 != ism->reserved)
974   {
975     GNUNET_break (0);
976     return GNUNET_SYSERR;
977   }
978   fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
979   if (NULL == fn)
980   {
981     GNUNET_break (0);
982     return GNUNET_SYSERR;
983   }
984   GNUNET_free (fn);
985   return GNUNET_OK;
986 }
987
988
989 /**
990  * We've validated the hash of the file we're about to index.  Signal
991  * success to the client and update our internal data structures.
992  *
993  * @param isc the data about the index info entry for the request
994  */
995 static void
996 signal_index_ok (struct IndexStartContext *isc)
997 {
998   struct GSF_LocalClient *lc = isc->lc;
999   struct GNUNET_MQ_Envelope *env;
1000   struct GNUNET_MessageHeader *msg;
1001
1002   GNUNET_FS_add_to_index (isc->filename,
1003                           &isc->file_id);
1004   env = GNUNET_MQ_msg (msg,
1005                        GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
1006   GNUNET_MQ_send (lc->mq,
1007                   env);
1008   GNUNET_free (isc->filename);
1009   GNUNET_free (isc);
1010   GNUNET_SERVICE_client_continue (lc->client);
1011 }
1012
1013
1014 /**
1015  * Function called once the hash computation over an
1016  * indexed file has completed.
1017  *
1018  * @param cls closure, our publishing context
1019  * @param res resulting hash, NULL on error
1020  */
1021 static void
1022 hash_for_index_val (void *cls,
1023                     const struct GNUNET_HashCode *res)
1024 {
1025   struct IndexStartContext *isc = cls;
1026   struct GSF_LocalClient *lc = isc->lc;
1027   struct GNUNET_MQ_Envelope *env;
1028   struct GNUNET_MessageHeader *msg;
1029
1030   GNUNET_CONTAINER_DLL_remove (lc->isc_head,
1031                                lc->isc_tail,
1032                                isc);
1033   isc->fhc = NULL;
1034   if ((NULL == res) ||
1035       (0 != memcmp (res,
1036                     &isc->file_id,
1037                     sizeof(struct GNUNET_HashCode))))
1038   {
1039     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1040                 _ (
1041                   "Hash mismatch trying to index file `%s' which does not have hash `%s'\n"),
1042                 isc->filename,
1043                 GNUNET_h2s (&isc->file_id));
1044     env = GNUNET_MQ_msg (msg,
1045                          GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
1046     GNUNET_MQ_send (lc->mq,
1047                     env);
1048     GNUNET_SERVICE_client_continue (lc->client);
1049     GNUNET_free (isc);
1050     return;
1051   }
1052   signal_index_ok (isc);
1053 }
1054
1055
1056 /**
1057  * Handle INDEX_START-message.
1058  *
1059  * @param cls identification of the client
1060  * @param message the actual message
1061  */
1062 static void
1063 handle_client_index_start (void *cls,
1064                            const struct IndexStartMessage *ism)
1065 {
1066   struct GSF_LocalClient *lc = cls;
1067   struct IndexStartContext *isc;
1068   char *fn;
1069   uint64_t dev;
1070   uint64_t ino;
1071   uint64_t mydev;
1072   uint64_t myino;
1073
1074   fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
1075   GNUNET_assert (NULL != fn);
1076   dev = GNUNET_ntohll (ism->device);
1077   ino = GNUNET_ntohll (ism->inode);
1078   isc = GNUNET_new (struct IndexStartContext);
1079   isc->filename = fn;
1080   isc->file_id = ism->file_id;
1081   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082               "Received START_INDEX message for file `%s'\n",
1083               isc->filename);
1084   isc->lc = lc;
1085   mydev = 0;
1086   myino = 0;
1087   if (((dev != 0) ||
1088        (ino != 0)) &&
1089       (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn,
1090                                                       &mydev,
1091                                                       &myino)) &&
1092       (dev == mydev) &&
1093       (ino == myino))
1094   {
1095     /* fast validation OK! */
1096     signal_index_ok (isc);
1097     return;
1098   }
1099   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100               "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
1101               (unsigned long long) ino,
1102               (unsigned long long) myino,
1103               (unsigned int) dev,
1104               (unsigned int) mydev);
1105   /* slow validation, need to hash full file (again) */
1106   GNUNET_CONTAINER_DLL_insert (lc->isc_head,
1107                                lc->isc_tail,
1108                                isc);
1109   isc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
1110                                       isc->filename,
1111                                       HASHING_BLOCKSIZE,
1112                                       &hash_for_index_val,
1113                                       isc);
1114   if (NULL == isc->fhc)
1115     hash_for_index_val (isc,
1116                         NULL);
1117 }
1118
1119
1120 /**
1121  * Handle INDEX_LIST_GET-message.
1122  *
1123  * @param cls closure
1124  * @param message the actual message
1125  */
1126 static void
1127 handle_client_index_list_get (void *cls,
1128                               const struct GNUNET_MessageHeader *message)
1129 {
1130   struct GSF_LocalClient *lc = cls;
1131
1132   GNUNET_FS_indexing_send_list (lc->mq);
1133   GNUNET_SERVICE_client_continue (lc->client);
1134 }
1135
1136
1137 /**
1138  * Handle UNINDEX-message.
1139  *
1140  * @param cls identification of the client
1141  * @param message the actual message
1142  */
1143 static void
1144 handle_client_unindex (void *cls,
1145                        const struct UnindexMessage *um)
1146 {
1147   struct GSF_LocalClient *lc = cls;
1148   struct GNUNET_MQ_Envelope *env;
1149   struct GNUNET_MessageHeader *msg;
1150   int found;
1151
1152   GNUNET_break (0 == um->reserved);
1153   found = GNUNET_FS_indexing_do_unindex (&um->file_id);
1154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1155               "Client requested unindexing of file `%s': %s\n",
1156               GNUNET_h2s (&um->file_id),
1157               found ? "found" : "not found");
1158   env = GNUNET_MQ_msg (msg,
1159                        GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK);
1160   GNUNET_MQ_send (lc->mq,
1161                   env);
1162   GNUNET_SERVICE_client_continue (lc->client);
1163 }
1164
1165
1166 /**
1167  * Task run during shutdown.
1168  *
1169  * @param cls unused
1170  */
1171 static void
1172 shutdown_task (void *cls)
1173 {
1174   GSF_cadet_stop_server ();
1175   if (NULL != GSF_core)
1176   {
1177     GNUNET_CORE_disconnect (GSF_core);
1178     GSF_core = NULL;
1179   }
1180   if (NULL != GSF_ats)
1181   {
1182     GNUNET_ATS_performance_done (GSF_ats);
1183     GSF_ats = NULL;
1184   }
1185   GSF_put_done_ ();
1186   GSF_push_done_ ();
1187   GSF_pending_request_done_ ();
1188   GSF_plan_done ();
1189   GSF_connected_peer_done_ ();
1190   GNUNET_DATASTORE_disconnect (GSF_dsh,
1191                                GNUNET_NO);
1192   GSF_dsh = NULL;
1193   GNUNET_DHT_disconnect (GSF_dht);
1194   GSF_dht = NULL;
1195   GNUNET_BLOCK_context_destroy (GSF_block_ctx);
1196   GSF_block_ctx = NULL;
1197   GNUNET_CONFIGURATION_destroy (block_cfg);
1198   block_cfg = NULL;
1199   GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO);
1200   GSF_stats = NULL;
1201   if (NULL != cover_age_task)
1202   {
1203     GNUNET_SCHEDULER_cancel (cover_age_task);
1204     cover_age_task = NULL;
1205   }
1206   GNUNET_FS_indexing_done ();
1207   GNUNET_LOAD_value_free (datastore_get_load);
1208   datastore_get_load = NULL;
1209   GNUNET_LOAD_value_free (GSF_rt_entry_lifetime);
1210   GSF_rt_entry_lifetime = NULL;
1211 }
1212
1213
1214 /**
1215  * Function called after GNUNET_CORE_connect has succeeded
1216  * (or failed for good).  Note that the private key of the
1217  * peer is intentionally not exposed here; if you need it,
1218  * your process should try to read the private key file
1219  * directly (which should work if you are authorized...).
1220  *
1221  * @param cls closure
1222  * @param my_identity ID of this peer, NULL if we failed
1223  */
1224 static void
1225 peer_init_handler (void *cls,
1226                    const struct GNUNET_PeerIdentity *my_identity)
1227 {
1228   if (0 != GNUNET_memcmp (&GSF_my_id,
1229                           my_identity))
1230   {
1231     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1232                 "Peer identity mismatch, refusing to start!\n");
1233     GNUNET_SCHEDULER_shutdown ();
1234   }
1235 }
1236
1237
1238 /**
1239  * Process fs requests.
1240  *
1241  * @param c configuration to use
1242  */
1243 static int
1244 main_init (const struct GNUNET_CONFIGURATION_Handle *c)
1245 {
1246   struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = {
1247     GNUNET_MQ_handler_end ()
1248   };
1249   struct GNUNET_MQ_MessageHandler p2p_handlers[] = {
1250     GNUNET_MQ_hd_var_size (p2p_get,
1251                            GNUNET_MESSAGE_TYPE_FS_GET,
1252                            struct GetMessage,
1253                            NULL),
1254     GNUNET_MQ_hd_var_size (p2p_put,
1255                            GNUNET_MESSAGE_TYPE_FS_PUT,
1256                            struct PutMessage,
1257                            NULL),
1258     GNUNET_MQ_hd_fixed_size (p2p_migration_stop,
1259                              GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP,
1260                              struct MigrationStopMessage,
1261                              NULL),
1262     GNUNET_MQ_handler_end ()
1263   };
1264   int anon_p2p_off;
1265   char *keyfile;
1266
1267   /* this option is really only for testcases that need to disable
1268      _anonymous_ file-sharing for some reason */
1269   anon_p2p_off = (GNUNET_YES ==
1270                   GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg,
1271                                                         "fs",
1272                                                         "DISABLE_ANON_TRANSFER"));
1273
1274   if (GNUNET_OK !=
1275       GNUNET_CONFIGURATION_get_value_filename (GSF_cfg,
1276                                                "PEER",
1277                                                "PRIVATE_KEY",
1278                                                &keyfile))
1279   {
1280     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1281                 _ (
1282                   "FS service is lacking HOSTKEY configuration setting.  Exiting.\n"));
1283     GNUNET_SCHEDULER_shutdown ();
1284     return GNUNET_SYSERR;
1285   }
1286   pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
1287   GNUNET_free (keyfile);
1288   GNUNET_assert (NULL != pk);
1289   GNUNET_CRYPTO_eddsa_key_get_public (pk,
1290                                       &GSF_my_id.public_key);
1291
1292   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293               "I am peer %s\n",
1294               GNUNET_i2s (&GSF_my_id));
1295   GSF_core
1296     = GNUNET_CORE_connect (GSF_cfg,
1297                            NULL,
1298                            &peer_init_handler,
1299                            &GSF_peer_connect_handler,
1300                            &GSF_peer_disconnect_handler,
1301                            (GNUNET_YES == anon_p2p_off)
1302                            ? no_p2p_handlers
1303                            : p2p_handlers);
1304   if (NULL == GSF_core)
1305   {
1306     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1307                 _ ("Failed to connect to `%s' service.\n"),
1308                 "core");
1309     return GNUNET_SYSERR;
1310   }
1311   cover_age_task =
1312     GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
1313                                   &age_cover_counters,
1314                                   NULL);
1315   datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE);
1316   GSF_cadet_start_server ();
1317   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1318                                  NULL);
1319   return GNUNET_OK;
1320 }
1321
1322
1323 /**
1324  * Process fs requests.
1325  *
1326  * @param cls closure
1327  * @param cfg configuration to use
1328  * @param service the initialized service
1329  */
1330 static void
1331 run (void *cls,
1332      const struct GNUNET_CONFIGURATION_Handle *cfg,
1333      struct GNUNET_SERVICE_Handle *service)
1334 {
1335   unsigned long long dqs;
1336
1337   GSF_cfg = cfg;
1338   if (GNUNET_OK !=
1339       GNUNET_CONFIGURATION_get_value_size (GSF_cfg,
1340                                            "fs",
1341                                            "DATASTORE_QUEUE_SIZE",
1342                                            &dqs))
1343   {
1344     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
1345                                "fs",
1346                                "DATASTORE_QUEUE_SIZE");
1347     dqs = 32;
1348   }
1349   GSF_datastore_queue_size = (unsigned int) dqs;
1350   GSF_enable_randomized_delays =
1351     GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY");
1352   GSF_dsh = GNUNET_DATASTORE_connect (cfg);
1353   if (NULL == GSF_dsh)
1354   {
1355     GNUNET_SCHEDULER_shutdown ();
1356     return;
1357   }
1358   GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL);
1359   GSF_stats = GNUNET_STATISTICS_create ("fs", cfg);
1360   block_cfg = GNUNET_CONFIGURATION_create ();
1361   GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg);
1362   GNUNET_assert (NULL != GSF_block_ctx);
1363   GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE);
1364   GSF_plan_init ();
1365   GSF_pending_request_init_ ();
1366   GSF_connected_peer_init_ ();
1367   GSF_ats = GNUNET_ATS_performance_init (GSF_cfg,
1368                                          &update_latencies,
1369                                          NULL);
1370   GSF_push_init_ ();
1371   GSF_put_init_ ();
1372   if ((GNUNET_OK != GNUNET_FS_indexing_init (cfg,
1373                                              GSF_dsh)) ||
1374       (GNUNET_OK != main_init (cfg)))
1375   {
1376     GNUNET_SCHEDULER_shutdown ();
1377     shutdown_task (NULL);
1378     return;
1379   }
1380 }
1381
1382
1383 /**
1384  * Define "main" method using service macro.
1385  */
1386 GNUNET_SERVICE_MAIN
1387   ("fs",
1388   GNUNET_SERVICE_OPTION_NONE,
1389   &run,
1390   &client_connect_cb,
1391   &client_disconnect_cb,
1392   NULL,
1393   GNUNET_MQ_hd_var_size (client_index_start,
1394                          GNUNET_MESSAGE_TYPE_FS_INDEX_START,
1395                          struct IndexStartMessage,
1396                          NULL),
1397   GNUNET_MQ_hd_fixed_size (client_index_list_get,
1398                            GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
1399                            struct GNUNET_MessageHeader,
1400                            NULL),
1401   GNUNET_MQ_hd_fixed_size (client_unindex,
1402                            GNUNET_MESSAGE_TYPE_FS_UNINDEX,
1403                            struct UnindexMessage,
1404                            NULL),
1405   GNUNET_MQ_hd_var_size (client_start_search,
1406                          GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
1407                          struct SearchMessage,
1408                          NULL),
1409   GNUNET_MQ_hd_fixed_size (client_loc_sign,
1410                            GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
1411                            struct RequestLocSignatureMessage,
1412                            NULL),
1413   GNUNET_MQ_handler_end ());
1414
1415
1416 /* end of gnunet-service-fs.c */