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