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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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.
79 * This is a doubly-linked list.
81 struct ClientRequest *next;
84 * This is a doubly-linked list.
86 struct ClientRequest *prev;
89 * Request this entry represents.
91 struct GSF_PendingRequest *pr;
94 * Client list this request belongs to.
96 struct GSF_LocalClient *lc;
99 * Task scheduled to destroy the request.
101 struct GNUNET_SCHEDULER_Task * kill_task;
107 * Replies to be transmitted to the client. The actual
108 * response message is allocated after this struct.
110 struct ClientResponse
113 * This is a doubly-linked list.
115 struct ClientResponse *next;
118 * This is a doubly-linked list.
120 struct ClientResponse *prev;
123 * Client list entry this response belongs to.
125 struct GSF_LocalClient *lc;
128 * Number of bytes in the response.
135 * Information we track while handling an index
136 * start request from a client.
138 struct IndexStartContext
142 * This is a doubly linked list.
144 struct IndexStartContext *next;
147 * This is a doubly linked list.
149 struct IndexStartContext *prev;
152 * Name of the indexed file.
157 * Context for transmitting confirmation to client.
159 struct GSF_LocalClient *lc;
162 * Context for hashing of the file.
164 struct GNUNET_CRYPTO_FileHashContext *fhc;
167 * Hash of the contents of the file.
169 struct GNUNET_HashCode file_id;
177 struct GSF_LocalClient
183 struct GNUNET_SERVICE_Client *client;
186 * Queue for sending replies.
188 struct GNUNET_MQ_Handle *mq;
191 * Head of list of requests performed on behalf
192 * of this client right now.
194 struct ClientRequest *cr_head;
197 * Tail of list of requests performed on behalf
198 * of this client right now.
200 struct ClientRequest *cr_tail;
203 * This is a doubly linked list.
205 struct IndexStartContext *isc_head;
208 * This is a doubly linked list.
210 struct IndexStartContext *isc_tail;
213 * Head of linked list of responses.
215 struct ClientResponse *res_head;
218 * Tail of linked list of responses.
220 struct ClientResponse *res_tail;
225 /* ****************************** globals ****************************** */
228 * Our connection to the datastore.
230 struct GNUNET_DATASTORE_Handle *GSF_dsh;
235 const struct GNUNET_CONFIGURATION_Handle *GSF_cfg;
238 * Handle for reporting statistics.
240 struct GNUNET_STATISTICS_Handle *GSF_stats;
243 * Handle for DHT operations.
245 struct GNUNET_DHT_Handle *GSF_dht;
248 * How long do requests typically stay in the routing table?
250 struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime;
253 * Running average of the observed latency to other peers (round trip).
254 * Initialized to 5s as the initial default.
256 struct GNUNET_TIME_Relative GSF_avg_latency = { 500 };
259 * Handle to ATS service.
261 struct GNUNET_ATS_PerformanceHandle *GSF_ats;
265 * Typical priorities we're seeing from other peers right now. Since
266 * most priorities will be zero, this value is the weighted average of
267 * non-zero priorities seen "recently". In order to ensure that new
268 * values do not dramatically change the ratio, values are first
269 * "capped" to a reasonable range (+N of the current value) and then
270 * averaged into the existing value by a ratio of 1:N. Hence
271 * receiving the largest possible priority can still only raise our
272 * "current_priorities" by at most 1.
274 double GSF_current_priorities;
277 * Size of the datastore queue we assume for common requests.
279 unsigned int GSF_datastore_queue_size;
282 * How many query messages have we received 'recently' that
283 * have not yet been claimed as cover traffic?
285 unsigned int GSF_cover_query_count;
288 * How many content messages have we received 'recently' that
289 * have not yet been claimed as cover traffic?
291 unsigned int GSF_cover_content_count;
296 struct GNUNET_BLOCK_Context *GSF_block_ctx;
299 * Pointer to handle to the core service (points to NULL until we've
302 struct GNUNET_CORE_Handle *GSF_core;
305 * Are we introducing randomized delays for better anonymity?
307 int GSF_enable_randomized_delays;
310 * Identity of this peer.
312 struct GNUNET_PeerIdentity GSF_my_id;
314 /* ***************************** locals ******************************* */
317 * Configuration for block library.
319 static struct GNUNET_CONFIGURATION_Handle *block_cfg;
322 * Private key of this peer. Used to sign LOC URI requests.
324 static struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
327 * ID of our task that we use to age the cover counters.
329 static struct GNUNET_SCHEDULER_Task * cover_age_task;
332 * Datastore 'GET' load tracking.
334 static struct GNUNET_LOAD_Value *datastore_get_load;
338 * Creates a fresh local client handle.
341 * @param client handle of the client
342 * @param mq message queue for @a client
343 * @return handle to local client entry
346 client_connect_cb (void *cls,
347 struct GNUNET_SERVICE_Client *client,
348 struct GNUNET_MQ_Handle *mq)
350 struct GSF_LocalClient *pos;
352 pos = GNUNET_new (struct GSF_LocalClient);
353 pos->client = client;
360 * Free the given client request.
362 * @param cls the client request to free
365 client_request_destroy (void *cls)
367 struct ClientRequest *cr = cls;
368 struct GSF_LocalClient *lc = cr->lc;
370 cr->kill_task = NULL;
371 GNUNET_CONTAINER_DLL_remove (lc->cr_head,
374 GSF_pending_request_cancel_ (cr->pr,
376 GNUNET_STATISTICS_update (GSF_stats,
377 gettext_noop ("# client searches active"),
385 * Handle a reply to a pending request. Also called if a request
386 * expires (then with data == NULL). The handler may be called
387 * many times (depending on the request type), but will not be
388 * called during or after a call to #GSF_pending_request_cancel()
389 * and will also not be called anymore after a call signalling
392 * @param cls user-specified closure
393 * @param eval evaluation of the result
394 * @param pr handle to the original pending request
395 * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
396 * @param expiration when does @a data expire?
397 * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
398 * @param type type of the block
399 * @param data response data, NULL on request expiration
400 * @param data_len number of bytes in @a data
403 client_response_handler (void *cls,
404 enum GNUNET_BLOCK_EvaluationResult eval,
405 struct GSF_PendingRequest *pr,
406 uint32_t reply_anonymity_level,
407 struct GNUNET_TIME_Absolute expiration,
408 struct GNUNET_TIME_Absolute last_transmission,
409 enum GNUNET_BLOCK_Type type,
413 struct ClientRequest *cr = cls;
414 struct GSF_LocalClient *lc;
415 struct GNUNET_MQ_Envelope *env;
416 struct ClientPutMessage *pm;
417 const struct GSF_PendingRequestData *prd;
421 /* local-only request, with no result, clean up. */
422 if (NULL == cr->kill_task)
423 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
427 prd = GSF_pending_request_get_data_ (pr);
428 GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
429 if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
434 GNUNET_STATISTICS_update (GSF_stats,
436 ("# replies received for local clients"), 1,
438 GNUNET_assert (pr == cr->pr);
440 env = GNUNET_MQ_msg_extra (pm,
442 GNUNET_MESSAGE_TYPE_FS_PUT);
443 pm->type = htonl (type);
444 pm->expiration = GNUNET_TIME_absolute_hton (expiration);
445 pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
446 pm->num_transmissions = htonl (prd->num_transmissions);
447 pm->respect_offered = htonl (prd->respect_offered);
448 GNUNET_memcpy (&pm[1],
451 GNUNET_MQ_send (lc->mq,
453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454 "Queued reply to query `%s' for local client\n",
455 GNUNET_h2s (&prd->query));
456 if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459 "Evaluation %d - keeping query alive\n",
463 if (NULL == cr->kill_task)
464 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
470 * A client disconnected from us. Tear down the local client
474 * @param client handle of the client
475 * @param app_ctx the `struct GSF_LocalClient`
478 client_disconnect_cb (void *cls,
479 struct GNUNET_SERVICE_Client *client,
482 struct GSF_LocalClient *lc = app_ctx;
483 struct IndexStartContext *isc;
484 struct ClientRequest *cr;
485 struct ClientResponse *res;
487 while (NULL != (cr = lc->cr_head))
489 if (NULL != cr->kill_task)
490 GNUNET_SCHEDULER_cancel (cr->kill_task);
491 client_request_destroy (cr);
493 while (NULL != (res = lc->res_head))
495 GNUNET_CONTAINER_DLL_remove (lc->res_head,
500 while (NULL != (isc = lc->isc_head))
502 GNUNET_CONTAINER_DLL_remove (lc->isc_head,
505 GNUNET_CRYPTO_hash_file_cancel (isc->fhc);
516 * Task that periodically ages our cover traffic statistics.
518 * @param cls unused closure
521 age_cover_counters (void *cls)
523 GSF_cover_content_count = (GSF_cover_content_count * 15) / 16;
524 GSF_cover_query_count = (GSF_cover_query_count * 15) / 16;
526 GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
533 * We've just now completed a datastore request. Update our
534 * datastore load calculations.
536 * @param start time when the datastore request was issued
539 GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start)
541 struct GNUNET_TIME_Relative delay;
543 delay = GNUNET_TIME_absolute_get_duration (start);
544 GNUNET_LOAD_update (datastore_get_load, delay.rel_value_us);
549 * Test if the DATABASE (GET) load on this peer is too high
550 * to even consider processing the query at
553 * @param priority priority of the request (used as a reference point to compare with the load)
554 * @return #GNUNET_YES if the load is too high to do anything (load high)
555 * #GNUNET_NO to process normally (load normal)
556 * #GNUNET_SYSERR to process for free (load low)
559 GSF_test_get_load_too_high_ (uint32_t priority)
563 ld = GNUNET_LOAD_get_load (datastore_get_load);
565 return GNUNET_SYSERR;
573 * We've received peer performance information. Update
574 * our running average for the P2P latency.
577 * @param address the address
578 * @param active is this address in active use
579 * @param bandwidth_out assigned outbound bandwidth for the connection
580 * @param bandwidth_in assigned inbound bandwidth for the connection
581 * @param prop performance data for the address (as far as known)
584 update_latencies (void *cls,
585 const struct GNUNET_HELLO_Address *address,
587 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
588 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
589 const struct GNUNET_ATS_Properties *prop)
593 /* ATS service temporarily disconnected */
597 if (GNUNET_YES != active)
599 GSF_update_peer_latency_ (&address->peer,
601 GSF_avg_latency.rel_value_us =
602 (GSF_avg_latency.rel_value_us * 31 +
603 GNUNET_MIN (5000, prop->delay.rel_value_us)) / 32;
604 GNUNET_STATISTICS_set (GSF_stats,
605 gettext_noop ("# running average P2P latency (ms)"),
606 GSF_avg_latency.rel_value_us / 1000LL,
612 * Check P2P "PUT" message.
614 * @param cls closure with the `struct GSF_ConnectedPeer`
615 * @param message the actual message
616 * @return #GNUNET_OK to keep the connection open,
617 * #GNUNET_SYSERR to close it (signal serious error)
620 check_p2p_put (void *cls,
621 const struct PutMessage *put)
623 enum GNUNET_BLOCK_Type type;
625 type = ntohl (put->type);
626 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
629 return GNUNET_SYSERR;
636 * We have a new request, consider forwarding it to the given
639 * @param cls the `struct GSF_PendingRequest`
640 * @param peer identity of the peer
641 * @param cp handle to the connected peer record
642 * @param ppd peer performance data
645 consider_request_for_forwarding (void *cls,
646 const struct GNUNET_PeerIdentity *peer,
647 struct GSF_ConnectedPeer *cp,
648 const struct GSF_PeerPerformanceData *ppd)
650 struct GSF_PendingRequest *pr = cls;
653 GSF_pending_request_test_target_ (pr, peer))
655 #if INSANE_STATISTICS
656 GNUNET_STATISTICS_update (GSF_stats,
657 gettext_noop ("# Loopback routes suppressed"), 1,
668 * Function to be called after we're done processing
669 * replies from the local lookup. If the result status
670 * code indicates that there may be more replies, plan
671 * forwarding the request.
673 * @param cls closure (NULL)
674 * @param pr the pending request we were processing
675 * @param result final datastore lookup result
678 GSF_consider_forwarding (void *cls,
679 struct GSF_PendingRequest *pr,
680 enum GNUNET_BLOCK_EvaluationResult result)
682 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
683 return; /* we're done... */
685 GSF_pending_request_test_active_ (pr))
686 return; /* request is not actually active, skip! */
687 GSF_iterate_connected_peers_ (&consider_request_for_forwarding,
693 * Check P2P "GET" request.
696 * @param gm the actual message
697 * @return #GNUNET_OK to keep the connection open,
698 * #GNUNET_SYSERR to close it (signal serious error)
701 check_p2p_get (void *cls,
702 const struct GetMessage *gm)
709 msize = ntohs (gm->header.size);
710 bm = ntohl (gm->hash_bitmap);
718 if (msize < sizeof (struct GetMessage) + bits * sizeof (struct GNUNET_PeerIdentity))
721 return GNUNET_SYSERR;
723 bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (struct GNUNET_PeerIdentity);
724 /* bfsize must be power of 2, check! */
725 if (0 != ((bfsize - 1) & bfsize))
728 return GNUNET_SYSERR;
735 * We're done with the local lookup, now consider
736 * P2P processing (depending on request options and
737 * result status). Also signal that we can now
738 * receive more request information from the client.
740 * @param cls the client doing the request (`struct GSF_LocalClient`)
741 * @param pr the pending request we were processing
742 * @param result final datastore lookup result
745 start_p2p_processing (void *cls,
746 struct GSF_PendingRequest *pr,
747 enum GNUNET_BLOCK_EvaluationResult result)
749 struct GSF_LocalClient *lc = cls;
750 struct GSF_PendingRequestData *prd;
752 GNUNET_SERVICE_client_continue (lc->client);
753 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
754 return; /* we're done, 'pr' was already destroyed... */
755 prd = GSF_pending_request_get_data_ (pr);
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757 "Finished database lookup for local request `%s' with result %d\n",
758 GNUNET_h2s (&prd->query),
760 if (0 == prd->anonymity_level)
764 case GNUNET_BLOCK_TYPE_FS_DBLOCK:
765 case GNUNET_BLOCK_TYPE_FS_IBLOCK:
766 /* the above block types MAY be available via 'cadet' */
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Considering cadet-based download for block\n");
769 GSF_cadet_lookup_ (pr);
771 case GNUNET_BLOCK_TYPE_FS_UBLOCK:
772 /* the above block types are in the DHT */
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
774 "Considering DHT-based search for block\n");
775 GSF_dht_lookup_ (pr);
782 GSF_consider_forwarding (NULL,
789 * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
792 * @param cls identification of the client
793 * @param sm the actual message
794 * @return #GNUNET_OK if @a sm is well-formed
797 check_client_start_search (void *cls,
798 const struct SearchMessage *sm)
802 msize = ntohs (sm->header.size) - sizeof (struct SearchMessage);
803 if (0 != msize % sizeof (struct GNUNET_HashCode))
806 return GNUNET_SYSERR;
813 * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
816 * Responsible for creating the request entry itself and setting
817 * up reply callback and cancellation on client disconnect.
819 * @param cls identification of the client
820 * @param sm the actual message
823 handle_client_start_search (void *cls,
824 const struct SearchMessage *sm)
826 static struct GNUNET_PeerIdentity all_zeros;
827 struct GSF_LocalClient *lc = cls;
828 struct ClientRequest *cr;
829 struct GSF_PendingRequestData *prd;
832 enum GNUNET_BLOCK_Type type;
833 enum GSF_PendingRequestOptions options;
835 GNUNET_STATISTICS_update (GSF_stats,
836 gettext_noop ("# client searches received"),
839 msize = ntohs (sm->header.size) - sizeof (struct SearchMessage);
840 sc = msize / sizeof (struct GNUNET_HashCode);
841 type = ntohl (sm->type);
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 "Received request for `%s' of type %u from local client\n",
844 GNUNET_h2s (&sm->query),
845 (unsigned int) type);
847 /* detect duplicate UBLOCK requests */
848 if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) ||
849 (type == GNUNET_BLOCK_TYPE_ANY))
854 prd = GSF_pending_request_get_data_ (cr->pr);
855 /* only unify with queries that hae not yet started local processing
856 (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a
857 matching query and type */
858 if ((GNUNET_YES != prd->has_started) &&
859 (0 != memcmp (&prd->query,
861 sizeof (struct GNUNET_HashCode))) &&
869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
870 "Have existing request, merging content-seen lists.\n");
871 GSF_pending_request_update_ (cr->pr,
872 (const struct GNUNET_HashCode *) &sm[1],
874 GNUNET_STATISTICS_update (GSF_stats,
875 gettext_noop ("# client searches updated (merged content seen list)"),
881 GNUNET_STATISTICS_update (GSF_stats,
882 gettext_noop ("# client searches active"),
885 cr = GNUNET_new (struct ClientRequest);
887 GNUNET_CONTAINER_DLL_insert (lc->cr_head,
890 options = GSF_PRO_LOCAL_REQUEST;
891 if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options)))
892 options |= GSF_PRO_LOCAL_ONLY;
893 cr->pr = GSF_pending_request_create_ (options, type,
898 sizeof (struct GNUNET_PeerIdentity)))
899 ? &sm->target : NULL, NULL, 0,
901 ntohl (sm->anonymity_level),
906 (const struct GNUNET_HashCode *) &sm[1], sc,
907 &client_response_handler,
910 if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options)))
912 GNUNET_SERVICE_client_continue (lc->client);
915 GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES;
916 GSF_local_lookup_ (cr->pr,
917 &start_p2p_processing,
923 * Handle request to sign a LOC URI (from client).
925 * @param cls identification of the client
926 * @param msg the actual message
929 handle_client_loc_sign (void *cls,
930 const struct RequestLocSignatureMessage *msg)
932 struct GSF_LocalClient *lc = cls;
933 struct GNUNET_FS_Uri base;
934 struct GNUNET_FS_Uri *loc;
935 struct GNUNET_MQ_Envelope *env;
936 struct ResponseLocSignatureMessage *resp;
938 GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
939 ntohl (msg->purpose));
940 base.type = GNUNET_FS_URI_CHK;
941 base.data.chk.chk = msg->chk;
942 base.data.chk.file_length = GNUNET_ntohll (msg->file_length);
943 loc = GNUNET_FS_uri_loc_create (&base,
945 GNUNET_TIME_absolute_ntoh (msg->expiration_time));
946 env = GNUNET_MQ_msg (resp,
947 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
948 resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
949 resp->expiration_time = GNUNET_TIME_absolute_hton (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,
955 GNUNET_SERVICE_client_continue (lc->client);
960 * Check INDEX_START-message.
962 * @param cls identification of the client
963 * @param ism the actual message
964 * @return #GNUNET_OK if @a ism is well-formed
967 check_client_index_start (void *cls,
968 const struct IndexStartMessage *ism)
973 msize = ntohs (ism->header.size);
974 if (((const char *) ism)[msize - 1] != '\0')
977 return GNUNET_SYSERR;
979 if (0 != ism->reserved)
982 return GNUNET_SYSERR;
984 fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
988 return GNUNET_SYSERR;
996 * We've validated the hash of the file we're about to index. Signal
997 * success to the client and update our internal data structures.
999 * @param isc the data about the index info entry for the request
1002 signal_index_ok (struct IndexStartContext *isc)
1004 struct GSF_LocalClient *lc = isc->lc;
1005 struct GNUNET_MQ_Envelope *env;
1006 struct GNUNET_MessageHeader *msg;
1008 GNUNET_FS_add_to_index (isc->filename,
1010 env = GNUNET_MQ_msg (msg,
1011 GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
1012 GNUNET_MQ_send (lc->mq,
1014 GNUNET_free (isc->filename);
1016 GNUNET_SERVICE_client_continue (lc->client);
1021 * Function called once the hash computation over an
1022 * indexed file has completed.
1024 * @param cls closure, our publishing context
1025 * @param res resulting hash, NULL on error
1028 hash_for_index_val (void *cls,
1029 const struct GNUNET_HashCode *res)
1031 struct IndexStartContext *isc = cls;
1032 struct GSF_LocalClient *lc = isc->lc;
1033 struct GNUNET_MQ_Envelope *env;
1034 struct GNUNET_MessageHeader *msg;
1036 GNUNET_CONTAINER_DLL_remove (lc->isc_head,
1040 if ( (NULL == res) ||
1043 sizeof (struct GNUNET_HashCode))))
1045 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1046 _("Hash mismatch trying to index file `%s' which does not have hash `%s'\n"),
1048 GNUNET_h2s (&isc->file_id));
1049 env = GNUNET_MQ_msg (msg,
1050 GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
1051 GNUNET_MQ_send (lc->mq,
1053 GNUNET_SERVICE_client_continue (lc->client);
1057 signal_index_ok (isc);
1062 * Handle INDEX_START-message.
1064 * @param cls identification of the client
1065 * @param message the actual message
1068 handle_client_index_start (void *cls,
1069 const struct IndexStartMessage *ism)
1071 struct GSF_LocalClient *lc = cls;
1072 struct IndexStartContext *isc;
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);
1085 isc->file_id = ism->file_id;
1086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1087 "Received START_INDEX message for file `%s'\n",
1092 if ( ( (dev != 0) ||
1094 (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn,
1100 /* fast validation OK! */
1101 signal_index_ok (isc);
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,
1109 (unsigned int) mydev);
1110 /* slow validation, need to hash full file (again) */
1111 GNUNET_CONTAINER_DLL_insert (lc->isc_head,
1114 isc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
1117 &hash_for_index_val,
1119 if (NULL == isc->fhc)
1120 hash_for_index_val (isc,
1126 * Handle INDEX_LIST_GET-message.
1128 * @param cls closure
1129 * @param message the actual message
1132 handle_client_index_list_get (void *cls,
1133 const struct GNUNET_MessageHeader *message)
1135 struct GSF_LocalClient *lc = cls;
1137 GNUNET_FS_indexing_send_list (lc->mq);
1138 GNUNET_SERVICE_client_continue (lc->client);
1143 * Handle UNINDEX-message.
1145 * @param cls identification of the client
1146 * @param message the actual message
1149 handle_client_unindex (void *cls,
1150 const struct UnindexMessage *um)
1152 struct GSF_LocalClient *lc = cls;
1153 struct GNUNET_MQ_Envelope *env;
1154 struct GNUNET_MessageHeader *msg;
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,
1167 GNUNET_SERVICE_client_continue (lc->client);
1172 * Task run during shutdown.
1177 shutdown_task (void *cls)
1179 GSF_cadet_stop_server ();
1180 if (NULL != GSF_core)
1182 GNUNET_CORE_disconnect (GSF_core);
1185 if (NULL != GSF_ats)
1187 GNUNET_ATS_performance_done (GSF_ats);
1192 GSF_pending_request_done_ ();
1194 GSF_connected_peer_done_ ();
1195 GNUNET_DATASTORE_disconnect (GSF_dsh,
1198 GNUNET_DHT_disconnect (GSF_dht);
1200 GNUNET_BLOCK_context_destroy (GSF_block_ctx);
1201 GSF_block_ctx = NULL;
1202 GNUNET_CONFIGURATION_destroy (block_cfg);
1204 GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO);
1206 if (NULL != cover_age_task)
1208 GNUNET_SCHEDULER_cancel (cover_age_task);
1209 cover_age_task = NULL;
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;
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...).
1226 * @param cls closure
1227 * @param my_identity ID of this peer, NULL if we failed
1230 peer_init_handler (void *cls,
1231 const struct GNUNET_PeerIdentity *my_identity)
1233 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&GSF_my_id,
1236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1237 "Peer identity missmatch, refusing to start!\n");
1238 GNUNET_SCHEDULER_shutdown ();
1244 * Process fs requests.
1246 * @param c configuration to use
1249 main_init (const struct GNUNET_CONFIGURATION_Handle *c)
1251 struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = {
1252 GNUNET_MQ_handler_end ()
1254 struct GNUNET_MQ_MessageHandler p2p_handlers[] = {
1255 GNUNET_MQ_hd_var_size (p2p_get,
1256 GNUNET_MESSAGE_TYPE_FS_GET,
1259 GNUNET_MQ_hd_var_size (p2p_put,
1260 GNUNET_MESSAGE_TYPE_FS_PUT,
1263 GNUNET_MQ_hd_fixed_size (p2p_migration_stop,
1264 GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP,
1265 struct MigrationStopMessage,
1267 GNUNET_MQ_handler_end ()
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,
1277 "DISABLE_ANON_TRANSFER"));
1280 GNUNET_CONFIGURATION_get_value_filename (GSF_cfg,
1285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1286 _("FS service is lacking HOSTKEY configuration setting. Exiting.\n"));
1287 GNUNET_SCHEDULER_shutdown ();
1288 return GNUNET_SYSERR;
1290 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
1291 GNUNET_free (keyfile);
1292 GNUNET_assert (NULL != pk);
1293 GNUNET_CRYPTO_eddsa_key_get_public (pk,
1294 &GSF_my_id.public_key);
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1298 GNUNET_i2s (&GSF_my_id));
1300 = GNUNET_CORE_connect (GSF_cfg,
1303 &GSF_peer_connect_handler,
1304 &GSF_peer_disconnect_handler,
1305 (GNUNET_YES == anon_p2p_off)
1308 if (NULL == GSF_core)
1310 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1311 _("Failed to connect to `%s' service.\n"),
1313 return GNUNET_SYSERR;
1316 GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
1317 &age_cover_counters,
1319 datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE);
1320 GSF_cadet_start_server ();
1321 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1328 * Process fs requests.
1330 * @param cls closure
1331 * @param cfg configuration to use
1332 * @param service the initialized service
1336 const struct GNUNET_CONFIGURATION_Handle *cfg,
1337 struct GNUNET_SERVICE_Handle *service)
1339 unsigned long long dqs;
1343 GNUNET_CONFIGURATION_get_value_size (GSF_cfg,
1345 "DATASTORE_QUEUE_SIZE",
1348 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
1350 "DATASTORE_QUEUE_SIZE");
1353 GSF_datastore_queue_size = (unsigned int) dqs;
1354 GSF_enable_randomized_delays =
1355 GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY");
1356 GSF_dsh = GNUNET_DATASTORE_connect (cfg);
1357 if (NULL == GSF_dsh)
1359 GNUNET_SCHEDULER_shutdown ();
1362 GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL);
1363 GSF_stats = GNUNET_STATISTICS_create ("fs", cfg);
1364 block_cfg = GNUNET_CONFIGURATION_create ();
1365 GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg);
1366 GNUNET_assert (NULL != GSF_block_ctx);
1367 GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE);
1369 GSF_pending_request_init_ ();
1370 GSF_connected_peer_init_ ();
1371 GSF_ats = GNUNET_ATS_performance_init (GSF_cfg,
1376 if ( (GNUNET_OK != GNUNET_FS_indexing_init (cfg,
1378 (GNUNET_OK != main_init (cfg)) )
1380 GNUNET_SCHEDULER_shutdown ();
1381 shutdown_task (NULL);
1388 * Define "main" method using service macro.
1392 GNUNET_SERVICE_OPTION_NONE,
1395 &client_disconnect_cb,
1397 GNUNET_MQ_hd_var_size (client_index_start,
1398 GNUNET_MESSAGE_TYPE_FS_INDEX_START,
1399 struct IndexStartMessage,
1401 GNUNET_MQ_hd_fixed_size (client_index_list_get,
1402 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
1403 struct GNUNET_MessageHeader,
1405 GNUNET_MQ_hd_fixed_size (client_unindex,
1406 GNUNET_MESSAGE_TYPE_FS_UNINDEX,
1407 struct UnindexMessage,
1409 GNUNET_MQ_hd_var_size (client_start_search,
1410 GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
1411 struct SearchMessage,
1413 GNUNET_MQ_hd_fixed_size (client_loc_sign,
1414 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
1415 struct RequestLocSignatureMessage,
1417 GNUNET_MQ_handler_end ());
1420 /* end of gnunet-service-fs.c */