aboutsummaryrefslogtreecommitdiff
path: root/src/dht/dht_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dht/dht_api.c')
-rw-r--r--src/dht/dht_api.c1436
1 files changed, 0 insertions, 1436 deletions
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
deleted file mode 100644
index 474198004..000000000
--- a/src/dht/dht_api.c
+++ /dev/null
@@ -1,1436 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2012, 2016, 2018, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file dht/dht_api.c
23 * @brief library to access the DHT service
24 * @author Christian Grothoff
25 * @author Nathan Evans
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_constants.h"
31#include "gnunet_signatures.h"
32#include "gnunet_arm_service.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_protocols.h"
35#include "gnunet_dht_service.h"
36#include "dht.h"
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "dht-api", __VA_ARGS__)
39
40
41/**
42 * Handle to a PUT request.
43 */
44struct GNUNET_DHT_PutHandle
45{
46 /**
47 * Kept in a DLL.
48 */
49 struct GNUNET_DHT_PutHandle *next;
50
51 /**
52 * Kept in a DLL.
53 */
54 struct GNUNET_DHT_PutHandle *prev;
55
56 /**
57 * Continuation to call when done.
58 */
59 GNUNET_SCHEDULER_TaskCallback cont;
60
61 /**
62 * Main handle to this DHT api
63 */
64 struct GNUNET_DHT_Handle *dht_handle;
65
66 /**
67 * Closure for @e cont.
68 */
69 void *cont_cls;
70
71 /**
72 * Envelope from the PUT operation.
73 */
74 struct GNUNET_MQ_Envelope *env;
75};
76
77/**
78 * Handle to a GET request
79 */
80struct GNUNET_DHT_GetHandle
81{
82 /**
83 * Iterator to call on data receipt
84 */
85 GNUNET_DHT_GetIterator iter;
86
87 /**
88 * Closure for @e iter.
89 */
90 void *iter_cls;
91
92 /**
93 * Main handle to this DHT api
94 */
95 struct GNUNET_DHT_Handle *dht_handle;
96
97 /**
98 * Array of hash codes over the results that we have already
99 * seen.
100 */
101 struct GNUNET_HashCode *seen_results;
102
103 /**
104 * Key that this get request is for
105 */
106 struct GNUNET_HashCode key;
107
108 /**
109 * Unique identifier for this request (for key collisions).
110 */
111 uint64_t unique_id;
112
113 /**
114 * Size of the extended query, allocated at the end of this struct.
115 */
116 size_t xquery_size;
117
118 /**
119 * Desired replication level.
120 */
121 uint32_t desired_replication_level;
122
123 /**
124 * Type of the block we are looking for.
125 */
126 enum GNUNET_BLOCK_Type type;
127
128 /**
129 * Routing options.
130 */
131 enum GNUNET_DHT_RouteOption options;
132
133 /**
134 * Size of the @e seen_results array. Note that not
135 * all positions might be used (as we over-allocate).
136 */
137 unsigned int seen_results_size;
138
139 /**
140 * Offset into the @e seen_results array marking the
141 * end of the positions that are actually used.
142 */
143 unsigned int seen_results_end;
144};
145
146
147/**
148 * Handle to a monitoring request.
149 */
150struct GNUNET_DHT_MonitorHandle
151{
152 /**
153 * DLL.
154 */
155 struct GNUNET_DHT_MonitorHandle *next;
156
157 /**
158 * DLL.
159 */
160 struct GNUNET_DHT_MonitorHandle *prev;
161
162 /**
163 * Main handle to this DHT api.
164 */
165 struct GNUNET_DHT_Handle *dht_handle;
166
167 /**
168 * Type of block looked for.
169 */
170 enum GNUNET_BLOCK_Type type;
171
172 /**
173 * Key being looked for, NULL == all.
174 */
175 struct GNUNET_HashCode *key;
176
177 /**
178 * Callback for each received message of type get.
179 */
180 GNUNET_DHT_MonitorGetCB get_cb;
181
182 /**
183 * Callback for each received message of type get response.
184 */
185 GNUNET_DHT_MonitorGetRespCB get_resp_cb;
186
187 /**
188 * Callback for each received message of type put.
189 */
190 GNUNET_DHT_MonitorPutCB put_cb;
191
192 /**
193 * Closure for @e get_cb, @e put_cb and @e get_resp_cb.
194 */
195 void *cb_cls;
196};
197
198
199/**
200 * Handle to get a HELLO URL from the DHT for manual bootstrapping.
201 */
202struct GNUNET_DHT_HelloGetHandle
203{
204
205 /**
206 * DLL.
207 */
208 struct GNUNET_DHT_HelloGetHandle *next;
209
210 /**
211 * DLL.
212 */
213 struct GNUNET_DHT_HelloGetHandle *prev;
214
215 /**
216 * Function to call with the result.
217 */
218 GNUNET_DHT_HelloGetCallback cb;
219
220 /**
221 * Closure for @a cb.
222 */
223 void *cb_cls;
224
225 /**
226 * Connection to the DHT service.
227 */
228 struct GNUNET_DHT_Handle *dht_handle;
229
230};
231
232
233/**
234 * Connection to the DHT service.
235 */
236struct GNUNET_DHT_Handle
237{
238 /**
239 * Configuration to use.
240 */
241 const struct GNUNET_CONFIGURATION_Handle *cfg;
242
243 /**
244 * Connection to DHT service.
245 */
246 struct GNUNET_MQ_Handle *mq;
247
248 /**
249 * Head of linked list of messages we would like to monitor.
250 */
251 struct GNUNET_DHT_MonitorHandle *monitor_head;
252
253 /**
254 * Tail of linked list of messages we would like to monitor.
255 */
256 struct GNUNET_DHT_MonitorHandle *monitor_tail;
257
258 /**
259 * Head of active PUT requests.
260 */
261 struct GNUNET_DHT_PutHandle *put_head;
262
263 /**
264 * Tail of active PUT requests.
265 */
266 struct GNUNET_DHT_PutHandle *put_tail;
267
268 /**
269 * DLL.
270 */
271 struct GNUNET_DHT_HelloGetHandle *hgh_head;
272
273 /**
274 * DLL.
275 */
276 struct GNUNET_DHT_HelloGetHandle *hgh_tail;
277
278 /**
279 * Hash map containing the current outstanding unique GET requests
280 * (values are of type `struct GNUNET_DHT_GetHandle`).
281 */
282 struct GNUNET_CONTAINER_MultiHashMap *active_requests;
283
284 /**
285 * Task for trying to reconnect.
286 */
287 struct GNUNET_SCHEDULER_Task *reconnect_task;
288
289 /**
290 * How quickly should we retry? Used for exponential back-off on
291 * connect-errors.
292 */
293 struct GNUNET_TIME_Relative retry_time;
294
295 /**
296 * Generator for unique ids.
297 */
298 uint64_t uid_gen;
299};
300
301
302/**
303 * Try to (re)connect to the DHT service.
304 *
305 * @param h DHT handle to reconnect
306 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
307 */
308static enum GNUNET_GenericReturnValue
309try_connect (struct GNUNET_DHT_Handle *h);
310
311
312/**
313 * Send GET message for a @a get_handle to DHT.
314 *
315 * @param gh GET to generate messages for.
316 */
317static void
318send_get (struct GNUNET_DHT_GetHandle *gh)
319{
320 struct GNUNET_DHT_Handle *h = gh->dht_handle;
321 struct GNUNET_MQ_Envelope *env;
322 struct GNUNET_DHT_ClientGetMessage *get_msg;
323
324 env = GNUNET_MQ_msg_extra (get_msg,
325 gh->xquery_size,
326 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET);
327 get_msg->options = htonl ((uint32_t) gh->options);
328 get_msg->desired_replication_level = htonl (gh->desired_replication_level);
329 get_msg->type = htonl (gh->type);
330 get_msg->key = gh->key;
331 get_msg->unique_id = gh->unique_id;
332 GNUNET_memcpy (&get_msg[1],
333 &gh[1],
334 gh->xquery_size);
335 GNUNET_MQ_send (h->mq,
336 env);
337}
338
339
340/**
341 * Send GET message(s) for indicating which results are already known
342 * for a @a get_handle to DHT. Complex as we need to send the list of
343 * known results, which means we may need multiple messages to block
344 * known results from the result set.
345 *
346 * @param gh GET to generate messages for
347 * @param transmission_offset_start at which offset should we start?
348 */
349static void
350send_get_known_results (struct GNUNET_DHT_GetHandle *gh,
351 unsigned int transmission_offset_start)
352{
353 struct GNUNET_DHT_Handle *h = gh->dht_handle;
354 struct GNUNET_MQ_Envelope *env;
355 struct GNUNET_DHT_ClientGetResultSeenMessage *msg;
356 unsigned int delta;
357 unsigned int max;
358 unsigned int transmission_offset;
359
360 max = (GNUNET_MAX_MESSAGE_SIZE - sizeof(*msg))
361 / sizeof(struct GNUNET_HashCode);
362 transmission_offset = transmission_offset_start;
363 while (transmission_offset < gh->seen_results_end)
364 {
365 delta = gh->seen_results_end - transmission_offset;
366 if (delta > max)
367 delta = max;
368 env = GNUNET_MQ_msg_extra (msg,
369 delta * sizeof(struct GNUNET_HashCode),
370 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_RESULTS_KNOWN);
371 msg->key = gh->key;
372 msg->unique_id = gh->unique_id;
373 GNUNET_memcpy (&msg[1],
374 &gh->seen_results[transmission_offset],
375 sizeof(struct GNUNET_HashCode) * delta);
376 GNUNET_MQ_send (h->mq,
377 env);
378 transmission_offset += delta;
379 }
380}
381
382
383/**
384 * Add the GET request corresponding to the given route handle
385 * to the pending queue (if it is not already in there).
386 *
387 * @param cls the `struct GNUNET_DHT_Handle *`
388 * @param key key for the request (not used)
389 * @param value the `struct GNUNET_DHT_GetHandle *`
390 * @return #GNUNET_YES (always)
391 */
392static enum GNUNET_GenericReturnValue
393add_get_request_to_pending (void *cls,
394 const struct GNUNET_HashCode *key,
395 void *value)
396{
397 struct GNUNET_DHT_Handle *handle = cls;
398 struct GNUNET_DHT_GetHandle *gh = value;
399
400 LOG (GNUNET_ERROR_TYPE_DEBUG,
401 "Retransmitting request related to %s to DHT %p\n",
402 GNUNET_h2s (key),
403 handle);
404 send_get (gh);
405 send_get_known_results (gh, 0);
406 return GNUNET_YES;
407}
408
409
410/**
411 * Send #GNUNET_MESSAGE_TYPE_DHT_MONITOR_START message.
412 *
413 * @param mh monitor handle to generate start message for
414 */
415static void
416send_monitor_start (struct GNUNET_DHT_MonitorHandle *mh)
417{
418 struct GNUNET_DHT_Handle *h = mh->dht_handle;
419 struct GNUNET_MQ_Envelope *env;
420 struct GNUNET_DHT_MonitorStartStopMessage *m;
421
422 env = GNUNET_MQ_msg (m,
423 GNUNET_MESSAGE_TYPE_DHT_MONITOR_START);
424 m->type = htonl (mh->type);
425 m->get = htons (NULL != mh->get_cb);
426 m->get_resp = htons (NULL != mh->get_resp_cb);
427 m->put = htons (NULL != mh->put_cb);
428 if (NULL != mh->key)
429 {
430 m->filter_key = htons (1);
431 m->key = *mh->key;
432 }
433 GNUNET_MQ_send (h->mq,
434 env);
435}
436
437
438/**
439 * Try reconnecting to the dht service.
440 *
441 * @param cls a `struct GNUNET_DHT_Handle`
442 */
443static void
444try_reconnect (void *cls)
445{
446 struct GNUNET_DHT_Handle *h = cls;
447 struct GNUNET_DHT_MonitorHandle *mh;
448
449 LOG (GNUNET_ERROR_TYPE_DEBUG,
450 "Reconnecting with DHT %p\n",
451 h);
452 h->retry_time = GNUNET_TIME_STD_BACKOFF (h->retry_time);
453 h->reconnect_task = NULL;
454 if (GNUNET_YES != try_connect (h))
455 {
456 LOG (GNUNET_ERROR_TYPE_WARNING,
457 "DHT reconnect failed!\n");
458 h->reconnect_task
459 = GNUNET_SCHEDULER_add_delayed (h->retry_time,
460 &try_reconnect,
461 h);
462 return;
463 }
464 GNUNET_CONTAINER_multihashmap_iterate (h->active_requests,
465 &add_get_request_to_pending,
466 h);
467 for (mh = h->monitor_head; NULL != mh; mh = mh->next)
468 send_monitor_start (mh);
469}
470
471
472/**
473 * Try reconnecting to the DHT service.
474 *
475 * @param h handle to dht to (possibly) disconnect and reconnect
476 */
477static void
478do_disconnect (struct GNUNET_DHT_Handle *h)
479{
480 struct GNUNET_DHT_PutHandle *ph;
481 GNUNET_SCHEDULER_TaskCallback cont;
482 void *cont_cls;
483
484 if (NULL == h->mq)
485 return;
486 GNUNET_MQ_destroy (h->mq);
487 h->mq = NULL;
488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489 "Disconnecting from DHT service, will try to reconnect in %s\n",
490 GNUNET_STRINGS_relative_time_to_string (h->retry_time,
491 GNUNET_YES));
492 /* notify client about all PUTs that (may) have failed due to disconnect */
493 while (NULL != (ph = h->put_head))
494 {
495 cont = ph->cont;
496 cont_cls = ph->cont_cls;
497 ph->env = NULL;
498 GNUNET_DHT_put_cancel (ph);
499 if (NULL != cont)
500 cont (cont_cls);
501 }
502 GNUNET_assert (NULL == h->reconnect_task);
503 h->reconnect_task
504 = GNUNET_SCHEDULER_add_delayed (h->retry_time,
505 &try_reconnect,
506 h);
507}
508
509
510/**
511 * Generic error handler, called with the appropriate error code and
512 * the same closure specified at the creation of the message queue.
513 * Not every message queue implementation supports an error handler.
514 *
515 * @param cls closure with the `struct GNUNET_DHT_Handle *`
516 * @param error error code
517 */
518static void
519mq_error_handler (void *cls,
520 enum GNUNET_MQ_Error error)
521{
522 struct GNUNET_DHT_Handle *h = cls;
523
524 do_disconnect (h);
525}
526
527
528/**
529 * Verify integrity of a get monitor message from the service.
530 *
531 * @param cls The DHT handle.
532 * @param msg Monitor get message from the service.
533 * @return #GNUNET_OK if everything went fine,
534 * #GNUNET_SYSERR if the message is malformed.
535 */
536static enum GNUNET_GenericReturnValue
537check_monitor_get (void *cls,
538 const struct GNUNET_DHT_MonitorGetMessage *msg)
539{
540 uint32_t plen = ntohl (msg->get_path_length);
541 uint16_t msize = ntohs (msg->header.size) - sizeof(*msg);
542
543 if ((plen > UINT16_MAX) ||
544 (plen * sizeof(struct GNUNET_DHT_PathElement) != msize))
545 {
546 GNUNET_break (0);
547 return GNUNET_SYSERR;
548 }
549 return GNUNET_OK;
550}
551
552
553/**
554 * Process a get monitor message from the service.
555 *
556 * @param cls The DHT handle.
557 * @param msg Monitor get message from the service.
558 */
559static void
560handle_monitor_get (void *cls,
561 const struct GNUNET_DHT_MonitorGetMessage *msg)
562{
563 struct GNUNET_DHT_Handle *handle = cls;
564
565 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
566 NULL != mh;
567 mh = mh->next)
568 {
569 if (NULL == mh->get_cb)
570 continue;
571 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
572 (mh->type == ntohl (msg->type))) &&
573 ((NULL == mh->key) ||
574 (0 == memcmp (mh->key,
575 &msg->key,
576 sizeof(struct GNUNET_HashCode)))))
577 mh->get_cb (mh->cb_cls,
578 ntohl (msg->options),
579 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
580 ntohl (msg->hop_count),
581 ntohl (msg->desired_replication_level),
582 ntohl (msg->get_path_length),
583 (struct GNUNET_DHT_PathElement *) &msg[1],
584 &msg->key);
585 }
586}
587
588
589/**
590 * Validate a get response monitor message from the service.
591 *
592 * @param cls The DHT handle.
593 * @param msg monitor get response message from the service
594 * @return #GNUNET_OK if everything went fine,
595 * #GNUNET_SYSERR if the message is malformed.
596 */
597static enum GNUNET_GenericReturnValue
598check_monitor_get_resp (void *cls,
599 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
600{
601 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
602 uint32_t getl = ntohl (msg->get_path_length);
603 uint32_t putl = ntohl (msg->put_path_length);
604
605 if ((getl + putl < getl) ||
606 ((msize / sizeof(struct GNUNET_DHT_PathElement)) < getl + putl))
607 {
608 GNUNET_break (0);
609 return GNUNET_SYSERR;
610 }
611 return GNUNET_OK;
612}
613
614
615/**
616 * Process a get response monitor message from the service.
617 *
618 * @param cls The DHT handle.
619 * @param msg monitor get response message from the service
620 */
621static void
622handle_monitor_get_resp (void *cls,
623 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
624{
625 struct GNUNET_DHT_Handle *handle = cls;
626 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
627 const struct GNUNET_DHT_PathElement *path;
628 uint32_t getl = ntohl (msg->get_path_length);
629 uint32_t putl = ntohl (msg->put_path_length);
630
631
632 path = (const struct GNUNET_DHT_PathElement *) &msg[1];
633 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
634 NULL != mh;
635 mh = mh->next)
636 {
637 if (NULL == mh->get_resp_cb)
638 continue;
639 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
640 (mh->type == ntohl (msg->type))) &&
641 ((NULL == mh->key) ||
642 (0 == memcmp (mh->key,
643 &msg->key,
644 sizeof(struct GNUNET_HashCode)))))
645 mh->get_resp_cb (mh->cb_cls,
646 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
647 &path[putl],
648 getl,
649 path,
650 putl,
651 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
652 &msg->key,
653 (const void *) &path[getl + putl],
654 msize - sizeof(struct GNUNET_DHT_PathElement) * (putl
655 + getl));
656 }
657}
658
659
660/**
661 * Check validity of a put monitor message from the service.
662 *
663 * @param cls The DHT handle.
664 * @param msg Monitor put message from the service.
665 * @return #GNUNET_OK if everything went fine,
666 * #GNUNET_SYSERR if the message is malformed.
667 */
668static enum GNUNET_GenericReturnValue
669check_monitor_put (void *cls,
670 const struct GNUNET_DHT_MonitorPutMessage *msg)
671{
672 size_t msize;
673 uint32_t putl;
674
675 msize = ntohs (msg->header.size) - sizeof(*msg);
676 putl = ntohl (msg->put_path_length);
677 if ((msize / sizeof(struct GNUNET_DHT_PathElement)) < putl)
678 {
679 GNUNET_break (0);
680 return GNUNET_SYSERR;
681 }
682 return GNUNET_OK;
683}
684
685
686/**
687 * Process a put monitor message from the service.
688 *
689 * @param cls The DHT handle.
690 * @param msg Monitor put message from the service.
691 */
692static void
693handle_monitor_put (void *cls,
694 const struct GNUNET_DHT_MonitorPutMessage *msg)
695{
696 struct GNUNET_DHT_Handle *handle = cls;
697 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
698 uint32_t putl = ntohl (msg->put_path_length);
699 const struct GNUNET_DHT_PathElement *path;
700 struct GNUNET_DHT_MonitorHandle *mh;
701
702 path = (const struct GNUNET_DHT_PathElement *) &msg[1];
703 for (mh = handle->monitor_head; NULL != mh; mh = mh->next)
704 {
705 if (NULL == mh->put_cb)
706 continue;
707 if (((GNUNET_BLOCK_TYPE_ANY == mh->type) ||
708 (mh->type == ntohl (msg->type))) &&
709 ((NULL == mh->key) ||
710 (0 == memcmp (mh->key,
711 &msg->key,
712 sizeof(struct GNUNET_HashCode)))))
713 mh->put_cb (mh->cb_cls,
714 ntohl (msg->options),
715 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
716 ntohl (msg->hop_count),
717 ntohl (msg->desired_replication_level),
718 putl,
719 path,
720 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
721 &msg->key,
722 (const void *) &path[putl],
723 msize - sizeof(struct GNUNET_DHT_PathElement) * putl);
724 }
725}
726
727
728/**
729 * Verify that client result message received from the service is well-formed.
730 *
731 * @param cls The DHT handle.
732 * @param msg Monitor put message from the service.
733 * @return #GNUNET_OK if everything went fine,
734 * #GNUNET_SYSERR if the message is malformed.
735 */
736static enum GNUNET_GenericReturnValue
737check_client_result (void *cls,
738 const struct GNUNET_DHT_ClientResultMessage *msg)
739{
740 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
741 uint32_t put_path_length = ntohl (msg->put_path_length);
742 uint32_t get_path_length = ntohl (msg->get_path_length);
743 size_t meta_length;
744
745 meta_length =
746 sizeof(struct GNUNET_DHT_PathElement) * (get_path_length + put_path_length);
747 if ((msize < meta_length) ||
748 (get_path_length >
749 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)) ||
750 (put_path_length >
751 GNUNET_MAX_MESSAGE_SIZE / sizeof(struct GNUNET_DHT_PathElement)))
752 {
753 GNUNET_break (0);
754 return GNUNET_SYSERR;
755 }
756 return GNUNET_OK;
757}
758
759
760/**
761 * Process a given reply that might match the given request.
762 *
763 * @param cls the `struct GNUNET_DHT_ClientResultMessage`
764 * @param key query of the request
765 * @param value the `struct GNUNET_DHT_GetHandle` of a request matching the same key
766 * @return #GNUNET_YES to continue to iterate over all results
767 */
768static enum GNUNET_GenericReturnValue
769process_client_result (void *cls,
770 const struct GNUNET_HashCode *key,
771 void *value)
772{
773 const struct GNUNET_DHT_ClientResultMessage *crm = cls;
774 struct GNUNET_DHT_GetHandle *get_handle = value;
775 size_t msize = ntohs (crm->header.size) - sizeof(*crm);
776 uint16_t type = ntohl (crm->type);
777 uint32_t put_path_length = ntohl (crm->put_path_length);
778 uint32_t get_path_length = ntohl (crm->get_path_length);
779 const struct GNUNET_DHT_PathElement *put_path
780 = (const struct GNUNET_DHT_PathElement *) &crm[1];
781 const struct GNUNET_DHT_PathElement *get_path
782 = &put_path[put_path_length];
783 const void *data
784 = &get_path[get_path_length];
785 size_t meta_length
786 = sizeof(struct GNUNET_DHT_PathElement) * (get_path_length
787 + put_path_length);
788 size_t data_length
789 = msize - meta_length;
790 struct GNUNET_HashCode hc;
791
792 if (crm->unique_id != get_handle->unique_id)
793 {
794 /* UID mismatch */
795 LOG (GNUNET_ERROR_TYPE_DEBUG,
796 "Ignoring reply for %s: UID mismatch: %llu/%llu\n",
797 GNUNET_h2s (key),
798 (unsigned long long) crm->unique_id,
799 (unsigned long long) get_handle->unique_id);
800 return GNUNET_YES;
801 }
802 if ( (get_handle->type != GNUNET_BLOCK_TYPE_ANY) &&
803 (get_handle->type != type) )
804 {
805 /* type mismatch */
806 GNUNET_break (0);
807 return GNUNET_YES;
808 }
809
810 {
811 char *pp;
812 char *gp;
813
814 gp = GNUNET_DHT_pp2s (get_path,
815 get_path_length);
816 pp = GNUNET_DHT_pp2s (put_path,
817 put_path_length);
818 LOG (GNUNET_ERROR_TYPE_DEBUG,
819 "Giving %u byte reply for %s to application (GP: %s, PP: %s)\n",
820 (unsigned int) data_length,
821 GNUNET_h2s (key),
822 gp,
823 pp);
824 GNUNET_free (gp);
825 GNUNET_free (pp);
826 }
827 /* remember that we've seen this result */
828 GNUNET_CRYPTO_hash (data,
829 data_length,
830 &hc);
831 if (get_handle->seen_results_size == get_handle->seen_results_end)
832 GNUNET_array_grow (get_handle->seen_results,
833 get_handle->seen_results_size,
834 get_handle->seen_results_size * 2 + 1);
835 get_handle->seen_results[get_handle->seen_results_end++] = hc;
836 /* no need to block it explicitly, service already knows about it! */
837 get_handle->iter (get_handle->iter_cls,
838 GNUNET_TIME_absolute_ntoh (crm->expiration),
839 key,
840 get_path,
841 get_path_length,
842 put_path,
843 put_path_length,
844 type,
845 data_length,
846 data);
847 return GNUNET_YES;
848}
849
850
851/**
852 * Process a client result message received from the service.
853 *
854 * @param cls The DHT handle.
855 * @param msg Monitor put message from the service.
856 */
857static void
858handle_client_result (void *cls,
859 const struct GNUNET_DHT_ClientResultMessage *msg)
860{
861 struct GNUNET_DHT_Handle *handle = cls;
862
863 GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests,
864 &msg->key,
865 &process_client_result,
866 (void *) msg);
867}
868
869
870/**
871 * Process a client HELLO message received from the service.
872 *
873 * @param cls The DHT handle.
874 * @param hdr HELLO URL message from the service.
875 * @return #GNUNET_OK if @a hdr is well-formed
876 */
877static enum GNUNET_GenericReturnValue
878check_client_hello (void *cls,
879 const struct GNUNET_MessageHeader *hdr)
880{
881 uint16_t len = ntohs (hdr->size);
882 const char *buf = (const char *) &hdr[1];
883
884 (void) cls;
885 if ('\0' != buf[len - sizeof (*hdr) - 1])
886 {
887 GNUNET_break (0);
888 return GNUNET_SYSERR;
889 }
890 return GNUNET_OK;
891}
892
893
894/**
895 * Process a client HELLO message received from the service.
896 *
897 * @param cls The DHT handle.
898 * @param hdr HELLO URL message from the service.
899 */
900static void
901handle_client_hello (void *cls,
902 const struct GNUNET_MessageHeader *hdr)
903{
904 struct GNUNET_DHT_Handle *handle = cls;
905 const char *url = (const char *) &hdr[1];
906 struct GNUNET_DHT_HelloGetHandle *hgh;
907
908 while (NULL != (hgh = handle->hgh_head))
909 {
910 hgh->cb (hgh->cb_cls,
911 url);
912 GNUNET_DHT_hello_get_cancel (hgh);
913 }
914}
915
916
917/**
918 * Process a MQ PUT transmission notification.
919 *
920 * @param cls The DHT handle.
921 */
922static void
923handle_put_cont (void *cls)
924{
925 struct GNUNET_DHT_PutHandle *ph = cls;
926 GNUNET_SCHEDULER_TaskCallback cont;
927 void *cont_cls;
928
929 cont = ph->cont;
930 cont_cls = ph->cont_cls;
931 ph->env = NULL;
932 GNUNET_DHT_put_cancel (ph);
933 if (NULL != cont)
934 cont (cont_cls);
935}
936
937
938/**
939 * Try to (re)connect to the DHT service.
940 *
941 * @param h DHT handle to reconnect
942 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
943 */
944static enum GNUNET_GenericReturnValue
945try_connect (struct GNUNET_DHT_Handle *h)
946{
947 struct GNUNET_MQ_MessageHandler handlers[] = {
948 GNUNET_MQ_hd_var_size (monitor_get,
949 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET,
950 struct GNUNET_DHT_MonitorGetMessage,
951 h),
952 GNUNET_MQ_hd_var_size (monitor_get_resp,
953 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP,
954 struct GNUNET_DHT_MonitorGetRespMessage,
955 h),
956 GNUNET_MQ_hd_var_size (monitor_put,
957 GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT,
958 struct GNUNET_DHT_MonitorPutMessage,
959 h),
960 GNUNET_MQ_hd_var_size (client_result,
961 GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT,
962 struct GNUNET_DHT_ClientResultMessage,
963 h),
964 GNUNET_MQ_hd_var_size (client_hello,
965 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL,
966 struct GNUNET_MessageHeader,
967 h),
968 GNUNET_MQ_handler_end ()
969 };
970
971 if (NULL != h->mq)
972 return GNUNET_OK;
973 h->mq = GNUNET_CLIENT_connect (h->cfg,
974 "dht",
975 handlers,
976 &mq_error_handler,
977 h);
978 if (NULL == h->mq)
979 {
980 LOG (GNUNET_ERROR_TYPE_WARNING,
981 "Failed to connect to the DHT service!\n");
982 return GNUNET_NO;
983 }
984 return GNUNET_YES;
985}
986
987
988struct GNUNET_DHT_Handle *
989GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
990 unsigned int ht_len)
991{
992 struct GNUNET_DHT_Handle *handle;
993
994 handle = GNUNET_new (struct GNUNET_DHT_Handle);
995 handle->cfg = cfg;
996 handle->uid_gen
997 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
998 UINT64_MAX);
999 handle->active_requests
1000 = GNUNET_CONTAINER_multihashmap_create (ht_len,
1001 GNUNET_YES);
1002 if (GNUNET_NO == try_connect (handle))
1003 {
1004 GNUNET_DHT_disconnect (handle);
1005 return NULL;
1006 }
1007 return handle;
1008}
1009
1010
1011void
1012GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle)
1013{
1014 struct GNUNET_DHT_PutHandle *ph;
1015
1016 GNUNET_assert (0 ==
1017 GNUNET_CONTAINER_multihashmap_size (handle->active_requests));
1018 while (NULL != (ph = handle->put_head))
1019 {
1020 if (NULL != ph->cont)
1021 ph->cont (ph->cont_cls);
1022 GNUNET_DHT_put_cancel (ph);
1023 }
1024 if (NULL != handle->mq)
1025 {
1026 GNUNET_MQ_destroy (handle->mq);
1027 handle->mq = NULL;
1028 }
1029 if (NULL != handle->reconnect_task)
1030 {
1031 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1032 handle->reconnect_task = NULL;
1033 }
1034 GNUNET_CONTAINER_multihashmap_destroy (handle->active_requests);
1035 GNUNET_free (handle);
1036}
1037
1038
1039struct GNUNET_DHT_PutHandle *
1040GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
1041 const struct GNUNET_HashCode *key,
1042 uint32_t desired_replication_level,
1043 enum GNUNET_DHT_RouteOption options,
1044 enum GNUNET_BLOCK_Type type,
1045 size_t size,
1046 const void *data,
1047 struct GNUNET_TIME_Absolute exp,
1048 GNUNET_SCHEDULER_TaskCallback cont,
1049 void *cont_cls)
1050{
1051 struct GNUNET_MQ_Envelope *env;
1052 struct GNUNET_DHT_ClientPutMessage *put_msg;
1053 size_t msize;
1054 struct GNUNET_DHT_PutHandle *ph;
1055
1056 msize = sizeof(struct GNUNET_DHT_ClientPutMessage) + size;
1057 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1058 (size >= GNUNET_MAX_MESSAGE_SIZE))
1059 {
1060 GNUNET_break (0);
1061 return NULL;
1062 }
1063 if (NULL == handle->mq)
1064 return NULL;
1065 LOG (GNUNET_ERROR_TYPE_DEBUG,
1066 "Sending PUT for %s to DHT via %p\n",
1067 GNUNET_h2s (key),
1068 handle);
1069 ph = GNUNET_new (struct GNUNET_DHT_PutHandle);
1070 ph->dht_handle = handle;
1071 ph->cont = cont;
1072 ph->cont_cls = cont_cls;
1073 GNUNET_CONTAINER_DLL_insert_tail (handle->put_head,
1074 handle->put_tail,
1075 ph);
1076 env = GNUNET_MQ_msg_extra (put_msg,
1077 size,
1078 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT);
1079 GNUNET_MQ_notify_sent (env,
1080 &handle_put_cont,
1081 ph);
1082 ph->env = env;
1083 put_msg->type = htonl ((uint32_t) type);
1084 put_msg->options = htonl ((uint32_t) options);
1085 put_msg->desired_replication_level = htonl (desired_replication_level);
1086 put_msg->expiration = GNUNET_TIME_absolute_hton (exp);
1087 put_msg->key = *key;
1088 GNUNET_memcpy (&put_msg[1],
1089 data,
1090 size);
1091 GNUNET_MQ_send (handle->mq,
1092 env);
1093 return ph;
1094}
1095
1096
1097void
1098GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph)
1099{
1100 struct GNUNET_DHT_Handle *handle = ph->dht_handle;
1101
1102 if (NULL != ph->env)
1103 GNUNET_MQ_notify_sent (ph->env,
1104 NULL,
1105 NULL);
1106 GNUNET_CONTAINER_DLL_remove (handle->put_head,
1107 handle->put_tail,
1108 ph);
1109 GNUNET_free (ph);
1110}
1111
1112
1113struct GNUNET_DHT_GetHandle *
1114GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
1115 enum GNUNET_BLOCK_Type type,
1116 const struct GNUNET_HashCode *key,
1117 uint32_t desired_replication_level,
1118 enum GNUNET_DHT_RouteOption options,
1119 const void *xquery,
1120 size_t xquery_size,
1121 GNUNET_DHT_GetIterator iter,
1122 void *iter_cls)
1123{
1124 struct GNUNET_DHT_GetHandle *gh;
1125 size_t msize;
1126
1127 msize = sizeof(struct GNUNET_DHT_ClientGetMessage) + xquery_size;
1128 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1129 (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
1130 {
1131 GNUNET_break (0);
1132 return NULL;
1133 }
1134 LOG (GNUNET_ERROR_TYPE_DEBUG,
1135 "Sending query for %s to DHT %p\n",
1136 GNUNET_h2s (key),
1137 handle);
1138 gh = GNUNET_malloc (sizeof(struct GNUNET_DHT_GetHandle)
1139 + xquery_size);
1140 gh->iter = iter;
1141 gh->iter_cls = iter_cls;
1142 gh->dht_handle = handle;
1143 gh->key = *key;
1144 gh->unique_id = ++handle->uid_gen;
1145 gh->xquery_size = xquery_size;
1146 gh->desired_replication_level = desired_replication_level;
1147 gh->type = type;
1148 gh->options = options;
1149 GNUNET_memcpy (&gh[1],
1150 xquery,
1151 xquery_size);
1152 GNUNET_CONTAINER_multihashmap_put (handle->active_requests,
1153 &gh->key,
1154 gh,
1155 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1156 if (NULL != handle->mq)
1157 send_get (gh);
1158 return gh;
1159}
1160
1161
1162void
1163GNUNET_DHT_get_filter_known_results (struct GNUNET_DHT_GetHandle *get_handle,
1164 unsigned int num_results,
1165 const struct GNUNET_HashCode *results)
1166{
1167 unsigned int needed;
1168 unsigned int had;
1169
1170 had = get_handle->seen_results_end;
1171 needed = had + num_results;
1172 if (needed > get_handle->seen_results_size)
1173 GNUNET_array_grow (get_handle->seen_results,
1174 get_handle->seen_results_size,
1175 needed);
1176 GNUNET_memcpy (&get_handle->seen_results[get_handle->seen_results_end],
1177 results,
1178 num_results * sizeof(struct GNUNET_HashCode));
1179 get_handle->seen_results_end += num_results;
1180 if (NULL != get_handle->dht_handle->mq)
1181 send_get_known_results (get_handle,
1182 had);
1183}
1184
1185
1186void
1187GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle)
1188{
1189 struct GNUNET_DHT_Handle *handle = get_handle->dht_handle;
1190
1191 LOG (GNUNET_ERROR_TYPE_DEBUG,
1192 "Sending STOP for %s to DHT via %p\n",
1193 GNUNET_h2s (&get_handle->key),
1194 handle);
1195 if (NULL != handle->mq)
1196 {
1197 struct GNUNET_MQ_Envelope *env;
1198 struct GNUNET_DHT_ClientGetStopMessage *stop_msg;
1199
1200 env = GNUNET_MQ_msg (stop_msg,
1201 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP);
1202 stop_msg->reserved = htonl (0);
1203 stop_msg->unique_id = get_handle->unique_id;
1204 stop_msg->key = get_handle->key;
1205 GNUNET_MQ_send (handle->mq,
1206 env);
1207 }
1208 GNUNET_assert (GNUNET_YES ==
1209 GNUNET_CONTAINER_multihashmap_remove (handle->active_requests,
1210 &get_handle->key,
1211 get_handle));
1212 GNUNET_array_grow (get_handle->seen_results,
1213 get_handle->seen_results_end,
1214 0);
1215 GNUNET_free (get_handle);
1216}
1217
1218
1219struct GNUNET_DHT_MonitorHandle *
1220GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle,
1221 enum GNUNET_BLOCK_Type type,
1222 const struct GNUNET_HashCode *key,
1223 GNUNET_DHT_MonitorGetCB get_cb,
1224 GNUNET_DHT_MonitorGetRespCB get_resp_cb,
1225 GNUNET_DHT_MonitorPutCB put_cb,
1226 void *cb_cls)
1227{
1228 struct GNUNET_DHT_MonitorHandle *mh;
1229
1230 mh = GNUNET_new (struct GNUNET_DHT_MonitorHandle);
1231 mh->get_cb = get_cb;
1232 mh->get_resp_cb = get_resp_cb;
1233 mh->put_cb = put_cb;
1234 mh->cb_cls = cb_cls;
1235 mh->type = type;
1236 mh->dht_handle = handle;
1237 if (NULL != key)
1238 {
1239 mh->key = GNUNET_new (struct GNUNET_HashCode);
1240 *mh->key = *key;
1241 }
1242 GNUNET_CONTAINER_DLL_insert (handle->monitor_head,
1243 handle->monitor_tail,
1244 mh);
1245 if (NULL != handle->mq)
1246 send_monitor_start (mh);
1247 return mh;
1248}
1249
1250
1251void
1252GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *mh)
1253{
1254 struct GNUNET_DHT_Handle *handle = mh->dht_handle;
1255 struct GNUNET_DHT_MonitorStartStopMessage *m;
1256 struct GNUNET_MQ_Envelope *env;
1257
1258 GNUNET_CONTAINER_DLL_remove (handle->monitor_head,
1259 handle->monitor_tail,
1260 mh);
1261 env = GNUNET_MQ_msg (m,
1262 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP);
1263 m->type = htonl (mh->type);
1264 m->get = htons (NULL != mh->get_cb);
1265 m->get_resp = htons (NULL != mh->get_resp_cb);
1266 m->put = htons (NULL != mh->put_cb);
1267 if (NULL != mh->key)
1268 {
1269 m->filter_key = htons (1);
1270 m->key = *mh->key;
1271 }
1272 GNUNET_MQ_send (handle->mq,
1273 env);
1274 GNUNET_free (mh->key);
1275 GNUNET_free (mh);
1276}
1277
1278
1279char *
1280GNUNET_DHT_pp2s (const struct GNUNET_DHT_PathElement *path,
1281 unsigned int path_len)
1282{
1283 char *buf;
1284 size_t off;
1285 size_t plen = path_len * 5 + 1;
1286
1287 GNUNET_assert (path_len < UINT32_MAX / 5);
1288 off = 0;
1289 buf = GNUNET_malloc (plen);
1290 for (unsigned int i = 0; i < path_len; i++)
1291 {
1292 off += GNUNET_snprintf (&buf[off],
1293 plen - off,
1294 "%s%s",
1295 GNUNET_i2s (&path[i].pred),
1296 (i == path_len - 1) ? "" : "-");
1297 }
1298 return buf;
1299}
1300
1301
1302unsigned int
1303GNUNET_DHT_verify_path (const void *data,
1304 size_t data_size,
1305 struct GNUNET_TIME_Absolute exp_time,
1306 const struct GNUNET_DHT_PathElement *put_path,
1307 unsigned int put_path_len,
1308 const struct GNUNET_DHT_PathElement *get_path,
1309 unsigned int get_path_len,
1310 const struct GNUNET_PeerIdentity *me)
1311{
1312 struct GNUNET_DHT_HopSignature hs = {
1313 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
1314 .purpose.size = htonl (sizeof (hs)),
1315 .expiration_time = GNUNET_TIME_absolute_hton (exp_time)
1316 };
1317 const struct GNUNET_PeerIdentity *pred;
1318 const struct GNUNET_PeerIdentity *succ;
1319 unsigned int i;
1320
1321 if (0 == get_path_len + put_path_len)
1322 return 0;
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "%s is verifying signatures with GPL: %u PPL: %u!\n",
1325 GNUNET_i2s (me),
1326 get_path_len,
1327 put_path_len);
1328 for (unsigned int j = 0; j<put_path_len; j++)
1329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1330 "PP%u=%s\n",
1331 j,
1332 GNUNET_i2s (&put_path[j].pred));
1333 for (unsigned int j = 0; j<get_path_len; j++)
1334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1335 "GP%u=%s\n",
1336 j,
1337 GNUNET_i2s (&get_path[j].pred));
1338
1339 i = put_path_len + get_path_len - 1;
1340 GNUNET_CRYPTO_hash (data,
1341 data_size,
1342 &hs.h_data);
1343 while (i > 0)
1344 {
1345 pred = (i - 1 >= put_path_len)
1346 ? &get_path[i - put_path_len - 1].pred
1347 : &put_path[i - 1].pred;
1348 if (i + 1 == get_path_len + put_path_len)
1349 succ = me;
1350 else
1351 succ = (i + 1 >= put_path_len)
1352 ? &get_path[i + 1 - put_path_len].pred
1353 : &put_path[i + 1].pred;
1354 hs.pred = *pred;
1355 hs.succ = *succ;
1356 if (GNUNET_OK !=
1357 GNUNET_CRYPTO_eddsa_verify (
1358 GNUNET_SIGNATURE_PURPOSE_DHT_HOP,
1359 &hs,
1360 (i - 1 >= put_path_len)
1361 ? &get_path[i - put_path_len - 1].sig
1362 : &put_path[i - 1].sig,
1363 (i >= put_path_len)
1364 ? &get_path[i - put_path_len].pred.public_key
1365 : &put_path[i].pred.public_key))
1366 {
1367 GNUNET_break_op (0);
1368 return i;
1369 }
1370 i--;
1371 }
1372 return i;
1373}
1374
1375
1376struct GNUNET_DHT_HelloGetHandle *
1377GNUNET_DHT_hello_get (struct GNUNET_DHT_Handle *dht_handle,
1378 GNUNET_DHT_HelloGetCallback cb,
1379 void *cb_cls)
1380{
1381 struct GNUNET_DHT_HelloGetHandle *hgh;
1382 struct GNUNET_MessageHeader *hdr;
1383 struct GNUNET_MQ_Envelope *env;
1384
1385 hgh = GNUNET_new (struct GNUNET_DHT_HelloGetHandle);
1386 hgh->cb = cb;
1387 hgh->cb_cls = cb_cls;
1388 hgh->dht_handle = dht_handle;
1389 GNUNET_CONTAINER_DLL_insert (dht_handle->hgh_head,
1390 dht_handle->hgh_tail,
1391 hgh);
1392 env = GNUNET_MQ_msg (hdr,
1393 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_GET);
1394 GNUNET_MQ_send (dht_handle->mq,
1395 env);
1396 return hgh;
1397}
1398
1399
1400void
1401GNUNET_DHT_hello_get_cancel (struct GNUNET_DHT_HelloGetHandle *hgh)
1402{
1403 struct GNUNET_DHT_Handle *dht_handle = hgh->dht_handle;
1404
1405 GNUNET_CONTAINER_DLL_remove (dht_handle->hgh_head,
1406 dht_handle->hgh_tail,
1407 hgh);
1408 GNUNET_free (hgh);
1409}
1410
1411
1412void
1413GNUNET_DHT_hello_offer (struct GNUNET_DHT_Handle *dht_handle,
1414 const char *url,
1415 GNUNET_SCHEDULER_TaskCallback cb,
1416 void *cb_cls)
1417{
1418 struct GNUNET_MessageHeader *hdr;
1419 size_t slen = strlen (url) + 1;
1420 struct GNUNET_MQ_Envelope *env;
1421
1422 env = GNUNET_MQ_msg_extra (hdr,
1423 slen,
1424 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL);
1425 memcpy (&hdr[1],
1426 url,
1427 slen);
1428 GNUNET_MQ_notify_sent (env,
1429 cb,
1430 cb_cls);
1431 GNUNET_MQ_send (dht_handle->mq,
1432 env);
1433}
1434
1435
1436/* end of dht_api.c */