2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
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 2, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file fs/gnunet-service-fs.c
23 * @brief gnunet anonymity protocol implementation
24 * @author Christian Grothoff
27 * - have non-zero preference / priority for requests we initiate!
28 * - track stats for hot-path routing
29 * - implement hot-path routing decision procedure
30 * - implement: bound_priority, test_load_too_high, validate_skblock
31 * - add content migration support (store locally)
36 #include "gnunet_constants.h"
37 #include "gnunet_core_service.h"
38 #include "gnunet_datastore_service.h"
39 #include "gnunet_peer_lib.h"
40 #include "gnunet_protocols.h"
41 #include "gnunet_signatures.h"
42 #include "gnunet_util_lib.h"
43 #include "gnunet-service-fs_drq.h"
44 #include "gnunet-service-fs_indexing.h"
47 #define DEBUG_FS GNUNET_YES
50 * Maximum number of outgoing messages we queue per peer.
51 * FIXME: set to a tiny value for testing; make configurable.
53 #define MAX_QUEUE_PER_PEER 2
57 * What is the maximum delay for a P2P FS message (in our interaction
58 * with core)? FS-internal delays are another story. The value is
59 * chosen based on the 32k block size. Given that peers typcially
60 * have at least 1 kb/s bandwidth, 45s waits give us a chance to
61 * transmit one message even to the lowest-bandwidth peers.
63 #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 45)
68 * Maximum number of requests (from other peers) that we're
69 * willing to have pending at any given point in time.
70 * FIXME: set from configuration (and 32 is a tiny value for testing only).
72 static uint64_t max_pending_requests = 32;
76 * Information we keep for each pending reply. The
77 * actual message follows at the end of this struct.
79 struct PendingMessage;
83 * Function called upon completion of a transmission.
86 * @param pid ID of receiving peer, 0 on transmission error
88 typedef void (*TransmissionContinuation)(void * cls,
93 * Information we keep for each pending message (GET/PUT). The
94 * actual message follows at the end of this struct.
99 * This is a doubly-linked list of messages to the same peer.
101 struct PendingMessage *next;
104 * This is a doubly-linked list of messages to the same peer.
106 struct PendingMessage *prev;
109 * Entry in pending message list for this pending message.
111 struct PendingMessageList *pml;
114 * Function to call immediately once we have transmitted this
117 TransmissionContinuation cont;
125 * Size of the reply; actual reply message follows
126 * at the end of this struct.
131 * How important is this message for us?
139 * Information about a peer that we are connected to.
140 * We track data that is useful for determining which
141 * peers should receive our requests. We also keep
142 * a list of messages to transmit to this peer.
148 * List of the last clients for which this peer successfully
151 struct GNUNET_SERVER_Client *last_client_replies[CS2P_SUCCESS_LIST_SIZE];
154 * List of the last PIDs for which
155 * this peer successfully answered a query;
156 * We use 0 to indicate no successful reply.
158 GNUNET_PEER_Id last_p2p_replies[P2P_SUCCESS_LIST_SIZE];
161 * Average delay between sending the peer a request and
162 * getting a reply (only calculated over the requests for
163 * which we actually got a reply). Calculated
164 * as a moving average: new_delay = ((n-1)*last_delay+curr_delay) / n
166 struct GNUNET_TIME_Relative avg_delay;
169 * Handle for an active request for transmission to this
172 struct GNUNET_CORE_TransmitHandle *cth;
175 * Messages (replies, queries, content migration) we would like to
176 * send to this peer in the near future. Sorted by priority, head.
178 struct PendingMessage *pending_messages_head;
181 * Messages (replies, queries, content migration) we would like to
182 * send to this peer in the near future. Sorted by priority, tail.
184 struct PendingMessage *pending_messages_tail;
187 * Average priority of successful replies. Calculated
188 * as a moving average: new_avg = ((n-1)*last_avg+curr_prio) / n
193 * Increase in traffic preference still to be submitted
194 * to the core service for this peer. FIXME: double or 'uint64_t'?
196 double inc_preference;
199 * The peer's identity.
204 * Size of the linked list of 'pending_messages'.
206 unsigned int pending_requests;
209 * Which offset in "last_p2p_replies" will be updated next?
210 * (we go round-robin).
212 unsigned int last_p2p_replies_woff;
215 * Which offset in "last_client_replies" will be updated next?
216 * (we go round-robin).
218 unsigned int last_client_replies_woff;
224 * Information we keep for each pending request. We should try to
225 * keep this struct as small as possible since its memory consumption
226 * is key to how many requests we can have pending at once.
228 struct PendingRequest;
232 * Doubly-linked list of requests we are performing
233 * on behalf of the same client.
235 struct ClientRequestList
239 * This is a doubly-linked list.
241 struct ClientRequestList *next;
244 * This is a doubly-linked list.
246 struct ClientRequestList *prev;
249 * Request this entry represents.
251 struct PendingRequest *req;
254 * Client list this request belongs to.
256 struct ClientList *client_list;
262 * Replies to be transmitted to the client. The actual
263 * response message is allocated after this struct.
265 struct ClientResponseMessage
268 * This is a doubly-linked list.
270 struct ClientResponseMessage *next;
273 * This is a doubly-linked list.
275 struct ClientResponseMessage *prev;
278 * Client list entry this response belongs to.
280 struct ClientList *client_list;
283 * Number of bytes in the response.
290 * Linked list of clients we are performing requests
296 * This is a linked list.
298 struct ClientList *next;
301 * ID of a client making a request, NULL if this entry is for a
304 struct GNUNET_SERVER_Client *client;
307 * Head of list of requests performed on behalf
308 * of this client right now.
310 struct ClientRequestList *rl_head;
313 * Tail of list of requests performed on behalf
314 * of this client right now.
316 struct ClientRequestList *rl_tail;
319 * Head of linked list of responses.
321 struct ClientResponseMessage *res_head;
324 * Tail of linked list of responses.
326 struct ClientResponseMessage *res_tail;
329 * Context for sending replies.
331 struct GNUNET_CONNECTION_TransmitHandle *th;
337 * Doubly-linked list of messages we are performing
338 * due to a pending request.
340 struct PendingMessageList
344 * This is a doubly-linked list of messages on behalf of the same request.
346 struct PendingMessageList *next;
349 * This is a doubly-linked list of messages on behalf of the same request.
351 struct PendingMessageList *prev;
354 * Message this entry represents.
356 struct PendingMessage *pm;
359 * Request this entry belongs to.
361 struct PendingRequest *req;
364 * Peer this message is targeted for.
366 struct ConnectedPeer *target;
372 * Information we keep for each pending request. We should try to
373 * keep this struct as small as possible since its memory consumption
374 * is key to how many requests we can have pending at once.
376 struct PendingRequest
380 * If this request was made by a client, this is our entry in the
381 * client request list; otherwise NULL.
383 struct ClientRequestList *client_request_list;
386 * Entry of peer responsible for this entry (if this request
387 * was made by a peer).
389 struct ConnectedPeer *cp;
392 * If this is a namespace query, pointer to the hash of the public
393 * key of the namespace; otherwise NULL. Pointer will be to the
394 * end of this struct (so no need to free it).
396 const GNUNET_HashCode *namespace;
399 * Bloomfilter we use to filter out replies that we don't care about
400 * (anymore). NULL as long as we are interested in all replies.
402 struct GNUNET_CONTAINER_BloomFilter *bf;
405 * Context of our GNUNET_CORE_peer_change_preference call.
407 struct GNUNET_CORE_InformationRequestContext *irc;
410 * Hash code of all replies that we have seen so far (only valid
411 * if client is not NULL since we only track replies like this for
414 GNUNET_HashCode *replies_seen;
417 * Node in the heap representing this entry; NULL
418 * if we have no heap node.
420 struct GNUNET_CONTAINER_HeapNode *hnode;
423 * Head of list of messages being performed on behalf of this
426 struct PendingMessageList *pending_head;
429 * Tail of list of messages being performed on behalf of this
432 struct PendingMessageList *pending_tail;
435 * When did we first see this request (form this peer), or, if our
436 * client is initiating, when did we last initiate a search?
438 struct GNUNET_TIME_Absolute start_time;
441 * The query that this request is for.
443 GNUNET_HashCode query;
446 * The task responsible for transmitting queries
449 GNUNET_SCHEDULER_TaskIdentifier task;
452 * (Interned) Peer identifier that identifies a preferred target
455 GNUNET_PEER_Id target_pid;
458 * (Interned) Peer identifiers of peers that have already
459 * received our query for this content.
461 GNUNET_PEER_Id *used_pids;
464 * Our entry in the DRQ (non-NULL while we wait for our
465 * turn to interact with the local database).
467 struct DatastoreRequestQueue *drq;
470 * Size of the 'bf' (in bytes).
475 * Desired anonymity level; only valid for requests from a local client.
477 uint32_t anonymity_level;
480 * How many entries in "used_pids" are actually valid?
482 unsigned int used_pids_off;
485 * How long is the "used_pids" array?
487 unsigned int used_pids_size;
490 * Number of results found for this request.
492 unsigned int results_found;
495 * How many entries in "replies_seen" are actually valid?
497 unsigned int replies_seen_off;
500 * How long is the "replies_seen" array?
502 unsigned int replies_seen_size;
505 * Priority with which this request was made. If one of our clients
506 * made the request, then this is the current priority that we are
507 * using when initiating the request. This value is used when
508 * we decide to reward other peers with trust for providing a reply.
513 * Priority points left for us to spend when forwarding this request
516 uint32_t remaining_priority;
519 * Number to mingle hashes for bloom-filter tests with.
524 * TTL with which we saw this request (or, if we initiated, TTL that
525 * we used for the request).
530 * Type of the content that this request is for.
540 static struct GNUNET_SCHEDULER_Handle *sched;
545 static const struct GNUNET_CONFIGURATION_Handle *cfg;
548 * Map of peer identifiers to "struct ConnectedPeer" (for that peer).
550 static struct GNUNET_CONTAINER_MultiHashMap *connected_peers;
553 * Map of peer identifiers to "struct PendingRequest" (for that peer).
555 static struct GNUNET_CONTAINER_MultiHashMap *peer_request_map;
558 * Map of query identifiers to "struct PendingRequest" (for that query).
560 static struct GNUNET_CONTAINER_MultiHashMap *query_request_map;
563 * Heap with the request that will expire next at the top. Contains
564 * pointers of type "struct PendingRequest*"; these will *also* be
565 * aliased from the "requests_by_peer" data structures and the
566 * "requests_by_query" table. Note that requests from our clients
567 * don't expire and are thus NOT in the "requests_by_expiration"
568 * (or the "requests_by_peer" tables).
570 static struct GNUNET_CONTAINER_Heap *requests_by_expiration_heap;
573 * Linked list of clients we are currently processing requests for.
575 struct ClientList *client_list;
578 * Pointer to handle to the core service (points to NULL until we've
581 struct GNUNET_CORE_Handle *core;
584 /* ******************* clean up functions ************************ */
588 * We're done with a particular message list entry.
589 * Free all associated resources.
591 * @param pml entry to destroy
594 destroy_pending_message_list_entry (struct PendingMessageList *pml)
596 GNUNET_CONTAINER_DLL_remove (pml->req->pending_head,
597 pml->req->pending_tail,
599 GNUNET_CONTAINER_DLL_remove (pml->target->pending_messages_head,
600 pml->target->pending_messages_tail,
602 pml->target->pending_requests--;
603 GNUNET_free (pml->pm);
609 * Destroy the given pending message (and call the respective
612 * @param pm message to destroy
613 * @param tpid id of peer that the message was delivered to, or 0 for none
616 destroy_pending_message (struct PendingMessage *pm,
619 struct PendingMessageList *pml = pm->pml;
620 TransmissionContinuation cont;
623 GNUNET_assert (pml->pm == pm);
624 GNUNET_assert ( (tpid == 0) || (tpid == pml->target->pid) );
626 cont_cls = pm->cont_cls;
627 destroy_pending_message_list_entry (pml);
633 * We're done processing a particular request.
634 * Free all associated resources.
636 * @param pr request to destroy
639 destroy_pending_request (struct PendingRequest *pr)
641 struct GNUNET_PeerIdentity pid;
643 if (pr->hnode != NULL)
645 GNUNET_CONTAINER_heap_remove_node (requests_by_expiration_heap,
649 /* might have already been removed from map in 'process_reply' (if
650 there was a unique reply) or never inserted if it was a
651 duplicate; hence ignore the return value here */
652 (void) GNUNET_CONTAINER_multihashmap_remove (query_request_map,
657 GNUNET_FS_drq_get_cancel (pr->drq);
660 if (pr->client_request_list != NULL)
662 GNUNET_CONTAINER_DLL_remove (pr->client_request_list->client_list->rl_head,
663 pr->client_request_list->client_list->rl_tail,
664 pr->client_request_list);
665 GNUNET_free (pr->client_request_list);
666 pr->client_request_list = NULL;
670 GNUNET_PEER_resolve (pr->cp->pid,
672 (void) GNUNET_CONTAINER_multihashmap_remove (peer_request_map,
679 GNUNET_CONTAINER_bloomfilter_free (pr->bf);
684 GNUNET_CORE_peer_change_preference_cancel (pr->irc);
687 if (pr->replies_seen != NULL)
689 GNUNET_free (pr->replies_seen);
690 pr->replies_seen = NULL;
692 if (pr->task != GNUNET_SCHEDULER_NO_TASK)
694 GNUNET_SCHEDULER_cancel (sched,
696 pr->task = GNUNET_SCHEDULER_NO_TASK;
698 while (NULL != pr->pending_head)
699 destroy_pending_message_list_entry (pr->pending_head);
700 GNUNET_PEER_change_rc (pr->target_pid, -1);
701 if (pr->used_pids != NULL)
703 GNUNET_PEER_decrement_rcs (pr->used_pids, pr->used_pids_off);
704 GNUNET_free (pr->used_pids);
705 pr->used_pids_off = 0;
706 pr->used_pids_size = 0;
707 pr->used_pids = NULL;
714 * Method called whenever a given peer connects.
716 * @param cls closure, not used
717 * @param peer peer identity this notification is about
718 * @param latency reported latency of the connection with 'other'
719 * @param distance reported distance (DV) to 'other'
722 peer_connect_handler (void *cls,
724 GNUNET_PeerIdentity * peer,
725 struct GNUNET_TIME_Relative latency,
728 struct ConnectedPeer *cp;
730 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
731 cp->pid = GNUNET_PEER_intern (peer);
732 GNUNET_CONTAINER_multihashmap_put (connected_peers,
735 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
740 * Free (each) request made by the peer.
742 * @param cls closure, points to peer that the request belongs to
743 * @param key current key code
744 * @param value value in the hash map
745 * @return GNUNET_YES (we should continue to iterate)
748 destroy_request (void *cls,
749 const GNUNET_HashCode * key,
752 const struct GNUNET_PeerIdentity * peer = cls;
753 struct PendingRequest *pr = value;
755 GNUNET_CONTAINER_multihashmap_remove (peer_request_map,
758 destroy_pending_request (pr);
764 * Method called whenever a peer disconnects.
766 * @param cls closure, not used
767 * @param peer peer identity this notification is about
770 peer_disconnect_handler (void *cls,
772 GNUNET_PeerIdentity * peer)
774 struct ConnectedPeer *cp;
775 struct PendingMessage *pm;
778 GNUNET_CONTAINER_multihashmap_get_multiple (peer_request_map,
782 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
786 for (i=0;i<CS2P_SUCCESS_LIST_SIZE;i++)
788 if (NULL != cp->last_client_replies[i])
790 GNUNET_SERVER_client_drop (cp->last_client_replies[i]);
791 cp->last_client_replies[i] = NULL;
794 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
797 GNUNET_PEER_change_rc (cp->pid, -1);
798 GNUNET_PEER_decrement_rcs (cp->last_p2p_replies, P2P_SUCCESS_LIST_SIZE);
800 GNUNET_CORE_notify_transmit_ready_cancel (cp->cth);
801 while (NULL != (pm = cp->pending_messages_head))
802 destroy_pending_message (pm, 0 /* delivery failed */);
803 GNUNET_break (0 == cp->pending_requests);
809 * Iterator over hash map entries that removes all occurences
810 * of the given 'client' from the 'last_client_replies' of the
811 * given connected peer.
813 * @param cls closure, the 'struct GNUNET_SERVER_Client*' to remove
814 * @param key current key code (unused)
815 * @param value value in the hash map (the 'struct ConnectedPeer*' to change)
816 * @return GNUNET_YES (we should continue to iterate)
819 remove_client_from_last_client_replies (void *cls,
820 const GNUNET_HashCode * key,
823 struct GNUNET_SERVER_Client *client = cls;
824 struct ConnectedPeer *cp = value;
827 for (i=0;i<CS2P_SUCCESS_LIST_SIZE;i++)
829 if (cp->last_client_replies[i] == client)
831 GNUNET_SERVER_client_drop (cp->last_client_replies[i]);
832 cp->last_client_replies[i] = NULL;
840 * A client disconnected. Remove all of its pending queries.
842 * @param cls closure, NULL
843 * @param client identification of the client
846 handle_client_disconnect (void *cls,
847 struct GNUNET_SERVER_Client
850 struct ClientList *pos;
851 struct ClientList *prev;
852 struct ClientRequestList *rcl;
853 struct ClientResponseMessage *creply;
859 while ( (NULL != pos) &&
860 (pos->client != client) )
866 return; /* no requests pending for this client */
867 while (NULL != (rcl = pos->rl_head))
868 destroy_pending_request (rcl->req);
870 client_list = pos->next;
872 prev->next = pos->next;
875 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
878 while (NULL != (creply = pos->res_head))
880 GNUNET_CONTAINER_DLL_remove (pos->res_head,
883 GNUNET_free (creply);
885 GNUNET_SERVER_client_drop (pos->client);
887 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
888 &remove_client_from_last_client_replies,
894 * Iterator to free peer entries.
896 * @param cls closure, unused
897 * @param key current key code
898 * @param value value in the hash map (peer entry)
899 * @return GNUNET_YES (we should continue to iterate)
902 clean_peer (void *cls,
903 const GNUNET_HashCode * key,
906 peer_disconnect_handler (NULL, (const struct GNUNET_PeerIdentity*) key);
912 * Task run during shutdown.
918 shutdown_task (void *cls,
919 const struct GNUNET_SCHEDULER_TaskContext *tc)
921 while (client_list != NULL)
922 handle_client_disconnect (NULL,
923 client_list->client);
924 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
927 GNUNET_break (0 == GNUNET_CONTAINER_heap_get_size (requests_by_expiration_heap));
928 GNUNET_CONTAINER_heap_destroy (requests_by_expiration_heap);
929 requests_by_expiration_heap = 0;
930 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
931 connected_peers = NULL;
932 GNUNET_break (0 == GNUNET_CONTAINER_multihashmap_size (query_request_map));
933 GNUNET_CONTAINER_multihashmap_destroy (query_request_map);
934 query_request_map = NULL;
935 GNUNET_break (0 == GNUNET_CONTAINER_multihashmap_size (peer_request_map));
936 GNUNET_CONTAINER_multihashmap_destroy (peer_request_map);
937 peer_request_map = NULL;
938 GNUNET_assert (NULL != core);
939 GNUNET_CORE_disconnect (core);
946 /* ******************* Utility functions ******************** */
950 * Transmit the given message by copying it to the target buffer
951 * "buf". "buf" will be NULL and "size" zero if the socket was closed
952 * for writing in the meantime. In that case, do nothing
953 * (the disconnect or shutdown handler will take care of the rest).
954 * If we were able to transmit messages and there are still more
955 * pending, ask core again for further calls to this function.
957 * @param cls closure, pointer to the 'struct ConnectedPeer*'
958 * @param size number of bytes available in buf
959 * @param buf where the callee should write the message
960 * @return number of bytes written to buf
963 transmit_to_peer (void *cls,
964 size_t size, void *buf)
966 struct ConnectedPeer *cp = cls;
968 struct GNUNET_PeerIdentity pid;
969 struct PendingMessage *pm;
976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977 "Dropping message, core too busy.\n");
982 while ( (NULL != (pm = cp->pending_messages_head) ) &&
983 (pm->msize <= size) )
985 memcpy (&cbuf[msize], &pm[1], pm->msize);
988 destroy_pending_message (pm, cp->pid);
992 GNUNET_PEER_resolve (cp->pid,
994 cp->cth = GNUNET_CORE_notify_transmit_ready (core,
996 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1004 "Transmitting %u bytes to peer %u.\n",
1013 * Add a message to the set of pending messages for the given peer.
1015 * @param cp peer to send message to
1016 * @param pm message to queue
1017 * @param pr request on which behalf this message is being queued
1020 add_to_pending_messages_for_peer (struct ConnectedPeer *cp,
1021 struct PendingMessage *pm,
1022 struct PendingRequest *pr)
1024 struct PendingMessage *pos;
1025 struct PendingMessageList *pml;
1026 struct GNUNET_PeerIdentity pid;
1028 GNUNET_assert (pm->next == NULL);
1029 GNUNET_assert (pm->pml == NULL);
1030 pml = GNUNET_malloc (sizeof (struct PendingMessageList));
1035 GNUNET_CONTAINER_DLL_insert (pr->pending_head,
1038 pos = cp->pending_messages_head;
1039 while ( (pos != NULL) &&
1040 (pm->priority < pos->priority) )
1042 GNUNET_CONTAINER_DLL_insert_after (cp->pending_messages_head,
1043 cp->pending_messages_tail,
1046 cp->pending_requests++;
1047 if (cp->pending_requests > MAX_QUEUE_PER_PEER)
1048 destroy_pending_message (cp->pending_messages_tail, 0);
1049 if (cp->cth == NULL)
1051 /* need to schedule transmission */
1052 GNUNET_PEER_resolve (cp->pid, &pid);
1053 cp->cth = GNUNET_CORE_notify_transmit_ready (core,
1054 cp->pending_messages_head->priority,
1057 cp->pending_messages_head->msize,
1061 if (cp->cth == NULL)
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065 "Failed to schedule transmission with core!\n");
1067 /* FIXME: call stats (rare, bad case) */
1073 * Mingle hash with the mingle_number to produce different bits.
1076 mingle_hash (const GNUNET_HashCode * in,
1077 int32_t mingle_number,
1078 GNUNET_HashCode * hc)
1082 GNUNET_CRYPTO_hash (&mingle_number,
1085 GNUNET_CRYPTO_hash_xor (&m, in, hc);
1090 * Test if the load on this peer is too high
1091 * to even consider processing the query at
1094 * @return GNUNET_YES if the load is too high, GNUNET_NO otherwise
1097 test_load_too_high ()
1099 return GNUNET_NO; // FIXME
1103 /* ******************* Pending Request Refresh Task ******************** */
1108 * We use a random delay to make the timing of requests less
1109 * predictable. This function returns such a random delay.
1111 * FIXME: make schedule dependent on the specifics of the request?
1112 * Or bandwidth and number of connected peers and load?
1114 * @return random delay to use for some request, between 0 and TTL_DECREMENT ms
1116 static struct GNUNET_TIME_Relative
1117 get_processing_delay ()
1119 return GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1120 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1126 * We're processing a GET request from another peer and have decided
1127 * to forward it to other peers. This function is called periodically
1128 * and should forward the request to other peers until we have all
1129 * possible replies. If we have transmitted the *only* reply to
1130 * the initiator we should destroy the pending request. If we have
1131 * many replies in the queue to the initiator, we should delay sending
1132 * out more queries until the reply queue has shrunk some.
1134 * @param cls our "struct ProcessGetContext *"
1138 forward_request_task (void *cls,
1139 const struct GNUNET_SCHEDULER_TaskContext *tc);
1143 * Function called after we either failed or succeeded
1144 * at transmitting a query to a peer.
1146 * @param cls the requests "struct PendingRequest*"
1147 * @param tpid ID of receiving peer, 0 on transmission error
1150 transmit_query_continuation (void *cls,
1151 GNUNET_PEER_Id tpid)
1153 struct PendingRequest *pr = cls;
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158 "Transmission of request failed, will try again later.\n");
1159 pr->task = GNUNET_SCHEDULER_add_delayed (sched,
1160 get_processing_delay (),
1161 &forward_request_task,
1165 GNUNET_PEER_change_rc (tpid, 1);
1166 if (pr->used_pids_off == pr->used_pids_size)
1167 GNUNET_array_grow (pr->used_pids,
1169 pr->used_pids_size * 2 + 2);
1170 pr->used_pids[pr->used_pids_off++] = tpid;
1171 pr->task = GNUNET_SCHEDULER_add_delayed (sched,
1172 get_processing_delay (),
1173 &forward_request_task,
1179 * How many bytes should a bloomfilter be if we have already seen
1180 * entry_count responses? Note that BLOOMFILTER_K gives us the number
1181 * of bits set per entry. Furthermore, we should not re-size the
1182 * filter too often (to keep it cheap).
1184 * Since other peers will also add entries but not resize the filter,
1185 * we should generally pick a slightly larger size than what the
1186 * strict math would suggest.
1188 * @return must be a power of two and smaller or equal to 2^15.
1191 compute_bloomfilter_size (unsigned int entry_count)
1194 unsigned int ideal = (entry_count * BLOOMFILTER_K) / 4;
1195 uint16_t max = 1 << 15;
1197 if (entry_count > max)
1200 while ((size < max) && (size < ideal))
1209 * Recalculate our bloom filter for filtering replies.
1211 * @param count number of entries we are filtering right now
1212 * @param mingle set to our new mingling value
1213 * @param bf_size set to the size of the bloomfilter
1214 * @param entries the entries to filter
1215 * @return updated bloomfilter, NULL for none
1217 static struct GNUNET_CONTAINER_BloomFilter *
1218 refresh_bloomfilter (unsigned int count,
1221 const GNUNET_HashCode *entries)
1223 struct GNUNET_CONTAINER_BloomFilter *bf;
1226 GNUNET_HashCode mhash;
1230 nsize = compute_bloomfilter_size (count);
1231 *mingle = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, -1);
1233 bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
1236 for (i=0;i<count;i++)
1238 mingle_hash (&entries[i], *mingle, &mhash);
1239 GNUNET_CONTAINER_bloomfilter_add (bf, &mhash);
1246 * Function called after we've tried to reserve a certain amount of
1247 * bandwidth for a reply. Check if we succeeded and if so send our
1250 * @param cls the requests "struct PendingRequest*"
1251 * @param peer identifies the peer
1252 * @param bpm_in set to the current bandwidth limit (receiving) for this peer
1253 * @param bpm_out set to the current bandwidth limit (sending) for this peer
1254 * @param amount set to the amount that was actually reserved or unreserved
1255 * @param preference current traffic preference for the given peer
1258 target_reservation_cb (void *cls,
1260 GNUNET_PeerIdentity * peer,
1261 struct GNUNET_BANDWIDTH_Value32NBO bpm_in,
1262 struct GNUNET_BANDWIDTH_Value32NBO bpm_out,
1264 uint64_t preference)
1266 struct PendingRequest *pr = cls;
1267 struct ConnectedPeer *cp;
1268 struct PendingMessage *pm;
1269 struct GetMessage *gm;
1270 GNUNET_HashCode *ext;
1278 GNUNET_assert (peer != NULL);
1279 // (3) transmit, update ttl/priority
1280 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1284 /* Peer must have just left */
1286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1287 "Selected peer disconnected!\n");
1289 pr->task = GNUNET_SCHEDULER_add_delayed (sched,
1290 get_processing_delay (),
1291 &forward_request_task,
1295 no_route = GNUNET_NO;
1296 /* FIXME: check against DBLOCK_SIZE and possibly return
1297 amount to reserve; however, this also needs to work
1298 with testcases which currently start out with a far
1299 too low per-peer bw limit, so they would never send
1300 anything. Big issue. */
1306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1307 "Failed to reserve bandwidth for reply (got %d/%u bytes only)!\n",
1311 pr->task = GNUNET_SCHEDULER_add_delayed (sched,
1312 get_processing_delay (),
1313 &forward_request_task,
1315 return; /* this target round failed */
1317 /* FIXME: if we are "quite" busy, we may still want to skip
1318 this round; need more load detection code! */
1319 no_route = GNUNET_YES;
1322 /* build message and insert message into priority queue */
1324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1325 "Forwarding request `%s' to `%4s'!\n",
1326 GNUNET_h2s (&pr->query),
1331 if (GNUNET_YES == no_route)
1333 bm |= GET_MESSAGE_BIT_RETURN_TO;
1336 if (pr->namespace != NULL)
1338 bm |= GET_MESSAGE_BIT_SKS_NAMESPACE;
1341 if (pr->target_pid != 0)
1343 bm |= GET_MESSAGE_BIT_TRANSMIT_TO;
1346 msize = sizeof (struct GetMessage) + pr->bf_size + k * sizeof(GNUNET_HashCode);
1347 GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1348 pm = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1350 gm = (struct GetMessage*) &pm[1];
1351 gm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_GET);
1352 gm->header.size = htons (msize);
1353 gm->type = htonl (pr->type);
1354 pr->remaining_priority /= 2;
1355 gm->priority = htonl (pr->remaining_priority);
1356 gm->ttl = htonl (pr->ttl);
1357 gm->filter_mutator = htonl(pr->mingle);
1358 gm->hash_bitmap = htonl (bm);
1359 gm->query = pr->query;
1360 ext = (GNUNET_HashCode*) &gm[1];
1362 if (GNUNET_YES == no_route)
1363 GNUNET_PEER_resolve (pr->cp->pid, (struct GNUNET_PeerIdentity*) &ext[k++]);
1364 if (pr->namespace != NULL)
1365 memcpy (&ext[k++], pr->namespace, sizeof (GNUNET_HashCode));
1366 if (pr->target_pid != 0)
1367 GNUNET_PEER_resolve (pr->target_pid, (struct GNUNET_PeerIdentity*) &ext[k++]);
1368 bfdata = (char *) &ext[k];
1370 GNUNET_CONTAINER_bloomfilter_get_raw_data (pr->bf,
1373 pm->cont = &transmit_query_continuation;
1375 add_to_pending_messages_for_peer (cp, pm, pr);
1380 * Closure used for "target_peer_select_cb".
1382 struct PeerSelectionContext
1385 * The request for which we are selecting
1388 struct PendingRequest *pr;
1391 * Current "prime" target.
1393 struct GNUNET_PeerIdentity target;
1396 * How much do we like this target?
1398 double target_score;
1404 * Function called for each connected peer to determine
1405 * which one(s) would make good targets for forwarding.
1407 * @param cls closure (struct PeerSelectionContext)
1408 * @param key current key code (peer identity)
1409 * @param value value in the hash map (struct ConnectedPeer)
1410 * @return GNUNET_YES if we should continue to
1415 target_peer_select_cb (void *cls,
1416 const GNUNET_HashCode * key,
1419 struct PeerSelectionContext *psc = cls;
1420 struct ConnectedPeer *cp = value;
1421 struct PendingRequest *pr = psc->pr;
1425 /* 1) check if we have already (recently) forwarded to this peer */
1426 for (i=0;i<pr->used_pids_off;i++)
1427 if (pr->used_pids[i] == cp->pid)
1428 return GNUNET_YES; /* skip */
1429 // 2) calculate how much we'd like to forward to this peer
1430 score = 42; // FIXME!
1431 // FIXME: also need API to gather data on responsiveness
1432 // of this peer (we have fields for that in 'cp', but
1433 // they are never set!)
1435 /* store best-fit in closure */
1436 if (score > psc->target_score)
1438 psc->target_score = score;
1439 psc->target.hashPubKey = *key;
1446 * We're processing a GET request from another peer and have decided
1447 * to forward it to other peers. This function is called periodically
1448 * and should forward the request to other peers until we have all
1449 * possible replies. If we have transmitted the *only* reply to
1450 * the initiator we should destroy the pending request. If we have
1451 * many replies in the queue to the initiator, we should delay sending
1452 * out more queries until the reply queue has shrunk some.
1454 * @param cls our "struct ProcessGetContext *"
1458 forward_request_task (void *cls,
1459 const struct GNUNET_SCHEDULER_TaskContext *tc)
1461 struct PendingRequest *pr = cls;
1462 struct PeerSelectionContext psc;
1463 struct ConnectedPeer *cp;
1465 pr->task = GNUNET_SCHEDULER_NO_TASK;
1466 GNUNET_assert (pr->irc == NULL);
1467 /* (1) select target */
1469 psc.target_score = DBL_MIN;
1470 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1471 &target_peer_select_cb,
1473 if (psc.target_score == DBL_MIN)
1476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477 "No peer selected for forwarding!\n");
1479 pr->task = GNUNET_SCHEDULER_add_delayed (sched,
1480 get_processing_delay (),
1481 &forward_request_task,
1483 return; /* nobody selected */
1486 /* (2) reserve reply bandwidth */
1487 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1488 &psc.target.hashPubKey);
1489 pr->irc = GNUNET_CORE_peer_change_preference (sched, cfg,
1491 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
1492 GNUNET_BANDWIDTH_value_init ((uint32_t) -1 /* no limit */),
1494 (uint64_t) cp->inc_preference,
1495 &target_reservation_cb,
1497 cp->inc_preference = 0.0;
1501 /* **************************** P2P PUT Handling ************************ */
1505 * Function called after we either failed or succeeded
1506 * at transmitting a reply to a peer.
1508 * @param cls the requests "struct PendingRequest*"
1509 * @param tpid ID of receiving peer, 0 on transmission error
1512 transmit_reply_continuation (void *cls,
1513 GNUNET_PEER_Id tpid)
1515 struct PendingRequest *pr = cls;
1519 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
1520 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
1521 /* only one reply expected, done with the request! */
1522 destroy_pending_request (pr);
1524 case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
1525 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
1535 * Check if the given KBlock is well-formed.
1537 * @param kb the kblock data (or at least "dsize" bytes claiming to be one)
1538 * @param dsize size of "kb" in bytes; check for < sizeof(struct KBlock)!
1539 * @param query where to store the query that this block answers
1540 * @return GNUNET_OK if this is actually a well-formed KBlock
1543 check_kblock (const struct KBlock *kb,
1545 GNUNET_HashCode *query)
1547 if (dsize < sizeof (struct KBlock))
1549 GNUNET_break_op (0);
1550 return GNUNET_SYSERR;
1552 if (dsize - sizeof (struct KBlock) !=
1553 ntohs (kb->purpose.size)
1554 - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)
1555 - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) )
1557 GNUNET_break_op (0);
1558 return GNUNET_SYSERR;
1561 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK,
1566 GNUNET_break_op (0);
1567 return GNUNET_SYSERR;
1570 GNUNET_CRYPTO_hash (&kb->keyspace,
1571 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1578 * Check if the given SBlock is well-formed.
1580 * @param sb the sblock data (or at least "dsize" bytes claiming to be one)
1581 * @param dsize size of "kb" in bytes; check for < sizeof(struct SBlock)!
1582 * @param query where to store the query that this block answers
1583 * @param namespace where to store the namespace that this block belongs to
1584 * @return GNUNET_OK if this is actually a well-formed SBlock
1587 check_sblock (const struct SBlock *sb,
1589 GNUNET_HashCode *query,
1590 GNUNET_HashCode *namespace)
1592 if (dsize < sizeof (struct SBlock))
1594 GNUNET_break_op (0);
1595 return GNUNET_SYSERR;
1598 ntohs (sb->purpose.size) + sizeof (struct GNUNET_CRYPTO_RsaSignature))
1600 GNUNET_break_op (0);
1601 return GNUNET_SYSERR;
1604 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK,
1609 GNUNET_break_op (0);
1610 return GNUNET_SYSERR;
1613 *query = sb->identifier;
1614 if (namespace != NULL)
1615 GNUNET_CRYPTO_hash (&sb->subspace,
1616 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1623 * Transmit the given message by copying it to the target buffer
1624 * "buf". "buf" will be NULL and "size" zero if the socket was closed
1625 * for writing in the meantime. In that case, do nothing
1626 * (the disconnect or shutdown handler will take care of the rest).
1627 * If we were able to transmit messages and there are still more
1628 * pending, ask core again for further calls to this function.
1630 * @param cls closure, pointer to the 'struct ClientList*'
1631 * @param size number of bytes available in buf
1632 * @param buf where the callee should write the message
1633 * @return number of bytes written to buf
1636 transmit_to_client (void *cls,
1637 size_t size, void *buf)
1639 struct ClientList *cl = cls;
1641 struct ClientResponseMessage *creply;
1648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1649 "Not sending reply, client communication problem.\n");
1654 while ( (NULL != (creply = cl->res_head) ) &&
1655 (creply->msize <= size) )
1657 memcpy (&cbuf[msize], &creply[1], creply->msize);
1658 msize += creply->msize;
1659 size -= creply->msize;
1660 GNUNET_CONTAINER_DLL_remove (cl->res_head,
1663 GNUNET_free (creply);
1666 cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client,
1668 GNUNET_TIME_UNIT_FOREVER_REL,
1669 &transmit_to_client,
1672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1673 "Transmitted %u bytes to client\n",
1674 (unsigned int) msize);
1681 * Closure for "process_reply" function.
1683 struct ProcessReplyClosure
1686 * The data for the reply.
1690 // FIXME: add 'struct ConnectedPeer' to track 'last_xxx_replies' here!
1693 * When the reply expires.
1695 struct GNUNET_TIME_Absolute expiration;
1703 * Namespace that this reply belongs to
1704 * (if it is of type SBLOCK).
1706 GNUNET_HashCode namespace;
1709 * Type of the block.
1714 * How much was this reply worth to us?
1721 * We have received a reply; handle it!
1723 * @param cls response (struct ProcessReplyClosure)
1724 * @param key our query
1725 * @param value value in the hash map (info about the query)
1726 * @return GNUNET_YES (we should continue to iterate)
1729 process_reply (void *cls,
1730 const GNUNET_HashCode * key,
1733 struct ProcessReplyClosure *prq = cls;
1734 struct PendingRequest *pr = value;
1735 struct PendingMessage *reply;
1736 struct ClientResponseMessage *creply;
1737 struct ClientList *cl;
1738 struct PutMessage *pm;
1739 struct ConnectedPeer *cp;
1740 GNUNET_HashCode chash;
1741 GNUNET_HashCode mhash;
1746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1747 "Matched result (type %u) for query `%s' with pending request\n",
1748 (unsigned int) prq->type,
1751 do_remove = GNUNET_NO;
1752 GNUNET_CRYPTO_hash (prq->data,
1757 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
1758 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
1759 /* only possible reply, stop requesting! */
1760 while (NULL != pr->pending_head)
1761 destroy_pending_message_list_entry (pr->pending_head);
1762 if (pr->drq != NULL)
1764 if (pr->client_request_list != NULL)
1765 GNUNET_SERVER_receive_done (pr->client_request_list->client_list->client,
1767 GNUNET_FS_drq_get_cancel (pr->drq);
1770 do_remove = GNUNET_YES;
1772 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
1773 if (0 != memcmp (pr->namespace,
1775 sizeof (GNUNET_HashCode)))
1776 return GNUNET_YES; /* wrong namespace */
1777 /* then: fall-through! */
1778 case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
1781 mingle_hash (&chash, pr->mingle, &mhash);
1782 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (pr->bf,
1784 return GNUNET_YES; /* duplicate */
1785 GNUNET_CONTAINER_bloomfilter_add (pr->bf,
1788 if (pr->client_request_list != NULL)
1790 if (pr->replies_seen_size == pr->replies_seen_off)
1792 GNUNET_array_grow (pr->replies_seen,
1793 pr->replies_seen_size,
1794 pr->replies_seen_size * 2 + 4);
1796 GNUNET_CONTAINER_bloomfilter_free (pr->bf);
1797 pr->bf = refresh_bloomfilter (pr->replies_seen_off,
1802 pr->replies_seen[pr->replies_seen_off++] = chash;
1806 case GNUNET_DATASTORE_BLOCKTYPE_SKBLOCK:
1807 // FIXME: any checks against duplicates for SKBlocks?
1813 prq->priority += pr->remaining_priority;
1814 pr->remaining_priority = 0;
1815 if (pr->client_request_list != NULL)
1818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1819 "Transmitting result for query `%s' to local client\n",
1822 cl = pr->client_request_list->client_list;
1823 msize = sizeof (struct PutMessage) + prq->size;
1824 creply = GNUNET_malloc (msize + sizeof (struct ClientResponseMessage));
1825 creply->msize = msize;
1826 creply->client_list = cl;
1827 GNUNET_CONTAINER_DLL_insert_after (cl->res_head,
1831 pm = (struct PutMessage*) &creply[1];
1832 pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT);
1833 pm->header.size = htons (msize);
1834 pm->type = htonl (prq->type);
1835 pm->expiration = GNUNET_TIME_absolute_hton (prq->expiration);
1836 memcpy (&pm[1], prq->data, prq->size);
1838 cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client,
1840 GNUNET_TIME_UNIT_FOREVER_REL,
1841 &transmit_to_client,
1843 GNUNET_break (cl->th != NULL);
1849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1850 "Transmitting result for query `%s' to other peer (PID=%u)\n",
1852 (unsigned int) cp->pid);
1854 msize = sizeof (struct PutMessage) + prq->size;
1855 reply = GNUNET_malloc (msize + sizeof (struct PendingMessage));
1856 reply->cont = &transmit_reply_continuation;
1857 reply->cont_cls = pr;
1858 reply->msize = msize;
1859 reply->priority = (uint32_t) -1; /* send replies first! */
1860 pm = (struct PutMessage*) &reply[1];
1861 pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT);
1862 pm->header.size = htons (msize);
1863 pm->type = htonl (prq->type);
1864 pm->expiration = GNUNET_TIME_absolute_hton (prq->expiration);
1865 memcpy (&pm[1], prq->data, prq->size);
1866 add_to_pending_messages_for_peer (cp, reply, pr);
1868 if (GNUNET_YES == do_remove)
1870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1871 "Removing request `%s' from request map (has been satisfied)\n",
1873 GNUNET_break (GNUNET_YES ==
1874 GNUNET_CONTAINER_multihashmap_remove (query_request_map,
1877 // FIXME: request somehow does not fully
1878 // disappear; how to fix?
1879 // destroy_pending_request (pr); (not like this!)
1882 // FIXME: implement hot-path routing statistics keeping!
1888 * Handle P2P "PUT" message.
1890 * @param cls closure, always NULL
1891 * @param other the other peer involved (sender or receiver, NULL
1892 * for loopback messages where we are both sender and receiver)
1893 * @param message the actual message
1894 * @param latency reported latency of the connection with 'other'
1895 * @param distance reported distance (DV) to 'other'
1896 * @return GNUNET_OK to keep the connection open,
1897 * GNUNET_SYSERR to close it (signal serious error)
1900 handle_p2p_put (void *cls,
1901 const struct GNUNET_PeerIdentity *other,
1902 const struct GNUNET_MessageHeader *message,
1903 struct GNUNET_TIME_Relative latency,
1906 const struct PutMessage *put;
1910 struct GNUNET_TIME_Absolute expiration;
1911 GNUNET_HashCode query;
1912 struct ProcessReplyClosure prq;
1914 msize = ntohs (message->size);
1915 if (msize < sizeof (struct PutMessage))
1918 return GNUNET_SYSERR;
1920 put = (const struct PutMessage*) message;
1921 dsize = msize - sizeof (struct PutMessage);
1922 type = ntohl (put->type);
1923 expiration = GNUNET_TIME_absolute_ntoh (put->expiration);
1925 /* first, validate! */
1928 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
1929 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
1930 GNUNET_CRYPTO_hash (&put[1], dsize, &query);
1932 case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
1934 check_kblock ((const struct KBlock*) &put[1],
1937 return GNUNET_SYSERR;
1939 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
1941 check_sblock ((const struct SBlock*) &put[1],
1945 return GNUNET_SYSERR;
1947 case GNUNET_DATASTORE_BLOCKTYPE_SKBLOCK:
1948 // FIXME -- validate SKBLOCK!
1952 /* unknown block type */
1953 GNUNET_break_op (0);
1954 return GNUNET_SYSERR;
1958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1959 "Received result for query `%s' from peer `%4s'\n",
1960 GNUNET_h2s (&query),
1961 GNUNET_i2s (other));
1963 /* now, lookup 'query' */
1964 prq.data = (const void*) &put[1];
1967 prq.expiration = expiration;
1969 GNUNET_CONTAINER_multihashmap_get_multiple (query_request_map,
1973 // FIXME: if migration is on and load is low,
1974 // queue to store data in datastore;
1975 // use "prq.priority" for that!
1980 /* **************************** P2P GET Handling ************************ */
1984 * Closure for 'check_duplicate_request_{peer,client}'.
1986 struct CheckDuplicateRequestClosure
1989 * The new request we should check if it already exists.
1991 const struct PendingRequest *pr;
1994 * Existing request found by the checker, NULL if none.
1996 struct PendingRequest *have;
2001 * Iterator over entries in the 'query_request_map' that
2002 * tries to see if we have the same request pending from
2003 * the same client already.
2005 * @param cls closure (our 'struct CheckDuplicateRequestClosure')
2006 * @param key current key code (query, ignored, must match)
2007 * @param value value in the hash map (a 'struct PendingRequest'
2008 * that already exists)
2009 * @return GNUNET_YES if we should continue to
2010 * iterate (no match yet)
2011 * GNUNET_NO if not (match found).
2014 check_duplicate_request_client (void *cls,
2015 const GNUNET_HashCode * key,
2018 struct CheckDuplicateRequestClosure *cdc = cls;
2019 struct PendingRequest *have = value;
2021 if (have->client_request_list == NULL)
2023 if ( (cdc->pr->client_request_list->client_list->client == have->client_request_list->client_list->client) &&
2034 * We're processing (local) results for a search request
2035 * from another peer. Pass applicable results to the
2036 * peer and if we are done either clean up (operation
2037 * complete) or forward to other peers (more results possible).
2039 * @param cls our closure (struct LocalGetContext)
2040 * @param key key for the content
2041 * @param size number of bytes in data
2042 * @param data content stored
2043 * @param type type of the content
2044 * @param priority priority of the content
2045 * @param anonymity anonymity-level for the content
2046 * @param expiration expiration time for the content
2047 * @param uid unique identifier for the datum;
2048 * maybe 0 if no unique identifier is available
2051 process_local_reply (void *cls,
2052 const GNUNET_HashCode * key,
2058 struct GNUNET_TIME_Absolute
2062 struct PendingRequest *pr = cls;
2063 struct ProcessReplyClosure prq;
2064 struct CheckDuplicateRequestClosure cdrc;
2065 GNUNET_HashCode dhash;
2066 GNUNET_HashCode mhash;
2067 GNUNET_HashCode query;
2072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2073 "Done processing local replies, forwarding request to other peers.\n");
2076 if (pr->client_request_list != NULL)
2078 GNUNET_SERVER_receive_done (pr->client_request_list->client_list->client,
2080 /* Figure out if this is a duplicate request and possibly
2081 merge 'struct PendingRequest' entries */
2084 GNUNET_CONTAINER_multihashmap_get_multiple (query_request_map,
2086 &check_duplicate_request_client,
2088 if (cdrc.have != NULL)
2091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2092 "Received request for block `%s' twice from client, will only request once.\n",
2093 GNUNET_h2s (&pr->query));
2096 destroy_pending_request (pr);
2101 /* no more results */
2102 if (pr->task == GNUNET_SCHEDULER_NO_TASK)
2103 pr->task = GNUNET_SCHEDULER_add_now (sched,
2104 &forward_request_task,
2108 if (type == GNUNET_DATASTORE_BLOCKTYPE_ONDEMAND)
2111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2112 "Found ONDEMAND block, performing on-demand encoding\n");
2115 GNUNET_FS_handle_on_demand_block (key, size, data, type, priority,
2116 anonymity, expiration, uid,
2117 &process_local_reply,
2119 GNUNET_FS_drq_get_next (GNUNET_YES);
2122 /* check for duplicates */
2123 GNUNET_CRYPTO_hash (data, size, &dhash);
2124 mingle_hash (&dhash,
2127 if ( (pr->bf != NULL) &&
2129 GNUNET_CONTAINER_bloomfilter_test (pr->bf,
2133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2134 "Result from datastore filtered by bloomfilter (duplicate).\n");
2136 GNUNET_FS_drq_get_next (GNUNET_YES);
2140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2141 "Found result for query `%s' in local datastore\n",
2144 pr->results_found++;
2145 if ( (pr->type == GNUNET_DATASTORE_BLOCKTYPE_KBLOCK) ||
2146 (pr->type == GNUNET_DATASTORE_BLOCKTYPE_SBLOCK) ||
2147 (pr->type == GNUNET_DATASTORE_BLOCKTYPE_SKBLOCK) )
2152 pr->bf = GNUNET_CONTAINER_bloomfilter_init (NULL,
2156 GNUNET_CONTAINER_bloomfilter_add (pr->bf,
2159 memset (&prq, 0, sizeof (prq));
2161 prq.expiration = expiration;
2163 if ( (type == GNUNET_DATASTORE_BLOCKTYPE_SBLOCK) &&
2164 (GNUNET_OK != check_sblock ((const struct SBlock*) data,
2170 /* FIXME: consider removing the block? */
2171 GNUNET_FS_drq_get_next (GNUNET_YES);
2175 prq.priority = priority;
2176 process_reply (&prq, key, pr);
2178 if ( ( (pr->client_request_list == NULL) &&
2179 ( (GNUNET_YES == test_load_too_high()) ||
2180 (pr->results_found > 5 + 2 * pr->priority) ) ) ||
2181 (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) )
2184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2185 "Unique reply found or load too high, done with request\n");
2187 GNUNET_FS_drq_get_next (GNUNET_NO);
2190 GNUNET_FS_drq_get_next (GNUNET_YES);
2195 * The priority level imposes a bound on the maximum
2196 * value for the ttl that can be requested.
2198 * @param ttl_in requested ttl
2199 * @param prio given priority
2200 * @return ttl_in if ttl_in is below the limit,
2201 * otherwise the ttl-limit for the given priority
2204 bound_ttl (int32_t ttl_in, uint32_t prio)
2206 unsigned long long allowed;
2210 allowed = ((unsigned long long) prio) * TTL_DECREMENT / 1000;
2211 if (ttl_in > allowed)
2213 if (allowed >= (1 << 30))
2222 * We've received a request with the specified priority. Bound it
2223 * according to how much we trust the given peer.
2225 * @param prio_in requested priority
2226 * @param cp the peer making the request
2227 * @return effective priority
2230 bound_priority (uint32_t prio_in,
2231 struct ConnectedPeer *cp)
2238 * Iterator over entries in the 'query_request_map' that
2239 * tries to see if we have the same request pending from
2240 * the same peer already.
2242 * @param cls closure (our 'struct CheckDuplicateRequestClosure')
2243 * @param key current key code (query, ignored, must match)
2244 * @param value value in the hash map (a 'struct PendingRequest'
2245 * that already exists)
2246 * @return GNUNET_YES if we should continue to
2247 * iterate (no match yet)
2248 * GNUNET_NO if not (match found).
2251 check_duplicate_request_peer (void *cls,
2252 const GNUNET_HashCode * key,
2255 struct CheckDuplicateRequestClosure *cdc = cls;
2256 struct PendingRequest *have = value;
2258 if (cdc->pr->target_pid == have->target_pid)
2268 * Handle P2P "GET" request.
2270 * @param cls closure, always NULL
2271 * @param other the other peer involved (sender or receiver, NULL
2272 * for loopback messages where we are both sender and receiver)
2273 * @param message the actual message
2274 * @param latency reported latency of the connection with 'other'
2275 * @param distance reported distance (DV) to 'other'
2276 * @return GNUNET_OK to keep the connection open,
2277 * GNUNET_SYSERR to close it (signal serious error)
2280 handle_p2p_get (void *cls,
2281 const struct GNUNET_PeerIdentity *other,
2282 const struct GNUNET_MessageHeader *message,
2283 struct GNUNET_TIME_Relative latency,
2286 struct PendingRequest *pr;
2287 struct ConnectedPeer *cp;
2288 struct ConnectedPeer *cps;
2289 struct CheckDuplicateRequestClosure cdc;
2290 struct GNUNET_TIME_Relative timeout;
2292 const struct GetMessage *gm;
2294 const GNUNET_HashCode *opt;
2297 uint32_t ttl_decrement;
2302 msize = ntohs(message->size);
2303 if (msize < sizeof (struct GetMessage))
2305 GNUNET_break_op (0);
2306 return GNUNET_SYSERR;
2308 gm = (const struct GetMessage*) message;
2309 type = ntohl (gm->type);
2312 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
2313 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
2314 case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
2315 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
2318 GNUNET_break_op (0);
2319 return GNUNET_SYSERR;
2321 bm = ntohl (gm->hash_bitmap);
2329 if (msize < sizeof (struct GetMessage) + bits * sizeof (GNUNET_HashCode))
2331 GNUNET_break_op (0);
2332 return GNUNET_SYSERR;
2334 opt = (const GNUNET_HashCode*) &gm[1];
2335 bfsize = msize - sizeof (struct GetMessage) + bits * sizeof (GNUNET_HashCode);
2336 bm = ntohl (gm->hash_bitmap);
2337 if ( (0 != (bm & GET_MESSAGE_BIT_SKS_NAMESPACE)) &&
2338 (ntohl (gm->type) == GNUNET_DATASTORE_BLOCKTYPE_SBLOCK) )
2340 GNUNET_break_op (0);
2341 return GNUNET_SYSERR;
2344 cps = GNUNET_CONTAINER_multihashmap_get (connected_peers,
2345 &other->hashPubKey);
2346 GNUNET_assert (NULL != cps);
2347 if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO))
2348 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
2355 if (0 != (bm & GET_MESSAGE_BIT_RETURN_TO))
2356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2357 "Failed to find RETURN-TO peer `%4s' in connection set. Dropping query.\n",
2358 GNUNET_i2s ((const struct GNUNET_PeerIdentity*) &opt[bits-1]));
2361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2362 "Failed to find peer `%4s' in connection set. Dropping query.\n",
2363 GNUNET_i2s (other));
2365 /* FIXME: try connect? */
2368 /* note that we can really only check load here since otherwise
2369 peers could find out that we are overloaded by not being
2370 disconnected after sending us a malformed query... */
2371 if (GNUNET_YES == test_load_too_high ())
2374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2375 "Dropping query from `%s', this peer is too busy.\n",
2376 GNUNET_i2s (other));
2382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2383 "Received request for `%s' of type %u from peer `%4s'\n",
2384 GNUNET_h2s (&gm->query),
2385 (unsigned int) ntohl (gm->type),
2386 GNUNET_i2s (other));
2388 have_ns = (0 != (bm & GET_MESSAGE_BIT_SKS_NAMESPACE));
2389 pr = GNUNET_malloc (sizeof (struct PendingRequest) +
2390 (have_ns ? sizeof(GNUNET_HashCode) : 0));
2392 pr->namespace = (GNUNET_HashCode*) &pr[1];
2394 pr->mingle = ntohl (gm->filter_mutator);
2395 if (0 != (bm & GET_MESSAGE_BIT_SKS_NAMESPACE))
2396 memcpy (&pr[1], &opt[bits++], sizeof (GNUNET_HashCode));
2397 else if (pr->type == GNUNET_DATASTORE_BLOCKTYPE_SBLOCK)
2399 GNUNET_break_op (0);
2401 return GNUNET_SYSERR;
2403 if (0 != (bm & GET_MESSAGE_BIT_TRANSMIT_TO))
2404 pr->target_pid = GNUNET_PEER_intern ((const struct GNUNET_PeerIdentity*) &opt[bits++]);
2406 pr->anonymity_level = 1;
2407 pr->priority = bound_priority (ntohl (gm->priority), cps);
2408 pr->ttl = bound_ttl (ntohl (gm->ttl), pr->priority);
2409 pr->query = gm->query;
2410 /* decrement ttl (always) */
2411 ttl_decrement = 2 * TTL_DECREMENT +
2412 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2414 if ( (pr->ttl < 0) &&
2415 (pr->ttl - ttl_decrement > 0) )
2418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2419 "Dropping query from `%s' due to TTL underflow.\n",
2420 GNUNET_i2s (other));
2422 /* integer underflow => drop (should be very rare)! */
2426 pr->ttl -= ttl_decrement;
2427 pr->start_time = GNUNET_TIME_absolute_get ();
2429 /* get bloom filter */
2432 pr->bf = GNUNET_CONTAINER_bloomfilter_init ((const char*) &opt[bits],
2435 pr->bf_size = bfsize;
2440 GNUNET_CONTAINER_multihashmap_get_multiple (query_request_map,
2442 &check_duplicate_request_peer,
2444 if (cdc.have != NULL)
2446 if (cdc.have->start_time.value + cdc.have->ttl >=
2447 pr->start_time.value + pr->ttl)
2449 /* existing request has higher TTL, drop new one! */
2450 cdc.have->priority += pr->priority;
2451 destroy_pending_request (pr);
2453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2454 "Have existing request with higher TTL, dropping new request.\n",
2455 GNUNET_i2s (other));
2461 /* existing request has lower TTL, drop old one! */
2462 pr->priority += cdc.have->priority;
2463 /* Possible optimization: if we have applicable pending
2464 replies in 'cdc.have', we might want to move those over
2465 (this is a really rare special-case, so it is not clear
2466 that this would be worth it) */
2467 destroy_pending_request (cdc.have);
2468 /* keep processing 'pr'! */
2473 GNUNET_CONTAINER_multihashmap_put (query_request_map,
2476 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2477 GNUNET_CONTAINER_multihashmap_put (peer_request_map,
2480 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2482 pr->hnode = GNUNET_CONTAINER_heap_insert (requests_by_expiration_heap,
2484 pr->start_time.value + pr->ttl);
2487 /* calculate change in traffic preference */
2488 preference = (double) pr->priority;
2489 if (preference < QUERY_BANDWIDTH_VALUE)
2490 preference = QUERY_BANDWIDTH_VALUE;
2491 cps->inc_preference += preference;
2493 /* process locally */
2494 if (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK)
2495 type = GNUNET_DATASTORE_BLOCKTYPE_ANY; /* to get on-demand as well */
2496 timeout = GNUNET_TIME_relative_multiply (BASIC_DATASTORE_REQUEST_DELAY,
2497 (pr->priority + 1));
2498 pr->drq = GNUNET_FS_drq_get (&gm->query,
2500 &process_local_reply,
2505 /* Are multiple results possible? If so, start processing remotely now! */
2508 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
2509 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
2510 /* only one result, wait for datastore */
2513 pr->task = GNUNET_SCHEDULER_add_now (sched,
2514 &forward_request_task,
2518 /* make sure we don't track too many requests */
2519 if (GNUNET_CONTAINER_heap_get_size (requests_by_expiration_heap) > max_pending_requests)
2521 pr = GNUNET_CONTAINER_heap_peek (requests_by_expiration_heap);
2522 destroy_pending_request (pr);
2528 /* **************************** CS GET Handling ************************ */
2532 * Handle START_SEARCH-message (search request from client).
2534 * @param cls closure
2535 * @param client identification of the client
2536 * @param message the actual message
2539 handle_start_search (void *cls,
2540 struct GNUNET_SERVER_Client *client,
2541 const struct GNUNET_MessageHeader *message)
2543 static GNUNET_HashCode all_zeros;
2544 const struct SearchMessage *sm;
2545 struct ClientList *cl;
2546 struct ClientRequestList *crl;
2547 struct PendingRequest *pr;
2552 msize = ntohs (message->size);
2553 if ( (msize < sizeof (struct SearchMessage)) ||
2554 (0 != (msize - sizeof (struct SearchMessage)) % sizeof (GNUNET_HashCode)) )
2557 GNUNET_SERVER_receive_done (client,
2561 sc = (msize - sizeof (struct SearchMessage)) / sizeof (GNUNET_HashCode);
2562 sm = (const struct SearchMessage*) message;
2565 while ( (cl != NULL) &&
2566 (cl->client != client) )
2570 cl = GNUNET_malloc (sizeof (struct ClientList));
2571 cl->client = client;
2572 GNUNET_SERVER_client_keep (client);
2573 cl->next = client_list;
2576 type = ntohl (sm->type);
2579 case GNUNET_DATASTORE_BLOCKTYPE_ANY:
2580 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
2581 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
2582 case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
2583 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
2587 GNUNET_SERVER_receive_done (client,
2592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2593 "Received request for `%s' of type %u from local client\n",
2594 GNUNET_h2s (&sm->query),
2595 (unsigned int) type);
2598 /* detect duplicate KBLOCK requests */
2599 if (type == GNUNET_DATASTORE_BLOCKTYPE_KBLOCK)
2602 while ( (crl != NULL) &&
2603 ( (0 != memcmp (&crl->req->query,
2605 sizeof (GNUNET_HashCode))) ||
2606 (crl->req->type != type) ) )
2611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2612 "Have existing request, merging content-seen lists.\n");
2615 /* Duplicate request (used to send long list of
2616 known/blocked results); merge 'pr->replies_seen'
2617 and update bloom filter */
2618 GNUNET_array_grow (pr->replies_seen,
2619 pr->replies_seen_size,
2620 pr->replies_seen_off + sc);
2621 memcpy (&pr->replies_seen[pr->replies_seen_off],
2623 sc * sizeof (GNUNET_HashCode));
2624 pr->replies_seen_off += sc;
2626 GNUNET_CONTAINER_bloomfilter_free (pr->bf);
2627 pr->bf = refresh_bloomfilter (pr->replies_seen_off,
2631 GNUNET_SERVER_receive_done (client,
2636 pr = GNUNET_malloc (sizeof (struct PendingRequest) +
2637 ((type == GNUNET_DATASTORE_BLOCKTYPE_SBLOCK)?sizeof(GNUNET_HashCode):0));
2638 crl = GNUNET_malloc (sizeof (struct ClientRequestList));
2639 memset (crl, 0, sizeof (struct ClientRequestList));
2640 crl->client_list = cl;
2641 GNUNET_CONTAINER_DLL_insert (cl->rl_head,
2646 pr->client_request_list = crl;
2647 GNUNET_array_grow (pr->replies_seen,
2648 pr->replies_seen_size,
2650 memcpy (pr->replies_seen,
2652 sc * sizeof (GNUNET_HashCode));
2653 pr->replies_seen_off = sc;
2654 pr->anonymity_level = ntohl (sm->anonymity_level);
2655 pr->bf = refresh_bloomfilter (pr->replies_seen_off,
2659 pr->query = sm->query;
2662 case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
2663 case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
2664 if (0 != memcmp (&sm->target,
2666 sizeof (GNUNET_HashCode)))
2667 pr->target_pid = GNUNET_PEER_intern ((const struct GNUNET_PeerIdentity*) &sm->target);
2669 case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
2670 pr->namespace = (GNUNET_HashCode*) &pr[1];
2671 memcpy (&pr[1], &sm->target, sizeof (GNUNET_HashCode));
2676 GNUNET_CONTAINER_multihashmap_put (query_request_map,
2679 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2680 if (type == GNUNET_DATASTORE_BLOCKTYPE_DBLOCK)
2681 type = GNUNET_DATASTORE_BLOCKTYPE_ANY; /* get on-demand blocks too! */
2682 pr->drq = GNUNET_FS_drq_get (&sm->query,
2684 &process_local_reply,
2686 GNUNET_TIME_UNIT_FOREVER_REL,
2691 /* **************************** Startup ************************ */
2695 * List of handlers for P2P messages
2696 * that we care about.
2698 static struct GNUNET_CORE_MessageHandler p2p_handlers[] =
2701 GNUNET_MESSAGE_TYPE_FS_GET, 0 },
2703 GNUNET_MESSAGE_TYPE_FS_PUT, 0 },
2709 * List of handlers for the messages understood by this
2712 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2713 {&GNUNET_FS_handle_index_start, NULL,
2714 GNUNET_MESSAGE_TYPE_FS_INDEX_START, 0},
2715 {&GNUNET_FS_handle_index_list_get, NULL,
2716 GNUNET_MESSAGE_TYPE_FS_INDEX_LIST_GET, sizeof(struct GNUNET_MessageHeader) },
2717 {&GNUNET_FS_handle_unindex, NULL, GNUNET_MESSAGE_TYPE_FS_UNINDEX,
2718 sizeof (struct UnindexMessage) },
2719 {&handle_start_search, NULL, GNUNET_MESSAGE_TYPE_FS_START_SEARCH,
2726 * Process fs requests.
2728 * @param s scheduler to use
2729 * @param server the initialized server
2730 * @param c configuration to use
2733 main_init (struct GNUNET_SCHEDULER_Handle *s,
2734 struct GNUNET_SERVER_Handle *server,
2735 const struct GNUNET_CONFIGURATION_Handle *c)
2739 connected_peers = GNUNET_CONTAINER_multihashmap_create (128); // FIXME: get size from config
2740 query_request_map = GNUNET_CONTAINER_multihashmap_create (128); // FIXME: get size from config
2741 peer_request_map = GNUNET_CONTAINER_multihashmap_create (128); // FIXME: get size from config
2742 requests_by_expiration_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2743 core = GNUNET_CORE_connect (sched,
2745 GNUNET_TIME_UNIT_FOREVER_REL,
2749 &peer_connect_handler,
2750 &peer_disconnect_handler,
2756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2757 _("Failed to connect to `%s' service.\n"),
2759 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
2760 connected_peers = NULL;
2761 GNUNET_CONTAINER_multihashmap_destroy (query_request_map);
2762 query_request_map = NULL;
2763 GNUNET_CONTAINER_heap_destroy (requests_by_expiration_heap);
2764 requests_by_expiration_heap = NULL;
2765 GNUNET_CONTAINER_multihashmap_destroy (peer_request_map);
2766 peer_request_map = NULL;
2768 return GNUNET_SYSERR;
2770 GNUNET_SERVER_disconnect_notify (server,
2771 &handle_client_disconnect,
2773 GNUNET_SERVER_add_handlers (server, handlers);
2774 GNUNET_SCHEDULER_add_delayed (sched,
2775 GNUNET_TIME_UNIT_FOREVER_REL,
2783 * Process fs requests.
2785 * @param cls closure
2786 * @param sched scheduler to use
2787 * @param server the initialized server
2788 * @param cfg configuration to use
2792 struct GNUNET_SCHEDULER_Handle *sched,
2793 struct GNUNET_SERVER_Handle *server,
2794 const struct GNUNET_CONFIGURATION_Handle *cfg)
2796 if ( (GNUNET_OK != GNUNET_FS_drq_init (sched, cfg)) ||
2797 (GNUNET_OK != GNUNET_FS_indexing_init (sched, cfg)) ||
2798 (GNUNET_OK != main_init (sched, server, cfg)) )
2800 GNUNET_SCHEDULER_shutdown (sched);
2807 * The main function for the fs service.
2809 * @param argc number of arguments from the command line
2810 * @param argv command line arguments
2811 * @return 0 ok, 1 on error
2814 main (int argc, char *const *argv)
2816 return (GNUNET_OK ==
2817 GNUNET_SERVICE_run (argc,
2820 GNUNET_SERVICE_OPTION_NONE,
2821 &run, NULL)) ? 0 : 1;
2824 /* end of gnunet-service-fs.c */