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 dht/gnunet-service-dht.c
23 * @brief main DHT service shell, building block for DHT implementations
24 * @author Christian Grothoff
25 * @author Nathan Evans
29 #include "gnunet_client_lib.h"
30 #include "gnunet_getopt_lib.h"
31 #include "gnunet_os_lib.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_service_lib.h"
34 #include "gnunet_core_service.h"
35 #include "gnunet_signal_lib.h"
36 #include "gnunet_util_lib.h"
37 #include "gnunet_datacache_lib.h"
41 * Handle to the datacache service (for inserting/retrieving data)
43 struct GNUNET_DATACACHE_Handle *datacache;
46 * The main scheduler to use for the DHT service
48 static struct GNUNET_SCHEDULER_Handle *sched;
51 * The configuration the DHT service is running with
53 static const struct GNUNET_CONFIGURATION_Handle *cfg;
56 * Timeout for transmissions to clients
58 static struct GNUNET_TIME_Relative client_transmit_timeout;
61 * Handle to the core service
63 static struct GNUNET_CORE_Handle *coreAPI;
66 * The identity of our peer.
68 static struct GNUNET_PeerIdentity my_identity;
71 * Task to run when we shut down, cleaning up all our trash
73 static GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
76 * Context for handling results from a get request.
78 struct DatacacheGetContext
81 * The client to send the result to.
83 struct GNUNET_SERVER_Client *client;
86 * The unique id of this request
88 unsigned long long unique_id;
92 struct DHT_MessageContext
95 * The client this request was received from.
97 struct GNUNET_SERVER_Client *client;
100 * The key this request was about
102 GNUNET_HashCode *key;
105 * The unique identifier of this request
107 unsigned long long unique_id;
110 * Desired replication level
115 * Any message options for this request
121 * Server handler for handling locally received dht requests
124 handle_dht_start_message (void *cls, struct GNUNET_SERVER_Client *client,
125 const struct GNUNET_MessageHeader *message);
128 handle_dht_stop_message (void *cls, struct GNUNET_SERVER_Client *client,
129 const struct GNUNET_MessageHeader *message);
131 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
132 {&handle_dht_start_message, NULL, GNUNET_MESSAGE_TYPE_DHT, 0},
133 {&handle_dht_stop_message, NULL, GNUNET_MESSAGE_TYPE_DHT_STOP, 0},
139 * Core handler for p2p dht get requests.
141 static int handle_dht_p2p_get (void *cls,
142 const struct GNUNET_PeerIdentity *peer,
143 const struct GNUNET_MessageHeader *message,
144 struct GNUNET_TIME_Relative latency,
148 * Core handler for p2p dht put requests.
150 static int handle_dht_p2p_put (void *cls,
151 const struct GNUNET_PeerIdentity *peer,
152 const struct GNUNET_MessageHeader *message,
153 struct GNUNET_TIME_Relative latency,
157 * Core handler for p2p dht find peer requests.
159 static int handle_dht_p2p_find_peer (void *cls,
160 const struct GNUNET_PeerIdentity *peer,
161 const struct GNUNET_MessageHeader
163 struct GNUNET_TIME_Relative latency,
166 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
167 {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_GET, 0},
168 {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
169 {&handle_dht_p2p_find_peer, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER, 0},
175 send_reply (void *cls, size_t size, void *buf)
177 struct GNUNET_DHT_Message *reply = cls;
179 if (buf == NULL) /* Message timed out, that's crappy... */
185 if (size >= ntohs (reply->header.size))
187 memcpy (buf, reply, ntohs (reply->header.size));
188 return ntohs (reply->header.size);
196 send_reply_to_client (struct GNUNET_SERVER_Client *client,
197 struct GNUNET_MessageHeader *message,
198 unsigned long long uid)
200 struct GNUNET_DHT_Message *reply;
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205 "`%s': Sending reply to client.\n", "DHT");
207 msize = ntohs (message->size);
208 tsize = sizeof (struct GNUNET_DHT_Message) + msize;
209 reply = GNUNET_malloc (tsize);
210 reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT);
211 reply->header.size = htons (tsize);
213 reply->unique = htons (GNUNET_YES);
214 reply->unique_id = GNUNET_htonll (uid);
215 memcpy (&reply[1], message, msize);
217 GNUNET_SERVER_notify_transmit_ready (client,
219 GNUNET_TIME_relative_multiply
220 (GNUNET_TIME_UNIT_SECONDS, 5),
227 * Iterator for local get request results, return
228 * GNUNET_OK to continue iteration, anything else
232 datacache_get_iterator (void *cls,
233 struct GNUNET_TIME_Absolute exp,
234 const GNUNET_HashCode * key,
235 uint32_t size, const char *data, uint32_t type)
237 struct DatacacheGetContext *datacache_get_ctx = cls;
238 struct GNUNET_DHT_GetResultMessage *get_result;
241 GNUNET_malloc (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
242 get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT);
243 get_result->header.size =
244 htons (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
245 get_result->data_size = htons (size);
246 get_result->expiration = exp;
247 memcpy (&get_result->key, key, sizeof (GNUNET_HashCode));
248 get_result->type = htons (type);
249 memcpy (&get_result[1], data, size);
251 send_reply_to_client (datacache_get_ctx->client, &get_result->header,
252 datacache_get_ctx->unique_id);
254 GNUNET_free (get_result);
259 * Server handler for initiating local dht get requests
262 handle_dht_get (void *cls, struct GNUNET_DHT_GetMessage *get_msg,
263 struct DHT_MessageContext *message_context)
266 GNUNET_HashCode get_key;
269 unsigned int results;
270 struct DatacacheGetContext *datacache_get_context;
272 GNUNET_assert (ntohs (get_msg->header.size) >=
273 sizeof (struct GNUNET_DHT_GetMessage));
274 get_type = ntohs (get_msg->type);
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "`%s': Received `%s' request from client, message type %d, key %s, uid %llu\n",
279 "DHT", "GET", get_type, GNUNET_h2s (&get_key),
280 message_context->unique_id);
283 datacache_get_context = GNUNET_malloc (sizeof (struct DatacacheGetContext));
284 datacache_get_context->client = message_context->client;
285 datacache_get_context->unique_id = message_context->unique_id;
288 if (datacache != NULL)
290 GNUNET_DATACACHE_get (datacache, message_context->key, get_type,
291 datacache_get_iterator, datacache_get_context);
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "`%s': Found %d results for local `%s' request\n", "DHT",
298 GNUNET_free (datacache_get_context);
299 /* FIXME: Implement get functionality here */
304 * Server handler for initiating local dht find peer requests
307 handle_dht_find_peer (void *cls, struct GNUNET_DHT_FindPeerMessage *find_msg,
308 struct DHT_MessageContext *message_context)
311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
312 "`%s': Received `%s' request from client, key %s (msg size %d, we expected %d)\n",
313 "DHT", "FIND PEER", GNUNET_h2s (message_context->key),
314 ntohs (find_msg->header.size),
315 sizeof (struct GNUNET_DHT_FindPeerMessage));
318 GNUNET_assert (ntohs (find_msg->header.size) >=
319 sizeof (struct GNUNET_DHT_FindPeerMessage));
321 /* FIXME: Implement find peer functionality here */
326 * Server handler for initiating local dht put requests
329 handle_dht_put (void *cls, struct GNUNET_DHT_PutMessage *put_msg,
330 struct DHT_MessageContext *message_context)
335 GNUNET_assert (ntohs (put_msg->header.size) >=
336 sizeof (struct GNUNET_DHT_PutMessage));
338 put_type = ntohs (put_msg->type);
339 data_size = ntohs (put_msg->data_size);
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "`%s': %s msg total size is %d, data size %d, struct size %d\n",
343 "DHT", "PUT", ntohs (put_msg->header.size), data_size,
344 sizeof (struct GNUNET_DHT_PutMessage));
346 GNUNET_assert (ntohs (put_msg->header.size) ==
347 sizeof (struct GNUNET_DHT_PutMessage) + data_size);
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351 "`%s': Received `%s' request from client, message type %d, key %s\n",
352 "DHT", "PUT", put_type, GNUNET_h2s (message_context->key));
356 * Simplest DHT functionality, store any message we receive a put request for.
358 if (datacache != NULL)
359 GNUNET_DATACACHE_put (datacache, message_context->key, data_size,
360 (char *) &put_msg[1], put_type,
361 put_msg->expiration);
363 * FIXME: Implement dht put request functionality here!
369 * Context for sending receipt confirmations. Not used yet.
371 struct SendConfirmationContext
374 * The message to send.
376 struct GNUNET_DHT_StopMessage *message;
381 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
385 send_confirmation (void *cls, size_t size, void *buf)
387 struct GNUNET_DHT_StopMessage *confirmation_message = cls;
389 if (buf == NULL) /* Message timed out, that's crappy... */
391 GNUNET_free (confirmation_message);
395 if (size >= ntohs (confirmation_message->header.size))
397 memcpy (buf, confirmation_message,
398 ntohs (confirmation_message->header.size));
399 return ntohs (confirmation_message->header.size);
407 send_client_receipt_confirmation (struct GNUNET_SERVER_Client *client,
410 struct GNUNET_DHT_StopMessage *confirm_message;
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "`%s': Sending receipt confirmation for uid %llu\n", "DHT",
417 confirm_message = GNUNET_malloc (sizeof (struct GNUNET_DHT_StopMessage));
418 confirm_message->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_STOP);
419 confirm_message->header.size =
420 htons (sizeof (struct GNUNET_DHT_StopMessage));
421 confirm_message->unique_id = GNUNET_htonll (uid);
423 GNUNET_SERVER_notify_transmit_ready (client,
424 sizeof (struct GNUNET_DHT_StopMessage),
425 GNUNET_TIME_relative_multiply
426 (GNUNET_TIME_UNIT_SECONDS, 5),
427 &send_confirmation, confirm_message);
432 handle_dht_start_message (void *cls, struct GNUNET_SERVER_Client *client,
433 const struct GNUNET_MessageHeader *message)
435 struct GNUNET_DHT_Message *dht_msg = (struct GNUNET_DHT_Message *) message;
436 struct GNUNET_MessageHeader *enc_msg;
437 struct DHT_MessageContext *message_context;
440 enc_msg = (struct GNUNET_MessageHeader *) &dht_msg[1];
441 enc_type = ntohs (enc_msg->type);
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446 "`%s': Received `%s' request from client, message type %d, key %s, uid %llu\n",
447 "DHT", "GENERIC", enc_type, GNUNET_h2s (&dht_msg->key),
448 GNUNET_ntohll (dht_msg->unique_id));
451 message_context = GNUNET_malloc (sizeof (struct DHT_MessageContext));
452 message_context->client = client;
453 message_context->key = &dht_msg->key;
454 message_context->unique_id = GNUNET_ntohll (dht_msg->unique_id);
455 message_context->replication = ntohs (dht_msg->desired_replication_level);
456 message_context->msg_options = ntohs (dht_msg->options);
460 case GNUNET_MESSAGE_TYPE_DHT_GET:
461 handle_dht_get (cls, (struct GNUNET_DHT_GetMessage *) enc_msg,
464 case GNUNET_MESSAGE_TYPE_DHT_PUT:
465 handle_dht_put (cls, (struct GNUNET_DHT_PutMessage *) enc_msg,
467 send_client_receipt_confirmation (client,
468 GNUNET_ntohll (dht_msg->unique_id));
470 case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER:
471 handle_dht_find_peer (cls,
472 (struct GNUNET_DHT_FindPeerMessage *) enc_msg,
476 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
477 "`%s': Message type (%d) not handled\n", "DHT", enc_type);
480 GNUNET_free (message_context);
481 GNUNET_SERVER_receive_done (client, GNUNET_OK);
487 handle_dht_stop_message (void *cls, struct GNUNET_SERVER_Client *client,
488 const struct GNUNET_MessageHeader *message)
490 struct GNUNET_DHT_StopMessage *dht_stop_msg =
491 (struct GNUNET_DHT_StopMessage *) message;
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "`%s': Received `%s' request from client, uid %llu\n", "DHT",
496 "GENERIC STOP", GNUNET_ntohll (dht_stop_msg->unique_id));
499 /* TODO: Put in demultiplexing here */
501 send_client_receipt_confirmation (client,
502 GNUNET_ntohll (dht_stop_msg->unique_id));
503 GNUNET_SERVER_receive_done (client, GNUNET_OK);
508 * Core handler for p2p dht get requests.
511 handle_dht_p2p_get (void *cls,
512 const struct GNUNET_PeerIdentity *peer,
513 const struct GNUNET_MessageHeader *message,
514 struct GNUNET_TIME_Relative latency, uint32_t distance)
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518 "`%s': Received `%s' request from another peer\n", "DHT",
526 * Core handler for p2p dht put requests.
529 handle_dht_p2p_put (void *cls,
530 const struct GNUNET_PeerIdentity *peer,
531 const struct GNUNET_MessageHeader *message,
532 struct GNUNET_TIME_Relative latency, uint32_t distance)
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "`%s': Received `%s' request from another peer\n", "DHT",
544 * Core handler for p2p dht find peer requests.
547 handle_dht_p2p_find_peer (void *cls,
548 const struct GNUNET_PeerIdentity *peer,
549 const struct GNUNET_MessageHeader *message,
550 struct GNUNET_TIME_Relative latency,
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 "`%s': Received `%s' request from another peer\n", "DHT",
563 * Task run during shutdown.
569 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
571 GNUNET_CORE_disconnect (coreAPI);
575 * To be called on core init/fail.
578 core_init (void *cls,
579 struct GNUNET_CORE_Handle *server,
580 const struct GNUNET_PeerIdentity *identity,
581 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
586 GNUNET_SCHEDULER_cancel (sched, cleanup_task);
587 GNUNET_SCHEDULER_add_now (sched, &shutdown_task, NULL);
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592 "%s: Core connection initialized, I am peer: %s\n", "dht",
593 GNUNET_i2s (identity));
595 memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity));
600 * Process dht requests.
603 * @param scheduler scheduler to use
604 * @param server the initialized server
605 * @param c configuration to use
609 struct GNUNET_SCHEDULER_Handle *scheduler,
610 struct GNUNET_SERVER_Handle *server,
611 const struct GNUNET_CONFIGURATION_Handle *c)
616 datacache = GNUNET_DATACACHE_create (sched, cfg, "dhtcache");
618 client_transmit_timeout =
619 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5);
620 GNUNET_SERVER_add_handlers (server, plugin_handlers);
622 coreAPI = GNUNET_CORE_connect (sched, /* Main scheduler */
623 cfg, /* Main configuration */
624 client_transmit_timeout, /* Delay for connecting */
625 NULL, /* FIXME: anything we want to pass around? */
626 &core_init, /* Call core_init once connected */
627 NULL, /* Don't care about pre-connects */
628 NULL, /* Don't care about connects */
629 NULL, /* Don't care about disconnects */
630 NULL, /* Don't want notified about all incoming messages */
631 GNUNET_NO, /* For header only inbound notification */
632 NULL, /* Don't want notified about all outbound messages */
633 GNUNET_NO, /* For header only outbound notification */
634 core_handlers); /* Register these handlers */
639 /* Scheduled the task to clean up when shutdown is called */
640 cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
641 GNUNET_TIME_UNIT_FOREVER_REL,
642 &shutdown_task, NULL);
647 * The main function for the dht service.
649 * @param argc number of arguments from the command line
650 * @param argv command line arguments
651 * @return 0 ok, 1 on error
654 main (int argc, char *const *argv)
657 GNUNET_SERVICE_run (argc,
660 GNUNET_SERVICE_OPTION_NONE,
661 &run, NULL)) ? 0 : 1;