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.c1504
1 files changed, 0 insertions, 1504 deletions
diff --git a/src/dht/dht_api.c b/src/dht/dht_api.c
deleted file mode 100644
index 5fa8f759f..000000000
--- a/src/dht/dht_api.c
+++ /dev/null
@@ -1,1504 +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 * Process a get monitor message from the service.
530 *
531 * @param cls The DHT handle.
532 * @param msg Monitor get message from the service.
533 */
534static void
535handle_monitor_get (void *cls,
536 const struct GNUNET_DHT_MonitorGetMessage *msg)
537{
538 struct GNUNET_DHT_Handle *handle = cls;
539 enum GNUNET_DHT_RouteOption ro
540 = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
541
542 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
543 NULL != mh;
544 mh = mh->next)
545 {
546 if (NULL == mh->get_cb)
547 continue;
548 if ( (GNUNET_BLOCK_TYPE_ANY != mh->type) &&
549 (mh->type != ntohl (msg->type)))
550 continue;
551 if ( (NULL != mh->key) &&
552 (0 != GNUNET_memcmp (mh->key,
553 &msg->key)) )
554 continue;
555 mh->get_cb (mh->cb_cls,
556 ro,
557 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
558 ntohl (msg->hop_count),
559 ntohl (msg->desired_replication_level),
560 &msg->key);
561 }
562}
563
564
565/**
566 * Validate a get response monitor message from the service.
567 *
568 * @param cls The DHT handle.
569 * @param msg monitor get response message from the service
570 * @return #GNUNET_OK if everything went fine,
571 * #GNUNET_SYSERR if the message is malformed.
572 */
573static enum GNUNET_GenericReturnValue
574check_monitor_get_resp (void *cls,
575 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
576{
577 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
578 uint32_t getl = ntohl (msg->get_path_length);
579 uint32_t putl = ntohl (msg->put_path_length);
580 enum GNUNET_DHT_RouteOption ro
581 = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
582 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
583
584 if (truncated)
585 {
586 if (msize < sizeof (struct GNUNET_PeerIdentity))
587 {
588 GNUNET_break (0);
589 return GNUNET_SYSERR;
590 }
591 msize -= sizeof (struct GNUNET_PeerIdentity);
592 }
593 if ((getl + putl < getl) ||
594 ((msize / sizeof(struct GNUNET_DHT_PathElement)) < getl + putl))
595 {
596 GNUNET_break (0);
597 return GNUNET_SYSERR;
598 }
599 return GNUNET_OK;
600}
601
602
603/**
604 * Process a get response monitor message from the service.
605 *
606 * @param cls The DHT handle.
607 * @param msg monitor get response message from the service
608 */
609static void
610handle_monitor_get_resp (void *cls,
611 const struct GNUNET_DHT_MonitorGetRespMessage *msg)
612{
613 struct GNUNET_DHT_Handle *handle = cls;
614 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
615 enum GNUNET_DHT_RouteOption ro
616 = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
617 uint32_t getl = ntohl (msg->get_path_length);
618 uint32_t putl = ntohl (msg->put_path_length);
619 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
620 const struct GNUNET_PeerIdentity *trunc_peer
621 = truncated
622 ? (const struct GNUNET_PeerIdentity *) &msg[1]
623 : NULL;
624 const struct GNUNET_DHT_PathElement *path
625 = truncated
626 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
627 : (const struct GNUNET_DHT_PathElement *) &msg[1];
628
629 if (truncated)
630 msize -= sizeof (struct GNUNET_PeerIdentity);
631 msize -= sizeof(struct GNUNET_DHT_PathElement) * (putl + getl);
632 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
633 NULL != mh;
634 mh = mh->next)
635 {
636 if (NULL == mh->get_resp_cb)
637 continue;
638 if ( (GNUNET_BLOCK_TYPE_ANY != mh->type) &&
639 (mh->type != ntohl (msg->type)) )
640 continue;
641 if ( (NULL != mh->key) &&
642 (0 != GNUNET_memcmp (mh->key,
643 &msg->key)) )
644 continue;
645 mh->get_resp_cb (mh->cb_cls,
646 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
647 trunc_peer,
648 &path[putl],
649 getl,
650 path,
651 putl,
652 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
653 &msg->key,
654 (const void *) &path[getl + putl],
655 msize);
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 = ntohs (msg->header.size) - sizeof(*msg);
673 uint32_t putl = ntohl (msg->put_path_length);
674 enum GNUNET_DHT_RouteOption ro
675 = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
676 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
677
678 if (truncated)
679 {
680 if (msize < sizeof (struct GNUNET_PeerIdentity))
681 {
682 GNUNET_break (0);
683 return GNUNET_SYSERR;
684 }
685 msize -= sizeof (struct GNUNET_PeerIdentity);
686 }
687 if ((msize / sizeof(struct GNUNET_DHT_PathElement)) < putl)
688 {
689 GNUNET_break (0);
690 return GNUNET_SYSERR;
691 }
692 return GNUNET_OK;
693}
694
695
696/**
697 * Process a put monitor message from the service.
698 *
699 * @param cls The DHT handle.
700 * @param msg Monitor put message from the service.
701 */
702static void
703handle_monitor_put (void *cls,
704 const struct GNUNET_DHT_MonitorPutMessage *msg)
705{
706 struct GNUNET_DHT_Handle *handle = cls;
707 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
708 uint32_t putl = ntohl (msg->put_path_length);
709 enum GNUNET_DHT_RouteOption ro
710 = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
711 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
712 const struct GNUNET_PeerIdentity *trunc_peer
713 = truncated
714 ? (const struct GNUNET_PeerIdentity *) &msg[1]
715 : NULL;
716 const struct GNUNET_DHT_PathElement *path
717 = truncated
718 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
719 : (const struct GNUNET_DHT_PathElement *) &msg[1];
720
721 if (truncated)
722 msize -= sizeof (struct GNUNET_PeerIdentity);
723 msize -= sizeof(struct GNUNET_DHT_PathElement) * putl;
724 for (struct GNUNET_DHT_MonitorHandle *mh = handle->monitor_head;
725 NULL != mh;
726 mh = mh->next)
727 {
728 if (NULL == mh->put_cb)
729 continue;
730 if ( (GNUNET_BLOCK_TYPE_ANY != mh->type) &&
731 (mh->type != ntohl (msg->type)) )
732 continue;
733 if ( (NULL != mh->key) &&
734 (0 != GNUNET_memcmp (mh->key,
735 &msg->key)) )
736 continue;
737 mh->put_cb (mh->cb_cls,
738 ro,
739 (enum GNUNET_BLOCK_Type) ntohl (msg->type),
740 ntohl (msg->hop_count),
741 ntohl (msg->desired_replication_level),
742 trunc_peer,
743 putl,
744 path,
745 GNUNET_TIME_absolute_ntoh (msg->expiration_time),
746 &msg->key,
747 (const void *) &path[putl],
748 msize);
749 }
750}
751
752
753/**
754 * Verify that client result message received from the service is well-formed.
755 *
756 * @param cls The DHT handle.
757 * @param msg Monitor put message from the service.
758 * @return #GNUNET_OK if everything went fine,
759 * #GNUNET_SYSERR if the message is malformed.
760 */
761static enum GNUNET_GenericReturnValue
762check_client_result (void *cls,
763 const struct GNUNET_DHT_ClientResultMessage *msg)
764{
765 size_t msize = ntohs (msg->header.size) - sizeof(*msg);
766 uint32_t put_path_length = ntohl (msg->put_path_length);
767 uint32_t get_path_length = ntohl (msg->get_path_length);
768 enum GNUNET_DHT_RouteOption ro
769 = (enum GNUNET_DHT_RouteOption) ntohl (msg->options);
770 bool truncated = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
771 size_t meta_length;
772
773 if (truncated)
774 {
775 if (msize < sizeof (struct GNUNET_PeerIdentity))
776 {
777 GNUNET_break (0);
778 return GNUNET_SYSERR;
779 }
780 msize -= sizeof (struct GNUNET_PeerIdentity);
781 }
782 meta_length = msize / sizeof(struct GNUNET_DHT_PathElement);
783 if ( (get_path_length + put_path_length >
784 meta_length) ||
785 (get_path_length + put_path_length <
786 get_path_length) )
787 {
788 GNUNET_break (0);
789 return GNUNET_SYSERR;
790 }
791 return GNUNET_OK;
792}
793
794
795/**
796 * Process a given reply that might match the given request.
797 *
798 * @param cls the `struct GNUNET_DHT_ClientResultMessage`
799 * @param key query of the request
800 * @param value the `struct GNUNET_DHT_GetHandle` of a request matching the same key
801 * @return #GNUNET_YES to continue to iterate over all results
802 */
803static enum GNUNET_GenericReturnValue
804process_client_result (void *cls,
805 const struct GNUNET_HashCode *key,
806 void *value)
807{
808 const struct GNUNET_DHT_ClientResultMessage *crm = cls;
809 struct GNUNET_DHT_GetHandle *get_handle = value;
810 size_t msize = ntohs (crm->header.size) - sizeof(*crm);
811 uint16_t type = ntohl (crm->type);
812 enum GNUNET_DHT_RouteOption ro
813 = (enum GNUNET_DHT_RouteOption) ntohl (crm->options);
814 bool truncated
815 = (0 != (ro & GNUNET_DHT_RO_TRUNCATED));
816 uint32_t put_path_length
817 = ntohl (crm->put_path_length);
818 uint32_t get_path_length
819 = ntohl (crm->get_path_length);
820 const struct GNUNET_PeerIdentity *trunc_peer
821 = truncated
822 ? (const struct GNUNET_PeerIdentity *) &crm[1]
823 : NULL;
824 const struct GNUNET_DHT_PathElement *put_path
825 = truncated
826 ? (const struct GNUNET_DHT_PathElement *) &trunc_peer[1]
827 : (const struct GNUNET_DHT_PathElement *) &crm[1];
828 const struct GNUNET_DHT_PathElement *get_path
829 = &put_path[put_path_length];
830 const void *data
831 = &get_path[get_path_length];
832 size_t meta_length
833 = sizeof(struct GNUNET_DHT_PathElement)
834 * (get_path_length + put_path_length);
835 size_t data_length
836 = msize - meta_length;
837 struct GNUNET_HashCode hc;
838
839 if (truncated)
840 data_length -= sizeof (struct GNUNET_PeerIdentity);
841 if (crm->unique_id != get_handle->unique_id)
842 {
843 /* UID mismatch */
844 LOG (GNUNET_ERROR_TYPE_DEBUG,
845 "Ignoring reply for %s: UID mismatch: %llu/%llu\n",
846 GNUNET_h2s (key),
847 (unsigned long long) crm->unique_id,
848 (unsigned long long) get_handle->unique_id);
849 return GNUNET_YES;
850 }
851 if ( (get_handle->type != GNUNET_BLOCK_TYPE_ANY) &&
852 (get_handle->type != type) )
853 {
854 /* type mismatch */
855 GNUNET_break (0);
856 return GNUNET_YES;
857 }
858
859 {
860 char *pp;
861 char *gp;
862
863 gp = GNUNET_DHT_pp2s (get_path,
864 get_path_length);
865 pp = GNUNET_DHT_pp2s (put_path,
866 put_path_length);
867 LOG (GNUNET_ERROR_TYPE_DEBUG,
868 "Giving %u byte reply for %s to application (GP: %s, PP: %s)\n",
869 (unsigned int) data_length,
870 GNUNET_h2s (key),
871 gp,
872 pp);
873 GNUNET_free (gp);
874 GNUNET_free (pp);
875 }
876 /* remember that we've seen this result */
877 GNUNET_CRYPTO_hash (data,
878 data_length,
879 &hc);
880 if (get_handle->seen_results_size == get_handle->seen_results_end)
881 GNUNET_array_grow (get_handle->seen_results,
882 get_handle->seen_results_size,
883 get_handle->seen_results_size * 2 + 1);
884 get_handle->seen_results[get_handle->seen_results_end++] = hc;
885 /* no need to block it explicitly, service already knows about it! */
886 get_handle->iter (get_handle->iter_cls,
887 GNUNET_TIME_absolute_ntoh (crm->expiration),
888 key,
889 trunc_peer,
890 get_path,
891 get_path_length,
892 put_path,
893 put_path_length,
894 type,
895 data_length,
896 data);
897 return GNUNET_YES;
898}
899
900
901/**
902 * Process a client result message received from the service.
903 *
904 * @param cls The DHT handle.
905 * @param msg Monitor put message from the service.
906 */
907static void
908handle_client_result (void *cls,
909 const struct GNUNET_DHT_ClientResultMessage *msg)
910{
911 struct GNUNET_DHT_Handle *handle = cls;
912
913 GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests,
914 &msg->key,
915 &process_client_result,
916 (void *) msg);
917}
918
919
920/**
921 * Process a client HELLO message received from the service.
922 *
923 * @param cls The DHT handle.
924 * @param hdr HELLO URL message from the service.
925 * @return #GNUNET_OK if @a hdr is well-formed
926 */
927static enum GNUNET_GenericReturnValue
928check_client_hello (void *cls,
929 const struct GNUNET_MessageHeader *hdr)
930{
931 uint16_t len = ntohs (hdr->size);
932 const char *buf = (const char *) &hdr[1];
933
934 (void) cls;
935 if ('\0' != buf[len - sizeof (*hdr) - 1])
936 {
937 GNUNET_break (0);
938 return GNUNET_SYSERR;
939 }
940 return GNUNET_OK;
941}
942
943
944/**
945 * Process a client HELLO message received from the service.
946 *
947 * @param cls The DHT handle.
948 * @param hdr HELLO URL message from the service.
949 */
950static void
951handle_client_hello (void *cls,
952 const struct GNUNET_MessageHeader *hdr)
953{
954 struct GNUNET_DHT_Handle *handle = cls;
955 const char *url = (const char *) &hdr[1];
956 struct GNUNET_DHT_HelloGetHandle *hgh;
957
958 while (NULL != (hgh = handle->hgh_head))
959 {
960 hgh->cb (hgh->cb_cls,
961 url);
962 GNUNET_DHT_hello_get_cancel (hgh);
963 }
964}
965
966
967/**
968 * Process a MQ PUT transmission notification.
969 *
970 * @param cls The DHT handle.
971 */
972static void
973handle_put_cont (void *cls)
974{
975 struct GNUNET_DHT_PutHandle *ph = cls;
976 GNUNET_SCHEDULER_TaskCallback cont;
977 void *cont_cls;
978
979 cont = ph->cont;
980 cont_cls = ph->cont_cls;
981 ph->env = NULL;
982 GNUNET_DHT_put_cancel (ph);
983 if (NULL != cont)
984 cont (cont_cls);
985}
986
987
988/**
989 * Try to (re)connect to the DHT service.
990 *
991 * @param h DHT handle to reconnect
992 * @return #GNUNET_YES on success, #GNUNET_NO on failure.
993 */
994static enum GNUNET_GenericReturnValue
995try_connect (struct GNUNET_DHT_Handle *h)
996{
997 struct GNUNET_MQ_MessageHandler handlers[] = {
998 GNUNET_MQ_hd_fixed_size (monitor_get,
999 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET,
1000 struct GNUNET_DHT_MonitorGetMessage,
1001 h),
1002 GNUNET_MQ_hd_var_size (monitor_get_resp,
1003 GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP,
1004 struct GNUNET_DHT_MonitorGetRespMessage,
1005 h),
1006 GNUNET_MQ_hd_var_size (monitor_put,
1007 GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT,
1008 struct GNUNET_DHT_MonitorPutMessage,
1009 h),
1010 GNUNET_MQ_hd_var_size (client_result,
1011 GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT,
1012 struct GNUNET_DHT_ClientResultMessage,
1013 h),
1014 GNUNET_MQ_hd_var_size (client_hello,
1015 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL,
1016 struct GNUNET_MessageHeader,
1017 h),
1018 GNUNET_MQ_handler_end ()
1019 };
1020
1021 if (NULL != h->mq)
1022 return GNUNET_OK;
1023 h->mq = GNUNET_CLIENT_connect (h->cfg,
1024 "dht",
1025 handlers,
1026 &mq_error_handler,
1027 h);
1028 if (NULL == h->mq)
1029 {
1030 LOG (GNUNET_ERROR_TYPE_WARNING,
1031 "Failed to connect to the DHT service!\n");
1032 return GNUNET_NO;
1033 }
1034 return GNUNET_YES;
1035}
1036
1037
1038struct GNUNET_DHT_Handle *
1039GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1040 unsigned int ht_len)
1041{
1042 struct GNUNET_DHT_Handle *handle;
1043
1044 handle = GNUNET_new (struct GNUNET_DHT_Handle);
1045 handle->cfg = cfg;
1046 handle->uid_gen
1047 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
1048 UINT64_MAX);
1049 handle->active_requests
1050 = GNUNET_CONTAINER_multihashmap_create (ht_len,
1051 GNUNET_YES);
1052 if (GNUNET_NO == try_connect (handle))
1053 {
1054 GNUNET_DHT_disconnect (handle);
1055 return NULL;
1056 }
1057 return handle;
1058}
1059
1060
1061void
1062GNUNET_DHT_disconnect (struct GNUNET_DHT_Handle *handle)
1063{
1064 struct GNUNET_DHT_PutHandle *ph;
1065
1066 GNUNET_assert (0 ==
1067 GNUNET_CONTAINER_multihashmap_size (handle->active_requests));
1068 while (NULL != (ph = handle->put_head))
1069 {
1070 if (NULL != ph->cont)
1071 ph->cont (ph->cont_cls);
1072 GNUNET_DHT_put_cancel (ph);
1073 }
1074 if (NULL != handle->mq)
1075 {
1076 GNUNET_MQ_destroy (handle->mq);
1077 handle->mq = NULL;
1078 }
1079 if (NULL != handle->reconnect_task)
1080 {
1081 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
1082 handle->reconnect_task = NULL;
1083 }
1084 GNUNET_CONTAINER_multihashmap_destroy (handle->active_requests);
1085 GNUNET_free (handle);
1086}
1087
1088
1089struct GNUNET_DHT_PutHandle *
1090GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
1091 const struct GNUNET_HashCode *key,
1092 uint32_t desired_replication_level,
1093 enum GNUNET_DHT_RouteOption options,
1094 enum GNUNET_BLOCK_Type type,
1095 size_t size,
1096 const void *data,
1097 struct GNUNET_TIME_Absolute exp,
1098 GNUNET_SCHEDULER_TaskCallback cont,
1099 void *cont_cls)
1100{
1101 struct GNUNET_MQ_Envelope *env;
1102 struct GNUNET_DHT_ClientPutMessage *put_msg;
1103 size_t msize;
1104 struct GNUNET_DHT_PutHandle *ph;
1105
1106 msize = sizeof(struct GNUNET_DHT_ClientPutMessage) + size;
1107 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1108 (size >= GNUNET_MAX_MESSAGE_SIZE))
1109 {
1110 GNUNET_break (0);
1111 return NULL;
1112 }
1113 if (NULL == handle->mq)
1114 return NULL;
1115 LOG (GNUNET_ERROR_TYPE_DEBUG,
1116 "Sending PUT for %s to DHT via %p\n",
1117 GNUNET_h2s (key),
1118 handle);
1119 ph = GNUNET_new (struct GNUNET_DHT_PutHandle);
1120 ph->dht_handle = handle;
1121 ph->cont = cont;
1122 ph->cont_cls = cont_cls;
1123 GNUNET_CONTAINER_DLL_insert_tail (handle->put_head,
1124 handle->put_tail,
1125 ph);
1126 env = GNUNET_MQ_msg_extra (put_msg,
1127 size,
1128 GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT);
1129 GNUNET_MQ_notify_sent (env,
1130 &handle_put_cont,
1131 ph);
1132 ph->env = env;
1133 put_msg->type = htonl ((uint32_t) type);
1134 put_msg->options = htonl ((uint32_t) options);
1135 put_msg->desired_replication_level = htonl (desired_replication_level);
1136 put_msg->expiration = GNUNET_TIME_absolute_hton (exp);
1137 put_msg->key = *key;
1138 GNUNET_memcpy (&put_msg[1],
1139 data,
1140 size);
1141 GNUNET_MQ_send (handle->mq,
1142 env);
1143 return ph;
1144}
1145
1146
1147void
1148GNUNET_DHT_put_cancel (struct GNUNET_DHT_PutHandle *ph)
1149{
1150 struct GNUNET_DHT_Handle *handle = ph->dht_handle;
1151
1152 if (NULL != ph->env)
1153 GNUNET_MQ_notify_sent (ph->env,
1154 NULL,
1155 NULL);
1156 GNUNET_CONTAINER_DLL_remove (handle->put_head,
1157 handle->put_tail,
1158 ph);
1159 GNUNET_free (ph);
1160}
1161
1162
1163struct GNUNET_DHT_GetHandle *
1164GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
1165 enum GNUNET_BLOCK_Type type,
1166 const struct GNUNET_HashCode *key,
1167 uint32_t desired_replication_level,
1168 enum GNUNET_DHT_RouteOption options,
1169 const void *xquery,
1170 size_t xquery_size,
1171 GNUNET_DHT_GetIterator iter,
1172 void *iter_cls)
1173{
1174 struct GNUNET_DHT_GetHandle *gh;
1175 size_t msize;
1176
1177 msize = sizeof(struct GNUNET_DHT_ClientGetMessage) + xquery_size;
1178 if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
1179 (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
1180 {
1181 GNUNET_break (0);
1182 return NULL;
1183 }
1184 LOG (GNUNET_ERROR_TYPE_DEBUG,
1185 "Sending query for %s to DHT %p\n",
1186 GNUNET_h2s (key),
1187 handle);
1188 gh = GNUNET_malloc (sizeof(struct GNUNET_DHT_GetHandle)
1189 + xquery_size);
1190 gh->iter = iter;
1191 gh->iter_cls = iter_cls;
1192 gh->dht_handle = handle;
1193 gh->key = *key;
1194 gh->unique_id = ++handle->uid_gen;
1195 gh->xquery_size = xquery_size;
1196 gh->desired_replication_level = desired_replication_level;
1197 gh->type = type;
1198 gh->options = options;
1199 GNUNET_memcpy (&gh[1],
1200 xquery,
1201 xquery_size);
1202 GNUNET_CONTAINER_multihashmap_put (handle->active_requests,
1203 &gh->key,
1204 gh,
1205 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1206 if (NULL != handle->mq)
1207 send_get (gh);
1208 return gh;
1209}
1210
1211
1212void
1213GNUNET_DHT_get_filter_known_results (struct GNUNET_DHT_GetHandle *get_handle,
1214 unsigned int num_results,
1215 const struct GNUNET_HashCode *results)
1216{
1217 unsigned int needed;
1218 unsigned int had;
1219
1220 had = get_handle->seen_results_end;
1221 needed = had + num_results;
1222 if (needed > get_handle->seen_results_size)
1223 GNUNET_array_grow (get_handle->seen_results,
1224 get_handle->seen_results_size,
1225 needed);
1226 GNUNET_memcpy (&get_handle->seen_results[get_handle->seen_results_end],
1227 results,
1228 num_results * sizeof(struct GNUNET_HashCode));
1229 get_handle->seen_results_end += num_results;
1230 if (NULL != get_handle->dht_handle->mq)
1231 send_get_known_results (get_handle,
1232 had);
1233}
1234
1235
1236void
1237GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle)
1238{
1239 struct GNUNET_DHT_Handle *handle = get_handle->dht_handle;
1240
1241 LOG (GNUNET_ERROR_TYPE_DEBUG,
1242 "Sending STOP for %s to DHT via %p\n",
1243 GNUNET_h2s (&get_handle->key),
1244 handle);
1245 if (NULL != handle->mq)
1246 {
1247 struct GNUNET_MQ_Envelope *env;
1248 struct GNUNET_DHT_ClientGetStopMessage *stop_msg;
1249
1250 env = GNUNET_MQ_msg (stop_msg,
1251 GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP);
1252 stop_msg->reserved = htonl (0);
1253 stop_msg->unique_id = get_handle->unique_id;
1254 stop_msg->key = get_handle->key;
1255 GNUNET_MQ_send (handle->mq,
1256 env);
1257 }
1258 GNUNET_assert (GNUNET_YES ==
1259 GNUNET_CONTAINER_multihashmap_remove (handle->active_requests,
1260 &get_handle->key,
1261 get_handle));
1262 GNUNET_array_grow (get_handle->seen_results,
1263 get_handle->seen_results_end,
1264 0);
1265 GNUNET_free (get_handle);
1266}
1267
1268
1269struct GNUNET_DHT_MonitorHandle *
1270GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle,
1271 enum GNUNET_BLOCK_Type type,
1272 const struct GNUNET_HashCode *key,
1273 GNUNET_DHT_MonitorGetCB get_cb,
1274 GNUNET_DHT_MonitorGetRespCB get_resp_cb,
1275 GNUNET_DHT_MonitorPutCB put_cb,
1276 void *cb_cls)
1277{
1278 struct GNUNET_DHT_MonitorHandle *mh;
1279
1280 mh = GNUNET_new (struct GNUNET_DHT_MonitorHandle);
1281 mh->get_cb = get_cb;
1282 mh->get_resp_cb = get_resp_cb;
1283 mh->put_cb = put_cb;
1284 mh->cb_cls = cb_cls;
1285 mh->type = type;
1286 mh->dht_handle = handle;
1287 if (NULL != key)
1288 {
1289 mh->key = GNUNET_new (struct GNUNET_HashCode);
1290 *mh->key = *key;
1291 }
1292 GNUNET_CONTAINER_DLL_insert (handle->monitor_head,
1293 handle->monitor_tail,
1294 mh);
1295 if (NULL != handle->mq)
1296 send_monitor_start (mh);
1297 return mh;
1298}
1299
1300
1301void
1302GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *mh)
1303{
1304 struct GNUNET_DHT_Handle *handle = mh->dht_handle;
1305 struct GNUNET_DHT_MonitorStartStopMessage *m;
1306 struct GNUNET_MQ_Envelope *env;
1307
1308 GNUNET_CONTAINER_DLL_remove (handle->monitor_head,
1309 handle->monitor_tail,
1310 mh);
1311 env = GNUNET_MQ_msg (m,
1312 GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP);
1313 m->type = htonl (mh->type);
1314 m->get = htons (NULL != mh->get_cb);
1315 m->get_resp = htons (NULL != mh->get_resp_cb);
1316 m->put = htons (NULL != mh->put_cb);
1317 if (NULL != mh->key)
1318 {
1319 m->filter_key = htons (1);
1320 m->key = *mh->key;
1321 }
1322 GNUNET_MQ_send (handle->mq,
1323 env);
1324 GNUNET_free (mh->key);
1325 GNUNET_free (mh);
1326}
1327
1328
1329char *
1330GNUNET_DHT_pp2s (const struct GNUNET_DHT_PathElement *path,
1331 unsigned int path_len)
1332{
1333 char *buf;
1334 size_t off;
1335 size_t plen = path_len * 5 + 1;
1336
1337 GNUNET_assert (path_len < UINT32_MAX / 5);
1338 off = 0;
1339 buf = GNUNET_malloc (plen);
1340 for (unsigned int i = 0; i < path_len; i++)
1341 {
1342 off += GNUNET_snprintf (&buf[off],
1343 plen - off,
1344 "%s%s",
1345 GNUNET_i2s (&path[i].pred),
1346 (i == path_len - 1) ? "" : "-");
1347 }
1348 return buf;
1349}
1350
1351
1352unsigned int
1353GNUNET_DHT_verify_path (const void *data,
1354 size_t data_size,
1355 struct GNUNET_TIME_Absolute exp_time,
1356 const struct GNUNET_PeerIdentity *bpid,
1357 const struct GNUNET_DHT_PathElement *put_path,
1358 unsigned int put_path_len,
1359 const struct GNUNET_DHT_PathElement *get_path,
1360 unsigned int get_path_len,
1361 const struct GNUNET_PeerIdentity *me)
1362{
1363 static struct GNUNET_PeerIdentity zero;
1364 struct GNUNET_DHT_HopSignature hs = {
1365 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_DHT_HOP),
1366 .purpose.size = htonl (sizeof (hs)),
1367 .expiration_time = GNUNET_TIME_absolute_hton (exp_time)
1368 };
1369 unsigned int i;
1370
1371 if (0 == get_path_len + put_path_len)
1372 return 0;
1373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1374 "%s is verifying signatures with GPL: %u PPL: %u!\n",
1375 GNUNET_i2s (me),
1376 get_path_len,
1377 put_path_len);
1378 for (unsigned int j = 0; j<put_path_len; j++)
1379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380 "PP%u=%s\n",
1381 j,
1382 GNUNET_i2s (&put_path[j].pred));
1383 for (unsigned int j = 0; j<get_path_len; j++)
1384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1385 "GP%u=%s\n",
1386 j,
1387 GNUNET_i2s (&get_path[j].pred));
1388
1389 GNUNET_CRYPTO_hash (data,
1390 data_size,
1391 &hs.h_data);
1392 i = put_path_len + get_path_len;
1393 while (i > 0)
1394 {
1395 const struct GNUNET_PeerIdentity *pred;
1396 const struct GNUNET_PeerIdentity *succ;
1397 const struct GNUNET_DHT_PathElement *pe;
1398
1399 i--;
1400 if (0 == i)
1401 {
1402 pred = (NULL == bpid) ? &zero : bpid;
1403 }
1404 else
1405 {
1406 unsigned int off = i - 1;
1407
1408 pred = (off >= put_path_len)
1409 ? &get_path[off - put_path_len].pred
1410 : &put_path[off].pred;
1411 }
1412 if (i == get_path_len + put_path_len - 1)
1413 {
1414 succ = me;
1415 }
1416 else
1417 {
1418 unsigned int off = i + 1;
1419
1420 succ = (off >= put_path_len)
1421 ? &get_path[off - put_path_len].pred
1422 : &put_path[off].pred;
1423 }
1424 hs.pred = *pred;
1425 hs.succ = *succ;
1426 pe = (i >= put_path_len)
1427 ? &get_path[i - put_path_len]
1428 : &put_path[i];
1429 if (GNUNET_OK !=
1430 GNUNET_CRYPTO_eddsa_verify (
1431 GNUNET_SIGNATURE_PURPOSE_DHT_HOP,
1432 &hs,
1433 &pe->sig,
1434 &pe->pred.public_key))
1435 {
1436 GNUNET_break_op (0);
1437 return i + 1;
1438 }
1439 }
1440 return i;
1441}
1442
1443
1444struct GNUNET_DHT_HelloGetHandle *
1445GNUNET_DHT_hello_get (struct GNUNET_DHT_Handle *dht_handle,
1446 GNUNET_DHT_HelloGetCallback cb,
1447 void *cb_cls)
1448{
1449 struct GNUNET_DHT_HelloGetHandle *hgh;
1450 struct GNUNET_MessageHeader *hdr;
1451 struct GNUNET_MQ_Envelope *env;
1452
1453 hgh = GNUNET_new (struct GNUNET_DHT_HelloGetHandle);
1454 hgh->cb = cb;
1455 hgh->cb_cls = cb_cls;
1456 hgh->dht_handle = dht_handle;
1457 GNUNET_CONTAINER_DLL_insert (dht_handle->hgh_head,
1458 dht_handle->hgh_tail,
1459 hgh);
1460 env = GNUNET_MQ_msg (hdr,
1461 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_GET);
1462 GNUNET_MQ_send (dht_handle->mq,
1463 env);
1464 return hgh;
1465}
1466
1467
1468void
1469GNUNET_DHT_hello_get_cancel (struct GNUNET_DHT_HelloGetHandle *hgh)
1470{
1471 struct GNUNET_DHT_Handle *dht_handle = hgh->dht_handle;
1472
1473 GNUNET_CONTAINER_DLL_remove (dht_handle->hgh_head,
1474 dht_handle->hgh_tail,
1475 hgh);
1476 GNUNET_free (hgh);
1477}
1478
1479
1480void
1481GNUNET_DHT_hello_offer (struct GNUNET_DHT_Handle *dht_handle,
1482 const char *url,
1483 GNUNET_SCHEDULER_TaskCallback cb,
1484 void *cb_cls)
1485{
1486 struct GNUNET_MessageHeader *hdr;
1487 size_t slen = strlen (url) + 1;
1488 struct GNUNET_MQ_Envelope *env;
1489
1490 env = GNUNET_MQ_msg_extra (hdr,
1491 slen,
1492 GNUNET_MESSAGE_TYPE_DHT_CLIENT_HELLO_URL);
1493 memcpy (&hdr[1],
1494 url,
1495 slen);
1496 GNUNET_MQ_notify_sent (env,
1497 cb,
1498 cb_cls);
1499 GNUNET_MQ_send (dht_handle->mq,
1500 env);
1501}
1502
1503
1504/* end of dht_api.c */