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