first batch of license fixes (boring)
[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 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
16 /**
17  * @file fs/gnunet-service-fs.c
18  * @brief gnunet anonymity protocol implementation
19  * @author Christian Grothoff
20  */
21 #include "platform.h"
22 #include <float.h>
23 #include "gnunet_constants.h"
24 #include "gnunet_core_service.h"
25 #include "gnunet_dht_service.h"
26 #include "gnunet_datastore_service.h"
27 #include "gnunet_load_lib.h"
28 #include "gnunet_peer_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_signatures.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet-service-fs_cp.h"
35 #include "gnunet-service-fs_indexing.h"
36 #include "gnunet-service-fs_pe.h"
37 #include "gnunet-service-fs_pr.h"
38 #include "gnunet-service-fs_push.h"
39 #include "gnunet-service-fs_put.h"
40 #include "gnunet-service-fs_cadet.h"
41 #include "fs.h"
42 #include "fs_api.h"
43
44 /**
45  * Size for the hash map for DHT requests from the FS
46  * service.  Should be about the number of concurrent
47  * DHT requests we plan to make.
48  */
49 #define FS_DHT_HT_SIZE 1024
50
51
52 /**
53  * How quickly do we age cover traffic?  At the given
54  * time interval, remaining cover traffic counters are
55  * decremented by 1/16th.
56  */
57 #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
58
59 /**
60  * Collect an instane number of statistics?  May cause excessive IPC.
61  */
62 #define INSANE_STATISTICS GNUNET_NO
63
64
65
66 /**
67  * Doubly-linked list of requests we are performing
68  * on behalf of the same client.
69  */
70 struct ClientRequest
71 {
72
73   /**
74    * This is a doubly-linked list.
75    */
76   struct ClientRequest *next;
77
78   /**
79    * This is a doubly-linked list.
80    */
81   struct ClientRequest *prev;
82
83   /**
84    * Request this entry represents.
85    */
86   struct GSF_PendingRequest *pr;
87
88   /**
89    * Client list this request belongs to.
90    */
91   struct GSF_LocalClient *lc;
92
93   /**
94    * Task scheduled to destroy the request.
95    */
96   struct GNUNET_SCHEDULER_Task * kill_task;
97
98 };
99
100
101 /**
102  * Replies to be transmitted to the client.  The actual
103  * response message is allocated after this struct.
104  */
105 struct ClientResponse
106 {
107   /**
108    * This is a doubly-linked list.
109    */
110   struct ClientResponse *next;
111
112   /**
113    * This is a doubly-linked list.
114    */
115   struct ClientResponse *prev;
116
117   /**
118    * Client list entry this response belongs to.
119    */
120   struct GSF_LocalClient *lc;
121
122   /**
123    * Number of bytes in the response.
124    */
125   size_t msize;
126 };
127
128
129 /**
130  * Information we track while handling an index
131  * start request from a client.
132  */
133 struct IndexStartContext
134 {
135
136   /**
137    * This is a doubly linked list.
138    */
139   struct IndexStartContext *next;
140
141   /**
142    * This is a doubly linked list.
143    */
144   struct IndexStartContext *prev;
145
146   /**
147    * Name of the indexed file.
148    */
149   char *filename;
150
151   /**
152    * Context for transmitting confirmation to client.
153    */
154   struct GSF_LocalClient *lc;
155
156   /**
157    * Context for hashing of the file.
158    */
159   struct GNUNET_CRYPTO_FileHashContext *fhc;
160
161   /**
162    * Hash of the contents of the file.
163    */
164   struct GNUNET_HashCode file_id;
165
166 };
167
168
169 /**
170  * A local client.
171  */
172 struct GSF_LocalClient
173 {
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
220 /* ****************************** globals ****************************** */
221
222 /**
223  * Our connection to the datastore.
224  */
225 struct GNUNET_DATASTORE_Handle *GSF_dsh;
226
227 /**
228  * Our configuration.
229  */
230 const struct GNUNET_CONFIGURATION_Handle *GSF_cfg;
231
232 /**
233  * Handle for reporting statistics.
234  */
235 struct GNUNET_STATISTICS_Handle *GSF_stats;
236
237 /**
238  * Handle for DHT operations.
239  */
240 struct GNUNET_DHT_Handle *GSF_dht;
241
242 /**
243  * How long do requests typically stay in the routing table?
244  */
245 struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime;
246
247 /**
248  * Running average of the observed latency to other peers (round trip).
249  * Initialized to 5s as the initial default.
250  */
251 struct GNUNET_TIME_Relative GSF_avg_latency = { 500 };
252
253 /**
254  * Handle to ATS service.
255  */
256 struct GNUNET_ATS_PerformanceHandle *GSF_ats;
257
258
259 /**
260  * Typical priorities we're seeing from other peers right now.  Since
261  * most priorities will be zero, this value is the weighted average of
262  * non-zero priorities seen "recently".  In order to ensure that new
263  * values do not dramatically change the ratio, values are first
264  * "capped" to a reasonable range (+N of the current value) and then
265  * averaged into the existing value by a ratio of 1:N.  Hence
266  * receiving the largest possible priority can still only raise our
267  * "current_priorities" by at most 1.
268  */
269 double GSF_current_priorities;
270
271 /**
272  * Size of the datastore queue we assume for common requests.
273  */
274 unsigned int GSF_datastore_queue_size;
275
276 /**
277  * How many query messages have we received 'recently' that
278  * have not yet been claimed as cover traffic?
279  */
280 unsigned int GSF_cover_query_count;
281
282 /**
283  * How many content messages have we received 'recently' that
284  * have not yet been claimed as cover traffic?
285  */
286 unsigned int GSF_cover_content_count;
287
288 /**
289  * Our block context.
290  */
291 struct GNUNET_BLOCK_Context *GSF_block_ctx;
292
293 /**
294  * Pointer to handle to the core service (points to NULL until we've
295  * connected to it).
296  */
297 struct GNUNET_CORE_Handle *GSF_core;
298
299 /**
300  * Are we introducing randomized delays for better anonymity?
301  */
302 int GSF_enable_randomized_delays;
303
304 /**
305  * Identity of this peer.
306  */
307 struct GNUNET_PeerIdentity GSF_my_id;
308
309 /* ***************************** locals ******************************* */
310
311 /**
312  * Configuration for block library.
313  */
314 static struct GNUNET_CONFIGURATION_Handle *block_cfg;
315
316 /**
317  * Private key of this peer.  Used to sign LOC URI requests.
318  */
319 static struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
320
321 /**
322  * ID of our task that we use to age the cover counters.
323  */
324 static struct GNUNET_SCHEDULER_Task * cover_age_task;
325
326 /**
327  * Datastore 'GET' load tracking.
328  */
329 static struct GNUNET_LOAD_Value *datastore_get_load;
330
331
332 /**
333  * Creates a fresh local client handle.
334  *
335  * @param cls NULL
336  * @param client handle of the client
337  * @param mq message queue for @a client
338  * @return handle to local client entry
339  */
340 static void *
341 client_connect_cb (void *cls,
342                    struct GNUNET_SERVICE_Client *client,
343                    struct GNUNET_MQ_Handle *mq)
344 {
345   struct GSF_LocalClient *pos;
346
347   pos = GNUNET_new (struct GSF_LocalClient);
348   pos->client = client;
349   pos->mq = mq;
350   return pos;
351 }
352
353
354 /**
355  * Free the given client request.
356  *
357  * @param cls the client request to free
358  */
359 static void
360 client_request_destroy (void *cls)
361 {
362   struct ClientRequest *cr = cls;
363   struct GSF_LocalClient *lc = cr->lc;
364
365   cr->kill_task = NULL;
366   GNUNET_CONTAINER_DLL_remove (lc->cr_head,
367                                lc->cr_tail,
368                                cr);
369   GSF_pending_request_cancel_ (cr->pr,
370                                GNUNET_YES);
371   GNUNET_STATISTICS_update (GSF_stats,
372                             gettext_noop ("# client searches active"),
373                             -1,
374                             GNUNET_NO);
375   GNUNET_free (cr);
376 }
377
378
379 /**
380  * Handle a reply to a pending request.  Also called if a request
381  * expires (then with data == NULL).  The handler may be called
382  * many times (depending on the request type), but will not be
383  * called during or after a call to #GSF_pending_request_cancel()
384  * and will also not be called anymore after a call signalling
385  * expiration.
386  *
387  * @param cls user-specified closure
388  * @param eval evaluation of the result
389  * @param pr handle to the original pending request
390  * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
391  * @param expiration when does @a data expire?
392  * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
393  * @param type type of the block
394  * @param data response data, NULL on request expiration
395  * @param data_len number of bytes in @a data
396  */
397 static void
398 client_response_handler (void *cls,
399                          enum GNUNET_BLOCK_EvaluationResult eval,
400                          struct GSF_PendingRequest *pr,
401                          uint32_t reply_anonymity_level,
402                          struct GNUNET_TIME_Absolute expiration,
403                          struct GNUNET_TIME_Absolute last_transmission,
404                          enum GNUNET_BLOCK_Type type,
405                          const void *data,
406                          size_t data_len)
407 {
408   struct ClientRequest *cr = cls;
409   struct GSF_LocalClient *lc;
410   struct GNUNET_MQ_Envelope *env;
411   struct ClientPutMessage *pm;
412   const struct GSF_PendingRequestData *prd;
413
414   if (NULL == data)
415   {
416     /* local-only request, with no result, clean up. */
417     if (NULL == cr->kill_task)
418       cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
419                                                 cr);
420     return;
421   }
422   prd = GSF_pending_request_get_data_ (pr);
423   GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
424   if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
425   {
426     GNUNET_break (0);
427     return;
428   }
429   GNUNET_STATISTICS_update (GSF_stats,
430                             gettext_noop
431                             ("# replies received for local clients"), 1,
432                             GNUNET_NO);
433   GNUNET_assert (pr == cr->pr);
434   lc = cr->lc;
435   env = GNUNET_MQ_msg_extra (pm,
436                              data_len,
437                              GNUNET_MESSAGE_TYPE_FS_PUT);
438   pm->type = htonl (type);
439   pm->expiration = GNUNET_TIME_absolute_hton (expiration);
440   pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
441   pm->num_transmissions = htonl (prd->num_transmissions);
442   pm->respect_offered = htonl (prd->respect_offered);
443   GNUNET_memcpy (&pm[1],
444                  data,
445                  data_len);
446   GNUNET_MQ_send (lc->mq,
447                   env);
448   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449               "Queued reply to query `%s' for local client\n",
450               GNUNET_h2s (&prd->query));
451   if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
452   {
453     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454                 "Evaluation %d - keeping query alive\n",
455                 (int) eval);
456     return;
457   }
458   if (NULL == cr->kill_task)
459     cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
460                                               cr);
461 }
462
463
464 /**
465  * A client disconnected from us.  Tear down the local client
466  * record.
467  *
468  * @param cls unused
469  * @param client handle of the client
470  * @param app_ctx the `struct GSF_LocalClient`
471  */
472 static void
473 client_disconnect_cb (void *cls,
474                       struct GNUNET_SERVICE_Client *client,
475                       void *app_ctx)
476 {
477   struct GSF_LocalClient *lc = app_ctx;
478   struct IndexStartContext *isc;
479   struct ClientRequest *cr;
480   struct ClientResponse *res;
481
482   while (NULL != (cr = lc->cr_head))
483   {
484     if (NULL != cr->kill_task)
485       GNUNET_SCHEDULER_cancel (cr->kill_task);
486     client_request_destroy (cr);
487   }
488   while (NULL != (res = lc->res_head))
489   {
490     GNUNET_CONTAINER_DLL_remove (lc->res_head,
491                                  lc->res_tail,
492                                  res);
493     GNUNET_free (res);
494   }
495   while (NULL != (isc = lc->isc_head))
496   {
497     GNUNET_CONTAINER_DLL_remove (lc->isc_head,
498                                  lc->isc_tail,
499                                  isc);
500     GNUNET_CRYPTO_hash_file_cancel (isc->fhc);
501     GNUNET_free (isc);
502   }
503   GNUNET_free (lc);
504 }
505
506
507
508
509
510 /**
511  * Task that periodically ages our cover traffic statistics.
512  *
513  * @param cls unused closure
514  */
515 static void
516 age_cover_counters (void *cls)
517 {
518   GSF_cover_content_count = (GSF_cover_content_count * 15) / 16;
519   GSF_cover_query_count = (GSF_cover_query_count * 15) / 16;
520   cover_age_task =
521       GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
522                                     &age_cover_counters,
523                                     NULL);
524 }
525
526
527 /**
528  * We've just now completed a datastore request.  Update our
529  * datastore load calculations.
530  *
531  * @param start time when the datastore request was issued
532  */
533 void
534 GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start)
535 {
536   struct GNUNET_TIME_Relative delay;
537
538   delay = GNUNET_TIME_absolute_get_duration (start);
539   GNUNET_LOAD_update (datastore_get_load, delay.rel_value_us);
540 }
541
542
543 /**
544  * Test if the DATABASE (GET) load on this peer is too high
545  * to even consider processing the query at
546  * all.
547  *
548  * @param priority priority of the request (used as a reference point to compare with the load)
549  * @return #GNUNET_YES if the load is too high to do anything (load high)
550  *         #GNUNET_NO to process normally (load normal)
551  *         #GNUNET_SYSERR to process for free (load low)
552  */
553 int
554 GSF_test_get_load_too_high_ (uint32_t priority)
555 {
556   double ld;
557
558   ld = GNUNET_LOAD_get_load (datastore_get_load);
559   if (ld < 1)
560     return GNUNET_SYSERR;
561   if (ld <= priority)
562     return GNUNET_NO;
563   return GNUNET_YES;
564 }
565
566
567 /**
568  * We've received peer performance information. Update
569  * our running average for the P2P latency.
570  *
571  * @param cls closure
572  * @param address the address
573  * @param active is this address in active use
574  * @param bandwidth_out assigned outbound bandwidth for the connection
575  * @param bandwidth_in assigned inbound bandwidth for the connection
576  * @param prop performance data for the address (as far as known)
577  */
578 static void
579 update_latencies (void *cls,
580                   const struct GNUNET_HELLO_Address *address,
581                   int active,
582                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
583                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
584                   const struct GNUNET_ATS_Properties *prop)
585 {
586   if (NULL == address)
587   {
588     /* ATS service temporarily disconnected */
589     return;
590   }
591
592   if (GNUNET_YES != active)
593     return;
594   GSF_update_peer_latency_ (&address->peer,
595                             prop->delay);
596   GSF_avg_latency.rel_value_us =
597     (GSF_avg_latency.rel_value_us * 31 +
598      GNUNET_MIN (5000, prop->delay.rel_value_us)) / 32;
599   GNUNET_STATISTICS_set (GSF_stats,
600                          gettext_noop ("# running average P2P latency (ms)"),
601                          GSF_avg_latency.rel_value_us / 1000LL,
602                          GNUNET_NO);
603 }
604
605
606 /**
607  * Check P2P "PUT" message.
608  *
609  * @param cls closure with the `struct GSF_ConnectedPeer`
610  * @param message the actual message
611  * @return #GNUNET_OK to keep the connection open,
612  *         #GNUNET_SYSERR to close it (signal serious error)
613  */
614 static int
615 check_p2p_put (void *cls,
616                const struct PutMessage *put)
617 {
618   enum GNUNET_BLOCK_Type type;
619
620   type = ntohl (put->type);
621   if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
622   {
623     GNUNET_break_op (0);
624     return GNUNET_SYSERR;
625   }
626   return GNUNET_OK;
627 }
628
629
630 /**
631  * We have a new request, consider forwarding it to the given
632  * peer.
633  *
634  * @param cls the `struct GSF_PendingRequest`
635  * @param peer identity of the peer
636  * @param cp handle to the connected peer record
637  * @param ppd peer performance data
638  */
639 static void
640 consider_request_for_forwarding (void *cls,
641                                  const struct GNUNET_PeerIdentity *peer,
642                                  struct GSF_ConnectedPeer *cp,
643                                  const struct GSF_PeerPerformanceData *ppd)
644 {
645   struct GSF_PendingRequest *pr = cls;
646
647   if (GNUNET_YES !=
648       GSF_pending_request_test_target_ (pr, peer))
649   {
650 #if INSANE_STATISTICS
651     GNUNET_STATISTICS_update (GSF_stats,
652                               gettext_noop ("# Loopback routes suppressed"), 1,
653                               GNUNET_NO);
654 #endif
655     return;
656   }
657   GSF_plan_add_ (cp,
658                  pr);
659 }
660
661
662 /**
663  * Function to be called after we're done processing
664  * replies from the local lookup.  If the result status
665  * code indicates that there may be more replies, plan
666  * forwarding the request.
667  *
668  * @param cls closure (NULL)
669  * @param pr the pending request we were processing
670  * @param result final datastore lookup result
671  */
672 void
673 GSF_consider_forwarding (void *cls,
674                          struct GSF_PendingRequest *pr,
675                          enum GNUNET_BLOCK_EvaluationResult result)
676 {
677   if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
678     return;                     /* we're done... */
679   if (GNUNET_YES !=
680       GSF_pending_request_test_active_ (pr))
681     return; /* request is not actually active, skip! */
682   GSF_iterate_connected_peers_ (&consider_request_for_forwarding,
683                                 pr);
684 }
685
686
687 /**
688  * Check P2P "GET" request.
689  *
690  * @param cls closure
691  * @param gm the actual message
692  * @return #GNUNET_OK to keep the connection open,
693  *         #GNUNET_SYSERR to close it (signal serious error)
694  */
695 static int
696 check_p2p_get (void *cls,
697                const struct GetMessage *gm)
698 {
699   size_t msize;
700   unsigned int bm;
701   unsigned int bits;
702   size_t bfsize;
703
704   msize = ntohs (gm->header.size);
705   bm = ntohl (gm->hash_bitmap);
706   bits = 0;
707   while (bm > 0)
708   {
709     if (1 == (bm & 1))
710       bits++;
711     bm >>= 1;
712   }
713   if (msize < sizeof (struct GetMessage) + bits * sizeof (struct GNUNET_PeerIdentity))
714   {
715     GNUNET_break_op (0);
716     return GNUNET_SYSERR;
717   }
718   bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (struct GNUNET_PeerIdentity);
719   /* bfsize must be power of 2, check! */
720   if (0 != ((bfsize - 1) & bfsize))
721   {
722     GNUNET_break_op (0);
723     return GNUNET_SYSERR;
724   }
725   return GNUNET_OK;
726 }
727
728
729 /**
730  * We're done with the local lookup, now consider
731  * P2P processing (depending on request options and
732  * result status).  Also signal that we can now
733  * receive more request information from the client.
734  *
735  * @param cls the client doing the request (`struct GSF_LocalClient`)
736  * @param pr the pending request we were processing
737  * @param result final datastore lookup result
738  */
739 static void
740 start_p2p_processing (void *cls,
741                       struct GSF_PendingRequest *pr,
742                       enum GNUNET_BLOCK_EvaluationResult result)
743 {
744   struct GSF_LocalClient *lc = cls;
745   struct GSF_PendingRequestData *prd;
746
747   GNUNET_SERVICE_client_continue (lc->client);
748   if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
749     return;                     /* we're done, 'pr' was already destroyed... */
750   prd = GSF_pending_request_get_data_ (pr);
751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
752               "Finished database lookup for local request `%s' with result %d\n",
753               GNUNET_h2s (&prd->query),
754               result);
755   if (0 == prd->anonymity_level)
756   {
757     switch (prd->type)
758     {
759     case GNUNET_BLOCK_TYPE_FS_DBLOCK:
760     case GNUNET_BLOCK_TYPE_FS_IBLOCK:
761       /* the above block types MAY be available via 'cadet' */
762       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763                   "Considering cadet-based download for block\n");
764       GSF_cadet_lookup_ (pr);
765       break;
766     case GNUNET_BLOCK_TYPE_FS_UBLOCK:
767       /* the above block types are in the DHT */
768       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769                   "Considering DHT-based search for block\n");
770       GSF_dht_lookup_ (pr);
771       break;
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 ("# client searches updated (merged content seen list)"),
871                               1,
872                               GNUNET_NO);
873   }
874   else
875   {
876     GNUNET_STATISTICS_update (GSF_stats,
877                               gettext_noop ("# client searches active"),
878                               1,
879                               GNUNET_NO);
880     cr = GNUNET_new (struct ClientRequest);
881     cr->lc = lc;
882     GNUNET_CONTAINER_DLL_insert (lc->cr_head,
883                                  lc->cr_tail,
884                                  cr);
885     options = GSF_PRO_LOCAL_REQUEST;
886     if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options)))
887       options |= GSF_PRO_LOCAL_ONLY;
888     cr->pr = GSF_pending_request_create_ (options, type,
889                                           &sm->query,
890                                           (0 !=
891                                            memcmp (&sm->target,
892                                                    &all_zeros,
893                                                    sizeof (struct GNUNET_PeerIdentity)))
894                                           ? &sm->target : NULL, NULL, 0,
895                                           0 /* bf */ ,
896                                           ntohl (sm->anonymity_level),
897                                           0 /* priority */ ,
898                                           0 /* ttl */ ,
899                                           0 /* sender PID */ ,
900                                           0 /* origin PID */ ,
901                                           (const struct GNUNET_HashCode *) &sm[1], sc,
902                                           &client_response_handler,
903                                           cr);
904   }
905   if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options)))
906   {
907     GNUNET_SERVICE_client_continue (lc->client);
908     return;
909   }
910   GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES;
911   GSF_local_lookup_ (cr->pr,
912                      &start_p2p_processing,
913                      lc);
914 }
915
916
917 /**
918  * Handle request to sign a LOC URI (from client).
919  *
920  * @param cls identification of the client
921  * @param msg the actual message
922  */
923 static void
924 handle_client_loc_sign (void *cls,
925                         const struct RequestLocSignatureMessage *msg)
926 {
927   struct GSF_LocalClient *lc = cls;
928   struct GNUNET_FS_Uri base;
929   struct GNUNET_FS_Uri *loc;
930   struct GNUNET_MQ_Envelope *env;
931   struct ResponseLocSignatureMessage *resp;
932
933   GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
934                 ntohl (msg->purpose));
935   base.type = GNUNET_FS_URI_CHK;
936   base.data.chk.chk = msg->chk;
937   base.data.chk.file_length = GNUNET_ntohll (msg->file_length);
938   loc = GNUNET_FS_uri_loc_create (&base,
939                                   pk,
940                                   GNUNET_TIME_absolute_ntoh (msg->expiration_time));
941   env = GNUNET_MQ_msg (resp,
942                        GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
943   resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
944   resp->expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime);
945   resp->signature = loc->data.loc.contentSignature;
946   resp->peer = loc->data.loc.peer;
947   GNUNET_FS_uri_destroy (loc);
948   GNUNET_MQ_send (lc->mq,
949                   env);
950   GNUNET_SERVICE_client_continue (lc->client);
951 }
952
953
954 /**
955  * Check INDEX_START-message.
956  *
957  * @param cls identification of the client
958  * @param ism the actual message
959  * @return #GNUNET_OK if @a ism is well-formed
960  */
961 static int
962 check_client_index_start (void *cls,
963                           const struct IndexStartMessage *ism)
964 {
965   uint16_t msize;
966   char *fn;
967
968   msize = ntohs (ism->header.size);
969   if (((const char *) ism)[msize - 1] != '\0')
970   {
971     GNUNET_break (0);
972     return GNUNET_SYSERR;
973   }
974   if (0 != ism->reserved)
975   {
976     GNUNET_break (0);
977     return GNUNET_SYSERR;
978   }
979   fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
980   if (NULL == fn)
981   {
982     GNUNET_break (0);
983     return GNUNET_SYSERR;
984   }
985   GNUNET_free (fn);
986   return GNUNET_OK;
987 }
988
989
990 /**
991  * We've validated the hash of the file we're about to index.  Signal
992  * success to the client and update our internal data structures.
993  *
994  * @param isc the data about the index info entry for the request
995  */
996 static void
997 signal_index_ok (struct IndexStartContext *isc)
998 {
999   struct GSF_LocalClient *lc = isc->lc;
1000   struct GNUNET_MQ_Envelope *env;
1001   struct GNUNET_MessageHeader *msg;
1002
1003   GNUNET_FS_add_to_index (isc->filename,
1004                           &isc->file_id);
1005   env = GNUNET_MQ_msg (msg,
1006                        GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
1007   GNUNET_MQ_send (lc->mq,
1008                   env);
1009   GNUNET_free (isc->filename);
1010   GNUNET_free (isc);
1011   GNUNET_SERVICE_client_continue (lc->client);
1012 }
1013
1014
1015 /**
1016  * Function called once the hash computation over an
1017  * indexed file has completed.
1018  *
1019  * @param cls closure, our publishing context
1020  * @param res resulting hash, NULL on error
1021  */
1022 static void
1023 hash_for_index_val (void *cls,
1024                     const struct GNUNET_HashCode *res)
1025 {
1026   struct IndexStartContext *isc = cls;
1027   struct GSF_LocalClient *lc = isc->lc;
1028   struct GNUNET_MQ_Envelope *env;
1029   struct GNUNET_MessageHeader *msg;
1030
1031   GNUNET_CONTAINER_DLL_remove (lc->isc_head,
1032                                lc->isc_tail,
1033                                isc);
1034   isc->fhc = NULL;
1035   if ( (NULL == res) ||
1036        (0 != memcmp (res,
1037                      &isc->file_id,
1038                      sizeof (struct GNUNET_HashCode))))
1039   {
1040     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
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_CRYPTO_cmp_peer_identity (&GSF_my_id,
1229                                             my_identity))
1230   {
1231     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1232                 "Peer identity missmatch, 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                 _("FS service is lacking HOSTKEY configuration setting.  Exiting.\n"));
1282     GNUNET_SCHEDULER_shutdown ();
1283     return GNUNET_SYSERR;
1284   }
1285   pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
1286   GNUNET_free (keyfile);
1287   GNUNET_assert (NULL != pk);
1288   GNUNET_CRYPTO_eddsa_key_get_public (pk,
1289                                       &GSF_my_id.public_key);
1290
1291   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1292               "I am peer %s\n",
1293               GNUNET_i2s (&GSF_my_id));
1294   GSF_core
1295     = GNUNET_CORE_connect (GSF_cfg,
1296                            NULL,
1297                            &peer_init_handler,
1298                            &GSF_peer_connect_handler,
1299                            &GSF_peer_disconnect_handler,
1300                            (GNUNET_YES == anon_p2p_off)
1301                            ? no_p2p_handlers
1302                            : p2p_handlers);
1303   if (NULL == GSF_core)
1304   {
1305     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1306                 _("Failed to connect to `%s' service.\n"),
1307                 "core");
1308     return GNUNET_SYSERR;
1309   }
1310   cover_age_task =
1311       GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
1312                                     &age_cover_counters,
1313                                     NULL);
1314   datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE);
1315   GSF_cadet_start_server ();
1316   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1317                                  NULL);
1318   return GNUNET_OK;
1319 }
1320
1321
1322 /**
1323  * Process fs requests.
1324  *
1325  * @param cls closure
1326  * @param cfg configuration to use
1327  * @param service the initialized service
1328  */
1329 static void
1330 run (void *cls,
1331      const struct GNUNET_CONFIGURATION_Handle *cfg,
1332      struct GNUNET_SERVICE_Handle *service)
1333 {
1334   unsigned long long dqs;
1335
1336   GSF_cfg = cfg;
1337   if (GNUNET_OK !=
1338       GNUNET_CONFIGURATION_get_value_size (GSF_cfg,
1339                                            "fs",
1340                                            "DATASTORE_QUEUE_SIZE",
1341                                            &dqs))
1342   {
1343     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
1344                                "fs",
1345                                "DATASTORE_QUEUE_SIZE");
1346     dqs = 32;
1347   }
1348   GSF_datastore_queue_size = (unsigned int) dqs;
1349   GSF_enable_randomized_delays =
1350       GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY");
1351   GSF_dsh = GNUNET_DATASTORE_connect (cfg);
1352   if (NULL == GSF_dsh)
1353   {
1354     GNUNET_SCHEDULER_shutdown ();
1355     return;
1356   }
1357   GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL);
1358   GSF_stats = GNUNET_STATISTICS_create ("fs", cfg);
1359   block_cfg = GNUNET_CONFIGURATION_create ();
1360   GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg);
1361   GNUNET_assert (NULL != GSF_block_ctx);
1362   GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE);
1363   GSF_plan_init ();
1364   GSF_pending_request_init_ ();
1365   GSF_connected_peer_init_ ();
1366   GSF_ats = GNUNET_ATS_performance_init (GSF_cfg,
1367                                          &update_latencies,
1368                                          NULL);
1369   GSF_push_init_ ();
1370   GSF_put_init_ ();
1371   if ( (GNUNET_OK != GNUNET_FS_indexing_init (cfg,
1372                                               GSF_dsh)) ||
1373        (GNUNET_OK != main_init (cfg)) )
1374   {
1375     GNUNET_SCHEDULER_shutdown ();
1376     shutdown_task (NULL);
1377     return;
1378   }
1379 }
1380
1381
1382 /**
1383  * Define "main" method using service macro.
1384  */
1385 GNUNET_SERVICE_MAIN
1386 ("fs",
1387  GNUNET_SERVICE_OPTION_NONE,
1388  &run,
1389  &client_connect_cb,
1390  &client_disconnect_cb,
1391  NULL,
1392  GNUNET_MQ_hd_var_size (client_index_start,
1393                         GNUNET_MESSAGE_TYPE_FS_INDEX_START,
1394                         struct IndexStartMessage,
1395                         NULL),
1396  GNUNET_MQ_hd_fixed_size (client_index_list_get,
1397                           GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
1398                           struct GNUNET_MessageHeader,
1399                           NULL),
1400  GNUNET_MQ_hd_fixed_size (client_unindex,
1401                           GNUNET_MESSAGE_TYPE_FS_UNINDEX,
1402                           struct UnindexMessage,
1403                           NULL),
1404  GNUNET_MQ_hd_var_size (client_start_search,
1405                         GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
1406                         struct SearchMessage,
1407                         NULL),
1408  GNUNET_MQ_hd_fixed_size (client_loc_sign,
1409                           GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
1410                           struct RequestLocSignatureMessage,
1411                           NULL),
1412  GNUNET_MQ_handler_end ());
1413
1414
1415 /* end of gnunet-service-fs.c */