change hostname in config files when created, if running remotely... Otherwise the...
[oweals/gnunet.git] / src / dht / gnunet-service-dht.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
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
26  */
27
28 #include "platform.h"
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"
38 #include "dht.h"
39
40 /**
41  * Handle to the datastore service (for inserting/retrieving data)
42  */
43 static struct GNUNET_DATASTORE_Handle *datastore;
44
45 /**
46  * The main scheduler to use for the DHT service
47  */
48 static struct GNUNET_SCHEDULER_Handle *sched;
49
50 /**
51  * The configuration the DHT service is running with
52  */
53 static const struct GNUNET_CONFIGURATION_Handle *cfg;
54
55 /**
56  * Timeout for transmissions to clients
57  */
58 static struct GNUNET_TIME_Relative client_transmit_timeout;
59
60 /**
61  * Handle to the core service
62  */
63 static struct GNUNET_CORE_Handle *coreAPI;
64
65 /**
66  * The identity of our peer.
67  */
68 static struct GNUNET_PeerIdentity my_identity;
69
70 /**
71  * Task to run when we shut down, cleaning up all our trash
72  */
73 static GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
74
75 struct ClientList
76 {
77   /**
78    * This is a linked list
79    */
80   struct ClientList *next;
81
82   /**
83    * The client in question
84    */
85   struct GNUNET_SERVER_Client *client;
86 };
87
88 /**
89  * Server handler for handling locally received dht requests
90  */
91 static void
92 handle_dht_start_message(void *cls, struct GNUNET_SERVER_Client * client,
93                          const struct GNUNET_MessageHeader *message);
94
95 static void
96 handle_dht_stop_message(void *cls, struct GNUNET_SERVER_Client * client,
97                          const struct GNUNET_MessageHeader *message);
98
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   {NULL, NULL, 0, 0}
103 };
104
105
106 /**
107  * Core handler for p2p dht get requests.
108  */
109 static int handle_dht_p2p_get (void *cls,
110                              const struct GNUNET_PeerIdentity * peer,
111                              const struct GNUNET_MessageHeader * message,
112                              struct GNUNET_TIME_Relative latency,
113                              uint32_t distance);
114
115 /**
116  * Core handler for p2p dht put requests.
117  */
118 static int handle_dht_p2p_put (void *cls,
119                              const struct GNUNET_PeerIdentity * peer,
120                              const struct GNUNET_MessageHeader * message,
121                              struct GNUNET_TIME_Relative latency,
122                              uint32_t distance);
123
124 /**
125  * Core handler for p2p dht find peer requests.
126  */
127 static int handle_dht_p2p_find_peer (void *cls,
128                              const struct GNUNET_PeerIdentity * peer,
129                              const struct GNUNET_MessageHeader * message,
130                              struct GNUNET_TIME_Relative latency,
131                              uint32_t distance);
132
133 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
134   {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_GET, 0},
135   {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
136   {&handle_dht_p2p_find_peer, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER, 0},
137   {NULL, 0, 0}
138 };
139
140
141
142 /**
143  * Server handler for initiating local dht get requests
144  */
145 static void handle_dht_get (void *cls, struct GNUNET_DHT_GetMessage *get_msg, GNUNET_HashCode *key)
146 {
147   GNUNET_HashCode get_key;
148   size_t get_type;
149
150   GNUNET_assert(ntohs(get_msg->header.size) >= sizeof(struct GNUNET_DHT_GetMessage));
151   get_type = ntohs(get_msg->type);
152
153 #if DEBUG_DHT
154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155               "`%s': Received `%s' request from client, message type %d, key %s\n", "DHT", "GET", get_type, GNUNET_h2s(&get_key));
156 #endif
157
158   /* FIXME: Implement get functionality here */
159 }
160
161
162 /**
163  * Server handler for initiating local dht find peer requests
164  */
165 static void handle_dht_find_peer (void *cls, struct GNUNET_DHT_FindPeerMessage *find_msg, GNUNET_HashCode *key)
166 {
167
168   GNUNET_assert(ntohs(find_msg->header.size) == sizeof(struct GNUNET_DHT_FindPeerMessage));
169
170 #if DEBUG_DHT
171   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
172               "`%s': Received `%s' request from client, key %s\n", "DHT", "FIND PEER", GNUNET_h2s(key));
173 #endif
174
175   /* FIXME: Implement find peer functionality here */
176 }
177
178
179 /**
180  * Server handler for initiating local dht put requests
181  */
182 static void handle_dht_put (void *cls, struct GNUNET_DHT_PutMessage *put_msg, GNUNET_HashCode *key)
183 {
184   size_t put_type;
185   size_t data_size;
186   char *data;
187
188   GNUNET_assert(ntohs(put_msg->header.size) >= sizeof(struct GNUNET_DHT_PutMessage));
189
190   put_type = ntohs(put_msg->type);
191   data_size = ntohs(put_msg->data_size);
192 #if DEBUG_DHT
193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194               "`%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));
195 #endif
196   GNUNET_assert(ntohs(put_msg->header.size) == sizeof(struct GNUNET_DHT_PutMessage) + data_size);
197   data = GNUNET_malloc(data_size);
198   memcpy(data, &put_msg[1], data_size);
199
200 #if DEBUG_DHT
201   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
202               "`%s': Received `%s' request from client, message type %d, key %s\n", "DHT", "PUT", put_type, GNUNET_h2s(key));
203 #endif
204
205
206   /**
207    * FIXME: Implement dht put request functionality here!
208    */
209
210   GNUNET_free(data);
211 }
212
213 /**
214  * Context for sending receipt confirmations. Not used yet.
215  */
216 struct SendConfirmationContext
217 {
218   /**
219    * The message to send.
220    */
221   struct GNUNET_DHT_StopMessage *message;
222
223   /**
224    * Transmit handle.
225    */
226   struct GNUNET_CONNECTION_TransmitHandle * transmit_handle;
227 };
228
229 static size_t send_confirmation (void *cls,
230                           size_t size, void *buf)
231 {
232   struct GNUNET_DHT_StopMessage *confirmation_message = cls;
233
234   if (buf == NULL) /* Message timed out, that's crappy... */
235   {
236     GNUNET_free(confirmation_message);
237     return 0;
238   }
239
240   if (size >= ntohs(confirmation_message->header.size))
241   {
242     memcpy(buf, confirmation_message, ntohs(confirmation_message->header.size));
243     return ntohs(confirmation_message->header.size);
244   }
245   else
246     return 0;
247 }
248
249 static void
250 send_client_receipt_confirmation(struct GNUNET_SERVER_Client *client, uint64_t uid)
251 {
252   struct GNUNET_DHT_StopMessage *confirm_message;
253
254 #if DEBUG_DHT
255   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
256               "`%s': Sending receipt confirmation for uid %llu\n", "DHT", uid);
257 #endif
258   confirm_message = GNUNET_malloc(sizeof(struct GNUNET_DHT_StopMessage));
259   confirm_message->header.type = htons(GNUNET_MESSAGE_TYPE_DHT_STOP);
260   confirm_message->header.size = htons(sizeof(struct GNUNET_DHT_StopMessage));
261   confirm_message->unique_id = GNUNET_htonll(uid);
262
263   GNUNET_SERVER_notify_transmit_ready (client,
264                                        sizeof(struct GNUNET_DHT_StopMessage),
265                                        GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
266                                        &send_confirmation, confirm_message);
267
268 }
269
270 static void
271 handle_dht_start_message(void *cls, struct GNUNET_SERVER_Client * client,
272                          const struct GNUNET_MessageHeader *message)
273 {
274   struct GNUNET_DHT_Message *dht_msg = (struct GNUNET_DHT_Message *)message;
275   struct GNUNET_MessageHeader *enc_msg;
276   size_t enc_type;
277
278   enc_msg = (struct GNUNET_MessageHeader *)&dht_msg[1];
279   enc_type = ntohs(enc_msg->type);
280
281
282 #if DEBUG_DHT
283   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284               "`%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));
285 #endif
286
287   /* FIXME: Implement demultiplexing functionality here */
288   switch (enc_type)
289     {
290     case GNUNET_MESSAGE_TYPE_DHT_GET:
291       handle_dht_get(cls, (struct GNUNET_DHT_GetMessage *)enc_msg, &dht_msg->key);
292       break;
293     case GNUNET_MESSAGE_TYPE_DHT_PUT:
294       handle_dht_put(cls, (struct GNUNET_DHT_PutMessage *)enc_msg, &dht_msg->key);
295       send_client_receipt_confirmation(client, GNUNET_ntohll(dht_msg->unique_id));
296       break;
297     case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER:
298       handle_dht_find_peer(cls, (struct GNUNET_DHT_FindPeerMessage *)enc_msg, &dht_msg->key);
299       break;
300     default:
301 #if DEBUG_DHT
302       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
303                   "`%s': Message type (%d) not handled\n", "DHT", enc_type);
304 #endif
305     }
306
307   GNUNET_SERVER_receive_done(client, GNUNET_OK);
308
309 }
310
311
312 static void
313 handle_dht_stop_message(void *cls, struct GNUNET_SERVER_Client * client,
314                         const struct GNUNET_MessageHeader *message)
315 {
316   struct GNUNET_DHT_StopMessage * dht_stop_msg = (struct GNUNET_DHT_StopMessage *)message;
317
318 #if DEBUG_DHT
319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320               "`%s': Received `%s' request from client, uid %llu\n", "DHT", "GENERIC STOP", GNUNET_ntohll(dht_stop_msg->unique_id));
321 #endif
322   send_client_receipt_confirmation(client, GNUNET_ntohll(dht_stop_msg->unique_id));
323   GNUNET_SERVER_receive_done(client, GNUNET_OK);
324 }
325
326
327 /**
328  * Core handler for p2p dht get requests.
329  */
330 static int handle_dht_p2p_get (void *cls,
331                                const struct GNUNET_PeerIdentity * peer,
332                                const struct GNUNET_MessageHeader * message,
333                                struct GNUNET_TIME_Relative latency,
334                                uint32_t distance)
335 {
336 #if DEBUG_DHT
337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338               "`%s': Received `%s' request from another peer\n", "DHT", "GET");
339 #endif
340
341   return GNUNET_YES;
342 }
343
344 /**
345  * Core handler for p2p dht put requests.
346  */
347 static int handle_dht_p2p_put (void *cls,
348                              const struct GNUNET_PeerIdentity * peer,
349                              const struct GNUNET_MessageHeader * message,
350                              struct GNUNET_TIME_Relative latency,
351                              uint32_t distance)
352 {
353 #if DEBUG_DHT
354   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355               "`%s': Received `%s' request from another peer\n", "DHT", "PUT");
356 #endif
357
358   return GNUNET_YES;
359 }
360
361 /**
362  * Core handler for p2p dht find peer requests.
363  */
364 static int handle_dht_p2p_find_peer (void *cls,
365                              const struct GNUNET_PeerIdentity * peer,
366                              const struct GNUNET_MessageHeader * message,
367                              struct GNUNET_TIME_Relative latency,
368                              uint32_t distance)
369 {
370 #if DEBUG_DHT
371   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
372               "`%s': Received `%s' request from another peer\n", "DHT", "FIND PEER");
373 #endif
374
375   return GNUNET_YES;
376 }
377
378 /**
379  * Task run during shutdown.
380  *
381  * @param cls unused
382  * @param tc unused
383  */
384 static void
385 shutdown_task (void *cls,
386                const struct GNUNET_SCHEDULER_TaskContext *tc)
387 {
388   GNUNET_CORE_disconnect (coreAPI);
389 }
390
391 /**
392  * To be called on core init/fail.
393  */
394 void core_init (void *cls,
395                 struct GNUNET_CORE_Handle * server,
396                 const struct GNUNET_PeerIdentity *identity,
397                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
398 {
399
400   if (server == NULL)
401     {
402       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
403       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
404       return;
405     }
406 #if DEBUG_DHT
407   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408               "%s: Core connection initialized, I am peer: %s\n", "dht", GNUNET_i2s(identity));
409 #endif
410   memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
411   coreAPI = server;
412 }
413
414 /**
415  * Process dht requests.
416  *
417  * @param cls closure
418  * @param scheduler scheduler to use
419  * @param server the initialized server
420  * @param c configuration to use
421  */
422 static void
423 run (void *cls,
424      struct GNUNET_SCHEDULER_Handle *scheduler,
425      struct GNUNET_SERVER_Handle *server,
426      const struct GNUNET_CONFIGURATION_Handle *c)
427 {
428   sched = scheduler;
429   cfg = c;
430
431   datastore = GNUNET_DATASTORE_connect(c, scheduler);
432
433   client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
434   GNUNET_SERVER_add_handlers (server, plugin_handlers);
435
436   coreAPI =
437   GNUNET_CORE_connect (sched, /* Main scheduler */
438                        cfg,   /* Main configuration */
439                        client_transmit_timeout, /* Delay for connecting */
440                        NULL, /* FIXME: anything we want to pass around? */
441                        &core_init, /* Call core_init once connected */
442                        NULL, /* Don't care about pre-connects */
443                        NULL, /* Don't care about connects */
444                        NULL, /* Don't care about disconnects */
445                        NULL, /* Don't want notified about all incoming messages */
446                        GNUNET_NO, /* For header only inbound notification */
447                        NULL, /* Don't want notified about all outbound messages */
448                        GNUNET_NO, /* For header only outbound notification */
449                        core_handlers); /* Register these handlers */
450
451   if (coreAPI == NULL)
452     return;
453
454   /* Scheduled the task to clean up when shutdown is called */
455   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
456                                 GNUNET_TIME_UNIT_FOREVER_REL,
457                                 &shutdown_task,
458                                 NULL);
459 }
460
461
462 /**
463  * The main function for the dht service.
464  *
465  * @param argc number of arguments from the command line
466  * @param argv command line arguments
467  * @return 0 ok, 1 on error
468  */
469 int
470 main (int argc, char *const *argv)
471 {
472   return (GNUNET_OK ==
473           GNUNET_SERVICE_run (argc,
474                               argv,
475                               "dht",
476                               GNUNET_SERVICE_OPTION_NONE,
477                               &run, NULL)) ? 0 : 1;
478 }