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_lc.h"
42 #include "gnunet-service-fs_pe.h"
43 #include "gnunet-service-fs_pr.h"
44 #include "gnunet-service-fs_push.h"
45 #include "gnunet-service-fs_put.h"
46 #include "gnunet-service-fs_cadet.h"
51 * Size for the hash map for DHT requests from the FS
52 * service. Should be about the number of concurrent
53 * DHT requests we plan to make.
55 #define FS_DHT_HT_SIZE 1024
59 * How quickly do we age cover traffic? At the given
60 * time interval, remaining cover traffic counters are
61 * decremented by 1/16th.
63 #define COVER_AGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
66 * Collect an instane number of statistics? May cause excessive IPC.
68 #define INSANE_STATISTICS GNUNET_NO
73 * Doubly-linked list of requests we are performing
74 * on behalf of the same client.
80 * This is a doubly-linked list.
82 struct ClientRequest *next;
85 * This is a doubly-linked list.
87 struct ClientRequest *prev;
90 * Request this entry represents.
92 struct GSF_PendingRequest *pr;
95 * Client list this request belongs to.
97 struct GSF_LocalClient *lc;
100 * Task scheduled to destroy the request.
102 struct GNUNET_SCHEDULER_Task * kill_task;
108 * Replies to be transmitted to the client. The actual
109 * response message is allocated after this struct.
111 struct ClientResponse
114 * This is a doubly-linked list.
116 struct ClientResponse *next;
119 * This is a doubly-linked list.
121 struct ClientResponse *prev;
124 * Client list entry this response belongs to.
126 struct GSF_LocalClient *lc;
129 * Number of bytes in the response.
136 * Information we track while handling an index
137 * start request from a client.
139 struct IndexStartContext
143 * This is a doubly linked list.
145 struct IndexStartContext *next;
148 * This is a doubly linked list.
150 struct IndexStartContext *prev;
153 * Name of the indexed file.
158 * Context for transmitting confirmation to client.
160 struct GSF_LocalClient *lc;
163 * Context for hashing of the file.
165 struct GNUNET_CRYPTO_FileHashContext *fhc;
168 * Hash of the contents of the file.
170 struct GNUNET_HashCode file_id;
178 struct GSF_LocalClient
184 struct GNUNET_SERVICE_Client *client;
187 * Queue for sending replies.
189 struct GNUNET_MQ_Handle *mq;
192 * Head of list of requests performed on behalf
193 * of this client right now.
195 struct ClientRequest *cr_head;
198 * Tail of list of requests performed on behalf
199 * of this client right now.
201 struct ClientRequest *cr_tail;
204 * This is a doubly linked list.
206 struct IndexStartContext *isc_head;
209 * This is a doubly linked list.
211 struct IndexStartContext *isc_tail;
214 * Head of linked list of responses.
216 struct ClientResponse *res_head;
219 * Tail of linked list of responses.
221 struct ClientResponse *res_tail;
226 /* ****************************** globals ****************************** */
229 * Our connection to the datastore.
231 struct GNUNET_DATASTORE_Handle *GSF_dsh;
236 const struct GNUNET_CONFIGURATION_Handle *GSF_cfg;
239 * Handle for reporting statistics.
241 struct GNUNET_STATISTICS_Handle *GSF_stats;
244 * Handle for DHT operations.
246 struct GNUNET_DHT_Handle *GSF_dht;
249 * How long do requests typically stay in the routing table?
251 struct GNUNET_LOAD_Value *GSF_rt_entry_lifetime;
254 * Running average of the observed latency to other peers (round trip).
255 * Initialized to 5s as the initial default.
257 struct GNUNET_TIME_Relative GSF_avg_latency = { 500 };
260 * Handle to ATS service.
262 struct GNUNET_ATS_PerformanceHandle *GSF_ats;
266 * Typical priorities we're seeing from other peers right now. Since
267 * most priorities will be zero, this value is the weighted average of
268 * non-zero priorities seen "recently". In order to ensure that new
269 * values do not dramatically change the ratio, values are first
270 * "capped" to a reasonable range (+N of the current value) and then
271 * averaged into the existing value by a ratio of 1:N. Hence
272 * receiving the largest possible priority can still only raise our
273 * "current_priorities" by at most 1.
275 double GSF_current_priorities;
278 * Size of the datastore queue we assume for common requests.
280 unsigned int GSF_datastore_queue_size;
283 * How many query messages have we received 'recently' that
284 * have not yet been claimed as cover traffic?
286 unsigned int GSF_cover_query_count;
289 * How many content messages have we received 'recently' that
290 * have not yet been claimed as cover traffic?
292 unsigned int GSF_cover_content_count;
297 struct GNUNET_BLOCK_Context *GSF_block_ctx;
300 * Pointer to handle to the core service (points to NULL until we've
303 struct GNUNET_CORE_Handle *GSF_core;
306 * Are we introducing randomized delays for better anonymity?
308 int GSF_enable_randomized_delays;
311 * Identity of this peer.
313 struct GNUNET_PeerIdentity GSF_my_id;
315 /* ***************************** locals ******************************* */
318 * Configuration for block library.
320 static struct GNUNET_CONFIGURATION_Handle *block_cfg;
323 * Private key of this peer. Used to sign LOC URI requests.
325 static struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
328 * ID of our task that we use to age the cover counters.
330 static struct GNUNET_SCHEDULER_Task * cover_age_task;
333 * Datastore 'GET' load tracking.
335 static struct GNUNET_LOAD_Value *datastore_get_load;
339 * Creates a fresh local client handle.
342 * @param client handle of the client
343 * @param mq message queue for @a client
344 * @return handle to local client entry
347 client_connect_cb (void *cls,
348 struct GNUNET_SERVICE_Client *client,
349 struct GNUNET_MQ_Handle *mq)
351 struct GSF_LocalClient *pos;
353 pos = GNUNET_new (struct GSF_LocalClient);
354 pos->client = client;
361 * Free the given client request.
363 * @param cls the client request to free
366 client_request_destroy (void *cls)
368 struct ClientRequest *cr = cls;
369 struct GSF_LocalClient *lc = cr->lc;
371 cr->kill_task = NULL;
372 GNUNET_CONTAINER_DLL_remove (lc->cr_head,
375 GSF_pending_request_cancel_ (cr->pr,
377 GNUNET_STATISTICS_update (GSF_stats,
378 gettext_noop ("# client searches active"),
386 * Handle a reply to a pending request. Also called if a request
387 * expires (then with data == NULL). The handler may be called
388 * many times (depending on the request type), but will not be
389 * called during or after a call to #GSF_pending_request_cancel()
390 * and will also not be called anymore after a call signalling
393 * @param cls user-specified closure
394 * @param eval evaluation of the result
395 * @param pr handle to the original pending request
396 * @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
397 * @param expiration when does @a data expire?
398 * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
399 * @param type type of the block
400 * @param data response data, NULL on request expiration
401 * @param data_len number of bytes in @a data
404 client_response_handler (void *cls,
405 enum GNUNET_BLOCK_EvaluationResult eval,
406 struct GSF_PendingRequest *pr,
407 uint32_t reply_anonymity_level,
408 struct GNUNET_TIME_Absolute expiration,
409 struct GNUNET_TIME_Absolute last_transmission,
410 enum GNUNET_BLOCK_Type type,
414 struct ClientRequest *cr = cls;
415 struct GSF_LocalClient *lc;
416 struct GNUNET_MQ_Envelope *env;
417 struct ClientPutMessage *pm;
418 const struct GSF_PendingRequestData *prd;
422 /* local-only request, with no result, clean up. */
423 if (NULL == cr->kill_task)
424 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
428 prd = GSF_pending_request_get_data_ (pr);
429 GNUNET_break (type != GNUNET_BLOCK_TYPE_ANY);
430 if ((prd->type != type) && (prd->type != GNUNET_BLOCK_TYPE_ANY))
435 GNUNET_STATISTICS_update (GSF_stats,
437 ("# replies received for local clients"), 1,
439 GNUNET_assert (pr == cr->pr);
441 env = GNUNET_MQ_msg_extra (pm,
443 GNUNET_MESSAGE_TYPE_FS_PUT);
444 pm->type = htonl (type);
445 pm->expiration = GNUNET_TIME_absolute_hton (expiration);
446 pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
447 pm->num_transmissions = htonl (prd->num_transmissions);
448 pm->respect_offered = htonl (prd->respect_offered);
449 GNUNET_memcpy (&pm[1],
452 GNUNET_MQ_send (lc->mq,
454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "Queued reply to query `%s' for local client\n",
456 GNUNET_h2s (&prd->query));
457 if (GNUNET_BLOCK_EVALUATION_OK_LAST != eval)
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Evaluation %d - keeping query alive\n",
464 if (NULL == cr->kill_task)
465 cr->kill_task = GNUNET_SCHEDULER_add_now (&client_request_destroy,
471 * A client disconnected from us. Tear down the local client
475 * @param client handle of the client
476 * @param app_ctx the `struct GSF_LocalClient`
479 client_disconnect_cb (void *cls,
480 struct GNUNET_SERVICE_Client *client,
483 struct GSF_LocalClient *lc = app_ctx;
484 struct IndexStartContext *isc;
485 struct ClientRequest *cr;
486 struct ClientResponse *res;
488 while (NULL != (cr = lc->cr_head))
490 if (NULL != cr->kill_task)
491 GNUNET_SCHEDULER_cancel (cr->kill_task);
492 client_request_destroy (cr);
494 while (NULL != (res = lc->res_head))
496 GNUNET_CONTAINER_DLL_remove (lc->res_head,
501 while (NULL != (isc = lc->isc_head))
503 GNUNET_CONTAINER_DLL_remove (lc->isc_head,
506 GNUNET_CRYPTO_hash_file_cancel (isc->fhc);
517 * Task that periodically ages our cover traffic statistics.
519 * @param cls unused closure
522 age_cover_counters (void *cls)
524 GSF_cover_content_count = (GSF_cover_content_count * 15) / 16;
525 GSF_cover_query_count = (GSF_cover_query_count * 15) / 16;
527 GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
534 * We've just now completed a datastore request. Update our
535 * datastore load calculations.
537 * @param start time when the datastore request was issued
540 GSF_update_datastore_delay_ (struct GNUNET_TIME_Absolute start)
542 struct GNUNET_TIME_Relative delay;
544 delay = GNUNET_TIME_absolute_get_duration (start);
545 GNUNET_LOAD_update (datastore_get_load, delay.rel_value_us);
550 * Test if the DATABASE (GET) load on this peer is too high
551 * to even consider processing the query at
554 * @param priority priority of the request (used as a reference point to compare with the load)
555 * @return #GNUNET_YES if the load is too high to do anything (load high)
556 * #GNUNET_NO to process normally (load normal)
557 * #GNUNET_SYSERR to process for free (load low)
560 GSF_test_get_load_too_high_ (uint32_t priority)
564 ld = GNUNET_LOAD_get_load (datastore_get_load);
566 return GNUNET_SYSERR;
574 * We've received peer performance information. Update
575 * our running average for the P2P latency.
578 * @param address the address
579 * @param active is this address in active use
580 * @param bandwidth_out assigned outbound bandwidth for the connection
581 * @param bandwidth_in assigned inbound bandwidth for the connection
582 * @param prop performance data for the address (as far as known)
585 update_latencies (void *cls,
586 const struct GNUNET_HELLO_Address *address,
588 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
589 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
590 const struct GNUNET_ATS_Properties *prop)
594 /* ATS service temporarily disconnected */
598 if (GNUNET_YES != active)
600 GSF_update_peer_latency_ (&address->peer,
602 GSF_avg_latency.rel_value_us =
603 (GSF_avg_latency.rel_value_us * 31 +
604 GNUNET_MIN (5000, prop->delay.rel_value_us)) / 32;
605 GNUNET_STATISTICS_set (GSF_stats,
606 gettext_noop ("# running average P2P latency (ms)"),
607 GSF_avg_latency.rel_value_us / 1000LL,
613 * Check P2P "PUT" message.
615 * @param cls closure with the `struct GSF_ConnectedPeer`
616 * @param message the actual message
617 * @return #GNUNET_OK to keep the connection open,
618 * #GNUNET_SYSERR to close it (signal serious error)
621 check_p2p_put (void *cls,
622 const struct PutMessage *put)
624 enum GNUNET_BLOCK_Type type;
626 type = ntohl (put->type);
627 if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
630 return GNUNET_SYSERR;
637 * We have a new request, consider forwarding it to the given
640 * @param cls the `struct GSF_PendingRequest`
641 * @param peer identity of the peer
642 * @param cp handle to the connected peer record
643 * @param ppd peer performance data
646 consider_request_for_forwarding (void *cls,
647 const struct GNUNET_PeerIdentity *peer,
648 struct GSF_ConnectedPeer *cp,
649 const struct GSF_PeerPerformanceData *ppd)
651 struct GSF_PendingRequest *pr = cls;
654 GSF_pending_request_test_target_ (pr, peer))
656 #if INSANE_STATISTICS
657 GNUNET_STATISTICS_update (GSF_stats,
658 gettext_noop ("# Loopback routes suppressed"), 1,
669 * Function to be called after we're done processing
670 * replies from the local lookup. If the result status
671 * code indicates that there may be more replies, plan
672 * forwarding the request.
674 * @param cls closure (NULL)
675 * @param pr the pending request we were processing
676 * @param result final datastore lookup result
679 GSF_consider_forwarding (void *cls,
680 struct GSF_PendingRequest *pr,
681 enum GNUNET_BLOCK_EvaluationResult result)
683 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
684 return; /* we're done... */
686 GSF_pending_request_test_active_ (pr))
687 return; /* request is not actually active, skip! */
688 GSF_iterate_connected_peers_ (&consider_request_for_forwarding,
694 * Check P2P "GET" request.
697 * @param gm the actual message
698 * @return #GNUNET_OK to keep the connection open,
699 * #GNUNET_SYSERR to close it (signal serious error)
702 check_p2p_get (void *cls,
703 const struct GetMessage *gm)
710 msize = ntohs (gm->header.size);
711 bm = ntohl (gm->hash_bitmap);
719 if (msize < sizeof (struct GetMessage) + bits * sizeof (struct GNUNET_PeerIdentity))
722 return GNUNET_SYSERR;
724 bfsize = msize - sizeof (struct GetMessage) - bits * sizeof (struct GNUNET_PeerIdentity);
725 /* bfsize must be power of 2, check! */
726 if (0 != ((bfsize - 1) & bfsize))
729 return GNUNET_SYSERR;
736 * We're done with the local lookup, now consider
737 * P2P processing (depending on request options and
738 * result status). Also signal that we can now
739 * receive more request information from the client.
741 * @param cls the client doing the request (`struct GSF_LocalClient`)
742 * @param pr the pending request we were processing
743 * @param result final datastore lookup result
746 start_p2p_processing (void *cls,
747 struct GSF_PendingRequest *pr,
748 enum GNUNET_BLOCK_EvaluationResult result)
750 struct GSF_LocalClient *lc = cls;
751 struct GSF_PendingRequestData *prd;
753 GNUNET_SERVICE_client_continue (lc->client);
754 if (GNUNET_BLOCK_EVALUATION_OK_LAST == result)
755 return; /* we're done, 'pr' was already destroyed... */
756 prd = GSF_pending_request_get_data_ (pr);
757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
758 "Finished database lookup for local request `%s' with result %d\n",
759 GNUNET_h2s (&prd->query),
761 if (0 == prd->anonymity_level)
765 case GNUNET_BLOCK_TYPE_FS_DBLOCK:
766 case GNUNET_BLOCK_TYPE_FS_IBLOCK:
767 /* the above block types MAY be available via 'cadet' */
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769 "Considering cadet-based download for block\n");
770 GSF_cadet_lookup_ (pr);
772 case GNUNET_BLOCK_TYPE_FS_UBLOCK:
773 /* the above block types are in the DHT */
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775 "Considering DHT-based search for block\n");
776 GSF_dht_lookup_ (pr);
783 GSF_consider_forwarding (NULL,
790 * Check #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
793 * @param cls identification of the client
794 * @param sm the actual message
795 * @return #GNUNET_OK if @a sm is well-formed
798 check_client_start_search (void *cls,
799 const struct SearchMessage *sm)
803 msize = ntohs (sm->header.size) - sizeof (struct SearchMessage);
804 if (0 != msize % sizeof (struct GNUNET_HashCode))
807 return GNUNET_SYSERR;
814 * Handle #GNUNET_MESSAGE_TYPE_FS_START_SEARCH-message (search request
817 * Responsible for creating the request entry itself and setting
818 * up reply callback and cancellation on client disconnect.
820 * @param cls identification of the client
821 * @param sm the actual message
824 handle_client_start_search (void *cls,
825 const struct SearchMessage *sm)
827 static struct GNUNET_PeerIdentity all_zeros;
828 struct GSF_LocalClient *lc = cls;
829 struct ClientRequest *cr;
830 struct GSF_PendingRequestData *prd;
833 enum GNUNET_BLOCK_Type type;
834 enum GSF_PendingRequestOptions options;
836 GNUNET_STATISTICS_update (GSF_stats,
837 gettext_noop ("# client searches received"),
840 msize = ntohs (sm->header.size) - sizeof (struct SearchMessage);
841 sc = msize / sizeof (struct GNUNET_HashCode);
842 type = ntohl (sm->type);
843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
844 "Received request for `%s' of type %u from local client\n",
845 GNUNET_h2s (&sm->query),
846 (unsigned int) type);
848 /* detect duplicate UBLOCK requests */
849 if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) ||
850 (type == GNUNET_BLOCK_TYPE_ANY))
855 prd = GSF_pending_request_get_data_ (cr->pr);
856 /* only unify with queries that hae not yet started local processing
857 (SEARCH_MESSAGE_OPTION_CONTINUED was always set) and that have a
858 matching query and type */
859 if ((GNUNET_YES != prd->has_started) &&
860 (0 != memcmp (&prd->query,
862 sizeof (struct GNUNET_HashCode))) &&
870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871 "Have existing request, merging content-seen lists.\n");
872 GSF_pending_request_update_ (cr->pr,
873 (const struct GNUNET_HashCode *) &sm[1],
875 GNUNET_STATISTICS_update (GSF_stats,
876 gettext_noop ("# client searches updated (merged content seen list)"),
882 GNUNET_STATISTICS_update (GSF_stats,
883 gettext_noop ("# client searches active"),
886 cr = GNUNET_new (struct ClientRequest);
888 GNUNET_CONTAINER_DLL_insert (lc->cr_head,
891 options = GSF_PRO_LOCAL_REQUEST;
892 if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options)))
893 options |= GSF_PRO_LOCAL_ONLY;
894 cr->pr = GSF_pending_request_create_ (options, type,
899 sizeof (struct GNUNET_PeerIdentity)))
900 ? &sm->target : NULL, NULL, 0,
902 ntohl (sm->anonymity_level),
907 (const struct GNUNET_HashCode *) &sm[1], sc,
908 &client_response_handler,
911 if (0 != (SEARCH_MESSAGE_OPTION_CONTINUED & ntohl (sm->options)))
913 GNUNET_SERVICE_client_continue (lc->client);
916 GSF_pending_request_get_data_ (cr->pr)->has_started = GNUNET_YES;
917 GSF_local_lookup_ (cr->pr,
918 &start_p2p_processing,
924 * Handle request to sign a LOC URI (from client).
926 * @param cls identification of the client
927 * @param msg the actual message
930 handle_client_loc_sign (void *cls,
931 const struct RequestLocSignatureMessage *msg)
933 struct GSF_LocalClient *lc = cls;
934 struct GNUNET_FS_Uri base;
935 struct GNUNET_FS_Uri *loc;
936 struct GNUNET_MQ_Envelope *env;
937 struct ResponseLocSignatureMessage *resp;
939 GNUNET_break (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT ==
940 ntohl (msg->purpose));
941 base.type = GNUNET_FS_URI_CHK;
942 base.data.chk.chk = msg->chk;
943 base.data.chk.file_length = GNUNET_ntohll (msg->file_length);
944 loc = GNUNET_FS_uri_loc_create (&base,
946 GNUNET_TIME_absolute_ntoh (msg->expiration_time));
947 env = GNUNET_MQ_msg (resp,
948 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGNATURE);
949 resp->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT);
950 resp->expiration_time = GNUNET_TIME_absolute_hton (loc->data.loc.expirationTime);
951 resp->signature = loc->data.loc.contentSignature;
952 resp->peer = loc->data.loc.peer;
953 GNUNET_FS_uri_destroy (loc);
954 GNUNET_MQ_send (lc->mq,
956 GNUNET_SERVICE_client_continue (lc->client);
961 * Check INDEX_START-message.
963 * @param cls identification of the client
964 * @param ism the actual message
965 * @return #GNUNET_OK if @a ism is well-formed
968 check_client_index_start (void *cls,
969 const struct IndexStartMessage *ism)
974 msize = ntohs (ism->header.size);
975 if (((const char *) ism)[msize - 1] != '\0')
978 return GNUNET_SYSERR;
980 if (0 != ism->reserved)
983 return GNUNET_SYSERR;
985 fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
989 return GNUNET_SYSERR;
997 * We've validated the hash of the file we're about to index. Signal
998 * success to the client and update our internal data structures.
1000 * @param isc the data about the index info entry for the request
1003 signal_index_ok (struct IndexStartContext *isc)
1005 struct GSF_LocalClient *lc = isc->lc;
1006 struct GNUNET_MQ_Envelope *env;
1007 struct GNUNET_MessageHeader *msg;
1009 GNUNET_FS_add_to_index (isc->filename,
1011 env = GNUNET_MQ_msg (msg,
1012 GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK);
1013 GNUNET_MQ_send (lc->mq,
1015 GNUNET_free (isc->filename);
1017 GNUNET_SERVICE_client_continue (lc->client);
1022 * Function called once the hash computation over an
1023 * indexed file has completed.
1025 * @param cls closure, our publishing context
1026 * @param res resulting hash, NULL on error
1029 hash_for_index_val (void *cls,
1030 const struct GNUNET_HashCode *res)
1032 struct IndexStartContext *isc = cls;
1033 struct GSF_LocalClient *lc = isc->lc;
1034 struct GNUNET_MQ_Envelope *env;
1035 struct GNUNET_MessageHeader *msg;
1037 GNUNET_CONTAINER_DLL_remove (lc->isc_head,
1041 if ( (NULL == res) ||
1044 sizeof (struct GNUNET_HashCode))))
1046 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1047 _("Hash mismatch trying to index file `%s' which does not have hash `%s'\n"),
1049 GNUNET_h2s (&isc->file_id));
1050 env = GNUNET_MQ_msg (msg,
1051 GNUNET_MESSAGE_TYPE_FS_INDEX_START_FAILED);
1052 GNUNET_MQ_send (lc->mq,
1054 GNUNET_SERVICE_client_continue (lc->client);
1058 signal_index_ok (isc);
1063 * Handle INDEX_START-message.
1065 * @param cls identification of the client
1066 * @param message the actual message
1069 handle_client_index_start (void *cls,
1070 const struct IndexStartMessage *ism)
1072 struct GSF_LocalClient *lc = cls;
1073 struct IndexStartContext *isc;
1080 fn = GNUNET_STRINGS_filename_expand ((const char *) &ism[1]);
1081 GNUNET_assert (NULL != fn);
1082 dev = GNUNET_ntohll (ism->device);
1083 ino = GNUNET_ntohll (ism->inode);
1084 isc = GNUNET_new (struct IndexStartContext);
1086 isc->file_id = ism->file_id;
1087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1088 "Received START_INDEX message for file `%s'\n",
1093 if ( ( (dev != 0) ||
1095 (GNUNET_OK == GNUNET_DISK_file_get_identifiers (fn,
1101 /* fast validation OK! */
1102 signal_index_ok (isc);
1105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1106 "Mismatch in file identifiers (%llu != %llu or %u != %u), need to hash.\n",
1107 (unsigned long long) ino,
1108 (unsigned long long) myino,
1110 (unsigned int) mydev);
1111 /* slow validation, need to hash full file (again) */
1112 GNUNET_CONTAINER_DLL_insert (lc->isc_head,
1115 isc->fhc = GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
1118 &hash_for_index_val,
1120 if (NULL == isc->fhc)
1121 hash_for_index_val (isc,
1127 * Handle INDEX_LIST_GET-message.
1129 * @param cls closure
1130 * @param message the actual message
1133 handle_client_index_list_get (void *cls,
1134 const struct GNUNET_MessageHeader *message)
1136 struct GSF_LocalClient *lc = cls;
1138 GNUNET_FS_indexing_send_list (lc->mq);
1139 GNUNET_SERVICE_client_continue (lc->client);
1144 * Handle UNINDEX-message.
1146 * @param cls identification of the client
1147 * @param message the actual message
1150 handle_client_unindex (void *cls,
1151 const struct UnindexMessage *um)
1153 struct GSF_LocalClient *lc = cls;
1154 struct GNUNET_MQ_Envelope *env;
1155 struct GNUNET_MessageHeader *msg;
1158 GNUNET_break (0 == um->reserved);
1159 found = GNUNET_FS_indexing_do_unindex (&um->file_id);
1160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1161 "Client requested unindexing of file `%s': %s\n",
1162 GNUNET_h2s (&um->file_id),
1163 found ? "found" : "not found");
1164 env = GNUNET_MQ_msg (msg,
1165 GNUNET_MESSAGE_TYPE_FS_UNINDEX_OK);
1166 GNUNET_MQ_send (lc->mq,
1168 GNUNET_SERVICE_client_continue (lc->client);
1173 * Task run during shutdown.
1178 shutdown_task (void *cls)
1180 GSF_cadet_stop_server ();
1181 if (NULL != GSF_core)
1183 GNUNET_CORE_disconnect (GSF_core);
1186 if (NULL != GSF_ats)
1188 GNUNET_ATS_performance_done (GSF_ats);
1193 GSF_pending_request_done_ ();
1195 GSF_connected_peer_done_ ();
1196 GNUNET_DATASTORE_disconnect (GSF_dsh,
1199 GNUNET_DHT_disconnect (GSF_dht);
1201 GNUNET_BLOCK_context_destroy (GSF_block_ctx);
1202 GSF_block_ctx = NULL;
1203 GNUNET_CONFIGURATION_destroy (block_cfg);
1205 GNUNET_STATISTICS_destroy (GSF_stats, GNUNET_NO);
1207 if (NULL != cover_age_task)
1209 GNUNET_SCHEDULER_cancel (cover_age_task);
1210 cover_age_task = NULL;
1212 GNUNET_FS_indexing_done ();
1213 GNUNET_LOAD_value_free (datastore_get_load);
1214 datastore_get_load = NULL;
1215 GNUNET_LOAD_value_free (GSF_rt_entry_lifetime);
1216 GSF_rt_entry_lifetime = NULL;
1221 * Function called after GNUNET_CORE_connect has succeeded
1222 * (or failed for good). Note that the private key of the
1223 * peer is intentionally not exposed here; if you need it,
1224 * your process should try to read the private key file
1225 * directly (which should work if you are authorized...).
1227 * @param cls closure
1228 * @param my_identity ID of this peer, NULL if we failed
1231 peer_init_handler (void *cls,
1232 const struct GNUNET_PeerIdentity *my_identity)
1234 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&GSF_my_id,
1237 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1238 "Peer identity missmatch, refusing to start!\n");
1239 GNUNET_SCHEDULER_shutdown ();
1245 * Process fs requests.
1247 * @param c configuration to use
1250 main_init (const struct GNUNET_CONFIGURATION_Handle *c)
1252 struct GNUNET_MQ_MessageHandler no_p2p_handlers[] = {
1253 GNUNET_MQ_handler_end ()
1255 struct GNUNET_MQ_MessageHandler p2p_handlers[] = {
1256 GNUNET_MQ_hd_var_size (p2p_get,
1257 GNUNET_MESSAGE_TYPE_FS_GET,
1260 GNUNET_MQ_hd_var_size (p2p_put,
1261 GNUNET_MESSAGE_TYPE_FS_PUT,
1264 GNUNET_MQ_hd_fixed_size (p2p_migration_stop,
1265 GNUNET_MESSAGE_TYPE_FS_MIGRATION_STOP,
1266 struct MigrationStopMessage,
1268 GNUNET_MQ_handler_end ()
1273 /* this option is really only for testcases that need to disable
1274 _anonymous_ file-sharing for some reason */
1275 anon_p2p_off = (GNUNET_YES ==
1276 GNUNET_CONFIGURATION_get_value_yesno (GSF_cfg,
1278 "DISABLE_ANON_TRANSFER"));
1281 GNUNET_CONFIGURATION_get_value_filename (GSF_cfg,
1286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1287 _("FS service is lacking HOSTKEY configuration setting. Exiting.\n"));
1288 GNUNET_SCHEDULER_shutdown ();
1289 return GNUNET_SYSERR;
1291 pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
1292 GNUNET_free (keyfile);
1293 GNUNET_assert (NULL != pk);
1294 GNUNET_CRYPTO_eddsa_key_get_public (pk,
1295 &GSF_my_id.public_key);
1297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1299 GNUNET_i2s (&GSF_my_id));
1301 = GNUNET_CORE_connect (GSF_cfg,
1304 &GSF_peer_connect_handler,
1305 &GSF_peer_disconnect_handler,
1306 (GNUNET_YES == anon_p2p_off)
1309 if (NULL == GSF_core)
1311 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1312 _("Failed to connect to `%s' service.\n"),
1314 return GNUNET_SYSERR;
1317 GNUNET_SCHEDULER_add_delayed (COVER_AGE_FREQUENCY,
1318 &age_cover_counters,
1320 datastore_get_load = GNUNET_LOAD_value_init (DATASTORE_LOAD_AUTODECLINE);
1321 GSF_cadet_start_server ();
1322 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1329 * Process fs requests.
1331 * @param cls closure
1332 * @param cfg configuration to use
1333 * @param service the initialized service
1337 const struct GNUNET_CONFIGURATION_Handle *cfg,
1338 struct GNUNET_SERVICE_Handle *service)
1340 unsigned long long dqs;
1344 GNUNET_CONFIGURATION_get_value_size (GSF_cfg,
1346 "DATASTORE_QUEUE_SIZE",
1349 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO,
1351 "DATASTORE_QUEUE_SIZE");
1354 GSF_datastore_queue_size = (unsigned int) dqs;
1355 GSF_enable_randomized_delays =
1356 GNUNET_CONFIGURATION_get_value_yesno (cfg, "fs", "DELAY");
1357 GSF_dsh = GNUNET_DATASTORE_connect (cfg);
1358 if (NULL == GSF_dsh)
1360 GNUNET_SCHEDULER_shutdown ();
1363 GSF_rt_entry_lifetime = GNUNET_LOAD_value_init (GNUNET_TIME_UNIT_FOREVER_REL);
1364 GSF_stats = GNUNET_STATISTICS_create ("fs", cfg);
1365 block_cfg = GNUNET_CONFIGURATION_create ();
1366 GSF_block_ctx = GNUNET_BLOCK_context_create (block_cfg);
1367 GNUNET_assert (NULL != GSF_block_ctx);
1368 GSF_dht = GNUNET_DHT_connect (cfg, FS_DHT_HT_SIZE);
1370 GSF_pending_request_init_ ();
1371 GSF_connected_peer_init_ ();
1372 GSF_ats = GNUNET_ATS_performance_init (GSF_cfg,
1377 if ( (GNUNET_OK != GNUNET_FS_indexing_init (cfg,
1379 (GNUNET_OK != main_init (cfg)) )
1381 GNUNET_SCHEDULER_shutdown ();
1382 shutdown_task (NULL);
1389 * Define "main" method using service macro.
1393 GNUNET_SERVICE_OPTION_NONE,
1396 &client_disconnect_cb,
1398 GNUNET_MQ_hd_var_size (client_index_start,
1399 GNUNET_MESSAGE_TYPE_FS_INDEX_START,
1400 struct IndexStartMessage,
1402 GNUNET_MQ_hd_fixed_size (client_index_list_get,
1403 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET,
1404 struct GNUNET_MessageHeader,
1406 GNUNET_MQ_hd_fixed_size (client_unindex,
1407 GNUNET_MESSAGE_TYPE_FS_UNINDEX,
1408 struct UnindexMessage,
1410 GNUNET_MQ_hd_var_size (client_start_search,
1411 GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
1412 struct SearchMessage,
1414 GNUNET_MQ_hd_fixed_size (client_loc_sign,
1415 GNUNET_MESSAGE_TYPE_FS_REQUEST_LOC_SIGN,
1416 struct RequestLocSignatureMessage,
1418 GNUNET_MQ_handler_end ());
1421 /* end of gnunet-service-fs.c */