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