beginning of changes
[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 initiating local dht get requests
90  */
91 static void handle_dht_get (void *cls, struct GNUNET_SERVER_Client * client,
92                      const struct GNUNET_MessageHeader *message);
93
94 /**
95  * Server handler for stopping local dht get requests
96  */
97 static void handle_dht_get_stop (void *cls, struct GNUNET_SERVER_Client * client,
98                      const struct GNUNET_MessageHeader *message);
99
100 /**
101  * Server handler for initiating local dht find peer requests
102  */
103 static void handle_dht_find_peer (void *cls, struct GNUNET_SERVER_Client *
104                            client, const struct GNUNET_MessageHeader *
105                            message);
106
107 /**
108  * Server handler for stopping local dht find peer requests
109  */
110 static void handle_dht_find_peer_stop (void *cls, struct GNUNET_SERVER_Client *
111                            client, const struct GNUNET_MessageHeader *
112                            message);
113
114 /**
115  * Server handler for initiating local dht put requests
116  */
117 static void handle_dht_put (void *cls, struct GNUNET_SERVER_Client * client,
118                      const struct GNUNET_MessageHeader *message);
119
120
121 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
122   {&handle_dht_get, NULL, GNUNET_MESSAGE_TYPE_DHT_GET, 0},
123   {&handle_dht_get_stop, NULL, GNUNET_MESSAGE_TYPE_DHT_GET_STOP, 0},
124   {&handle_dht_put, NULL, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
125   {&handle_dht_find_peer, NULL, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER, 0},
126   {&handle_dht_find_peer_stop, NULL, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER_STOP, 0},
127   {NULL, NULL, 0, 0}
128 };
129
130
131 /**
132  * Core handler for p2p dht get requests.
133  */
134 static int handle_dht_p2p_get (void *cls,
135                              const struct GNUNET_PeerIdentity * peer,
136                              const struct GNUNET_MessageHeader * message,
137                              struct GNUNET_TIME_Relative latency,
138                              uint32_t distance);
139
140 /**
141  * Core handler for p2p dht put requests.
142  */
143 static int handle_dht_p2p_put (void *cls,
144                              const struct GNUNET_PeerIdentity * peer,
145                              const struct GNUNET_MessageHeader * message,
146                              struct GNUNET_TIME_Relative latency,
147                              uint32_t distance);
148
149 /**
150  * Core handler for p2p dht find peer requests.
151  */
152 static int handle_dht_p2p_find_peer (void *cls,
153                              const struct GNUNET_PeerIdentity * peer,
154                              const struct GNUNET_MessageHeader * message,
155                              struct GNUNET_TIME_Relative latency,
156                              uint32_t distance);
157
158 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
159   {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_GET, 0},
160   {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
161   {&handle_dht_p2p_find_peer, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
162   {NULL, 0, 0}
163 };
164
165
166 /**
167  * Server handler for initiating local dht get requests
168  */
169 static void handle_dht_get (void *cls, struct GNUNET_SERVER_Client * client,
170                             const struct GNUNET_MessageHeader *message)
171 {
172   struct GNUNET_DHT_GetMessage *get_msg = (struct GNUNET_DHT_GetMessage *)message;
173   GNUNET_HashCode get_key;
174   size_t get_type;
175
176   GNUNET_assert(ntohs(get_msg->header.size) >= sizeof(struct GNUNET_DHT_GetMessage));
177   memcpy(&get_key, &get_msg->key, sizeof(GNUNET_HashCode));
178   get_type = ntohs(get_msg->type);
179
180 #if DEBUG_DHT
181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182               "`%s': Received `%s' request from client, message type %d, key %s\n", "DHT", "GET", get_type, GNUNET_h2s(&get_key));
183 #endif
184
185   /* FIXME: Implement get stop functionality here */
186
187 }
188
189 /**
190  * Server handler for stopping local dht get requests
191  */
192 static void handle_dht_get_stop (void *cls, struct GNUNET_SERVER_Client * client,
193                           const struct GNUNET_MessageHeader *message)
194 {
195   struct GNUNET_DHT_GetMessage *get_msg = (struct GNUNET_DHT_GetMessage *)message; /* Get message and get stop message are the same except for type */
196   GNUNET_HashCode get_key;
197   size_t get_type;
198
199   GNUNET_assert(ntohs(get_msg->header.size) >= sizeof(struct GNUNET_DHT_GetMessage));
200
201   memcpy(&get_key, &get_msg->key, sizeof(GNUNET_HashCode));
202   get_type = ntohs(get_msg->type);
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", "GET STOP", get_type, GNUNET_h2s(&get_key));
207 #endif
208
209   /* FIXME: Implement get stop functionality here */
210
211 }
212
213 /**
214  * Server handler for initiating local dht find peer requests
215  */
216 static void handle_dht_find_peer (void *cls, struct GNUNET_SERVER_Client *
217                                   client, const struct GNUNET_MessageHeader *
218                                   message)
219 {
220   struct GNUNET_DHT_FindPeerMessage *find_msg = (struct GNUNET_DHT_FindPeerMessage *)message;
221   struct GNUNET_PeerIdentity peer;
222
223   GNUNET_assert(ntohs(find_msg->header.size) == sizeof(struct GNUNET_DHT_FindPeerMessage));
224   memcpy(&peer, &find_msg->peer, sizeof(struct GNUNET_PeerIdentity));
225
226 #if DEBUG_DHT
227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
228               "`%s': Received `%s' request from client, peer id %s\n", "DHT", "FIND PEER", GNUNET_i2s(&peer));
229 #endif
230
231   /* FIXME: Implement find peer functionality here */
232 }
233
234 /**
235  * Server handler for stopping local dht find peer requests
236  */
237 static void handle_dht_find_peer_stop (void *cls, struct GNUNET_SERVER_Client *
238                            client, const struct GNUNET_MessageHeader *
239                            message)
240 {
241   struct GNUNET_DHT_FindPeerMessage *find_msg = (struct GNUNET_DHT_FindPeerMessage *)message; /* Find peer stop message is identical to find peer message */
242   struct GNUNET_PeerIdentity peer;
243
244   GNUNET_assert(ntohs(find_msg->header.size) == sizeof(struct GNUNET_DHT_FindPeerMessage));
245   memcpy(&peer, &find_msg->peer, sizeof(struct GNUNET_PeerIdentity));
246
247 #if DEBUG_DHT
248   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
249               "`%s': Received `%s' request from client, for peer id %s\n", "DHT", "FIND PEER STOP", GNUNET_i2s(&peer));
250 #endif
251
252   /* FIXME: Implement find peer stop functionality here */
253
254 }
255
256 /**
257  * Server handler for initiating local dht put requests
258  */
259 static void handle_dht_put (void *cls, struct GNUNET_SERVER_Client * client,
260                      const struct GNUNET_MessageHeader *message)
261 {
262   struct GNUNET_DHT_PutMessage *put_msg = (struct GNUNET_DHT_PutMessage *)message;
263   GNUNET_HashCode put_key;
264   size_t put_type;
265   size_t data_size;
266   char *data;
267
268   GNUNET_assert(ntohs(put_msg->header.size) >= sizeof(struct GNUNET_DHT_PutMessage));
269
270   memcpy(&put_key, &put_msg->key, sizeof(GNUNET_HashCode));
271   put_type = ntohs(put_msg->type);
272   data_size = ntohs(put_msg->data_size);
273   GNUNET_assert(ntohs(put_msg->header.size) == sizeof(struct GNUNET_DHT_PutMessage) + data_size);
274   data = GNUNET_malloc(data_size);
275   memcpy(data, &put_msg[1], data_size);
276
277 #if DEBUG_DHT
278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
279               "`%s': Received `%s' request from client, message type %d, key %s\n", "DHT", "PUT", put_type, GNUNET_h2s(&put_key));
280 #endif
281
282   /**
283    * FIXME: Implement dht put request functionality here!
284    */
285
286   GNUNET_free(data);
287
288 }
289
290 /**
291  * Core handler for p2p dht get requests.
292  */
293 static int handle_dht_p2p_get (void *cls,
294                                const struct GNUNET_PeerIdentity * peer,
295                                const struct GNUNET_MessageHeader * message,
296                                struct GNUNET_TIME_Relative latency,
297                                uint32_t distance)
298 {
299 #if DEBUG_DHT
300   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
301               "`%s': Received `%s' request from another peer\n", "DHT", "GET");
302 #endif
303
304   return GNUNET_YES;
305 }
306
307 /**
308  * Core handler for p2p dht put requests.
309  */
310 static int handle_dht_p2p_put (void *cls,
311                              const struct GNUNET_PeerIdentity * peer,
312                              const struct GNUNET_MessageHeader * message,
313                              struct GNUNET_TIME_Relative latency,
314                              uint32_t distance)
315 {
316 #if DEBUG_DHT
317   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318               "`%s': Received `%s' request from another peer\n", "DHT", "PUT");
319 #endif
320
321   return GNUNET_YES;
322 }
323
324 /**
325  * Core handler for p2p dht find peer requests.
326  */
327 static int handle_dht_p2p_find_peer (void *cls,
328                              const struct GNUNET_PeerIdentity * peer,
329                              const struct GNUNET_MessageHeader * message,
330                              struct GNUNET_TIME_Relative latency,
331                              uint32_t distance)
332 {
333 #if DEBUG_DHT
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335               "`%s': Received `%s' request from another peer\n", "DHT", "FIND PEER");
336 #endif
337
338   return GNUNET_YES;
339 }
340
341 /**
342  * Task run during shutdown.
343  *
344  * @param cls unused
345  * @param tc unused
346  */
347 static void
348 shutdown_task (void *cls,
349                const struct GNUNET_SCHEDULER_TaskContext *tc)
350 {
351   GNUNET_CORE_disconnect (coreAPI);
352 }
353
354 /**
355  * To be called on core init/fail.
356  */
357 void core_init (void *cls,
358                 struct GNUNET_CORE_Handle * server,
359                 const struct GNUNET_PeerIdentity *identity,
360                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
361 {
362
363   if (server == NULL)
364     {
365       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
366       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
367       return;
368     }
369 #if DEBUG_DHT
370   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371               "%s: Core connection initialized, I am peer: %s\n", "dht", GNUNET_i2s(identity));
372 #endif
373   memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
374   coreAPI = server;
375 }
376
377 /**
378  * Process dht requests.
379  *
380  * @param cls closure
381  * @param scheduler scheduler to use
382  * @param server the initialized server
383  * @param c configuration to use
384  */
385 static void
386 run (void *cls,
387      struct GNUNET_SCHEDULER_Handle *scheduler,
388      struct GNUNET_SERVER_Handle *server,
389      const struct GNUNET_CONFIGURATION_Handle *c)
390 {
391   sched = scheduler;
392   cfg = c;
393
394   datastore = GNUNET_DATASTORE_connect(c, scheduler);
395
396   client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
397   GNUNET_SERVER_add_handlers (server, plugin_handlers);
398
399   coreAPI =
400   GNUNET_CORE_connect (sched, /* Main scheduler */
401                        cfg,   /* Main configuration */
402                        client_transmit_timeout, /* Delay for connecting */
403                        NULL, /* FIXME: anything we want to pass around? */
404                        &core_init, /* Call core_init once connected */
405                        NULL, /* Don't care about pre-connects */
406                        NULL, /* Don't care about connects */
407                        NULL, /* Don't care about disconnects */
408                        NULL, /* Don't want notified about all incoming messages */
409                        GNUNET_NO, /* For header only inbound notification */
410                        NULL, /* Don't want notified about all outbound messages */
411                        GNUNET_NO, /* For header only outbound notification */
412                        core_handlers); /* Register these handlers */
413
414   if (coreAPI == NULL)
415     return;
416
417   /* Scheduled the task to clean up when shutdown is called */
418   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
419                                 GNUNET_TIME_UNIT_FOREVER_REL,
420                                 &shutdown_task,
421                                 NULL);
422 }
423
424
425 /**
426  * The main function for the dv service.
427  *
428  * @param argc number of arguments from the command line
429  * @param argv command line arguments
430  * @return 0 ok, 1 on error
431  */
432 int
433 main (int argc, char *const *argv)
434 {
435   return (GNUNET_OK ==
436           GNUNET_SERVICE_run (argc,
437                               argv,
438                               "dht",
439                               GNUNET_SERVICE_OPTION_NONE,
440                               &run, NULL)) ? 0 : 1;
441 }