426d7809779d2bfa0099bbf96ad36f8159cff05b
[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_dht_service.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 /*  {&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},*/
106   {NULL, NULL, 0, 0}
107 };
108
109
110 /**
111  * Core handler for p2p dht get requests.
112  */
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,
117                              uint32_t distance);
118
119 /**
120  * Core handler for p2p dht put requests.
121  */
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,
126                              uint32_t distance);
127
128 /**
129  * Core handler for p2p dht find peer requests.
130  */
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,
135                              uint32_t distance);
136
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},
141   {NULL, 0, 0}
142 };
143
144
145
146 /**
147  * Server handler for initiating local dht get requests
148  */
149 static void handle_dht_get (void *cls, struct GNUNET_DHT_GetMessage *get_msg, GNUNET_HashCode *key)
150 {
151   GNUNET_HashCode get_key;
152   size_t get_type;
153
154   GNUNET_assert(ntohs(get_msg->header.size) >= sizeof(struct GNUNET_DHT_GetMessage));
155   get_type = ntohs(get_msg->type);
156
157 #if DEBUG_DHT
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));
160 #endif
161
162   /* FIXME: Implement get functionality here */
163 }
164
165
166 /**
167  * Server handler for initiating local dht find peer requests
168  */
169 static void handle_dht_find_peer (void *cls, struct GNUNET_DHT_FindPeerMessage *find_msg, GNUNET_HashCode *key)
170 {
171
172   GNUNET_assert(ntohs(find_msg->header.size) == sizeof(struct GNUNET_DHT_FindPeerMessage));
173
174 #if DEBUG_DHT
175   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176               "`%s': Received `%s' request from client, key %s\n", "DHT", "FIND PEER", GNUNET_h2s(key));
177 #endif
178
179   /* FIXME: Implement find peer functionality here */
180 }
181
182
183 /**
184  * Server handler for initiating local dht put requests
185  */
186 static void handle_dht_put (void *cls, struct GNUNET_DHT_PutMessage *put_msg, GNUNET_HashCode *key)
187 {
188   size_t put_type;
189   size_t data_size;
190   char *data;
191
192   GNUNET_assert(ntohs(put_msg->header.size) >= sizeof(struct GNUNET_DHT_PutMessage));
193
194   put_type = ntohs(put_msg->type);
195   data_size = ntohs(put_msg->data_size);
196 #if DEBUG_DHT
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));
199 #endif
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);
203
204 #if DEBUG_DHT
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));
207 #endif
208
209
210   /**
211    * FIXME: Implement dht put request functionality here!
212    */
213
214   GNUNET_free(data);
215 }
216
217 /**
218  * Context for sending receipt confirmations. Not used yet.
219  */
220 struct SendConfirmationContext
221 {
222   /**
223    * The message to send.
224    */
225   struct GNUNET_DHT_StopMessage *message;
226
227   /**
228    * Transmit handle.
229    */
230   struct GNUNET_CONNECTION_TransmitHandle * transmit_handle;
231 };
232
233 size_t send_confirmation (void *cls,
234                           size_t size, void *buf)
235 {
236   struct GNUNET_DHT_StopMessage *confirmation_message = cls;
237
238   if (buf == NULL) /* Message timed out, that's crappy... */
239   {
240     GNUNET_free(confirmation_message);
241     return 0;
242   }
243
244   if (size >= ntohs(confirmation_message->header.size))
245   {
246     memcpy(buf, confirmation_message, ntohs(confirmation_message->header.size));
247     return ntohs(confirmation_message->header.size);
248   }
249   else
250     return 0;
251 }
252
253 static void
254 send_client_receipt_confirmation(struct GNUNET_SERVER_Client *client, uint64_t uid)
255 {
256   struct GNUNET_DHT_StopMessage *confirm_message;
257
258 #if DEBUG_DHT
259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260               "`%s': Sending receipt confirmation for uid %llu\n", "DHT", uid);
261 #endif
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);
266
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);
271
272 }
273
274 static void
275 handle_dht_start_message(void *cls, struct GNUNET_SERVER_Client * client,
276                          const struct GNUNET_MessageHeader *message)
277 {
278   struct GNUNET_DHT_Message *dht_msg = (struct GNUNET_DHT_Message *)message;
279   struct GNUNET_MessageHeader *enc_msg;
280   size_t enc_type;
281
282   enc_msg = (struct GNUNET_MessageHeader *)&dht_msg[1];
283   enc_type = ntohs(enc_msg->type);
284
285
286 #if DEBUG_DHT
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));
289 #endif
290
291   /* FIXME: Implement demultiplexing functionality here */
292   switch (enc_type)
293     {
294     case GNUNET_MESSAGE_TYPE_DHT_GET:
295       handle_dht_get(cls, (struct GNUNET_DHT_GetMessage *)enc_msg, &dht_msg->key);
296       break;
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));
300       break;
301     case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER:
302       handle_dht_find_peer(cls, (struct GNUNET_DHT_FindPeerMessage *)enc_msg, &dht_msg->key);
303       break;
304     default:
305 #if DEBUG_DHT
306       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307                   "`%s': Message type (%d) not handled\n", "DHT", enc_type);
308 #endif
309     }
310
311   GNUNET_SERVER_receive_done(client, GNUNET_OK);
312
313 }
314
315
316 static void
317 handle_dht_stop_message(void *cls, struct GNUNET_SERVER_Client * client,
318                         const struct GNUNET_MessageHeader *message)
319 {
320   struct GNUNET_DHT_StopMessage * dht_stop_msg = (struct GNUNET_DHT_StopMessage *)message;
321
322 #if DEBUG_DHT
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));
325 #endif
326   send_client_receipt_confirmation(client, GNUNET_ntohll(dht_stop_msg->unique_id));
327   GNUNET_SERVER_receive_done(client, GNUNET_OK);
328 }
329
330
331 /**
332  * Core handler for p2p dht get requests.
333  */
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,
338                                uint32_t distance)
339 {
340 #if DEBUG_DHT
341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342               "`%s': Received `%s' request from another peer\n", "DHT", "GET");
343 #endif
344
345   return GNUNET_YES;
346 }
347
348 /**
349  * Core handler for p2p dht put requests.
350  */
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,
355                              uint32_t distance)
356 {
357 #if DEBUG_DHT
358   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359               "`%s': Received `%s' request from another peer\n", "DHT", "PUT");
360 #endif
361
362   return GNUNET_YES;
363 }
364
365 /**
366  * Core handler for p2p dht find peer requests.
367  */
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,
372                              uint32_t distance)
373 {
374 #if DEBUG_DHT
375   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376               "`%s': Received `%s' request from another peer\n", "DHT", "FIND PEER");
377 #endif
378
379   return GNUNET_YES;
380 }
381
382 /**
383  * Task run during shutdown.
384  *
385  * @param cls unused
386  * @param tc unused
387  */
388 static void
389 shutdown_task (void *cls,
390                const struct GNUNET_SCHEDULER_TaskContext *tc)
391 {
392   GNUNET_CORE_disconnect (coreAPI);
393 }
394
395 /**
396  * To be called on core init/fail.
397  */
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)
402 {
403
404   if (server == NULL)
405     {
406       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
407       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
408       return;
409     }
410 #if DEBUG_DHT
411   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412               "%s: Core connection initialized, I am peer: %s\n", "dht", GNUNET_i2s(identity));
413 #endif
414   memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
415   coreAPI = server;
416 }
417
418 /**
419  * Process dht requests.
420  *
421  * @param cls closure
422  * @param scheduler scheduler to use
423  * @param server the initialized server
424  * @param c configuration to use
425  */
426 static void
427 run (void *cls,
428      struct GNUNET_SCHEDULER_Handle *scheduler,
429      struct GNUNET_SERVER_Handle *server,
430      const struct GNUNET_CONFIGURATION_Handle *c)
431 {
432   sched = scheduler;
433   cfg = c;
434
435   datastore = GNUNET_DATASTORE_connect(c, scheduler);
436
437   client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
438   GNUNET_SERVER_add_handlers (server, plugin_handlers);
439
440   coreAPI =
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 */
454
455   if (coreAPI == NULL)
456     return;
457
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,
461                                 &shutdown_task,
462                                 NULL);
463 }
464
465
466 /**
467  * The main function for the dv service.
468  *
469  * @param argc number of arguments from the command line
470  * @param argv command line arguments
471  * @return 0 ok, 1 on error
472  */
473 int
474 main (int argc, char *const *argv)
475 {
476   return (GNUNET_OK ==
477           GNUNET_SERVICE_run (argc,
478                               argv,
479                               "dht",
480                               GNUNET_SERVICE_OPTION_NONE,
481                               &run, NULL)) ? 0 : 1;
482 }