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