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