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