2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file fs/gnunet-service-fs.c
23 * @brief gnunet anonymity protocol implementation
24 * @author Christian Grothoff
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"
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.
54 #define FS_DHT_HT_SIZE 1024
58 * How quickly do we age cover traffic? At the given
59 * time interval, remaining cover traffic counters are
60 * decremented by 1/16th.
62 #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
65 * Collect an instane number of statistics? May cause excessive IPC.
67 #define INSANE_STATISTICS GNUNET_NO
72 * Doubly-linked list of requests we are performing
73 * on behalf of the same client.
75 struct ClientRequest {
77 * This is a doubly-linked list.
79 struct ClientRequest *next;
82 * This is a doubly-linked list.
84 struct ClientRequest *prev;
87 * Request this entry represents.
89 struct GSF_PendingRequest *pr;
92 * Client list this request belongs to.
94 struct GSF_LocalClient *lc;
97 * Task scheduled to destroy the request.
99 struct GNUNET_SCHEDULER_Task * kill_task;
104 * Replies to be transmitted to the client. The actual
105 * response message is allocated after this struct.
107 struct ClientResponse {
109 * This is a doubly-linked list.
111 struct ClientResponse *next;
114 * This is a doubly-linked list.
116 struct ClientResponse *prev;
119 * Client list entry this response belongs to.
121 struct GSF_LocalClient *lc;
124 * Number of bytes in the response.
131 * Information we track while handling an index
132 * start request from a client.
134 struct IndexStartContext {
136 * This is a doubly linked list.
138 struct IndexStartContext *next;
141 * This is a doubly linked list.
143 struct IndexStartContext *prev;
146 * Name of the indexed file.
151 * Context for transmitting confirmation to client.
153 struct GSF_LocalClient *lc;
156 * Context for hashing of the file.
158 struct GNUNET_CRYPTO_FileHashContext *fhc;
161 * Hash of the contents of the file.
163 struct GNUNET_HashCode file_id;
170 struct GSF_LocalClient {
174 struct GNUNET_SERVICE_Client *client;
177 * Queue for sending replies.
179 struct GNUNET_MQ_Handle *mq;
182 * Head of list of requests performed on behalf
183 * of this client right now.
185 struct ClientRequest *cr_head;
188 * Tail of list of requests performed on behalf
189 * of this client right now.
191 struct ClientRequest *cr_tail;
194 * This is a doubly linked list.
196 struct IndexStartContext *isc_head;
199 * This is a doubly linked list.
201 struct IndexStartContext *isc_tail;
204 * Head of linked list of responses.
206 struct ClientResponse *res_head;
209 * Tail of linked list of responses.
211 struct ClientResponse *res_tail;
215 /* ****************************** globals ****************************** */
218 * Our connection to the datastore.
220 struct GNUNET_DATASTORE_Handle *GSF_dsh;
225 const struct GNUNET_CONFIGURATION_Handle *GSF_cfg;
228 * Handle for reporting statistics.
230 struct GNUNET_STATISTICS_Handle *GSF_stats;
233 * Handle for DHT operations.
235 struct GNUNET_DHT_Handle *GSF_dht;
238 * How long do requests typically stay in the routing table?
240 struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime;
243 * Running average of the observed latency to other peers (round trip).
244 * Initialized to 5s as the initial default.
246 struct GNUNET_TIME_Relative GSF_avg_latency = { 500 };
249 * Handle to ATS service.
251 struct GNUNET_ATS_PerformanceHandle *GSF_ats;
255 * Typical priorities we're seeing from other peers right now. Since
256 * most priorities will be zero, this value is the weighted average of
257 * non-zero priorities seen "recently". In order to ensure that new
258 * values do not dramatically change the ratio, values are first
259 * "capped" to a reasonable range (+N of the current value) and then
260 * averaged into the existing value by a ratio of 1:N. Hence
261 * receiving the largest possible priority can still only raise our
262 * "current_priorities" by at most 1.
264 double GSF_current_priorities;
267 * Size of the datastore queue we assume for common requests.
269 unsigned int GSF_datastore_queue_size;
272 * How many query messages have we received 'recently' that
273 * have not yet been claimed as cover traffic?
275 unsigned int GSF_cover_query_count;
278 * How many content messages have we received 'recently' that
279 * have not yet been claimed as cover traffic?
281 unsigned int GSF_cover_content_count;
286 struct GNUNET_BLOCK_Context *GSF_block_ctx;
289 * Pointer to handle to the core service (points to NULL until we've
292 struct GNUNET_CORE_Handle *GSF_core;
295 * Are we introducing randomized delays for better anonymity?
297 int GSF_enable_randomized_delays;
300 * Identity of this peer.
302 struct GNUNET_PeerIdentity GSF_my_id;
304 /* ***************************** locals ******************************* */
307 * Configuration for block library.
309 static struct GNUNET_CONFIGURATION_Handle *block_cfg;
312 * Private key of this peer. Used to sign LOC URI requests.
314 static struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
317 * ID of our task that we use to age the cover counters.
319 static struct GNUNET_SCHEDULER_Task * cover_age_task;
322 * Datastore 'GET' load tracking.
324 static struct GNUNET_LOAD_Value *datastore_get_load;
328 * Creates a fresh local client handle.
331 * @param client handle of the client
332 * @param mq message queue for @a client
333 * @return handle to local client entry
336 client_connect_cb(void *cls,
337 struct GNUNET_SERVICE_Client *client,
338 struct GNUNET_MQ_Handle *mq)
340 struct GSF_LocalClient *pos;
342 pos = GNUNET_new(struct GSF_LocalClient);
343 pos->client = client;
350 * Free the given client request.
352 * @param cls the client request to free
355 client_request_destroy(void *cls)
357 struct ClientRequest *cr = cls;
358 struct GSF_LocalClient *lc = cr->lc;
360 cr->kill_task = NULL;
361 GNUNET_CONTAINER_DLL_remove(lc->cr_head,
364 GSF_pending_request_cancel_(cr->pr,
366 GNUNET_STATISTICS_update(GSF_stats,
367 gettext_noop("# client searches active"),
375 * Handle a reply to a pending request. Also called if a request
376 * expires (then with data == NULL). The handler may be called
377 * many times (depending on the request type), but will not be
378 * called during or after a call to #GSF_pending_request_cancel()
379 * and will also not be called anymore after a call signalling
382 * @param cls user-specified closure
383 * @param eval evaluation of the result
384 * @param pr handle to the original pending request
385 * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
386 * @param expiration when does @a data expire?
387 * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
388 * @param type type of the block
389 * @param data response data, NULL on request expiration
390 * @param data_len number of bytes in @a data
393 client_response_handler(void *cls,
394 enum GNUNET_BLOCK_EvaluationResult eval,
395 struct GSF_PendingRequest *pr,
396 uint32_t reply_anonymity_level,
397 struct GNUNET_TIME_Absolute expiration,
398 struct GNUNET_TIME_Absolute last_transmission,
399 enum GNUNET_BLOCK_Type type,
403 struct ClientRequest *cr = cls;
404 struct GSF_LocalClient *lc;
405 struct GNUNET_MQ_Envelope *env;
406 struct ClientPutMessage *pm;
407 const struct GSF_PendingRequestData *prd;
411 /* local-only request, with no result, clean up. */
412 if (NULL == cr->kill_task)
413 cr->kill_task = GNUNET_SCHEDULER_add_now(&client_request_destroy,
417 prd = GSF_pending_request_get_data_(pr);
418 GNUNET_break(type != GNUNET_BLOCK_TYPE_ANY);
419 if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
424 GNUNET_STATISTICS_update(GSF_stats,
426 ("# replies received for local clients"), 1,
428 GNUNET_assert(pr == cr->pr);
430 env = GNUNET_MQ_msg_extra(pm,
432 GNUNET_MESSAGE_TYPE_FS_PUT);
433 pm->type = htonl(type);
434 pm->expiration = GNUNET_TIME_absolute_hton(expiration);
435 pm->last_transmission = GNUNET_TIME_absolute_hton(last_transmission);
436 pm->num_transmissions = htonl(prd->num_transmissions);
437 pm->respect_offered = htonl(prd->respect_offered);
438 GNUNET_memcpy(&pm[1],
441 GNUNET_MQ_send(lc->mq,
443 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
444 "Queued reply to query `%s' for local client\n",
445 GNUNET_h2s(&prd->query));
446 if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
448 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
449 "Evaluation %d - keeping query alive\n",
453 if (NULL == cr->kill_task)
454 cr->kill_task = GNUNET_SCHEDULER_add_now(&client_request_destroy,
460 * A client disconnected from us. Tear down the local client
464 * @param client handle of the client
465 * @param app_ctx the `struct GSF_LocalClient`
468 client_disconnect_cb(void *cls,
469 struct GNUNET_SERVICE_Client *client,
472 struct GSF_LocalClient *lc = app_ctx;
473 struct IndexStartContext *isc;
474 struct ClientRequest *cr;
475 struct ClientResponse *res;
477 while (NULL != (cr = lc->cr_head))
479 if (NULL != cr->kill_task)
480 GNUNET_SCHEDULER_cancel(cr->kill_task);
481 client_request_destroy(cr);
483 while (NULL != (res = lc->res_head))
485 GNUNET_CONTAINER_DLL_remove(lc->res_head,
490 while (NULL != (isc = lc->isc_head))
492 GNUNET_CONTAINER_DLL_remove(lc->isc_head,
495 GNUNET_CRYPTO_hash_file_cancel(isc->fhc);
506 * Task that periodically ages our cover traffic statistics.
508 * @param cls unused closure
511 age_cover_counters(void *cls)
513 GSF_cover_content_count = (GSF_cover_content_count * 15) / 16;
514 GSF_cover_query_count = (GSF_cover_query_count * 15) / 16;
516 GNUNET_SCHEDULER_add_delayed(COVER_AGE_FREQUENCY,
523 * We've just now completed a datastore request. Update our
524 * datastore load calculations.
526 * @param start time when the datastore request was issued
529 GSF_update_datastore_delay_(struct GNUNET_TIME_Absolute start)
531 struct GNUNET_TIME_Relative delay;
533 delay = GNUNET_TIME_absolute_get_duration(start);
534 GNUNET_LOAD_update(datastore_get_load, delay.rel_value_us);
539 * Test if the DATABASE (GET) load on this peer is too high
540 * to even consider processing the query at
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)
549 GSF_test_get_load_too_high_(uint32_t priority)
553 ld = GNUNET_LOAD_get_load(datastore_get_load);
555 return GNUNET_SYSERR;
563 * We've received peer performance information. Update
564 * our running average for the P2P latency.
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)
574 update_latencies(void *cls,
575 const struct GNUNET_HELLO_Address *address,
577 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
578 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
579 const struct GNUNET_ATS_Properties *prop)
583 /* ATS service temporarily disconnected */
587 if (GNUNET_YES != active)
589 GSF_update_peer_latency_(&address->peer,
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,
602 * Check P2P "PUT" message.
604 * @param cls closure with the `struct GSF_ConnectedPeer`
605 * @param message the actual message
606 * @return #GNUNET_OK to keep the connection open,
607 * #GNUNET_SYSERR to close it (signal serious error)
610 check_p2p_put(void *cls,
611 const struct PutMessage *put)
613 enum GNUNET_BLOCK_Type type;
615 type = ntohl(put->type);
616 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
619 return GNUNET_SYSERR;
626 * We have a new request, consider forwarding it to the given
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
635 consider_request_for_forwarding(void *cls,
636 const struct GNUNET_PeerIdentity *peer,
637 struct GSF_ConnectedPeer *cp,
638 const struct GSF_PeerPerformanceData *ppd)
640 struct GSF_PendingRequest *pr = cls;
643 GSF_pending_request_test_target_(pr, peer))
645 #if INSANE_STATISTICS
646 GNUNET_STATISTICS_update(GSF_stats,
647 gettext_noop("# Loopback routes suppressed"), 1,
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.
663 * @param cls closure (NULL)
664 * @param pr the pending request we were processing
665 * @param result final datastore lookup result
668 GSF_consider_forwarding(void *cls,
669 struct GSF_PendingRequest *pr,
670 enum GNUNET_BLOCK_EvaluationResult result)
672 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
673 return; /* we're done... */
675 GSF_pending_request_test_active_(pr))
676 return; /* request is not actually active, skip! */
677 GSF_iterate_connected_peers_(&consider_request_for_forwarding,
683 * Check P2P "GET" request.
686 * @param gm the actual message
687 * @return #GNUNET_OK to keep the connection open,
688 * #GNUNET_SYSERR to close it (signal serious error)
691 check_p2p_get(void *cls,
692 const struct GetMessage *gm)
699 msize = ntohs(gm->header.size);
700 bm = ntohl(gm->hash_bitmap);
708 if (msize < sizeof(struct GetMessage) + bits * sizeof(struct GNUNET_PeerIdentity))
711 return GNUNET_SYSERR;
713 bfsize = msize - sizeof(struct GetMessage) - bits * sizeof(struct GNUNET_PeerIdentity);
714 /* bfsize must be power of 2, check! */
715 if (0 != ((bfsize - 1) & bfsize))
718 return GNUNET_SYSERR;
725 * We're done with the local lookup, now consider
726 * P2P processing (depending on request options and
727 * result status). Also signal that we can now
728 * receive more request information from the client.
730 * @param cls the client doing the request (`struct GSF_LocalClient`)
731 * @param pr the pending request we were processing
732 * @param result final datastore lookup result
735 start_p2p_processing(void *cls,
736 struct GSF_PendingRequest *pr,
737 enum GNUNET_BLOCK_EvaluationResult result)
739 struct GSF_LocalClient *lc = cls;
740 struct GSF_PendingRequestData *prd;
742 GNUNET_SERVICE_client_continue(lc->client);
743 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
744 return; /* we're done, 'pr' was already destroyed... */
745 prd = GSF_pending_request_get_data_(pr);
746 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
747 "Finished database lookup for local request `%s' with result %d\n",
748 GNUNET_h2s(&prd->query),
750 if (0 == prd->anonymity_level)
754 case GNUNET_BLOCK_TYPE_FS_DBLOCK:
755 case GNUNET_BLOCK_TYPE_FS_IBLOCK:
756 /* the above block types MAY be available via 'cadet' */
757 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
758 "Considering cadet-based download for block\n");
759 GSF_cadet_lookup_(pr);
762 case GNUNET_BLOCK_TYPE_FS_UBLOCK:
763 /* the above block types are in the DHT */
764 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
765 "Considering DHT-based search for block\n");
774 GSF_consider_forwarding(NULL,
781 * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
784 * @param cls identification of the client
785 * @param sm the actual message
786 * @return #GNUNET_OK if @a sm is well-formed
789 check_client_start_search(void *cls,
790 const struct SearchMessage *sm)
794 msize = ntohs(sm->header.size) - sizeof(struct SearchMessage);
795 if (0 != msize % sizeof(struct GNUNET_HashCode))
798 return GNUNET_SYSERR;
805 * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
808 * Responsible for creating the request entry itself and setting
809 * up reply callback and cancellation on client disconnect.
811 * @param cls identification of the client
812 * @param sm the actual message
815 handle_client_start_search(void *cls,
816 const struct SearchMessage *sm)
818 static struct GNUNET_PeerIdentity all_zeros;
819 struct GSF_LocalClient *lc = cls;
820 struct ClientRequest *cr;
821 struct GSF_PendingRequestData *prd;
824 enum GNUNET_BLOCK_Type type;
825 enum GSF_PendingRequestOptions options;
827 GNUNET_STATISTICS_update(GSF_stats,
828 gettext_noop("# client searches received"),
831 msize = ntohs(sm->header.size) - sizeof(struct SearchMessage);
832 sc = msize / sizeof(struct GNUNET_HashCode);
833 type = ntohl(sm->type);
834 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
835 "Received request for `%s' of type %u from local client\n",
836 GNUNET_h2s(&sm->query),
839 /* detect duplicate UBLOCK requests */
840 if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) ||
841 (type == GNUNET_BLOCK_TYPE_ANY))
846 prd = GSF_pending_request_get_data_(cr->pr);
847 /* only unify with queries that hae not yet started local processing
848 (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a
849 matching query and type */
850 if ((GNUNET_YES != prd->has_started) &&
851 (0 != memcmp(&prd->query,
853 sizeof(struct GNUNET_HashCode))) &&
861 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
862 "Have existing request, merging content-seen lists.\n");
863 GSF_pending_request_update_(cr->pr,
864 (const struct GNUNET_HashCode *)&sm[1],
866 GNUNET_STATISTICS_update(GSF_stats,
867 gettext_noop("# client searches updated (merged content seen list)"),
873 GNUNET_STATISTICS_update(GSF_stats,
874 gettext_noop("# client searches active"),
877 cr = GNUNET_new(struct ClientRequest);
879 GNUNET_CONTAINER_DLL_insert(lc->cr_head,
882 options = GSF_PRO_LOCAL_REQUEST;
883 if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl(sm->options)))
884 options |= GSF_PRO_LOCAL_ONLY;
885 cr->pr = GSF_pending_request_create_(options, type,
890 sizeof(struct GNUNET_PeerIdentity)))
891 ? &sm->target : NULL, NULL, 0,
893 ntohl(sm->anonymity_level),
898 (const struct GNUNET_HashCode *)&sm[1], sc,
899 &client_response_handler,
902 if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl(sm->options)))
904 GNUNET_SERVICE_client_continue(lc->client);
907 GSF_pending_request_get_data_(cr->pr)->has_started = GNUNET_YES;
908 GSF_local_lookup_(cr->pr,
909 &start_p2p_processing,
915 * Handle request to sign a LOC URI (from client).
917 * @param cls identification of the client
918 * @param msg the actual message
921 handle_client_loc_sign(void *cls,
922 const struct RequestLocSignatureMessage *msg)
924 struct GSF_LocalClient *lc = cls;
925 struct GNUNET_FS_Uri base;
926 struct GNUNET_FS_Uri *loc;
927 struct GNUNET_MQ_Envelope *env;
928 struct ResponseLocSignatureMessage *resp;
930 GNUNET_break(GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
931 ntohl(msg->purpose));
932 base.type = GNUNET_FS_URI_CHK;
933 base.data.chk.chk = msg->chk;
934 base.data.chk.file_length = GNUNET_ntohll(msg->file_length);
935 loc = GNUNET_FS_uri_loc_create(&base,
937 GNUNET_TIME_absolute_ntoh(msg->expiration_time));
938 env = GNUNET_MQ_msg(resp,
939 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
940 resp->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
941 resp->expiration_time = GNUNET_TIME_absolute_hton(loc->data.loc.expirationTime);
942 resp->signature = loc->data.loc.contentSignature;
943 resp->peer = loc->data.loc.peer;
944 GNUNET_FS_uri_destroy(loc);
945 GNUNET_MQ_send(lc->mq,
947 GNUNET_SERVICE_client_continue(lc->client);
952 * Check INDEX_START-message.
954 * @param cls identification of the client
955 * @param ism the actual message
956 * @return #GNUNET_OK if @a ism is well-formed
959 check_client_index_start(void *cls,
960 const struct IndexStartMessage *ism)
964 GNUNET_MQ_check_zero_termination(ism);
965 if (0 != ism->reserved)
968 return GNUNET_SYSERR;
970 fn = GNUNET_STRINGS_filename_expand((const char *)&ism[1]);
974 return GNUNET_SYSERR;
982 * We've validated the hash of the file we're about to index. Signal
983 * success to the client and update our internal data structures.
985 * @param isc the data about the index info entry for the request
988 signal_index_ok(struct IndexStartContext *isc)
990 struct GSF_LocalClient *lc = isc->lc;
991 struct GNUNET_MQ_Envelope *env;
992 struct GNUNET_MessageHeader *msg;
994 GNUNET_FS_add_to_index(isc->filename,
996 env = GNUNET_MQ_msg(msg,
997 GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
998 GNUNET_MQ_send(lc->mq,
1000 GNUNET_free(isc->filename);
1002 GNUNET_SERVICE_client_continue(lc->client);
1007 * Function called once the hash computation over an
1008 * indexed file has completed.
1010 * @param cls closure, our publishing context
1011 * @param res resulting hash, NULL on error
1014 hash_for_index_val(void *cls,
1015 const struct GNUNET_HashCode *res)
1017 struct IndexStartContext *isc = cls;
1018 struct GSF_LocalClient *lc = isc->lc;
1019 struct GNUNET_MQ_Envelope *env;
1020 struct GNUNET_MessageHeader *msg;
1022 GNUNET_CONTAINER_DLL_remove(lc->isc_head,
1026 if ((NULL == res) ||
1029 sizeof(struct GNUNET_HashCode))))
1031 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1032 _("Hash mismatch trying to index file `%s' which does not have hash `%s'\n"),
1034 GNUNET_h2s(&isc->file_id));
1035 env = GNUNET_MQ_msg(msg,
1036 GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
1037 GNUNET_MQ_send(lc->mq,
1039 GNUNET_SERVICE_client_continue(lc->client);
1043 signal_index_ok(isc);
1048 * Handle INDEX_START-message.
1050 * @param cls identification of the client
1051 * @param message the actual message
1054 handle_client_index_start(void *cls,
1055 const struct IndexStartMessage *ism)
1057 struct GSF_LocalClient *lc = cls;
1058 struct IndexStartContext *isc;
1065 fn = GNUNET_STRINGS_filename_expand((const char *)&ism[1]);
1066 GNUNET_assert(NULL != fn);
1067 dev = GNUNET_ntohll(ism->device);
1068 ino = GNUNET_ntohll(ism->inode);
1069 isc = GNUNET_new(struct IndexStartContext);
1071 isc->file_id = ism->file_id;
1072 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1073 "Received START_INDEX message for file `%s'\n",
1080 (GNUNET_OK == GNUNET_DISK_file_get_identifiers(fn,
1086 /* fast validation OK! */
1087 signal_index_ok(isc);
1090 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1091 "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
1092 (unsigned long long)ino,
1093 (unsigned long long)myino,
1095 (unsigned int)mydev);
1096 /* slow validation, need to hash full file (again) */
1097 GNUNET_CONTAINER_DLL_insert(lc->isc_head,
1100 isc->fhc = GNUNET_CRYPTO_hash_file(GNUNET_SCHEDULER_PRIORITY_IDLE,
1103 &hash_for_index_val,
1105 if (NULL == isc->fhc)
1106 hash_for_index_val(isc,
1112 * Handle INDEX_LIST_GET-message.
1114 * @param cls closure
1115 * @param message the actual message
1118 handle_client_index_list_get(void *cls,
1119 const struct GNUNET_MessageHeader *message)
1121 struct GSF_LocalClient *lc = cls;
1123 GNUNET_FS_indexing_send_list(lc->mq);
1124 GNUNET_SERVICE_client_continue(lc->client);
1129 * Handle UNINDEX-message.
1131 * @param cls identification of the client
1132 * @param message the actual message
1135 handle_client_unindex(void *cls,
1136 const struct UnindexMessage *um)
1138 struct GSF_LocalClient *lc = cls;
1139 struct GNUNET_MQ_Envelope *env;
1140 struct GNUNET_MessageHeader *msg;
1143 GNUNET_break(0 == um->reserved);
1144 found = GNUNET_FS_indexing_do_unindex(&um->file_id);
1145 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1146 "Client requested unindexing of file `%s': %s\n",
1147 GNUNET_h2s(&um->file_id),
1148 found ? "found" : "not found");
1149 env = GNUNET_MQ_msg(msg,
1150 GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK);
1151 GNUNET_MQ_send(lc->mq,
1153 GNUNET_SERVICE_client_continue(lc->client);
1158 * Task run during shutdown.
1163 shutdown_task(void *cls)
1165 GSF_cadet_stop_server();
1166 if (NULL != GSF_core)
1168 GNUNET_CORE_disconnect(GSF_core);
1171 if (NULL != GSF_ats)
1173 GNUNET_ATS_performance_done(GSF_ats);
1178 GSF_pending_request_done_();
1180 GSF_connected_peer_done_();
1181 GNUNET_DATASTORE_disconnect(GSF_dsh,
1184 GNUNET_DHT_disconnect(GSF_dht);
1186 GNUNET_BLOCK_context_destroy(GSF_block_ctx);
1187 GSF_block_ctx = NULL;
1188 GNUNET_CONFIGURATION_destroy(block_cfg);
1190 GNUNET_STATISTICS_destroy(GSF_stats, GNUNET_NO);
1192 if (NULL != cover_age_task)
1194 GNUNET_SCHEDULER_cancel(cover_age_task);
1195 cover_age_task = NULL;
1197 GNUNET_FS_indexing_done();
1198 GNUNET_LOAD_value_free(datastore_get_load);
1199 datastore_get_load = NULL;
1200 GNUNET_LOAD_value_free(GSF_rt_entry_lifetime);
1201 GSF_rt_entry_lifetime = NULL;
1206 * Function called after GNUNET_CORE_connect has succeeded
1207 * (or failed for good). Note that the private key of the
1208 * peer is intentionally not exposed here; if you need it,
1209 * your process should try to read the private key file
1210 * directly (which should work if you are authorized...).
1212 * @param cls closure
1213 * @param my_identity ID of this peer, NULL if we failed
1216 peer_init_handler(void *cls,
1217 const struct GNUNET_PeerIdentity *my_identity)
1219 if (0 != GNUNET_memcmp(&GSF_my_id,
1222 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1223 "Peer identity mismatch, refusing to start!\n");
1224 GNUNET_SCHEDULER_shutdown();
1230 * Process fs requests.
1232 * @param c configuration to use
1235 main_init(const struct GNUNET_CONFIGURATION_Handle *c)
1237 struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = {
1238 GNUNET_MQ_handler_end()
1240 struct GNUNET_MQ_MessageHandler p2p_handlers[] = {
1241 GNUNET_MQ_hd_var_size(p2p_get,
1242 GNUNET_MESSAGE_TYPE_FS_GET,
1245 GNUNET_MQ_hd_var_size(p2p_put,
1246 GNUNET_MESSAGE_TYPE_FS_PUT,
1249 GNUNET_MQ_hd_fixed_size(p2p_migration_stop,
1250 GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP,
1251 struct MigrationStopMessage,
1253 GNUNET_MQ_handler_end()
1258 /* this option is really only for testcases that need to disable
1259 _anonymous_ file-sharing for some reason */
1260 anon_p2p_off = (GNUNET_YES ==
1261 GNUNET_CONFIGURATION_get_value_yesno(GSF_cfg,
1263 "DISABLE_ANON_TRANSFER"));
1266 GNUNET_CONFIGURATION_get_value_filename(GSF_cfg,
1271 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1272 _("FS service is lacking HOSTKEY configuration setting. Exiting.\n"));
1273 GNUNET_SCHEDULER_shutdown();
1274 return GNUNET_SYSERR;
1276 pk = GNUNET_CRYPTO_eddsa_key_create_from_file(keyfile);
1277 GNUNET_free(keyfile);
1278 GNUNET_assert(NULL != pk);
1279 GNUNET_CRYPTO_eddsa_key_get_public(pk,
1280 &GSF_my_id.public_key);
1282 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1284 GNUNET_i2s(&GSF_my_id));
1286 = GNUNET_CORE_connect(GSF_cfg,
1289 &GSF_peer_connect_handler,
1290 &GSF_peer_disconnect_handler,
1291 (GNUNET_YES == anon_p2p_off)
1294 if (NULL == GSF_core)
1296 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1297 _("Failed to connect to `%s' service.\n"),
1299 return GNUNET_SYSERR;
1302 GNUNET_SCHEDULER_add_delayed(COVER_AGE_FREQUENCY,
1303 &age_cover_counters,
1305 datastore_get_load = GNUNET_LOAD_value_init(DATASTORE_LOAD_AUTODECLINE);
1306 GSF_cadet_start_server();
1307 GNUNET_SCHEDULER_add_shutdown(&shutdown_task,
1314 * Process fs requests.
1316 * @param cls closure
1317 * @param cfg configuration to use
1318 * @param service the initialized service
1322 const struct GNUNET_CONFIGURATION_Handle *cfg,
1323 struct GNUNET_SERVICE_Handle *service)
1325 unsigned long long dqs;
1329 GNUNET_CONFIGURATION_get_value_size(GSF_cfg,
1331 "DATASTORE_QUEUE_SIZE",
1334 GNUNET_log_config_missing(GNUNET_ERROR_TYPE_INFO,
1336 "DATASTORE_QUEUE_SIZE");
1339 GSF_datastore_queue_size = (unsigned int)dqs;
1340 GSF_enable_randomized_delays =
1341 GNUNET_CONFIGURATION_get_value_yesno(cfg, "fs", "DELAY");
1342 GSF_dsh = GNUNET_DATASTORE_connect(cfg);
1343 if (NULL == GSF_dsh)
1345 GNUNET_SCHEDULER_shutdown();
1348 GSF_rt_entry_lifetime = GNUNET_LOAD_value_init(GNUNET_TIME_UNIT_FOREVER_REL);
1349 GSF_stats = GNUNET_STATISTICS_create("fs", cfg);
1350 block_cfg = GNUNET_CONFIGURATION_create();
1351 GSF_block_ctx = GNUNET_BLOCK_context_create(block_cfg);
1352 GNUNET_assert(NULL != GSF_block_ctx);
1353 GSF_dht = GNUNET_DHT_connect(cfg, FS_DHT_HT_SIZE);
1355 GSF_pending_request_init_();
1356 GSF_connected_peer_init_();
1357 GSF_ats = GNUNET_ATS_performance_init(GSF_cfg,
1362 if ((GNUNET_OK != GNUNET_FS_indexing_init(cfg,
1364 (GNUNET_OK != main_init(cfg)))
1366 GNUNET_SCHEDULER_shutdown();
1367 shutdown_task(NULL);
1374 * Define "main" method using service macro.
1378 GNUNET_SERVICE_OPTION_NONE,
1381 &client_disconnect_cb,
1383 GNUNET_MQ_hd_var_size(client_index_start,
1384 GNUNET_MESSAGE_TYPE_FS_INDEX_START,
1385 struct IndexStartMessage,
1387 GNUNET_MQ_hd_fixed_size(client_index_list_get,
1388 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
1389 struct GNUNET_MessageHeader,
1391 GNUNET_MQ_hd_fixed_size(client_unindex,
1392 GNUNET_MESSAGE_TYPE_FS_UNINDEX,
1393 struct UnindexMessage,
1395 GNUNET_MQ_hd_var_size(client_start_search,
1396 GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
1397 struct SearchMessage,
1399 GNUNET_MQ_hd_fixed_size(client_loc_sign,
1400 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
1401 struct RequestLocSignatureMessage,
1403 GNUNET_MQ_handler_end());
1406 /* end of gnunet-service-fs.c */