diff options
author | Schanzenbach, Martin <mschanzenbach@posteo.de> | 2017-01-20 07:00:54 +0100 |
---|---|---|
committer | Schanzenbach, Martin <mschanzenbach@posteo.de> | 2017-01-20 07:00:54 +0100 |
commit | 3cb90c74c5f591fd2541d154a8e7b05a1c2f4539 (patch) | |
tree | 620638f54539749f2a1b27a5991a90880fe7c14d /src/cadet/gnunet-service-cadet-new_peer.c | |
parent | 7122f35e2c00c29b1af31bdd294e93e6fcc84498 (diff) | |
parent | aedd5919e802370061850486c96da72b25df7f22 (diff) | |
download | gnunet-3cb90c74c5f591fd2541d154a8e7b05a1c2f4539.tar.gz gnunet-3cb90c74c5f591fd2541d154a8e7b05a1c2f4539.zip |
- merge; service API change
Diffstat (limited to 'src/cadet/gnunet-service-cadet-new_peer.c')
-rw-r--r-- | src/cadet/gnunet-service-cadet-new_peer.c | 1056 |
1 files changed, 1056 insertions, 0 deletions
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c new file mode 100644 index 000000000..47f725e09 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_peer.c | |||
@@ -0,0 +1,1056 @@ | |||
1 | |||
2 | /* | ||
3 | This file is part of GNUnet. | ||
4 | Copyright (C) 2001-2017 GNUnet e.V. | ||
5 | |||
6 | GNUnet is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 3, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | GNUnet is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with GNUnet; see the file COPYING. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @file cadet/gnunet-service-cadet-new_peer.c | ||
24 | * @brief Information we track per peer. | ||
25 | * @author Bartlomiej Polot | ||
26 | * @author Christian Grothoff | ||
27 | * | ||
28 | * TODO: | ||
29 | * - implement GCP_set_hello() / do HELLO advertising properly | ||
30 | * - optimize stopping/restarting DHT search to situations | ||
31 | * where we actually need it (i.e. not if we have a direct connection, | ||
32 | * or if we already have plenty of good short ones, or maybe even | ||
33 | * to take a break if we have some connections and have searched a lot (?)) | ||
34 | * - optimize MQM ready scans (O(n) -> O(1)) | ||
35 | */ | ||
36 | #include "platform.h" | ||
37 | #include "gnunet_util_lib.h" | ||
38 | #include "gnunet_signatures.h" | ||
39 | #include "gnunet_transport_service.h" | ||
40 | #include "gnunet_ats_service.h" | ||
41 | #include "gnunet_core_service.h" | ||
42 | #include "gnunet_statistics_service.h" | ||
43 | #include "cadet_protocol.h" | ||
44 | #include "cadet_path.h" | ||
45 | #include "gnunet-service-cadet-new.h" | ||
46 | #include "gnunet-service-cadet-new_connection.h" | ||
47 | #include "gnunet-service-cadet-new_dht.h" | ||
48 | #include "gnunet-service-cadet-new_peer.h" | ||
49 | #include "gnunet-service-cadet-new_paths.h" | ||
50 | #include "gnunet-service-cadet-new_tunnels.h" | ||
51 | |||
52 | /** | ||
53 | * How long do we wait until tearing down an idle peer? | ||
54 | */ | ||
55 | #define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | ||
56 | |||
57 | /** | ||
58 | * How long do we keep paths around if we no longer care about the peer? | ||
59 | */ | ||
60 | #define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2) | ||
61 | |||
62 | |||
63 | |||
64 | |||
65 | /** | ||
66 | * Data structure used to track whom we have to notify about changes | ||
67 | * to our message queue. | ||
68 | */ | ||
69 | struct GCP_MessageQueueManager | ||
70 | { | ||
71 | |||
72 | /** | ||
73 | * Kept in a DLL. | ||
74 | */ | ||
75 | struct GCP_MessageQueueManager *next; | ||
76 | |||
77 | /** | ||
78 | * Kept in a DLL. | ||
79 | */ | ||
80 | struct GCP_MessageQueueManager *prev; | ||
81 | |||
82 | /** | ||
83 | * Function to call with updated message queue object. | ||
84 | */ | ||
85 | GCP_MessageQueueNotificationCallback cb; | ||
86 | |||
87 | /** | ||
88 | * Closure for @e cb. | ||
89 | */ | ||
90 | void *cb_cls; | ||
91 | |||
92 | /** | ||
93 | * The peer this is for. | ||
94 | */ | ||
95 | struct CadetPeer *cp; | ||
96 | |||
97 | /** | ||
98 | * Envelope this manager would like to transmit once it is its turn. | ||
99 | */ | ||
100 | struct GNUNET_MQ_Envelope *env; | ||
101 | |||
102 | }; | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Struct containing all information regarding a given peer | ||
107 | */ | ||
108 | struct CadetPeer | ||
109 | { | ||
110 | /** | ||
111 | * ID of the peer | ||
112 | */ | ||
113 | struct GNUNET_PeerIdentity pid; | ||
114 | |||
115 | /** | ||
116 | * Last time we heard from this peer | ||
117 | */ | ||
118 | struct GNUNET_TIME_Absolute last_contact; | ||
119 | |||
120 | /** | ||
121 | * Array of DLLs of paths traversing the peer, organized by the | ||
122 | * offset of the peer on the larger path. | ||
123 | */ | ||
124 | struct CadetPeerPathEntry **path_heads; | ||
125 | |||
126 | /** | ||
127 | * Array of DLL of paths traversing the peer, organized by the | ||
128 | * offset of the peer on the larger path. | ||
129 | */ | ||
130 | struct CadetPeerPathEntry **path_tails; | ||
131 | |||
132 | /** | ||
133 | * Notifications to call when @e core_mq changes. | ||
134 | */ | ||
135 | struct GCP_MessageQueueManager *mqm_head; | ||
136 | |||
137 | /** | ||
138 | * Notifications to call when @e core_mq changes. | ||
139 | */ | ||
140 | struct GCP_MessageQueueManager *mqm_tail; | ||
141 | |||
142 | /** | ||
143 | * MIN-heap of paths owned by this peer (they also end at this | ||
144 | * peer). Ordered by desirability. | ||
145 | */ | ||
146 | struct GNUNET_CONTAINER_Heap *path_heap; | ||
147 | |||
148 | /** | ||
149 | * Handle to stop the DHT search for paths to this peer | ||
150 | */ | ||
151 | struct GCD_search_handle *search_h; | ||
152 | |||
153 | /** | ||
154 | * Task to stop the DHT search for paths to this peer | ||
155 | */ | ||
156 | struct GNUNET_SCHEDULER_Task *search_delayedXXX; | ||
157 | |||
158 | /** | ||
159 | * Task to destroy this entry. | ||
160 | */ | ||
161 | struct GNUNET_SCHEDULER_Task *destroy_task; | ||
162 | |||
163 | /** | ||
164 | * Tunnel to this peer, if any. | ||
165 | */ | ||
166 | struct CadetTunnel *t; | ||
167 | |||
168 | /** | ||
169 | * Connections that go through this peer; indexed by tid. | ||
170 | */ | ||
171 | struct GNUNET_CONTAINER_MultiShortmap *connections; | ||
172 | |||
173 | /** | ||
174 | * Handle for core transmissions. | ||
175 | */ | ||
176 | struct GNUNET_MQ_Handle *core_mq; | ||
177 | |||
178 | /** | ||
179 | * Hello message of the peer. | ||
180 | */ | ||
181 | struct GNUNET_HELLO_Message *hello; | ||
182 | |||
183 | /** | ||
184 | * Handle to us offering the HELLO to the transport. | ||
185 | */ | ||
186 | struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer; | ||
187 | |||
188 | /** | ||
189 | * Handle to our ATS request asking ATS to suggest an address | ||
190 | * to TRANSPORT for this peer (to establish a direct link). | ||
191 | */ | ||
192 | struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion; | ||
193 | |||
194 | /** | ||
195 | * How many messages are in the queue to this peer. | ||
196 | */ | ||
197 | unsigned int queue_n; | ||
198 | |||
199 | /** | ||
200 | * How many paths do we have to this peer (in all @e path_heads DLLs combined). | ||
201 | */ | ||
202 | unsigned int num_paths; | ||
203 | |||
204 | /** | ||
205 | * Number of message queue managers of this peer that have a message in waiting. | ||
206 | * | ||
207 | * Used to quickly see if we need to bother scanning the @e msm_head DLL. | ||
208 | * TODO: could be replaced by another DLL that would then allow us to avoid | ||
209 | * the O(n)-scan of the DLL for ready entries! | ||
210 | */ | ||
211 | unsigned int mqm_ready_counter; | ||
212 | |||
213 | /** | ||
214 | * Current length of the @e path_heads and @path_tails arrays. | ||
215 | * The arrays should be grown as needed. | ||
216 | */ | ||
217 | unsigned int path_dll_length; | ||
218 | |||
219 | }; | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Get the static string for a peer ID. | ||
224 | * | ||
225 | * @param peer Peer. | ||
226 | * | ||
227 | * @return Static string for it's ID. | ||
228 | */ | ||
229 | const char * | ||
230 | GCP_2s (const struct CadetPeer *peer) | ||
231 | { | ||
232 | if (NULL == peer) | ||
233 | return "PEER(NULL)"; | ||
234 | return GNUNET_i2s (&peer->pid); | ||
235 | } | ||
236 | |||
237 | |||
238 | /** | ||
239 | * This peer is no longer be needed, clean it up now. | ||
240 | * | ||
241 | * @param cls peer to clean up | ||
242 | */ | ||
243 | static void | ||
244 | destroy_peer (void *cls) | ||
245 | { | ||
246 | struct CadetPeer *cp = cls; | ||
247 | |||
248 | cp->destroy_task = NULL; | ||
249 | GNUNET_assert (NULL == cp->t); | ||
250 | GNUNET_assert (NULL == cp->core_mq); | ||
251 | GNUNET_assert (0 == cp->path_dll_length); | ||
252 | GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)); | ||
253 | GNUNET_assert (GNUNET_YES == | ||
254 | GNUNET_CONTAINER_multipeermap_remove (peers, | ||
255 | &cp->pid, | ||
256 | cp)); | ||
257 | GNUNET_free_non_null (cp->path_heads); | ||
258 | GNUNET_free_non_null (cp->path_tails); | ||
259 | cp->path_dll_length = 0; | ||
260 | if (NULL != cp->search_h) | ||
261 | { | ||
262 | GCD_search_stop (cp->search_h); | ||
263 | cp->search_h = NULL; | ||
264 | } | ||
265 | /* FIXME: clean up search_delayedXXX! */ | ||
266 | |||
267 | if (NULL != cp->hello_offer) | ||
268 | { | ||
269 | GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer); | ||
270 | cp->hello_offer = NULL; | ||
271 | } | ||
272 | if (NULL != cp->connectivity_suggestion) | ||
273 | { | ||
274 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
275 | cp->connectivity_suggestion = NULL; | ||
276 | } | ||
277 | GNUNET_CONTAINER_multishortmap_destroy (cp->connections); | ||
278 | GNUNET_CONTAINER_heap_destroy (cp->path_heap); | ||
279 | GNUNET_free_non_null (cp->hello); | ||
280 | /* Peer should not be freed if paths exist; if there are no paths, | ||
281 | there ought to be no connections, and without connections, no | ||
282 | notifications. Thus we can assert that mqm_head is empty at this | ||
283 | point. */ | ||
284 | GNUNET_assert (NULL == cp->mqm_head); | ||
285 | GNUNET_free (cp); | ||
286 | } | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Set the message queue to @a mq for peer @a cp and notify watchers. | ||
291 | * | ||
292 | * @param cp peer to modify | ||
293 | * @param mq message queue to set (can be NULL) | ||
294 | */ | ||
295 | void | ||
296 | GCP_set_mq (struct CadetPeer *cp, | ||
297 | struct GNUNET_MQ_Handle *mq) | ||
298 | { | ||
299 | cp->core_mq = mq; | ||
300 | |||
301 | for (struct GCP_MessageQueueManager *mqm = cp->mqm_head; | ||
302 | NULL != mqm; | ||
303 | mqm = mqm->next) | ||
304 | { | ||
305 | if (NULL == mq) | ||
306 | { | ||
307 | if (NULL != mqm->env) | ||
308 | { | ||
309 | GNUNET_MQ_discard (mqm->env); | ||
310 | mqm->env = NULL; | ||
311 | mqm->cb (mqm->cb_cls, | ||
312 | GNUNET_SYSERR); | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | mqm->cb (mqm->cb_cls, | ||
317 | GNUNET_NO); | ||
318 | } | ||
319 | } | ||
320 | else | ||
321 | { | ||
322 | GNUNET_assert (NULL == mqm->env); | ||
323 | mqm->cb (mqm->cb_cls, | ||
324 | GNUNET_YES); | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Transmit current envelope from this @a mqm. | ||
332 | * | ||
333 | * @param mqm mqm to transmit message for now | ||
334 | */ | ||
335 | static void | ||
336 | mqm_execute (struct GCP_MessageQueueManager *mqm) | ||
337 | { | ||
338 | struct CadetPeer *cp = mqm->cp; | ||
339 | |||
340 | /* Move entry to the end of the DLL, to be fair. */ | ||
341 | if (mqm != cp->mqm_tail) | ||
342 | { | ||
343 | GNUNET_CONTAINER_DLL_remove (cp->mqm_head, | ||
344 | cp->mqm_tail, | ||
345 | mqm); | ||
346 | GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head, | ||
347 | cp->mqm_tail, | ||
348 | mqm); | ||
349 | } | ||
350 | GNUNET_MQ_send (cp->core_mq, | ||
351 | mqm->env); | ||
352 | mqm->env = NULL; | ||
353 | cp->mqm_ready_counter--; | ||
354 | } | ||
355 | |||
356 | |||
357 | /** | ||
358 | * Function called when CORE took one of the messages from | ||
359 | * a message queue manager and transmitted it. | ||
360 | * | ||
361 | * @param cls the `struct CadetPeeer` where we made progress | ||
362 | */ | ||
363 | static void | ||
364 | mqm_send_done (void *cls) | ||
365 | { | ||
366 | struct CadetPeer *cp = cls; | ||
367 | |||
368 | if (0 == cp->mqm_ready_counter) | ||
369 | return; /* nothing to do */ | ||
370 | for (struct GCP_MessageQueueManager *mqm = cp->mqm_head; | ||
371 | NULL != mqm; | ||
372 | mqm = mqm->next) | ||
373 | { | ||
374 | if (NULL == mqm->env) | ||
375 | continue; | ||
376 | mqm_execute (mqm); | ||
377 | return; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | |||
382 | /** | ||
383 | * Send the message in @a env to @a cp. | ||
384 | * | ||
385 | * @param mqm the message queue manager to use for transmission | ||
386 | * @param env envelope with the message to send; must NOT | ||
387 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
388 | */ | ||
389 | void | ||
390 | GCP_send (struct GCP_MessageQueueManager *mqm, | ||
391 | struct GNUNET_MQ_Envelope *env) | ||
392 | { | ||
393 | struct CadetPeer *cp = mqm->cp; | ||
394 | |||
395 | GNUNET_assert (NULL != cp->core_mq); | ||
396 | GNUNET_assert (NULL == mqm->env); | ||
397 | GNUNET_MQ_notify_sent (env, | ||
398 | &mqm_send_done, | ||
399 | cp); | ||
400 | mqm->env = env; | ||
401 | cp->mqm_ready_counter++; | ||
402 | if (0 != GNUNET_MQ_get_length (cp->core_mq)) | ||
403 | return; | ||
404 | mqm_execute (mqm); | ||
405 | } | ||
406 | |||
407 | |||
408 | /** | ||
409 | * Function called to destroy a peer now. | ||
410 | * | ||
411 | * @param cls NULL | ||
412 | * @param pid identity of the peer (unused) | ||
413 | * @param value the `struct CadetPeer` to clean up | ||
414 | * @return #GNUNET_OK (continue to iterate) | ||
415 | */ | ||
416 | static int | ||
417 | destroy_iterator_cb (void *cls, | ||
418 | const struct GNUNET_PeerIdentity *pid, | ||
419 | void *value) | ||
420 | { | ||
421 | struct CadetPeer *cp = value; | ||
422 | |||
423 | if (NULL != cp->destroy_task) | ||
424 | { | ||
425 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
426 | cp->destroy_task = NULL; | ||
427 | } | ||
428 | destroy_peer (cp); | ||
429 | return GNUNET_OK; | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * Clean up all entries about all peers. | ||
435 | * Must only be called after all tunnels, CORE-connections and | ||
436 | * connections are down. | ||
437 | */ | ||
438 | void | ||
439 | GCP_destroy_all_peers () | ||
440 | { | ||
441 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
442 | &destroy_iterator_cb, | ||
443 | NULL); | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | * This peer may no longer be needed, consider cleaning it up. | ||
449 | * | ||
450 | * @param cp peer to clean up | ||
451 | */ | ||
452 | static void | ||
453 | consider_peer_destroy (struct CadetPeer *cp); | ||
454 | |||
455 | |||
456 | /** | ||
457 | * We really no longere care about a peer, stop hogging memory with paths to it. | ||
458 | * Afterwards, see if there is more to be cleaned up about this peer. | ||
459 | * | ||
460 | * @param cls a `struct CadetPeer`. | ||
461 | */ | ||
462 | static void | ||
463 | drop_paths (void *cls) | ||
464 | { | ||
465 | struct CadetPeer *cp = cls; | ||
466 | struct CadetPeerPath *path; | ||
467 | |||
468 | cp->destroy_task = NULL; | ||
469 | while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap))) | ||
470 | GCPP_release (path); | ||
471 | consider_peer_destroy (cp); | ||
472 | } | ||
473 | |||
474 | |||
475 | /** | ||
476 | * This peer may no longer be needed, consider cleaning it up. | ||
477 | * | ||
478 | * @param cp peer to clean up | ||
479 | */ | ||
480 | static void | ||
481 | consider_peer_destroy (struct CadetPeer *cp) | ||
482 | { | ||
483 | struct GNUNET_TIME_Relative exp; | ||
484 | |||
485 | if (NULL != cp->destroy_task) | ||
486 | { | ||
487 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
488 | cp->destroy_task = NULL; | ||
489 | } | ||
490 | if (NULL != cp->t) | ||
491 | return; /* still relevant! */ | ||
492 | if (NULL != cp->core_mq) | ||
493 | return; /* still relevant! */ | ||
494 | if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections)) | ||
495 | return; /* still relevant! */ | ||
496 | if (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) | ||
497 | { | ||
498 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT, | ||
499 | &drop_paths, | ||
500 | cp); | ||
501 | return; | ||
502 | } | ||
503 | if (0 < cp->path_dll_length) | ||
504 | return; /* still relevant! */ | ||
505 | if (NULL != cp->hello) | ||
506 | { | ||
507 | /* relevant only until HELLO expires */ | ||
508 | exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello)); | ||
509 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp, | ||
510 | &destroy_peer, | ||
511 | cp); | ||
512 | return; | ||
513 | } | ||
514 | cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT, | ||
515 | &destroy_peer, | ||
516 | cp); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Add an entry to the DLL of all of the paths that this peer is on. | ||
522 | * | ||
523 | * @param cp peer to modify | ||
524 | * @param entry an entry on a path | ||
525 | * @param off offset of this peer on the path | ||
526 | */ | ||
527 | void | ||
528 | GCP_path_entry_add (struct CadetPeer *cp, | ||
529 | struct CadetPeerPathEntry *entry, | ||
530 | unsigned int off) | ||
531 | { | ||
532 | if (off >= cp->path_dll_length) | ||
533 | { | ||
534 | unsigned int len = cp->path_dll_length; | ||
535 | |||
536 | GNUNET_array_grow (cp->path_heads, | ||
537 | len, | ||
538 | off + 4); | ||
539 | GNUNET_array_grow (cp->path_tails, | ||
540 | cp->path_dll_length, | ||
541 | off + 4); | ||
542 | } | ||
543 | GNUNET_CONTAINER_DLL_insert (cp->path_heads[off], | ||
544 | cp->path_tails[off], | ||
545 | entry); | ||
546 | cp->num_paths++; | ||
547 | |||
548 | /* If we have a tunnel to this peer, tell the tunnel that there is a | ||
549 | new path available. */ | ||
550 | if (NULL != cp->t) | ||
551 | GCT_consider_path (cp->t, | ||
552 | entry->path, | ||
553 | off); | ||
554 | } | ||
555 | |||
556 | |||
557 | /** | ||
558 | * Remove an entry from the DLL of all of the paths that this peer is on. | ||
559 | * | ||
560 | * @param cp peer to modify | ||
561 | * @param entry an entry on a path | ||
562 | * @param off offset of this peer on the path | ||
563 | */ | ||
564 | void | ||
565 | GCP_path_entry_remove (struct CadetPeer *cp, | ||
566 | struct CadetPeerPathEntry *entry, | ||
567 | unsigned int off) | ||
568 | { | ||
569 | GNUNET_CONTAINER_DLL_remove (cp->path_heads[off], | ||
570 | cp->path_tails[off], | ||
571 | entry); | ||
572 | GNUNET_assert (0 < cp->num_paths); | ||
573 | cp->num_paths--; | ||
574 | } | ||
575 | |||
576 | |||
577 | /** | ||
578 | * Try adding a @a path to this @a peer. If the peer already | ||
579 | * has plenty of paths, return NULL. | ||
580 | * | ||
581 | * @param cp peer to which the @a path leads to | ||
582 | * @param path a path looking for an owner; may not be fully initialized yet! | ||
583 | * @param off offset of @a cp in @a path | ||
584 | * @return NULL if this peer does not care to become a new owner, | ||
585 | * otherwise the node in the peer's path heap for the @a path. | ||
586 | */ | ||
587 | struct GNUNET_CONTAINER_HeapNode * | ||
588 | GCP_attach_path (struct CadetPeer *cp, | ||
589 | struct CadetPeerPath *path, | ||
590 | unsigned int off) | ||
591 | { | ||
592 | GNUNET_CONTAINER_HeapCostType desirability; | ||
593 | struct CadetPeerPath *root; | ||
594 | GNUNET_CONTAINER_HeapCostType root_desirability; | ||
595 | struct GNUNET_CONTAINER_HeapNode *hn; | ||
596 | |||
597 | /* FIXME: desirability is not yet initialized; tricky! */ | ||
598 | desirability = GCPP_get_desirability (path); | ||
599 | if (GNUNET_NO == | ||
600 | GNUNET_CONTAINER_heap_peek2 (cp->path_heap, | ||
601 | (void **) &root, | ||
602 | &root_desirability)) | ||
603 | { | ||
604 | root = NULL; | ||
605 | root_desirability = 0; | ||
606 | } | ||
607 | |||
608 | if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) && | ||
609 | (desirability < root_desirability) ) | ||
610 | return NULL; | ||
611 | |||
612 | /* Yes, we'd like to add this path, add to our heap */ | ||
613 | hn = GNUNET_CONTAINER_heap_insert (cp->path_heap, | ||
614 | (void *) cp, | ||
615 | desirability); | ||
616 | |||
617 | /* Consider maybe dropping other paths because of the new one */ | ||
618 | if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >= | ||
619 | 2 * DESIRED_CONNECTIONS_PER_TUNNEL) | ||
620 | { | ||
621 | /* Now we have way too many, drop least desirable UNLESS it is in use! | ||
622 | (Note that this intentionally keeps highly desireable, but currently | ||
623 | unused paths around in the hope that we might be able to switch, even | ||
624 | if the number of paths exceeds the threshold.) */ | ||
625 | root = GNUNET_CONTAINER_heap_peek (cp->path_heap); | ||
626 | if (NULL == | ||
627 | GCPP_get_connection (root, | ||
628 | cp, | ||
629 | GCPP_get_length (root) - 1)) | ||
630 | { | ||
631 | /* Got plenty of paths to this destination, and this is a low-quality | ||
632 | one that we don't care, allow it to die. */ | ||
633 | GNUNET_assert (root == | ||
634 | GNUNET_CONTAINER_heap_remove_root (cp->path_heap)); | ||
635 | GCPP_release (root); | ||
636 | } | ||
637 | } | ||
638 | return hn; | ||
639 | } | ||
640 | |||
641 | |||
642 | /** | ||
643 | * This peer can no longer own @a path as the path | ||
644 | * has been extended and a peer further down the line | ||
645 | * is now the new owner. | ||
646 | * | ||
647 | * @param cp old owner of the @a path | ||
648 | * @param path path where the ownership is lost | ||
649 | * @param hn note in @a cp's path heap that must be deleted | ||
650 | */ | ||
651 | void | ||
652 | GCP_detach_path (struct CadetPeer *cp, | ||
653 | struct CadetPeerPath *path, | ||
654 | struct GNUNET_CONTAINER_HeapNode *hn) | ||
655 | { | ||
656 | GNUNET_assert (path == | ||
657 | GNUNET_CONTAINER_heap_remove_node (hn)); | ||
658 | } | ||
659 | |||
660 | |||
661 | /** | ||
662 | * Add a @a connection to this @a cp. | ||
663 | * | ||
664 | * @param cp peer via which the @a connection goes | ||
665 | * @param cc the connection to add | ||
666 | */ | ||
667 | void | ||
668 | GCP_add_connection (struct CadetPeer *cp, | ||
669 | struct CadetConnection *cc) | ||
670 | { | ||
671 | GNUNET_assert (GNUNET_OK == | ||
672 | GNUNET_CONTAINER_multishortmap_put (cp->connections, | ||
673 | &GCC_get_id (cc)->connection_of_tunnel, | ||
674 | cc, | ||
675 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
676 | } | ||
677 | |||
678 | |||
679 | /** | ||
680 | * Remove a @a connection that went via this @a cp. | ||
681 | * | ||
682 | * @param cp peer via which the @a connection went | ||
683 | * @param cc the connection to remove | ||
684 | */ | ||
685 | void | ||
686 | GCP_remove_connection (struct CadetPeer *cp, | ||
687 | struct CadetConnection *cc) | ||
688 | { | ||
689 | GNUNET_assert (GNUNET_YES == | ||
690 | GNUNET_CONTAINER_multishortmap_remove (cp->connections, | ||
691 | &GCC_get_id (cc)->connection_of_tunnel, | ||
692 | cc)); | ||
693 | } | ||
694 | |||
695 | |||
696 | /** | ||
697 | * This peer is now on more "active" duty, activate processes related to it. | ||
698 | * | ||
699 | * @param cp the more-active peer | ||
700 | */ | ||
701 | static void | ||
702 | consider_peer_activate (struct CadetPeer *cp) | ||
703 | { | ||
704 | uint32_t strength; | ||
705 | |||
706 | if (NULL != cp->destroy_task) | ||
707 | { | ||
708 | /* It's active, do not destory! */ | ||
709 | GNUNET_SCHEDULER_cancel (cp->destroy_task); | ||
710 | cp->destroy_task = NULL; | ||
711 | } | ||
712 | if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) && | ||
713 | (NULL == cp->t) ) | ||
714 | { | ||
715 | /* We're just on a path or directly connected; don't bother too much */ | ||
716 | if (NULL != cp->connectivity_suggestion) | ||
717 | { | ||
718 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
719 | cp->connectivity_suggestion = NULL; | ||
720 | } | ||
721 | if (NULL != cp->search_h) | ||
722 | { | ||
723 | GCD_search_stop (cp->search_h); | ||
724 | cp->search_h = NULL; | ||
725 | } | ||
726 | return; | ||
727 | } | ||
728 | if (NULL == cp->core_mq) | ||
729 | { | ||
730 | /* Lacks direct connection, try to create one by querying the DHT */ | ||
731 | if ( (NULL == cp->search_h) && | ||
732 | (DESIRED_CONNECTIONS_PER_TUNNEL < cp->num_paths) ) | ||
733 | cp->search_h | ||
734 | = GCD_search (&cp->pid); | ||
735 | } | ||
736 | else | ||
737 | { | ||
738 | /* Have direct connection, stop DHT search if active */ | ||
739 | if (NULL != cp->search_h) | ||
740 | { | ||
741 | GCD_search_stop (cp->search_h); | ||
742 | cp->search_h = NULL; | ||
743 | } | ||
744 | } | ||
745 | |||
746 | /* If we have a tunnel, our urge for connections is much bigger */ | ||
747 | strength = (NULL != cp->t) ? 32 : 1; | ||
748 | if (NULL != cp->connectivity_suggestion) | ||
749 | GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion); | ||
750 | cp->connectivity_suggestion | ||
751 | = GNUNET_ATS_connectivity_suggest (ats_ch, | ||
752 | &cp->pid, | ||
753 | strength); | ||
754 | } | ||
755 | |||
756 | |||
757 | /** | ||
758 | * Retrieve the CadetPeer stucture associated with the | ||
759 | * peer. Optionally create one and insert it in the appropriate | ||
760 | * structures if the peer is not known yet. | ||
761 | * | ||
762 | * @param peer_id Full identity of the peer. | ||
763 | * @param create #GNUNET_YES if a new peer should be created if unknown. | ||
764 | * #GNUNET_NO to return NULL if peer is unknown. | ||
765 | * @return Existing or newly created peer structure. | ||
766 | * NULL if unknown and not requested @a create | ||
767 | */ | ||
768 | struct CadetPeer * | ||
769 | GCP_get (const struct GNUNET_PeerIdentity *peer_id, | ||
770 | int create) | ||
771 | { | ||
772 | struct CadetPeer *cp; | ||
773 | |||
774 | cp = GNUNET_CONTAINER_multipeermap_get (peers, | ||
775 | peer_id); | ||
776 | if (NULL != cp) | ||
777 | return cp; | ||
778 | if (GNUNET_NO == create) | ||
779 | return NULL; | ||
780 | cp = GNUNET_new (struct CadetPeer); | ||
781 | cp->pid = *peer_id; | ||
782 | cp->connections = GNUNET_CONTAINER_multishortmap_create (32, | ||
783 | GNUNET_YES); | ||
784 | cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
785 | GNUNET_assert (GNUNET_YES == | ||
786 | GNUNET_CONTAINER_multipeermap_put (peers, | ||
787 | &cp->pid, | ||
788 | cp, | ||
789 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
790 | return cp; | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Obtain the peer identity for a `struct CadetPeer`. | ||
796 | * | ||
797 | * @param cp our peer handle | ||
798 | * @return the peer identity | ||
799 | */ | ||
800 | const struct GNUNET_PeerIdentity * | ||
801 | GCP_get_id (struct CadetPeer *cp) | ||
802 | { | ||
803 | return &cp->pid; | ||
804 | } | ||
805 | |||
806 | |||
807 | /** | ||
808 | * Iterate over all known peers. | ||
809 | * | ||
810 | * @param iter Iterator. | ||
811 | * @param cls Closure for @c iter. | ||
812 | */ | ||
813 | void | ||
814 | GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, | ||
815 | void *cls) | ||
816 | { | ||
817 | GNUNET_CONTAINER_multipeermap_iterate (peers, | ||
818 | iter, | ||
819 | cls); | ||
820 | } | ||
821 | |||
822 | |||
823 | /** | ||
824 | * Count the number of known paths toward the peer. | ||
825 | * | ||
826 | * @param peer Peer to get path info. | ||
827 | * @return Number of known paths. | ||
828 | */ | ||
829 | unsigned int | ||
830 | GCP_count_paths (const struct CadetPeer *peer) | ||
831 | { | ||
832 | return peer->num_paths; | ||
833 | } | ||
834 | |||
835 | |||
836 | /** | ||
837 | * Iterate over the paths to a peer. | ||
838 | * | ||
839 | * @param peer Peer to get path info. | ||
840 | * @param callback Function to call for every path. | ||
841 | * @param callback_cls Closure for @a callback. | ||
842 | * @return Number of iterated paths. | ||
843 | */ | ||
844 | unsigned int | ||
845 | GCP_iterate_paths (struct CadetPeer *peer, | ||
846 | GCP_PathIterator callback, | ||
847 | void *callback_cls) | ||
848 | { | ||
849 | unsigned int ret = 0; | ||
850 | |||
851 | for (unsigned int i=0;i<peer->path_dll_length;i++) | ||
852 | { | ||
853 | for (struct CadetPeerPathEntry *pe = peer->path_heads[i]; | ||
854 | NULL != pe; | ||
855 | pe = pe->next) | ||
856 | { | ||
857 | if (GNUNET_NO == | ||
858 | callback (callback_cls, | ||
859 | pe->path, | ||
860 | i)) | ||
861 | return ret; | ||
862 | ret++; | ||
863 | } | ||
864 | } | ||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | |||
869 | /** | ||
870 | * Iterate over the paths to @a peer where | ||
871 | * @a peer is at distance @a dist from us. | ||
872 | * | ||
873 | * @param peer Peer to get path info. | ||
874 | * @param dist desired distance of @a peer to us on the path | ||
875 | * @param callback Function to call for every path. | ||
876 | * @param callback_cls Closure for @a callback. | ||
877 | * @return Number of iterated paths. | ||
878 | */ | ||
879 | unsigned int | ||
880 | GCP_iterate_paths_at (struct CadetPeer *peer, | ||
881 | unsigned int dist, | ||
882 | GCP_PathIterator callback, | ||
883 | void *callback_cls) | ||
884 | { | ||
885 | unsigned int ret = 0; | ||
886 | |||
887 | if (dist<peer->path_dll_length) | ||
888 | return 0; | ||
889 | for (struct CadetPeerPathEntry *pe = peer->path_heads[dist]; | ||
890 | NULL != pe; | ||
891 | pe = pe->next) | ||
892 | { | ||
893 | if (GNUNET_NO == | ||
894 | callback (callback_cls, | ||
895 | pe->path, | ||
896 | dist)) | ||
897 | return ret; | ||
898 | ret++; | ||
899 | } | ||
900 | return ret; | ||
901 | } | ||
902 | |||
903 | |||
904 | /** | ||
905 | * Get the tunnel towards a peer. | ||
906 | * | ||
907 | * @param peer Peer to get from. | ||
908 | * @param create #GNUNET_YES to create a tunnel if we do not have one | ||
909 | * @return Tunnel towards peer. | ||
910 | */ | ||
911 | struct CadetTunnel * | ||
912 | GCP_get_tunnel (struct CadetPeer *peer, | ||
913 | int create) | ||
914 | { | ||
915 | if (NULL == peer) | ||
916 | return NULL; | ||
917 | if ( (NULL != peer->t) || | ||
918 | (GNUNET_NO == create) ) | ||
919 | return peer->t; | ||
920 | peer->t = GCT_create_tunnel (peer); | ||
921 | consider_peer_activate (peer); | ||
922 | return peer->t; | ||
923 | } | ||
924 | |||
925 | |||
926 | /** | ||
927 | * We got a HELLO for a @a peer, remember it, and possibly | ||
928 | * trigger adequate actions (like trying to connect). | ||
929 | * | ||
930 | * @param peer the peer we got a HELLO for | ||
931 | * @param hello the HELLO to remember | ||
932 | */ | ||
933 | void | ||
934 | GCP_set_hello (struct CadetPeer *peer, | ||
935 | const struct GNUNET_HELLO_Message *hello) | ||
936 | { | ||
937 | /* FIXME: keep HELLO, possibly offer to TRANSPORT... */ | ||
938 | |||
939 | consider_peer_destroy (peer); | ||
940 | } | ||
941 | |||
942 | |||
943 | /** | ||
944 | * The tunnel to the given peer no longer exists, remove it from our | ||
945 | * data structures, and possibly clean up the peer itself. | ||
946 | * | ||
947 | * @param peer the peer affected | ||
948 | * @param t the dead tunnel | ||
949 | */ | ||
950 | void | ||
951 | GCP_drop_tunnel (struct CadetPeer *peer, | ||
952 | struct CadetTunnel *t) | ||
953 | { | ||
954 | GNUNET_assert (peer->t == t); | ||
955 | peer->t = NULL; | ||
956 | consider_peer_destroy (peer); | ||
957 | } | ||
958 | |||
959 | |||
960 | /** | ||
961 | * Test if @a cp has a core-level connection | ||
962 | * | ||
963 | * @param cp peer to test | ||
964 | * @return #GNUNET_YES if @a cp has a core-level connection | ||
965 | */ | ||
966 | int | ||
967 | GCP_has_core_connection (struct CadetPeer *cp) | ||
968 | { | ||
969 | return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO; | ||
970 | } | ||
971 | |||
972 | |||
973 | /** | ||
974 | * Start message queue change notifications. | ||
975 | * | ||
976 | * @param cp peer to notify for | ||
977 | * @param cb function to call if mq becomes available or unavailable | ||
978 | * @param cb_cls closure for @a cb | ||
979 | * @return handle to cancel request | ||
980 | */ | ||
981 | struct GCP_MessageQueueManager * | ||
982 | GCP_request_mq (struct CadetPeer *cp, | ||
983 | GCP_MessageQueueNotificationCallback cb, | ||
984 | void *cb_cls) | ||
985 | { | ||
986 | struct GCP_MessageQueueManager *mqm; | ||
987 | |||
988 | mqm = GNUNET_new (struct GCP_MessageQueueManager); | ||
989 | mqm->cb = cb; | ||
990 | mqm->cb_cls = cb_cls; | ||
991 | mqm->cp = cp; | ||
992 | GNUNET_CONTAINER_DLL_insert (cp->mqm_head, | ||
993 | cp->mqm_tail, | ||
994 | mqm); | ||
995 | if (NULL != cp->core_mq) | ||
996 | cb (cb_cls, | ||
997 | GNUNET_YES); | ||
998 | return mqm; | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | /** | ||
1003 | * Stops message queue change notifications. | ||
1004 | * | ||
1005 | * @param mqm handle matching request to cancel | ||
1006 | * @param last_env final message to transmit, or NULL | ||
1007 | */ | ||
1008 | void | ||
1009 | GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm, | ||
1010 | struct GNUNET_MQ_Envelope *last_env) | ||
1011 | { | ||
1012 | struct CadetPeer *cp = mqm->cp; | ||
1013 | |||
1014 | if (NULL != mqm->env) | ||
1015 | GNUNET_MQ_discard (mqm->env); | ||
1016 | if (NULL != last_env) | ||
1017 | { | ||
1018 | if (NULL != cp->core_mq) | ||
1019 | GNUNET_MQ_send (cp->core_mq, | ||
1020 | last_env); | ||
1021 | else | ||
1022 | GNUNET_MQ_discard (last_env); | ||
1023 | } | ||
1024 | GNUNET_CONTAINER_DLL_remove (cp->mqm_head, | ||
1025 | cp->mqm_tail, | ||
1026 | mqm); | ||
1027 | GNUNET_free (mqm); | ||
1028 | } | ||
1029 | |||
1030 | |||
1031 | /** | ||
1032 | * Send the message in @a env to @a cp, overriding queueing logic. | ||
1033 | * This function should only be used to send error messages outside | ||
1034 | * of flow and congestion control, similar to ICMP. Note that | ||
1035 | * the envelope may be silently discarded as well. | ||
1036 | * | ||
1037 | * @param cp peer to send the message to | ||
1038 | * @param env envelope with the message to send | ||
1039 | */ | ||
1040 | void | ||
1041 | GCP_send_ooo (struct CadetPeer *cp, | ||
1042 | struct GNUNET_MQ_Envelope *env) | ||
1043 | { | ||
1044 | if (NULL == cp->core_mq) | ||
1045 | { | ||
1046 | GNUNET_MQ_discard (env); | ||
1047 | return; | ||
1048 | } | ||
1049 | GNUNET_MQ_send (cp->core_mq, | ||
1050 | env); | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | |||
1055 | |||
1056 | /* end of gnunet-service-cadet-new_peer.c */ | ||