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