diff options
Diffstat (limited to 'src/dht/dht_api.c')
-rw-r--r-- | src/dht/dht_api.c | 1504 |
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 | */ | ||
44 | struct 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 | */ | ||
80 | struct 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 | */ | ||
150 | struct 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 | */ | ||
202 | struct 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 | */ | ||
236 | struct 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 | */ | ||
308 | static enum GNUNET_GenericReturnValue | ||
309 | try_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 | */ | ||
317 | static void | ||
318 | send_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 | */ | ||
349 | static void | ||
350 | send_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 | */ | ||
392 | static enum GNUNET_GenericReturnValue | ||
393 | add_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 | */ | ||
415 | static void | ||
416 | send_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 | */ | ||
443 | static void | ||
444 | try_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 | */ | ||
477 | static void | ||
478 | do_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 | */ | ||
518 | static void | ||
519 | mq_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 | */ | ||
534 | static void | ||
535 | handle_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 | */ | ||
573 | static enum GNUNET_GenericReturnValue | ||
574 | check_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 | */ | ||
609 | static void | ||
610 | handle_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 | */ | ||
668 | static enum GNUNET_GenericReturnValue | ||
669 | check_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 | */ | ||
702 | static void | ||
703 | handle_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 | */ | ||
761 | static enum GNUNET_GenericReturnValue | ||
762 | check_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 | */ | ||
803 | static enum GNUNET_GenericReturnValue | ||
804 | process_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 | */ | ||
907 | static void | ||
908 | handle_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 | */ | ||
927 | static enum GNUNET_GenericReturnValue | ||
928 | check_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 | */ | ||
950 | static void | ||
951 | handle_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 | */ | ||
972 | static void | ||
973 | handle_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 | */ | ||
994 | static enum GNUNET_GenericReturnValue | ||
995 | try_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 | |||
1038 | struct GNUNET_DHT_Handle * | ||
1039 | GNUNET_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 | |||
1061 | void | ||
1062 | GNUNET_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 | |||
1089 | struct GNUNET_DHT_PutHandle * | ||
1090 | GNUNET_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 | |||
1147 | void | ||
1148 | GNUNET_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 | |||
1163 | struct GNUNET_DHT_GetHandle * | ||
1164 | GNUNET_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 | |||
1212 | void | ||
1213 | GNUNET_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 | |||
1236 | void | ||
1237 | GNUNET_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 | |||
1269 | struct GNUNET_DHT_MonitorHandle * | ||
1270 | GNUNET_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 | |||
1301 | void | ||
1302 | GNUNET_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 | |||
1329 | char * | ||
1330 | GNUNET_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 | |||
1352 | unsigned int | ||
1353 | GNUNET_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 | |||
1444 | struct GNUNET_DHT_HelloGetHandle * | ||
1445 | GNUNET_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 | |||
1468 | void | ||
1469 | GNUNET_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 | |||
1480 | void | ||
1481 | GNUNET_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 */ | ||