see if timing is cause
[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_datacache_lib.h"
38 #include "gnunet_transport_service.h"
39 #include "gnunet_hello_lib.h"
40 #include "dht.h"
41
42 /**
43  * Handle to the datacache service (for inserting/retrieving data)
44  */
45 struct GNUNET_DATACACHE_Handle *datacache;
46
47 /**
48  * The main scheduler to use for the DHT service
49  */
50 static struct GNUNET_SCHEDULER_Handle *sched;
51
52 /**
53  * The configuration the DHT service is running with
54  */
55 static const struct GNUNET_CONFIGURATION_Handle *cfg;
56
57 /**
58  * Timeout for transmissions to clients
59  */
60 static struct GNUNET_TIME_Relative client_transmit_timeout;
61
62 /**
63  * Handle to the core service
64  */
65 static struct GNUNET_CORE_Handle *coreAPI;
66
67 /**
68  * Handle to the transport service, for getting our hello
69  */
70 static struct GNUNET_TRANSPORT_Handle *transport_handle;
71
72 /**
73  * The identity of our peer.
74  */
75 static struct GNUNET_PeerIdentity my_identity;
76
77 /**
78  * Our HELLO
79  */
80 static struct GNUNET_MessageHeader *my_hello;
81
82 /**
83  * Task to run when we shut down, cleaning up all our trash
84  */
85 static GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
86
87
88 /**
89  * Linked list of messages to send to clients.
90  */
91 struct PendingMessage
92 {
93   /**
94    * Pointer to next item in the list
95    */
96   struct PendingMessage *next;
97
98   /**
99    * Actual message to be sent
100    */
101   struct GNUNET_MessageHeader *msg;
102
103 };
104
105 /**
106  * Struct containing information about a client,
107  * handle to connect to it, and any pending messages
108  * that need to be sent to it.
109  */
110 struct ClientList
111 {
112   /**
113    * Linked list of active clients
114    */
115   struct ClientList *next;
116
117   /**
118    * The handle to this client
119    */
120   struct GNUNET_SERVER_Client *client_handle;
121
122   /**
123    * Handle to the current transmission request, NULL
124    * if none pending.
125    */
126   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
127
128   /**
129    * Linked list of pending messages for this client
130    */
131   struct PendingMessage *pending_head;
132
133 };
134
135 /**
136  * Context for handling results from a get request.
137  */
138 struct DatacacheGetContext
139 {
140   /**
141    * The client to send the result to.
142    */
143   struct ClientList *client;
144
145   /**
146    * The unique id of this request
147    */
148   unsigned long long unique_id;
149 };
150
151 /**
152  * Context containing information about a DHT message received.
153  */
154 struct DHT_MessageContext
155 {
156   /**
157    * The client this request was received from.
158    */
159   struct ClientList *client;
160
161   /**
162    * The key this request was about
163    */
164   GNUNET_HashCode *key;
165
166   /**
167    * The unique identifier of this request
168    */
169   unsigned long long unique_id;
170
171   /**
172    * Desired replication level
173    */
174   size_t replication;
175
176   /**
177    * Any message options for this request
178    */
179   size_t msg_options;
180 };
181
182 /**
183  * List of active clients.
184  */
185 static struct ClientList *client_list;
186
187
188 /**
189  * Server handlers for handling locally received dht requests
190  */
191 static void
192 handle_dht_start_message (void *cls, struct GNUNET_SERVER_Client *client,
193                           const struct GNUNET_MessageHeader *message);
194
195 static void
196 handle_dht_stop_message (void *cls, struct GNUNET_SERVER_Client *client,
197                          const struct GNUNET_MessageHeader *message);
198
199 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
200   {&handle_dht_start_message, NULL, GNUNET_MESSAGE_TYPE_DHT, 0},
201   {&handle_dht_stop_message, NULL, GNUNET_MESSAGE_TYPE_DHT_STOP, 0},
202   {NULL, NULL, 0, 0}
203 };
204
205
206 /**
207  * Core handler for p2p dht get requests.
208  */
209 static int handle_dht_p2p_get (void *cls,
210                                const struct GNUNET_PeerIdentity *peer,
211                                const struct GNUNET_MessageHeader *message,
212                                struct GNUNET_TIME_Relative latency,
213                                uint32_t distance);
214
215 /**
216  * Core handler for p2p dht put requests.
217  */
218 static int handle_dht_p2p_put (void *cls,
219                                const struct GNUNET_PeerIdentity *peer,
220                                const struct GNUNET_MessageHeader *message,
221                                struct GNUNET_TIME_Relative latency,
222                                uint32_t distance);
223
224 /**
225  * Core handler for p2p dht find peer requests.
226  */
227 static int handle_dht_p2p_find_peer (void *cls,
228                                      const struct GNUNET_PeerIdentity *peer,
229                                      const struct GNUNET_MessageHeader
230                                      *message,
231                                      struct GNUNET_TIME_Relative latency,
232                                      uint32_t distance);
233
234 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
235   {&handle_dht_p2p_get, GNUNET_MESSAGE_TYPE_DHT_GET, 0},
236   {&handle_dht_p2p_put, GNUNET_MESSAGE_TYPE_DHT_PUT, 0},
237   {&handle_dht_p2p_find_peer, GNUNET_MESSAGE_TYPE_DHT_FIND_PEER, 0},
238   {NULL, 0, 0}
239 };
240
241 /**
242  * Forward declaration.
243  */
244 static size_t send_generic_reply (void *cls, size_t size, void *buf);
245
246 /**
247  * Task run to check for messages that need to be sent to a client.
248  *
249  * @param cls a ClientList, containing the client and any messages to be sent to it
250  * @param tc reason this was called
251  */
252 static void
253 process_pending_messages (void *cls,
254                           const struct GNUNET_SCHEDULER_TaskContext *tc)
255 {
256   struct ClientList *client = cls;
257
258   if (client->pending_head == NULL)     /* No messages queued */
259     {
260 #if DEBUG_DHT
261       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262                   "`%s': Have no pending messages for client.\n", "DHT");
263 #endif
264       return;
265     }
266
267   if (client->transmit_handle == NULL)  /* No current pending messages, we can try to send! */
268     client->transmit_handle =
269       GNUNET_SERVER_notify_transmit_ready (client->client_handle,
270                                            ntohs (client->pending_head->msg->
271                                                   size),
272                                            GNUNET_TIME_relative_multiply
273                                            (GNUNET_TIME_UNIT_SECONDS, 5),
274                                            &send_generic_reply, client);
275   else
276     {
277 #if DEBUG_DHT
278       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
279                   "`%s': Transmit handle is non-null.\n", "DHT");
280 #endif
281     }
282 }
283
284 /**
285  * Callback called as a result of issuing a GNUNET_SERVER_notify_transmit_ready
286  * request.  A ClientList is passed as closure, take the head of the list
287  * and copy it into buf, which has the result of sending the message to the
288  * client.
289  *
290  * @param cls closure to this call
291  * @param size maximum number of bytes available to send
292  * @param buf where to copy the actual message to
293  *
294  * @return the number of bytes actually copied, 0 indicates failure
295  */
296 static size_t
297 send_generic_reply (void *cls, size_t size, void *buf)
298 {
299   struct ClientList *client = cls;
300   struct PendingMessage *reply = client->pending_head;
301   int ret;
302
303   client->transmit_handle = NULL;
304   if (buf == NULL)              /* Message timed out, that's crappy... */
305     {
306 #if DEBUG_DHT
307       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s': buffer was NULL\n", "DHT");
308 #endif
309       client->pending_head = reply->next;
310       GNUNET_free (reply->msg);
311       GNUNET_free (reply);
312       return 0;
313     }
314
315   if (size >= ntohs (reply->msg->size))
316     {
317 #if DEBUG_DHT
318       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319                   "`%s': Copying reply to buffer, REALLY SENT\n", "DHT");
320 #endif
321       memcpy (buf, reply->msg, ntohs (reply->msg->size));
322
323       ret = ntohs (reply->msg->size);
324     }
325   else
326     ret = 0;
327
328   client->pending_head = reply->next;
329   GNUNET_free (reply->msg);
330   GNUNET_free (reply);
331
332   GNUNET_SCHEDULER_add_now (sched, &process_pending_messages, client);
333   return ret;
334 }
335
336 /**
337  * Add a PendingMessage to the clients list of messages to be sent
338  *
339  * @param client the active client to send the message to
340  * @param pending_message the actual message to send
341  */
342 static void
343 add_pending_message (struct ClientList *client,
344                      struct PendingMessage *pending_message)
345 {
346   struct PendingMessage *pos;
347   struct PendingMessage *prev;
348
349   pos = client->pending_head;
350
351 #if DEBUG_DHT
352   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353               "`%s': Adding pending message for client.\n", "DHT");
354 #endif
355
356   if (pos == NULL)
357     {
358       client->pending_head = pending_message;
359     }
360   else                          /* This means another request is already queued, rely on send_reply to process all pending messages */
361     {
362       while (pos != NULL)       /* Find end of list */
363         {
364           prev = pos;
365           pos = pos->next;
366         }
367
368       GNUNET_assert (prev != NULL);
369       prev->next = pending_message;
370     }
371
372   GNUNET_SCHEDULER_add_now (sched, &process_pending_messages, client);
373
374 }
375
376 /**
377  * Called when a reply needs to be sent to a client, either as
378  * a result it found to a GET or FIND PEER request.
379  *
380  * @param client the client to send the reply to
381  * @param message the encapsulated message to send
382  * @param uid the unique identifier of this request
383  */
384 static void
385 send_reply_to_client (struct ClientList *client,
386                       struct GNUNET_MessageHeader *message,
387                       unsigned long long uid)
388 {
389   struct GNUNET_DHT_Message *reply;
390   struct PendingMessage *pending_message;
391
392   size_t msize;
393   size_t tsize;
394 #if DEBUG_DHT
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396               "`%s': Sending reply to client.\n", "DHT");
397 #endif
398   msize = ntohs (message->size);
399   tsize = sizeof (struct GNUNET_DHT_Message) + msize;
400   reply = GNUNET_malloc (tsize);
401   reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT);
402   reply->header.size = htons (tsize);
403   if (uid != 0)
404     reply->unique = htons (GNUNET_YES);
405   reply->unique_id = GNUNET_htonll (uid);
406   memcpy (&reply[1], message, msize);
407
408   pending_message = GNUNET_malloc (sizeof (struct PendingMessage));
409   pending_message->msg = &reply->header;
410
411   add_pending_message (client, pending_message);
412 }
413
414
415 /**
416  * Iterator for local get request results,
417  *
418  * @param cls closure for iterator, a DatacacheGetContext
419  * @param exp when does this value expire?
420  * @param key the key this data is stored under
421  * @param size the size of the data identified by key
422  * @param data the actual data
423  * @param type the type of the data
424  *
425  * @return GNUNET_OK to continue iteration, anything else
426  * to stop iteration.
427  */
428 static int
429 datacache_get_iterator (void *cls,
430                         struct GNUNET_TIME_Absolute exp,
431                         const GNUNET_HashCode * key,
432                         uint32_t size, const char *data, uint32_t type)
433 {
434   struct DatacacheGetContext *datacache_get_ctx = cls;
435   struct GNUNET_DHT_GetResultMessage *get_result;
436 #if DEBUG_DHT
437   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438               "`%s': Received `%s' response from datacache\n", "DHT", "GET");
439 #endif
440   get_result =
441     GNUNET_malloc (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
442   get_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_GET_RESULT);
443   get_result->header.size =
444     htons (sizeof (struct GNUNET_DHT_GetResultMessage) + size);
445   get_result->data_size = htons (size);
446   get_result->expiration = exp;
447   memcpy (&get_result->key, key, sizeof (GNUNET_HashCode));
448   get_result->type = htons (type);
449   memcpy (&get_result[1], data, size);
450
451   send_reply_to_client (datacache_get_ctx->client, &get_result->header,
452                         datacache_get_ctx->unique_id);
453
454   GNUNET_free (get_result);
455   return GNUNET_OK;
456 }
457
458 /**
459  * Server handler for initiating local dht get requests
460  *
461  * @param cls closure for service
462  * @param get_msg the actual get message
463  * @param message_context struct containing pertinent information about the get request
464  *
465  */
466 static void
467 handle_dht_get (void *cls, struct GNUNET_DHT_GetMessage *get_msg,
468                 struct DHT_MessageContext *message_context)
469 {
470 #if DEBUG_DHT
471   GNUNET_HashCode get_key;
472 #endif
473   size_t get_type;
474   unsigned int results;
475   struct DatacacheGetContext *datacache_get_context;
476
477   GNUNET_assert (ntohs (get_msg->header.size) >=
478                  sizeof (struct GNUNET_DHT_GetMessage));
479   get_type = ntohs (get_msg->type);
480
481 #if DEBUG_DHT
482   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
483               "`%s': Received `%s' request from client, message type %d, key %s, uid %llu\n",
484               "DHT", "GET", get_type, GNUNET_h2s (&get_key),
485               message_context->unique_id);
486 #endif
487
488   datacache_get_context = GNUNET_malloc (sizeof (struct DatacacheGetContext));
489   datacache_get_context->client = message_context->client;
490   datacache_get_context->unique_id = message_context->unique_id;
491
492   results = 0;
493   if (datacache != NULL)
494     results =
495       GNUNET_DATACACHE_get (datacache, message_context->key, get_type,
496                             &datacache_get_iterator, datacache_get_context);
497
498 #if DEBUG_DHT
499   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
500               "`%s': Found %d results for local `%s' request\n", "DHT",
501               results, "GET");
502 #endif
503   GNUNET_free (datacache_get_context);
504   /* FIXME: Implement get functionality here */
505 }
506
507
508 /**
509  * Server handler for initiating local dht find peer requests
510  *
511  * @param cls closure for service
512  * @param find_msg the actual find peer message
513  * @param message_context struct containing pertinent information about the request
514  *
515  */
516 static void
517 handle_dht_find_peer (void *cls, struct GNUNET_DHT_FindPeerMessage *find_msg,
518                       struct DHT_MessageContext *message_context)
519 {
520   struct GNUNET_DHT_FindPeerResultMessage *find_peer_result;
521   size_t hello_size;
522   size_t tsize;
523 #if DEBUG_DHT
524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525               "`%s': Received `%s' request from client, key %s (msg size %d, we expected %d)\n",
526               "DHT", "FIND PEER", GNUNET_h2s (message_context->key),
527               ntohs (find_msg->header.size),
528               sizeof (struct GNUNET_DHT_FindPeerMessage));
529 #endif
530
531   GNUNET_assert (ntohs (find_msg->header.size) >=
532                  sizeof (struct GNUNET_DHT_FindPeerMessage));
533
534   if (my_hello == NULL)
535   {
536 #if DEBUG_DHT
537     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
538                 "`%s': Our HELLO is null, can't return.\n",
539                 "DHT");
540 #endif
541
542     return;
543   }
544
545   /* Simplistic find_peer functionality, always return our hello */
546   hello_size = ntohs(my_hello->size);
547   tsize = hello_size + sizeof (struct GNUNET_DHT_FindPeerResultMessage);
548   find_peer_result = GNUNET_malloc (tsize);
549   find_peer_result->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_FIND_PEER_RESULT);
550   find_peer_result->header.size = htons (tsize);
551   find_peer_result->data_size = htons (hello_size);
552   memcpy(&find_peer_result->peer, &my_identity, sizeof(struct GNUNET_PeerIdentity));
553   memcpy (&find_peer_result[1], &my_hello, hello_size);
554
555   send_reply_to_client(message_context->client, &find_peer_result->header, message_context->unique_id);
556   GNUNET_free(find_peer_result);
557   /* FIXME: Implement find peer functionality here */
558 }
559
560
561 /**
562  * Server handler for initiating local dht put requests
563  *
564  * @param cls closure for service
565  * @param put_msg the actual put message
566  * @param message_context struct containing pertinent information about the request
567  */
568 static void
569 handle_dht_put (void *cls, struct GNUNET_DHT_PutMessage *put_msg,
570                 struct DHT_MessageContext *message_context)
571 {
572   size_t put_type;
573   size_t data_size;
574
575   GNUNET_assert (ntohs (put_msg->header.size) >=
576                  sizeof (struct GNUNET_DHT_PutMessage));
577
578   put_type = ntohs (put_msg->type);
579   data_size = ntohs (put_msg->data_size);
580 #if DEBUG_DHT
581   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582               "`%s': %s msg total size is %d, data size %d, struct size %d\n",
583               "DHT", "PUT", ntohs (put_msg->header.size), data_size,
584               sizeof (struct GNUNET_DHT_PutMessage));
585 #endif
586   GNUNET_assert (ntohs (put_msg->header.size) ==
587                  sizeof (struct GNUNET_DHT_PutMessage) + data_size);
588
589 #if DEBUG_DHT
590   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591               "`%s': Received `%s' request from client, message type %d, key %s\n",
592               "DHT", "PUT", put_type, GNUNET_h2s (message_context->key));
593 #endif
594
595   /**
596    * Simplest DHT functionality, store any message we receive a put request for.
597    */
598   if (datacache != NULL)
599     GNUNET_DATACACHE_put (datacache, message_context->key, data_size,
600                           (char *) &put_msg[1], put_type,
601                           put_msg->expiration);
602   /**
603    * FIXME: Implement dht put request functionality here!
604    */
605
606 }
607
608
609 /**
610  * Find a client if it exists, add it otherwise.
611  *
612  * @param client the server handle to the client
613  *
614  * @return the client if found, a new client otherwise
615  */
616 static struct ClientList *
617 find_active_client (struct GNUNET_SERVER_Client *client)
618 {
619   struct ClientList *pos = client_list;
620   struct ClientList *ret;
621
622   while (pos != NULL)
623     {
624       if (pos->client_handle == client)
625         return pos;
626       pos = pos->next;
627     }
628
629   ret = GNUNET_malloc (sizeof (struct ClientList));
630   ret->client_handle = client;
631   ret->next = client_list;
632   client_list = ret;
633   ret->pending_head = NULL;
634
635   return ret;
636 }
637
638 /**
639  * Construct a message receipt confirmation for a particular uid.
640  * Receipt confirmations are used for any requests that don't expect
641  * a reply otherwise (i.e. put requests, stop requests).
642  *
643  * @param client the handle for the client
644  * @param uid the unique identifier of this message
645  */
646 static void
647 send_client_receipt_confirmation (struct GNUNET_SERVER_Client *client,
648                                   uint64_t uid)
649 {
650   struct GNUNET_DHT_StopMessage *confirm_message;
651   struct ClientList *active_client;
652   struct PendingMessage *pending_message;
653
654 #if DEBUG_DHT
655   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
656               "`%s': Sending receipt confirmation for uid %llu\n", "DHT",
657               uid);
658 #endif
659   confirm_message = GNUNET_malloc (sizeof (struct GNUNET_DHT_StopMessage));
660   confirm_message->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_STOP);
661   confirm_message->header.size =
662     htons (sizeof (struct GNUNET_DHT_StopMessage));
663   confirm_message->unique_id = GNUNET_htonll (uid);
664
665   active_client = find_active_client (client);
666   pending_message = GNUNET_malloc (sizeof (struct PendingMessage));
667   pending_message->msg = &confirm_message->header;
668
669   add_pending_message (active_client, pending_message);
670
671 }
672
673 /**
674  * Handler for any generic DHT messages, calls the appropriate handler
675  * depending on message type, sends confirmation if responses aren't otherwise
676  * expected.
677  *
678  * @param cls closure for the service
679  * @param client the client we received this message from
680  * @param message the actual message received
681  */
682 static void
683 handle_dht_start_message (void *cls, struct GNUNET_SERVER_Client *client,
684                           const struct GNUNET_MessageHeader *message)
685 {
686   struct GNUNET_DHT_Message *dht_msg = (struct GNUNET_DHT_Message *) message;
687   struct GNUNET_MessageHeader *enc_msg;
688   struct DHT_MessageContext *message_context;
689
690   size_t enc_type;
691
692   enc_msg = (struct GNUNET_MessageHeader *) &dht_msg[1];
693   enc_type = ntohs (enc_msg->type);
694
695
696 #if DEBUG_DHT
697   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
698               "`%s': Received `%s' request from client, message type %d, key %s, uid %llu\n",
699               "DHT", "GENERIC", enc_type, GNUNET_h2s (&dht_msg->key),
700               GNUNET_ntohll (dht_msg->unique_id));
701 #endif
702
703   message_context = GNUNET_malloc (sizeof (struct DHT_MessageContext));
704   message_context->client = find_active_client (client);
705   message_context->key = &dht_msg->key;
706   message_context->unique_id = GNUNET_ntohll (dht_msg->unique_id);
707   message_context->replication = ntohs (dht_msg->desired_replication_level);
708   message_context->msg_options = ntohs (dht_msg->options);
709
710   switch (enc_type)
711     {
712     case GNUNET_MESSAGE_TYPE_DHT_GET:
713       handle_dht_get (cls, (struct GNUNET_DHT_GetMessage *) enc_msg,
714                       message_context);
715       break;
716     case GNUNET_MESSAGE_TYPE_DHT_PUT:
717       handle_dht_put (cls, (struct GNUNET_DHT_PutMessage *) enc_msg,
718                       message_context);
719       send_client_receipt_confirmation (client,
720                                         GNUNET_ntohll (dht_msg->unique_id));
721       break;
722     case GNUNET_MESSAGE_TYPE_DHT_FIND_PEER:
723       handle_dht_find_peer (cls,
724                             (struct GNUNET_DHT_FindPeerMessage *) enc_msg,
725                             message_context);
726       break;
727     default:
728       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
729                   "`%s': Message type (%d) not handled\n", "DHT", enc_type);
730     }
731
732   GNUNET_free (message_context);
733   GNUNET_SERVER_receive_done (client, GNUNET_OK);
734
735 }
736
737 /**
738  * Handler for any generic DHT stop messages, calls the appropriate handler
739  * depending on message type, sends confirmation by default (stop messages
740  * do not otherwise expect replies)
741  *
742  * @param cls closure for the service
743  * @param client the client we received this message from
744  * @param message the actual message received
745  *
746  * TODO: add demultiplexing for stop message types.
747  */
748 static void
749 handle_dht_stop_message (void *cls, struct GNUNET_SERVER_Client *client,
750                          const struct GNUNET_MessageHeader *message)
751 {
752   struct GNUNET_DHT_StopMessage *dht_stop_msg =
753     (struct GNUNET_DHT_StopMessage *) message;
754
755 #if DEBUG_DHT
756   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757               "`%s': Received `%s' request from client, uid %llu\n", "DHT",
758               "GENERIC STOP", GNUNET_ntohll (dht_stop_msg->unique_id));
759 #endif
760
761   /* TODO: Put in demultiplexing here */
762
763   send_client_receipt_confirmation (client,
764                                     GNUNET_ntohll (dht_stop_msg->unique_id));
765   GNUNET_SERVER_receive_done (client, GNUNET_OK);
766 }
767
768
769 /**
770  * Core handler for p2p dht get requests.
771  */
772 static int
773 handle_dht_p2p_get (void *cls,
774                     const struct GNUNET_PeerIdentity *peer,
775                     const struct GNUNET_MessageHeader *message,
776                     struct GNUNET_TIME_Relative latency, uint32_t distance)
777 {
778 #if DEBUG_DHT
779   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
780               "`%s': Received `%s' request from another peer\n", "DHT",
781               "GET");
782 #endif
783
784   return GNUNET_YES;
785 }
786
787 /**
788  * Core handler for p2p dht put requests.
789  */
790 static int
791 handle_dht_p2p_put (void *cls,
792                     const struct GNUNET_PeerIdentity *peer,
793                     const struct GNUNET_MessageHeader *message,
794                     struct GNUNET_TIME_Relative latency, uint32_t distance)
795 {
796 #if DEBUG_DHT
797   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
798               "`%s': Received `%s' request from another peer\n", "DHT",
799               "PUT");
800 #endif
801
802   return GNUNET_YES;
803 }
804
805 /**
806  * Core handler for p2p dht find peer requests.
807  */
808 static int
809 handle_dht_p2p_find_peer (void *cls,
810                           const struct GNUNET_PeerIdentity *peer,
811                           const struct GNUNET_MessageHeader *message,
812                           struct GNUNET_TIME_Relative latency,
813                           uint32_t distance)
814 {
815 #if DEBUG_DHT
816   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
817               "`%s': Received `%s' request from another peer\n", "DHT",
818               "FIND PEER");
819 #endif
820
821   return GNUNET_YES;
822 }
823
824
825 /**
826  * Receive the HELLO from transport service,
827  * free current and replace if necessary.
828  *
829  * @param cls NULL
830  * @param message HELLO message of peer
831  */
832 static void
833 process_hello (void *cls, const struct GNUNET_MessageHeader *message)
834 {
835 #if DEBUG_DHT
836   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
837               "Received our `%s' from transport service\n",
838               "HELLO");
839 #endif
840
841   GNUNET_assert (message != NULL);
842   GNUNET_free_non_null(my_hello);
843   my_hello = GNUNET_malloc(ntohs(message->size));
844   memcpy(my_hello, message, ntohs(message->size));
845 }
846
847 /**
848  * Task run during shutdown.
849  *
850  * @param cls unused
851  * @param tc unused
852  */
853 static void
854 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
855 {
856   if (transport_handle != NULL)
857   {
858     GNUNET_free_non_null(my_hello);
859     GNUNET_TRANSPORT_get_hello_cancel(transport_handle, &process_hello, NULL);
860     GNUNET_TRANSPORT_disconnect(transport_handle);
861   }
862   if (coreAPI != NULL)
863     GNUNET_CORE_disconnect (coreAPI);
864 }
865
866
867 /**
868  * To be called on core init/fail.
869  *
870  * @param cls service closure
871  * @param server handle to the server for this service
872  * @param identity the public identity of this peer
873  * @param publicKey the public key of this peer
874  */
875 void
876 core_init (void *cls,
877            struct GNUNET_CORE_Handle *server,
878            const struct GNUNET_PeerIdentity *identity,
879            const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
880 {
881
882   if (server == NULL)
883     {
884 #if DEBUG_DHT
885   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
886               "%s: Connection to core FAILED!\n", "dht",
887               GNUNET_i2s (identity));
888 #endif
889       GNUNET_SCHEDULER_cancel (sched, cleanup_task);
890       GNUNET_SCHEDULER_add_now (sched, &shutdown_task, NULL);
891       return;
892     }
893 #if DEBUG_DHT
894   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
895               "%s: Core connection initialized, I am peer: %s\n", "dht",
896               GNUNET_i2s (identity));
897 #endif
898   /* Copy our identity so we can use it */
899   memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity));
900   /* Set the server to local variable */
901   coreAPI = server;
902 }
903
904
905 /**
906  * Process dht requests.
907  *
908  * @param cls closure
909  * @param scheduler scheduler to use
910  * @param server the initialized server
911  * @param c configuration to use
912  */
913 static void
914 run (void *cls,
915      struct GNUNET_SCHEDULER_Handle *scheduler,
916      struct GNUNET_SERVER_Handle *server,
917      const struct GNUNET_CONFIGURATION_Handle *c)
918 {
919   sched = scheduler;
920   cfg = c;
921
922   datacache = GNUNET_DATACACHE_create (sched, cfg, "dhtcache");
923
924   client_transmit_timeout =
925     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5);
926   GNUNET_SERVER_add_handlers (server, plugin_handlers);
927
928   coreAPI = GNUNET_CORE_connect (sched, /* Main scheduler */
929                                  cfg,   /* Main configuration */
930                                  client_transmit_timeout,       /* Delay for connecting */
931                                  NULL,  /* FIXME: anything we want to pass around? */
932                                  &core_init,    /* Call core_init once connected */
933                                  NULL,  /* Don't care about pre-connects */
934                                  NULL,  /* Don't care about connects */
935                                  NULL,  /* Don't care about disconnects */
936                                  NULL,  /* Don't want notified about all incoming messages */
937                                  GNUNET_NO,     /* For header only inbound notification */
938                                  NULL,  /* Don't want notified about all outbound messages */
939                                  GNUNET_NO,     /* For header only outbound notification */
940                                  core_handlers);        /* Register these handlers */
941
942   transport_handle = GNUNET_TRANSPORT_connect(sched, cfg, NULL, NULL, NULL, NULL);
943
944   if (transport_handle != NULL)
945     GNUNET_TRANSPORT_get_hello (transport_handle, &process_hello, NULL);
946   else
947     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to connect to transport service!\n");
948
949
950   if (coreAPI == NULL)
951     return;
952
953   /* Scheduled the task to clean up when shutdown is called */
954   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
955                                                GNUNET_TIME_UNIT_FOREVER_REL,
956                                                &shutdown_task, NULL);
957 }
958
959
960 /**
961  * The main function for the dht service.
962  *
963  * @param argc number of arguments from the command line
964  * @param argv command line arguments
965  * @return 0 ok, 1 on error
966  */
967 int
968 main (int argc, char *const *argv)
969 {
970   return (GNUNET_OK ==
971           GNUNET_SERVICE_run (argc,
972                               argv,
973                               "dht",
974                               GNUNET_SERVICE_OPTION_NONE,
975                               &run, NULL)) ? 0 : 1;
976 }