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_datastore_service.h"
41 * Handle to the datastore service (for inserting/retrieving data)
43 static struct GNUNET_DATASTORE_Handle *datastore;
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;
78 * This is a linked list
80 struct ClientList *next;
83 * The client in question
85 struct GNUNET_SERVER_Client *client;
89 * Server handler for handling locally received dht requests
92 handle_dht_start_message(void *cls, struct GNUNET_SERVER_Client * client,
93 const struct GNUNET_MessageHeader *message);
96 handle_dht_stop_message(void *cls, struct GNUNET_SERVER_Client * client,
97 const struct GNUNET_MessageHeader *message);
99 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
100 {&handle_dht_start_message, NULL, GNUNET_MESSAGE_TYPE_DHT, 0},
101 {&handle_dht_stop_message, NULL, GNUNET_MESSAGE_TYPE_DHT_STOP, 0},
102 /* {&handle_dht_get_stop, NULL, GNUNET_MESSAGE_TYPE_DHT_GET_STOP, 0},
103 {&handle_dht_put, NULL, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
104 {&handle_dht_find_peer, NULL, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER, 0},
105 {&handle_dht_find_peer_stop, NULL, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER_STOP, 0},*/
111 * Core handler for p2p dht get requests.
113 static int handle_dht_p2p_get (void *cls,
114 const struct GNUNET_PeerIdentity * peer,
115 const struct GNUNET_MessageHeader * message,
116 struct GNUNET_TIME_Relative latency,
120 * Core handler for p2p dht put requests.
122 static int handle_dht_p2p_put (void *cls,
123 const struct GNUNET_PeerIdentity * peer,
124 const struct GNUNET_MessageHeader * message,
125 struct GNUNET_TIME_Relative latency,
129 * Core handler for p2p dht find peer requests.
131 static int handle_dht_p2p_find_peer (void *cls,
132 const struct GNUNET_PeerIdentity * peer,
133 const struct GNUNET_MessageHeader * message,
134 struct GNUNET_TIME_Relative latency,
137 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
138 {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_GET, 0},
139 {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
140 {&handle_dht_p2p_find_peer, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
147 * Server handler for initiating local dht get requests
149 static void handle_dht_get (void *cls, struct GNUNET_DHT_GetMessage *get_msg, GNUNET_HashCode *key)
151 GNUNET_HashCode get_key;
154 GNUNET_assert(ntohs(get_msg->header.size) >= sizeof(struct GNUNET_DHT_GetMessage));
155 get_type = ntohs(get_msg->type);
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159 "`%s': Received `%s' request from client, message type %d, key %s\n", "DHT", "GET", get_type, GNUNET_h2s(&get_key));
162 /* FIXME: Implement get functionality here */
167 * Server handler for initiating local dht find peer requests
169 static void handle_dht_find_peer (void *cls, struct GNUNET_DHT_FindPeerMessage *find_msg, GNUNET_HashCode *key)
172 GNUNET_assert(ntohs(find_msg->header.size) == sizeof(struct GNUNET_DHT_FindPeerMessage));
175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176 "`%s': Received `%s' request from client, key %s\n", "DHT", "FIND PEER", GNUNET_h2s(key));
179 /* FIXME: Implement find peer functionality here */
184 * Server handler for initiating local dht put requests
186 static void handle_dht_put (void *cls, struct GNUNET_DHT_PutMessage *put_msg, GNUNET_HashCode *key)
192 GNUNET_assert(ntohs(put_msg->header.size) >= sizeof(struct GNUNET_DHT_PutMessage));
194 put_type = ntohs(put_msg->type);
195 data_size = ntohs(put_msg->data_size);
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198 "`%s': %s msg total size is %d, data size %d, struct size %d\n", "DHT", "PUT", ntohs(put_msg->header.size), data_size, sizeof(struct GNUNET_DHT_PutMessage));
200 GNUNET_assert(ntohs(put_msg->header.size) == sizeof(struct GNUNET_DHT_PutMessage) + data_size);
201 data = GNUNET_malloc(data_size);
202 memcpy(data, &put_msg[1], data_size);
205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
206 "`%s': Received `%s' request from client, message type %d, key %s\n", "DHT", "PUT", put_type, GNUNET_h2s(key));
211 * FIXME: Implement dht put request functionality here!
218 * Context for sending receipt confirmations. Not used yet.
220 struct SendConfirmationContext
223 * The message to send.
225 struct GNUNET_DHT_StopMessage *message;
230 struct GNUNET_CONNECTION_TransmitHandle * transmit_handle;
233 size_t send_confirmation (void *cls,
234 size_t size, void *buf)
236 struct GNUNET_DHT_StopMessage *confirmation_message = cls;
238 if (buf == NULL) /* Message timed out, that's crappy... */
240 GNUNET_free(confirmation_message);
244 if (size >= ntohs(confirmation_message->header.size))
246 memcpy(buf, confirmation_message, ntohs(confirmation_message->header.size));
247 return ntohs(confirmation_message->header.size);
254 send_client_receipt_confirmation(struct GNUNET_SERVER_Client *client, uint64_t uid)
256 struct GNUNET_DHT_StopMessage *confirm_message;
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260 "`%s': Sending receipt confirmation for uid %llu\n", "DHT", uid);
262 confirm_message = GNUNET_malloc(sizeof(struct GNUNET_DHT_StopMessage));
263 confirm_message->header.type = htons(GNUNET_MESSAGE_TYPE_DHT_STOP);
264 confirm_message->header.size = htons(sizeof(struct GNUNET_DHT_StopMessage));
265 confirm_message->unique_id = GNUNET_htonll(uid);
267 GNUNET_SERVER_notify_transmit_ready (client,
268 sizeof(struct GNUNET_DHT_StopMessage),
269 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
270 &send_confirmation, confirm_message);
275 handle_dht_start_message(void *cls, struct GNUNET_SERVER_Client * client,
276 const struct GNUNET_MessageHeader *message)
278 struct GNUNET_DHT_Message *dht_msg = (struct GNUNET_DHT_Message *)message;
279 struct GNUNET_MessageHeader *enc_msg;
282 enc_msg = (struct GNUNET_MessageHeader *)&dht_msg[1];
283 enc_type = ntohs(enc_msg->type);
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "`%s': Received `%s' request from client, message type %d, key %s, uid %llu\n", "DHT", "GENERIC", enc_type, GNUNET_h2s(&dht_msg->key), GNUNET_ntohll(dht_msg->unique_id));
291 /* FIXME: Implement demultiplexing functionality here */
294 case GNUNET_MESSAGE_TYPE_DHT_GET:
295 handle_dht_get(cls, (struct GNUNET_DHT_GetMessage *)enc_msg, &dht_msg->key);
297 case GNUNET_MESSAGE_TYPE_DHT_PUT:
298 handle_dht_put(cls, (struct GNUNET_DHT_PutMessage *)enc_msg, &dht_msg->key);
299 send_client_receipt_confirmation(client, GNUNET_ntohll(dht_msg->unique_id));
301 case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER:
302 handle_dht_find_peer(cls, (struct GNUNET_DHT_FindPeerMessage *)enc_msg, &dht_msg->key);
306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307 "`%s': Message type (%d) not handled\n", "DHT", enc_type);
311 GNUNET_SERVER_receive_done(client, GNUNET_OK);
317 handle_dht_stop_message(void *cls, struct GNUNET_SERVER_Client * client,
318 const struct GNUNET_MessageHeader *message)
320 struct GNUNET_DHT_StopMessage * dht_stop_msg = (struct GNUNET_DHT_StopMessage *)message;
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "`%s': Received `%s' request from client, uid %llu\n", "DHT", "GENERIC STOP", GNUNET_ntohll(dht_stop_msg->unique_id));
326 send_client_receipt_confirmation(client, GNUNET_ntohll(dht_stop_msg->unique_id));
327 GNUNET_SERVER_receive_done(client, GNUNET_OK);
332 * Core handler for p2p dht get requests.
334 static int handle_dht_p2p_get (void *cls,
335 const struct GNUNET_PeerIdentity * peer,
336 const struct GNUNET_MessageHeader * message,
337 struct GNUNET_TIME_Relative latency,
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "`%s': Received `%s' request from another peer\n", "DHT", "GET");
349 * Core handler for p2p dht put requests.
351 static int handle_dht_p2p_put (void *cls,
352 const struct GNUNET_PeerIdentity * peer,
353 const struct GNUNET_MessageHeader * message,
354 struct GNUNET_TIME_Relative latency,
358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359 "`%s': Received `%s' request from another peer\n", "DHT", "PUT");
366 * Core handler for p2p dht find peer requests.
368 static int handle_dht_p2p_find_peer (void *cls,
369 const struct GNUNET_PeerIdentity * peer,
370 const struct GNUNET_MessageHeader * message,
371 struct GNUNET_TIME_Relative latency,
375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376 "`%s': Received `%s' request from another peer\n", "DHT", "FIND PEER");
383 * Task run during shutdown.
389 shutdown_task (void *cls,
390 const struct GNUNET_SCHEDULER_TaskContext *tc)
392 GNUNET_CORE_disconnect (coreAPI);
396 * To be called on core init/fail.
398 void core_init (void *cls,
399 struct GNUNET_CORE_Handle * server,
400 const struct GNUNET_PeerIdentity *identity,
401 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
406 GNUNET_SCHEDULER_cancel(sched, cleanup_task);
407 GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "%s: Core connection initialized, I am peer: %s\n", "dht", GNUNET_i2s(identity));
414 memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
419 * Process dht requests.
422 * @param scheduler scheduler to use
423 * @param server the initialized server
424 * @param c configuration to use
428 struct GNUNET_SCHEDULER_Handle *scheduler,
429 struct GNUNET_SERVER_Handle *server,
430 const struct GNUNET_CONFIGURATION_Handle *c)
435 datastore = GNUNET_DATASTORE_connect(c, scheduler);
437 client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
438 GNUNET_SERVER_add_handlers (server, plugin_handlers);
441 GNUNET_CORE_connect (sched, /* Main scheduler */
442 cfg, /* Main configuration */
443 client_transmit_timeout, /* Delay for connecting */
444 NULL, /* FIXME: anything we want to pass around? */
445 &core_init, /* Call core_init once connected */
446 NULL, /* Don't care about pre-connects */
447 NULL, /* Don't care about connects */
448 NULL, /* Don't care about disconnects */
449 NULL, /* Don't want notified about all incoming messages */
450 GNUNET_NO, /* For header only inbound notification */
451 NULL, /* Don't want notified about all outbound messages */
452 GNUNET_NO, /* For header only outbound notification */
453 core_handlers); /* Register these handlers */
458 /* Scheduled the task to clean up when shutdown is called */
459 cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
460 GNUNET_TIME_UNIT_FOREVER_REL,
467 * The main function for the dv service.
469 * @param argc number of arguments from the command line
470 * @param argv command line arguments
471 * @return 0 ok, 1 on error
474 main (int argc, char *const *argv)
477 GNUNET_SERVICE_run (argc,
480 GNUNET_SERVICE_OPTION_NONE,
481 &run, NULL)) ? 0 : 1;