diff options
Diffstat (limited to 'src/service/cadet/gnunet-service-cadet_core.c')
-rw-r--r-- | src/service/cadet/gnunet-service-cadet_core.c | 1337 |
1 files changed, 1337 insertions, 0 deletions
diff --git a/src/service/cadet/gnunet-service-cadet_core.c b/src/service/cadet/gnunet-service-cadet_core.c new file mode 100644 index 000000000..68f7405c3 --- /dev/null +++ b/src/service/cadet/gnunet-service-cadet_core.c | |||
@@ -0,0 +1,1337 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2017 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 cadet/gnunet-service-cadet_core.c | ||
23 | * @brief cadet service; interaction with CORE service | ||
24 | * @author Bartlomiej Polot | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom)) | ||
28 | * | ||
29 | * TODO: | ||
30 | * - Optimization: given BROKEN messages, destroy paths (?) | ||
31 | */ | ||
32 | #include "platform.h" | ||
33 | #include "gnunet-service-cadet_core.h" | ||
34 | #include "gnunet-service-cadet_paths.h" | ||
35 | #include "gnunet-service-cadet_peer.h" | ||
36 | #include "gnunet-service-cadet_connection.h" | ||
37 | #include "gnunet-service-cadet_tunnels.h" | ||
38 | #include "gnunet_core_service.h" | ||
39 | #include "gnunet_statistics_service.h" | ||
40 | #include "cadet_protocol.h" | ||
41 | |||
42 | #define LOG(level, ...) GNUNET_log_from (level, "cadet-cor", __VA_ARGS__) | ||
43 | |||
44 | /** | ||
45 | * Information we keep per direction for a route. | ||
46 | */ | ||
47 | struct RouteDirection; | ||
48 | |||
49 | /** | ||
50 | * Set of CadetRoutes that have exactly the same number of messages | ||
51 | * in their buffer. Used so we can efficiently find all of those | ||
52 | * routes that have the current maximum of messages in the buffer (in | ||
53 | * case we have to purge). | ||
54 | */ | ||
55 | struct Rung | ||
56 | { | ||
57 | /** | ||
58 | * Rung of RouteDirections with one more buffer entry each. | ||
59 | */ | ||
60 | struct Rung *next; | ||
61 | |||
62 | /** | ||
63 | * Rung of RouteDirections with one less buffer entry each. | ||
64 | */ | ||
65 | struct Rung *prev; | ||
66 | |||
67 | /** | ||
68 | * DLL of route directions with a number of buffer entries matching this rung. | ||
69 | */ | ||
70 | struct RouteDirection *rd_head; | ||
71 | |||
72 | /** | ||
73 | * DLL of route directions with a number of buffer entries matching this rung. | ||
74 | */ | ||
75 | struct RouteDirection *rd_tail; | ||
76 | |||
77 | /** | ||
78 | * Total number of route directions in this rung. | ||
79 | */ | ||
80 | unsigned int num_routes; | ||
81 | |||
82 | /** | ||
83 | * Number of messages route directions at this rung have | ||
84 | * in their buffer. | ||
85 | */ | ||
86 | unsigned int rung_off; | ||
87 | }; | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Information we keep per direction for a route. | ||
92 | */ | ||
93 | struct RouteDirection | ||
94 | { | ||
95 | /** | ||
96 | * DLL of other route directions within the same `struct Rung`. | ||
97 | */ | ||
98 | struct RouteDirection *prev; | ||
99 | |||
100 | /** | ||
101 | * DLL of other route directions within the same `struct Rung`. | ||
102 | */ | ||
103 | struct RouteDirection *next; | ||
104 | |||
105 | /** | ||
106 | * Rung of this route direction (matches length of the buffer DLL). | ||
107 | */ | ||
108 | struct Rung *rung; | ||
109 | |||
110 | /** | ||
111 | * Head of DLL of envelopes we have in the buffer for this direction. | ||
112 | */ | ||
113 | struct GNUNET_MQ_Envelope *env_head; | ||
114 | |||
115 | /** | ||
116 | * Tail of DLL of envelopes we have in the buffer for this direction. | ||
117 | */ | ||
118 | struct GNUNET_MQ_Envelope *env_tail; | ||
119 | |||
120 | /** | ||
121 | * Target peer. | ||
122 | */ | ||
123 | struct CadetPeer *hop; | ||
124 | |||
125 | /** | ||
126 | * Route this direction is part of. | ||
127 | */ | ||
128 | struct CadetRoute *my_route; | ||
129 | |||
130 | /** | ||
131 | * Message queue manager for @e hop. | ||
132 | */ | ||
133 | struct GCP_MessageQueueManager *mqm; | ||
134 | |||
135 | /** | ||
136 | * Is @e mqm currently ready for transmission? | ||
137 | */ | ||
138 | int is_ready; | ||
139 | }; | ||
140 | |||
141 | |||
142 | struct CadetRoute | ||
143 | { | ||
144 | /** | ||
145 | * Information about the next hop on this route. | ||
146 | */ | ||
147 | struct RouteDirection next; | ||
148 | |||
149 | /** | ||
150 | * Information about the previous hop on this route. | ||
151 | */ | ||
152 | struct RouteDirection prev; | ||
153 | |||
154 | /** | ||
155 | * Unique identifier for the connection that uses this route. | ||
156 | */ | ||
157 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
158 | |||
159 | /** | ||
160 | * When was this route last in use? | ||
161 | */ | ||
162 | struct GNUNET_TIME_Absolute last_use; | ||
163 | |||
164 | /** | ||
165 | * Position of this route in the #route_heap. | ||
166 | */ | ||
167 | struct GNUNET_CONTAINER_HeapNode *hn; | ||
168 | }; | ||
169 | |||
170 | |||
171 | /** | ||
172 | * Handle to the CORE service. | ||
173 | */ | ||
174 | static struct GNUNET_CORE_Handle *core; | ||
175 | |||
176 | /** | ||
177 | * Routes on which this peer is an intermediate. | ||
178 | */ | ||
179 | static struct GNUNET_CONTAINER_MultiShortmap *routes; | ||
180 | |||
181 | /** | ||
182 | * Heap of routes, MIN-sorted by last activity. | ||
183 | */ | ||
184 | static struct GNUNET_CONTAINER_Heap *route_heap; | ||
185 | |||
186 | /** | ||
187 | * Rung zero (always pointed to by #rung_head). | ||
188 | */ | ||
189 | static struct Rung rung_zero; | ||
190 | |||
191 | /** | ||
192 | * DLL of rungs, with the head always point to a rung of | ||
193 | * route directions with no messages in the queue. | ||
194 | */ | ||
195 | static struct Rung *rung_head = &rung_zero; | ||
196 | |||
197 | /** | ||
198 | * Tail of the #rung_head DLL. | ||
199 | */ | ||
200 | static struct Rung *rung_tail = &rung_zero; | ||
201 | |||
202 | /** | ||
203 | * Maximum number of concurrent routes this peer will support. | ||
204 | */ | ||
205 | static unsigned long long max_routes; | ||
206 | |||
207 | /** | ||
208 | * Maximum number of envelopes we will buffer at this peer. | ||
209 | */ | ||
210 | static unsigned long long max_buffers; | ||
211 | |||
212 | /** | ||
213 | * Current number of envelopes we have buffered at this peer. | ||
214 | */ | ||
215 | static unsigned long long cur_buffers; | ||
216 | |||
217 | /** | ||
218 | * Task to timeout routes. | ||
219 | */ | ||
220 | static struct GNUNET_SCHEDULER_Task *timeout_task; | ||
221 | |||
222 | /** | ||
223 | * Get the route corresponding to a hash. | ||
224 | * | ||
225 | * @param cid hash generated from the connection identifier | ||
226 | */ | ||
227 | static struct CadetRoute * | ||
228 | get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
229 | { | ||
230 | return GNUNET_CONTAINER_multishortmap_get (routes, | ||
231 | &cid->connection_of_tunnel); | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Lower the rung in which @a dir is by 1. | ||
237 | * | ||
238 | * @param dir direction to lower in rung. | ||
239 | */ | ||
240 | static void | ||
241 | lower_rung (struct RouteDirection *dir) | ||
242 | { | ||
243 | struct Rung *rung = dir->rung; | ||
244 | struct Rung *prev; | ||
245 | |||
246 | GNUNET_CONTAINER_DLL_remove (rung->rd_head, rung->rd_tail, dir); | ||
247 | prev = rung->prev; | ||
248 | GNUNET_assert (NULL != prev); | ||
249 | if (prev->rung_off != rung->rung_off - 1) | ||
250 | { | ||
251 | prev = GNUNET_new (struct Rung); | ||
252 | prev->rung_off = rung->rung_off - 1; | ||
253 | GNUNET_CONTAINER_DLL_insert_after (rung_head, rung_tail, rung->prev, prev); | ||
254 | } | ||
255 | GNUNET_assert (NULL != prev); | ||
256 | GNUNET_CONTAINER_DLL_insert (prev->rd_head, prev->rd_tail, dir); | ||
257 | dir->rung = prev; | ||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Discard the buffer @a env from the route direction @a dir and | ||
263 | * move @a dir down a rung. | ||
264 | * | ||
265 | * @param dir direction that contains the @a env in the buffer | ||
266 | * @param env envelope to discard | ||
267 | */ | ||
268 | static void | ||
269 | discard_buffer (struct RouteDirection *dir, struct GNUNET_MQ_Envelope *env) | ||
270 | { | ||
271 | GNUNET_MQ_dll_remove (&dir->env_head, &dir->env_tail, env); | ||
272 | cur_buffers--; | ||
273 | GNUNET_MQ_discard (env); | ||
274 | lower_rung (dir); | ||
275 | GNUNET_STATISTICS_set (stats, "# buffer use", cur_buffers, GNUNET_NO); | ||
276 | } | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Discard all messages from the highest rung, to make space. | ||
281 | */ | ||
282 | static void | ||
283 | discard_all_from_rung_tail () | ||
284 | { | ||
285 | struct Rung *tail = rung_tail; | ||
286 | struct RouteDirection *dir; | ||
287 | |||
288 | while (NULL != (dir = tail->rd_head)) | ||
289 | { | ||
290 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
291 | "Queue full due new message on connection %s, dropping old message\n", | ||
292 | GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel)); | ||
293 | GNUNET_STATISTICS_update (stats, | ||
294 | "# messages dropped due to full buffer", | ||
295 | 1, | ||
296 | GNUNET_NO); | ||
297 | discard_buffer (dir, dir->env_head); | ||
298 | } | ||
299 | GNUNET_CONTAINER_DLL_remove (rung_head, rung_tail, tail); | ||
300 | GNUNET_free (tail); | ||
301 | } | ||
302 | |||
303 | |||
304 | /** | ||
305 | * We message @a msg from @a prev. Find its route by @a cid and | ||
306 | * forward to the next hop. Drop and signal broken route if we do not | ||
307 | * have a route. | ||
308 | * | ||
309 | * @param prev previous hop (sender) | ||
310 | * @param cid connection identifier, tells us which route to use | ||
311 | * @param msg the message to forward | ||
312 | */ | ||
313 | static void | ||
314 | route_message (struct CadetPeer *prev, | ||
315 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
316 | const struct GNUNET_MessageHeader *msg, | ||
317 | const enum GNUNET_MQ_PriorityPreferences priority) | ||
318 | { | ||
319 | struct CadetRoute *route; | ||
320 | struct RouteDirection *dir; | ||
321 | struct Rung *rung; | ||
322 | struct Rung *nxt; | ||
323 | struct GNUNET_MQ_Envelope *env; | ||
324 | |||
325 | route = get_route (cid); | ||
326 | if (NULL == route) | ||
327 | { | ||
328 | struct GNUNET_MQ_Envelope *env; | ||
329 | struct GNUNET_CADET_ConnectionBrokenMessage *bm; | ||
330 | |||
331 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "Failed to route message of type %u from %s on connection %s: no route\n", | ||
333 | ntohs (msg->type), | ||
334 | GCP_2s (prev), | ||
335 | GNUNET_sh2s (&cid->connection_of_tunnel)); | ||
336 | switch (ntohs (msg->type)) | ||
337 | { | ||
338 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: | ||
339 | case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: | ||
340 | /* No need to respond to these! */ | ||
341 | return; | ||
342 | } | ||
343 | env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); | ||
344 | bm->cid = *cid; | ||
345 | bm->peer1 = my_full_id; | ||
346 | GCP_send_ooo (prev, env); | ||
347 | return; | ||
348 | } | ||
349 | route->last_use = GNUNET_TIME_absolute_get (); | ||
350 | GNUNET_CONTAINER_heap_update_cost (route->hn, route->last_use.abs_value_us); | ||
351 | dir = (prev == route->prev.hop) ? &route->next : &route->prev; | ||
352 | if (GNUNET_YES == dir->is_ready) | ||
353 | { | ||
354 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
355 | "Routing message of type %u from %s to %s on connection %s\n", | ||
356 | ntohs (msg->type), | ||
357 | GCP_2s (prev), | ||
358 | GNUNET_i2s (GCP_get_id (dir->hop)), | ||
359 | GNUNET_sh2s (&cid->connection_of_tunnel)); | ||
360 | dir->is_ready = GNUNET_NO; | ||
361 | GCP_send (dir->mqm, GNUNET_MQ_msg_copy (msg)); | ||
362 | return; | ||
363 | } | ||
364 | /* Check if low latency is required and if the previous message was | ||
365 | unreliable; if so, make sure we only queue one message per | ||
366 | direction (no buffering). */ | ||
367 | if ((0 != (priority & GNUNET_MQ_PREF_LOW_LATENCY)) && | ||
368 | (NULL != dir->env_head) && | ||
369 | (0 == | ||
370 | (GNUNET_MQ_env_get_options (dir->env_head) & GNUNET_MQ_PREF_UNRELIABLE))) | ||
371 | discard_buffer (dir, dir->env_head); | ||
372 | /* Check for duplicates */ | ||
373 | for (const struct GNUNET_MQ_Envelope *env = dir->env_head; NULL != env; | ||
374 | env = GNUNET_MQ_env_next (env)) | ||
375 | { | ||
376 | const struct GNUNET_MessageHeader *hdr = GNUNET_MQ_env_get_msg (env); | ||
377 | |||
378 | if ((hdr->size == msg->size) && (0 == memcmp (hdr, msg, ntohs (msg->size)))) | ||
379 | { | ||
380 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
381 | "Received duplicate of message already in buffer, dropping\n"); | ||
382 | GNUNET_STATISTICS_update (stats, | ||
383 | "# messages dropped due to duplicate in buffer", | ||
384 | 1, | ||
385 | GNUNET_NO); | ||
386 | return; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | rung = dir->rung; | ||
391 | if (cur_buffers == max_buffers) | ||
392 | { | ||
393 | /* Need to make room. */ | ||
394 | if (NULL != rung->next) | ||
395 | { | ||
396 | /* Easy case, drop messages from route directions in highest rung */ | ||
397 | discard_all_from_rung_tail (); | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | /* We are in the highest rung, drop our own! */ | ||
402 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
403 | "Queue full due new message on connection %s, dropping old message\n", | ||
404 | GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel)); | ||
405 | GNUNET_STATISTICS_update (stats, | ||
406 | "# messages dropped due to full buffer", | ||
407 | 1, | ||
408 | GNUNET_NO); | ||
409 | discard_buffer (dir, dir->env_head); | ||
410 | rung = dir->rung; | ||
411 | } | ||
412 | } | ||
413 | /* remove 'dir' from current rung */ | ||
414 | GNUNET_CONTAINER_DLL_remove (rung->rd_head, rung->rd_tail, dir); | ||
415 | /* make 'nxt' point to the next higher rung, create if necessary */ | ||
416 | nxt = rung->next; | ||
417 | if ((NULL == nxt) || (rung->rung_off + 1 != nxt->rung_off)) | ||
418 | { | ||
419 | nxt = GNUNET_new (struct Rung); | ||
420 | nxt->rung_off = rung->rung_off + 1; | ||
421 | GNUNET_CONTAINER_DLL_insert_after (rung_head, rung_tail, rung, nxt); | ||
422 | } | ||
423 | /* insert 'dir' into next higher rung */ | ||
424 | GNUNET_CONTAINER_DLL_insert (nxt->rd_head, nxt->rd_tail, dir); | ||
425 | dir->rung = nxt; | ||
426 | |||
427 | /* add message into 'dir' buffer */ | ||
428 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
429 | "Queueing new message of type %u from %s to %s on connection %s\n", | ||
430 | ntohs (msg->type), | ||
431 | GCP_2s (prev), | ||
432 | GNUNET_i2s (GCP_get_id (dir->hop)), | ||
433 | GNUNET_sh2s (&cid->connection_of_tunnel)); | ||
434 | env = GNUNET_MQ_msg_copy (msg); | ||
435 | GNUNET_MQ_env_set_options (env, priority); | ||
436 | if ((0 != (priority & GNUNET_MQ_PREF_LOW_LATENCY)) && | ||
437 | (0 != (priority & GNUNET_MQ_PREF_OUT_OF_ORDER)) && | ||
438 | (NULL != dir->env_head) && | ||
439 | (0 == (GNUNET_MQ_env_get_options (dir->env_head) | ||
440 | & GNUNET_MQ_PREF_LOW_LATENCY))) | ||
441 | GNUNET_MQ_dll_insert_head (&dir->env_head, &dir->env_tail, env); | ||
442 | else | ||
443 | GNUNET_MQ_dll_insert_tail (&dir->env_head, &dir->env_tail, env); | ||
444 | cur_buffers++; | ||
445 | GNUNET_STATISTICS_set (stats, "# buffer use", cur_buffers, GNUNET_NO); | ||
446 | /* Clean up 'rung' if now empty (and not head) */ | ||
447 | if ((NULL == rung->rd_head) && (rung != rung_head)) | ||
448 | { | ||
449 | GNUNET_CONTAINER_DLL_remove (rung_head, rung_tail, rung); | ||
450 | GNUNET_free (rung); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | |||
455 | /** | ||
456 | * Check if the create_connection message has the appropriate size. | ||
457 | * | ||
458 | * @param cls Closure (unused). | ||
459 | * @param msg Message to check. | ||
460 | * | ||
461 | * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise. | ||
462 | */ | ||
463 | static int | ||
464 | check_connection_create (void *cls, | ||
465 | const struct GNUNET_CADET_ConnectionCreateMessage *msg) | ||
466 | { | ||
467 | uint16_t size = ntohs (msg->header.size) - sizeof(*msg); | ||
468 | |||
469 | if (0 != (size % sizeof(struct GNUNET_PeerIdentity))) | ||
470 | { | ||
471 | GNUNET_break_op (0); | ||
472 | return GNUNET_NO; | ||
473 | } | ||
474 | return GNUNET_YES; | ||
475 | } | ||
476 | |||
477 | |||
478 | /** | ||
479 | * Free internal data of a route direction. | ||
480 | * | ||
481 | * @param dir direction to destroy (do NOT free memory of 'dir' itself) | ||
482 | */ | ||
483 | static void | ||
484 | destroy_direction (struct RouteDirection *dir) | ||
485 | { | ||
486 | struct GNUNET_MQ_Envelope *env; | ||
487 | |||
488 | while (NULL != (env = dir->env_head)) | ||
489 | { | ||
490 | GNUNET_STATISTICS_update (stats, | ||
491 | "# messages dropped due to route destruction", | ||
492 | 1, | ||
493 | GNUNET_NO); | ||
494 | discard_buffer (dir, env); | ||
495 | } | ||
496 | if (NULL != dir->mqm) | ||
497 | { | ||
498 | GCP_request_mq_cancel (dir->mqm, NULL); | ||
499 | dir->mqm = NULL; | ||
500 | } | ||
501 | GNUNET_CONTAINER_DLL_remove (rung_head->rd_head, rung_head->rd_tail, dir); | ||
502 | } | ||
503 | |||
504 | |||
505 | /** | ||
506 | * Destroy our state for @a route. | ||
507 | * | ||
508 | * @param route route to destroy | ||
509 | */ | ||
510 | static void | ||
511 | destroy_route (struct CadetRoute *route) | ||
512 | { | ||
513 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
514 | "Destroying route from %s to %s of connection %s\n", | ||
515 | GNUNET_i2s (GCP_get_id (route->prev.hop)), | ||
516 | GNUNET_i2s2 (GCP_get_id (route->next.hop)), | ||
517 | GNUNET_sh2s (&route->cid.connection_of_tunnel)); | ||
518 | GNUNET_assert (route == GNUNET_CONTAINER_heap_remove_node (route->hn)); | ||
519 | GNUNET_assert ( | ||
520 | GNUNET_YES == | ||
521 | GNUNET_CONTAINER_multishortmap_remove (routes, | ||
522 | &route->cid.connection_of_tunnel, | ||
523 | route)); | ||
524 | GNUNET_STATISTICS_set (stats, | ||
525 | "# routes", | ||
526 | GNUNET_CONTAINER_multishortmap_size (routes), | ||
527 | GNUNET_NO); | ||
528 | destroy_direction (&route->prev); | ||
529 | destroy_direction (&route->next); | ||
530 | GNUNET_free (route); | ||
531 | } | ||
532 | |||
533 | |||
534 | /** | ||
535 | * Send message that a route is broken between @a peer1 and @a peer2. | ||
536 | * | ||
537 | * @param target where to send the message | ||
538 | * @param cid connection identifier to use | ||
539 | * @param peer1 one of the peers where a link is broken | ||
540 | * @param peer2 another one of the peers where a link is broken | ||
541 | */ | ||
542 | static void | ||
543 | send_broken (struct RouteDirection *target, | ||
544 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
545 | const struct GNUNET_PeerIdentity *peer1, | ||
546 | const struct GNUNET_PeerIdentity *peer2) | ||
547 | { | ||
548 | struct GNUNET_MQ_Envelope *env; | ||
549 | struct GNUNET_CADET_ConnectionBrokenMessage *bm; | ||
550 | |||
551 | if (NULL == target->mqm) | ||
552 | return; /* Can't send notification, connection is down! */ | ||
553 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
554 | "Notifying %s about BROKEN route at %s-%s of connection %s\n", | ||
555 | GCP_2s (target->hop), | ||
556 | GNUNET_i2s (peer1), | ||
557 | GNUNET_i2s2 (peer2), | ||
558 | GNUNET_sh2s (&cid->connection_of_tunnel)); | ||
559 | |||
560 | env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); | ||
561 | bm->cid = *cid; | ||
562 | if (NULL != peer1) | ||
563 | bm->peer1 = *peer1; | ||
564 | if (NULL != peer2) | ||
565 | bm->peer2 = *peer2; | ||
566 | GCP_request_mq_cancel (target->mqm, env); | ||
567 | target->mqm = NULL; | ||
568 | } | ||
569 | |||
570 | |||
571 | /** | ||
572 | * Function called to check if any routes have timed out, and if | ||
573 | * so, to clean them up. Finally, schedules itself again at the | ||
574 | * earliest time where there might be more work. | ||
575 | * | ||
576 | * @param cls NULL | ||
577 | */ | ||
578 | static void | ||
579 | timeout_cb (void *cls) | ||
580 | { | ||
581 | struct CadetRoute *r; | ||
582 | struct GNUNET_TIME_Relative linger; | ||
583 | struct GNUNET_TIME_Absolute exp; | ||
584 | |||
585 | timeout_task = NULL; | ||
586 | linger = GNUNET_TIME_relative_multiply (keepalive_period, 3); | ||
587 | while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap))) | ||
588 | { | ||
589 | exp = GNUNET_TIME_absolute_add (r->last_use, linger); | ||
590 | if (0 != GNUNET_TIME_absolute_get_remaining (exp).rel_value_us) | ||
591 | { | ||
592 | /* Route not yet timed out, wait until it does. */ | ||
593 | timeout_task = GNUNET_SCHEDULER_add_at (exp, &timeout_cb, NULL); | ||
594 | return; | ||
595 | } | ||
596 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
597 | "Sending BROKEN due to timeout (%s was last use, %s linger)\n", | ||
598 | GNUNET_STRINGS_absolute_time_to_string (r->last_use), | ||
599 | GNUNET_STRINGS_relative_time_to_string (linger, GNUNET_YES)); | ||
600 | send_broken (&r->prev, &r->cid, NULL, NULL); | ||
601 | send_broken (&r->next, &r->cid, NULL, NULL); | ||
602 | destroy_route (r); | ||
603 | } | ||
604 | /* No more routes left, so no need for a #timeout_task */ | ||
605 | } | ||
606 | |||
607 | |||
608 | /** | ||
609 | * Function called when the message queue to the previous hop | ||
610 | * becomes available/unavailable. We expect this function to | ||
611 | * be called immediately when we register, and then again | ||
612 | * later if the connection ever goes down. | ||
613 | * | ||
614 | * @param cls the `struct RouteDirection` | ||
615 | * @param ready #GNUNET_YES if sending is now possible, | ||
616 | * #GNUNET_NO if sending is no longer possible | ||
617 | * #GNUNET_SYSERR if sending is no longer possible | ||
618 | * and the last envelope was discarded | ||
619 | */ | ||
620 | static void | ||
621 | dir_ready_cb (void *cls, int ready) | ||
622 | { | ||
623 | struct RouteDirection *dir = cls; | ||
624 | struct CadetRoute *route = dir->my_route; | ||
625 | struct RouteDirection *odir; | ||
626 | |||
627 | if (GNUNET_YES == ready) | ||
628 | { | ||
629 | struct GNUNET_MQ_Envelope *env; | ||
630 | |||
631 | dir->is_ready = GNUNET_YES; | ||
632 | if (NULL != (env = dir->env_head)) | ||
633 | { | ||
634 | GNUNET_MQ_dll_remove (&dir->env_head, &dir->env_tail, env); | ||
635 | cur_buffers--; | ||
636 | GNUNET_STATISTICS_set (stats, "# buffer use", cur_buffers, GNUNET_NO); | ||
637 | lower_rung (dir); | ||
638 | dir->is_ready = GNUNET_NO; | ||
639 | GCP_send (dir->mqm, env); | ||
640 | } | ||
641 | return; | ||
642 | } | ||
643 | odir = (dir == &route->next) ? &route->prev : &route->next; | ||
644 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending BROKEN due to MQ going down\n"); | ||
645 | send_broken (&route->next, &route->cid, GCP_get_id (odir->hop), &my_full_id); | ||
646 | destroy_route (route); | ||
647 | } | ||
648 | |||
649 | |||
650 | /** | ||
651 | * Initialize one of the directions of a route. | ||
652 | * | ||
653 | * @param route route the direction belongs to | ||
654 | * @param dir direction to initialize | ||
655 | * @param hop next hop on in the @a dir | ||
656 | */ | ||
657 | static void | ||
658 | dir_init (struct RouteDirection *dir, | ||
659 | struct CadetRoute *route, | ||
660 | struct CadetPeer *hop) | ||
661 | { | ||
662 | dir->hop = hop; | ||
663 | dir->my_route = route; | ||
664 | dir->mqm = GCP_request_mq (hop, &dir_ready_cb, dir); | ||
665 | GNUNET_CONTAINER_DLL_insert (rung_head->rd_head, rung_head->rd_tail, dir); | ||
666 | dir->rung = rung_head; | ||
667 | GNUNET_assert (GNUNET_YES == dir->is_ready); | ||
668 | } | ||
669 | |||
670 | |||
671 | /** | ||
672 | * We could not create the desired route. Send a | ||
673 | * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN | ||
674 | * message to @a target. | ||
675 | * | ||
676 | * @param target who should receive the message | ||
677 | * @param cid identifier of the connection/route that failed | ||
678 | * @param failure_at neighbour with which we failed to route, | ||
679 | * or NULL. | ||
680 | */ | ||
681 | static void | ||
682 | send_broken_without_mqm ( | ||
683 | struct CadetPeer *target, | ||
684 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
685 | const struct GNUNET_PeerIdentity *failure_at) | ||
686 | { | ||
687 | struct GNUNET_MQ_Envelope *env; | ||
688 | struct GNUNET_CADET_ConnectionBrokenMessage *bm; | ||
689 | |||
690 | env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN); | ||
691 | bm->cid = *cid; | ||
692 | bm->peer1 = my_full_id; | ||
693 | if (NULL != failure_at) | ||
694 | bm->peer2 = *failure_at; | ||
695 | GCP_send_ooo (target, env); | ||
696 | } | ||
697 | |||
698 | |||
699 | /** | ||
700 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE | ||
701 | * | ||
702 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
703 | * @param msg Message itself. | ||
704 | */ | ||
705 | static void | ||
706 | handle_connection_create ( | ||
707 | void *cls, | ||
708 | const struct GNUNET_CADET_ConnectionCreateMessage *msg) | ||
709 | { | ||
710 | struct CadetPeer *sender = cls; | ||
711 | struct CadetPeer *next; | ||
712 | const struct GNUNET_PeerIdentity *pids = | ||
713 | (const struct GNUNET_PeerIdentity *) &msg[1]; | ||
714 | struct CadetRoute *route; | ||
715 | uint16_t size = ntohs (msg->header.size) - sizeof(*msg); | ||
716 | unsigned int path_length; | ||
717 | unsigned int off; | ||
718 | struct CadetTunnel *t; | ||
719 | |||
720 | path_length = size / sizeof(struct GNUNET_PeerIdentity); | ||
721 | if (0 == path_length) | ||
722 | { | ||
723 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
724 | "Dropping CADET_CONNECTION_CREATE with empty path\n"); | ||
725 | GNUNET_break_op (0); | ||
726 | return; | ||
727 | } | ||
728 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
729 | "Handling CADET_CONNECTION_CREATE from %s for CID %s with %u hops\n", | ||
730 | GCP_2s (sender), | ||
731 | GNUNET_sh2s (&msg->cid.connection_of_tunnel), | ||
732 | path_length); | ||
733 | /* Check for loops */ | ||
734 | { | ||
735 | struct GNUNET_CONTAINER_MultiPeerMap *map; | ||
736 | |||
737 | map = GNUNET_CONTAINER_multipeermap_create (path_length * 2, GNUNET_YES); | ||
738 | GNUNET_assert (NULL != map); | ||
739 | for (unsigned int i = 0; i < path_length; i++) | ||
740 | { | ||
741 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
742 | "CADET_CONNECTION_CREATE has peer %s at offset %u\n", | ||
743 | GNUNET_i2s (&pids[i]), | ||
744 | i); | ||
745 | if (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put ( | ||
746 | map, | ||
747 | &pids[i], | ||
748 | NULL, | ||
749 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
750 | { | ||
751 | /* bogus request */ | ||
752 | GNUNET_CONTAINER_multipeermap_destroy (map); | ||
753 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
754 | "Dropping CADET_CONNECTION_CREATE with cyclic path\n"); | ||
755 | GNUNET_break_op (0); | ||
756 | return; | ||
757 | } | ||
758 | } | ||
759 | GNUNET_CONTAINER_multipeermap_destroy (map); | ||
760 | } | ||
761 | /* Initiator is at offset 0, find us */ | ||
762 | for (off = 1; off < path_length; off++) | ||
763 | if (0 == GNUNET_memcmp (&my_full_id, &pids[off])) | ||
764 | break; | ||
765 | if (off == path_length) | ||
766 | { | ||
767 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
768 | "Dropping CADET_CONNECTION_CREATE without us in the path\n"); | ||
769 | GNUNET_break_op (0); | ||
770 | return; | ||
771 | } | ||
772 | /* Check previous hop */ | ||
773 | if (sender != GCP_get (&pids[off - 1], GNUNET_NO)) | ||
774 | { | ||
775 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
776 | "Dropping CADET_CONNECTION_CREATE without sender at previous hop in the path\n"); | ||
777 | GNUNET_break_op (0); | ||
778 | return; | ||
779 | } | ||
780 | if (NULL != (route = get_route (&msg->cid))) | ||
781 | { | ||
782 | /* Duplicate CREATE, pass it on, previous one might have been lost! */ | ||
783 | |||
784 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
785 | "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n", | ||
786 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
787 | route_message (sender, | ||
788 | &msg->cid, | ||
789 | &msg->header, | ||
790 | GNUNET_MQ_PRIO_CRITICAL_CONTROL | ||
791 | | GNUNET_MQ_PREF_LOW_LATENCY); | ||
792 | return; | ||
793 | } | ||
794 | if (off == path_length - 1) | ||
795 | { | ||
796 | /* We are the destination, create connection */ | ||
797 | struct CadetConnection *cc; | ||
798 | struct CadetPeerPath *path; | ||
799 | struct CadetPeer *origin; | ||
800 | |||
801 | cc = GCC_lookup (&msg->cid); | ||
802 | if (NULL != cc) | ||
803 | { | ||
804 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
805 | "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n", | ||
806 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
807 | GCC_handle_duplicate_create (cc); | ||
808 | return; | ||
809 | } | ||
810 | |||
811 | origin = GCP_get (&pids[0], GNUNET_YES); | ||
812 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
813 | "I am destination for CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n", | ||
814 | GCP_2s (origin), | ||
815 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
816 | path = GCPP_get_path_from_route (path_length - 1, pids); | ||
817 | t = GCP_get_tunnel (origin, GNUNET_YES); | ||
818 | |||
819 | // Check for CADET state in case the other side has lost the tunnel (xrs,t3ss) | ||
820 | if ((GNUNET_YES == msg->has_monotime) && | ||
821 | (GNUNET_YES == GCP_check_and_update_monotime (origin, msg->monotime)) && | ||
822 | (GNUNET_OK == GCP_check_monotime_sig (origin, msg)) && | ||
823 | (CADET_TUNNEL_KEY_OK == GCT_get_estate (t))) | ||
824 | { | ||
825 | GCT_change_estate (t, CADET_TUNNEL_KEY_UNINITIALIZED); | ||
826 | } | ||
827 | |||
828 | if (GNUNET_OK != | ||
829 | GCT_add_inbound_connection (t, | ||
830 | &msg->cid, | ||
831 | path)) | ||
832 | { | ||
833 | /* Send back BROKEN: duplicate connection on the same path, | ||
834 | we will use the other one. */ | ||
835 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
836 | "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n", | ||
837 | GCP_2s (sender), | ||
838 | GNUNET_sh2s (&msg->cid.connection_of_tunnel), | ||
839 | GCPP_2s (path)); | ||
840 | send_broken_without_mqm (sender, &msg->cid, NULL); | ||
841 | return; | ||
842 | } | ||
843 | return; | ||
844 | } | ||
845 | /* We are merely a hop on the way, check if we can support the route */ | ||
846 | next = GCP_get (&pids[off + 1], GNUNET_NO); | ||
847 | if ((NULL == next) || (GNUNET_NO == GCP_has_core_connection (next))) | ||
848 | { | ||
849 | /* unworkable, send back BROKEN notification */ | ||
850 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
851 | "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n", | ||
852 | GCP_2s (sender), | ||
853 | GNUNET_sh2s (&msg->cid.connection_of_tunnel), | ||
854 | GNUNET_i2s (&pids[off + 1]), | ||
855 | off + 1); | ||
856 | send_broken_without_mqm (sender, &msg->cid, &pids[off + 1]); | ||
857 | return; | ||
858 | } | ||
859 | if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes)) | ||
860 | { | ||
861 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
862 | "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n", | ||
863 | GCP_2s (sender), | ||
864 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
865 | send_broken_without_mqm (sender, &msg->cid, &pids[off - 1]); | ||
866 | return; | ||
867 | } | ||
868 | |||
869 | /* Workable route, create routing entry */ | ||
870 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
871 | "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n", | ||
872 | GCP_2s (sender), | ||
873 | GNUNET_sh2s (&msg->cid.connection_of_tunnel), | ||
874 | GNUNET_i2s (&pids[off + 1]), | ||
875 | off + 1); | ||
876 | route = GNUNET_new (struct CadetRoute); | ||
877 | route->cid = msg->cid; | ||
878 | route->last_use = GNUNET_TIME_absolute_get (); | ||
879 | dir_init (&route->prev, route, sender); | ||
880 | dir_init (&route->next, route, next); | ||
881 | GNUNET_assert (GNUNET_OK == | ||
882 | GNUNET_CONTAINER_multishortmap_put ( | ||
883 | routes, | ||
884 | &route->cid.connection_of_tunnel, | ||
885 | route, | ||
886 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
887 | GNUNET_STATISTICS_set (stats, | ||
888 | "# routes", | ||
889 | GNUNET_CONTAINER_multishortmap_size (routes), | ||
890 | GNUNET_NO); | ||
891 | route->hn = GNUNET_CONTAINER_heap_insert (route_heap, | ||
892 | route, | ||
893 | route->last_use.abs_value_us); | ||
894 | if (NULL == timeout_task) | ||
895 | timeout_task = | ||
896 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply ( | ||
897 | keepalive_period, | ||
898 | 3), | ||
899 | &timeout_cb, | ||
900 | NULL); | ||
901 | /* also pass CREATE message along to next hop */ | ||
902 | route_message (sender, | ||
903 | &msg->cid, | ||
904 | &msg->header, | ||
905 | GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY); | ||
906 | } | ||
907 | |||
908 | |||
909 | /** | ||
910 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK | ||
911 | * | ||
912 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
913 | * @param msg Message itself. | ||
914 | */ | ||
915 | static void | ||
916 | handle_connection_create_ack ( | ||
917 | void *cls, | ||
918 | const struct GNUNET_CADET_ConnectionCreateAckMessage *msg) | ||
919 | { | ||
920 | struct CadetPeer *peer = cls; | ||
921 | struct CadetConnection *cc; | ||
922 | |||
923 | /* First, check if ACK belongs to a connection that ends here. */ | ||
924 | cc = GCC_lookup (&msg->cid); | ||
925 | if (NULL != cc) | ||
926 | { | ||
927 | /* verify ACK came from the right direction */ | ||
928 | unsigned int len; | ||
929 | struct CadetPeerPath *path = GCC_get_path (cc, &len); | ||
930 | |||
931 | if (peer != GCPP_get_peer_at_offset (path, 0)) | ||
932 | { | ||
933 | /* received ACK from unexpected direction, ignore! */ | ||
934 | GNUNET_break_op (0); | ||
935 | return; | ||
936 | } | ||
937 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
938 | "Received CONNECTION_CREATE_ACK for connection %s.\n", | ||
939 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
940 | GCC_handle_connection_create_ack (cc); | ||
941 | return; | ||
942 | } | ||
943 | |||
944 | /* We're just an intermediary peer, route the message along its path */ | ||
945 | route_message (peer, | ||
946 | &msg->cid, | ||
947 | &msg->header, | ||
948 | GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY); | ||
949 | } | ||
950 | |||
951 | |||
952 | /** | ||
953 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN | ||
954 | * | ||
955 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
956 | * @param msg Message itself. | ||
957 | * @deprecated duplicate logic with #handle_destroy(); dedup! | ||
958 | */ | ||
959 | static void | ||
960 | handle_connection_broken ( | ||
961 | void *cls, | ||
962 | const struct GNUNET_CADET_ConnectionBrokenMessage *msg) | ||
963 | { | ||
964 | struct CadetPeer *peer = cls; | ||
965 | struct CadetConnection *cc; | ||
966 | struct CadetRoute *route; | ||
967 | |||
968 | /* First, check if message belongs to a connection that ends here. */ | ||
969 | cc = GCC_lookup (&msg->cid); | ||
970 | if (NULL != cc) | ||
971 | { | ||
972 | /* verify message came from the right direction */ | ||
973 | unsigned int len; | ||
974 | struct CadetPeerPath *path = GCC_get_path (cc, &len); | ||
975 | |||
976 | if (peer != GCPP_get_peer_at_offset (path, 0)) | ||
977 | { | ||
978 | /* received message from unexpected direction, ignore! */ | ||
979 | GNUNET_break_op (0); | ||
980 | return; | ||
981 | } | ||
982 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
983 | "Received CONNECTION_BROKEN for connection %s. Destroying it.\n", | ||
984 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
985 | GCC_destroy_without_core (cc); | ||
986 | |||
987 | /* FIXME: also destroy the path up to the specified link! */ | ||
988 | return; | ||
989 | } | ||
990 | |||
991 | /* We're just an intermediary peer, route the message along its path */ | ||
992 | route_message (peer, | ||
993 | &msg->cid, | ||
994 | &msg->header, | ||
995 | GNUNET_MQ_PREF_LOW_LATENCY | GNUNET_MQ_PRIO_CRITICAL_CONTROL); | ||
996 | route = get_route (&msg->cid); | ||
997 | if (NULL != route) | ||
998 | destroy_route (route); | ||
999 | /* FIXME: also destroy paths we MAY have up to the specified link! */ | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | /** | ||
1004 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY | ||
1005 | * | ||
1006 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
1007 | * @param msg Message itself. | ||
1008 | */ | ||
1009 | static void | ||
1010 | handle_connection_destroy ( | ||
1011 | void *cls, | ||
1012 | const struct GNUNET_CADET_ConnectionDestroyMessage *msg) | ||
1013 | { | ||
1014 | struct CadetPeer *peer = cls; | ||
1015 | struct CadetConnection *cc; | ||
1016 | struct CadetRoute *route; | ||
1017 | |||
1018 | /* First, check if message belongs to a connection that ends here. */ | ||
1019 | cc = GCC_lookup (&msg->cid); | ||
1020 | if (NULL != cc) | ||
1021 | { | ||
1022 | /* verify message came from the right direction */ | ||
1023 | unsigned int len; | ||
1024 | struct CadetPeerPath *path = GCC_get_path (cc, &len); | ||
1025 | |||
1026 | if (peer != GCPP_get_peer_at_offset (path, 0)) | ||
1027 | { | ||
1028 | /* received message from unexpected direction, ignore! */ | ||
1029 | GNUNET_break_op (0); | ||
1030 | return; | ||
1031 | } | ||
1032 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1033 | "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n", | ||
1034 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
1035 | |||
1036 | GCC_destroy_without_core (cc); | ||
1037 | return; | ||
1038 | } | ||
1039 | |||
1040 | /* We're just an intermediary peer, route the message along its path */ | ||
1041 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1042 | "Received CONNECTION_DESTROY for connection %s. Destroying route.\n", | ||
1043 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
1044 | route_message (peer, | ||
1045 | &msg->cid, | ||
1046 | &msg->header, | ||
1047 | GNUNET_MQ_PREF_LOW_LATENCY | GNUNET_MQ_PRIO_CRITICAL_CONTROL); | ||
1048 | route = get_route (&msg->cid); | ||
1049 | if (NULL != route) | ||
1050 | destroy_route (route); | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | /** | ||
1055 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX | ||
1056 | * | ||
1057 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
1058 | * @param msg Message itself. | ||
1059 | */ | ||
1060 | static void | ||
1061 | handle_tunnel_kx (void *cls, | ||
1062 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) | ||
1063 | { | ||
1064 | struct CadetPeer *peer = cls; | ||
1065 | struct CadetConnection *cc; | ||
1066 | |||
1067 | /* First, check if message belongs to a connection that ends here. */ | ||
1068 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1069 | "Routing KX with ephemeral %s on CID %s\n", | ||
1070 | GNUNET_e2s (&msg->ephemeral_key), | ||
1071 | GNUNET_sh2s (&msg->cid.connection_of_tunnel)); | ||
1072 | |||
1073 | |||
1074 | cc = GCC_lookup (&msg->cid); | ||
1075 | if (NULL != cc) | ||
1076 | { | ||
1077 | /* verify message came from the right direction */ | ||
1078 | unsigned int len; | ||
1079 | struct CadetPeerPath *path = GCC_get_path (cc, &len); | ||
1080 | |||
1081 | if (peer != GCPP_get_peer_at_offset (path, 0)) | ||
1082 | { | ||
1083 | /* received message from unexpected direction, ignore! */ | ||
1084 | GNUNET_break_op (0); | ||
1085 | return; | ||
1086 | } | ||
1087 | GCC_handle_kx (cc, msg); | ||
1088 | return; | ||
1089 | } | ||
1090 | |||
1091 | /* We're just an intermediary peer, route the message along its path */ | ||
1092 | route_message (peer, | ||
1093 | &msg->cid, | ||
1094 | &msg->header, | ||
1095 | GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY); | ||
1096 | } | ||
1097 | |||
1098 | |||
1099 | /** | ||
1100 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH | ||
1101 | * | ||
1102 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
1103 | * @param msg Message itself. | ||
1104 | */ | ||
1105 | static void | ||
1106 | handle_tunnel_kx_auth ( | ||
1107 | void *cls, | ||
1108 | const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg) | ||
1109 | { | ||
1110 | struct CadetPeer *peer = cls; | ||
1111 | struct CadetConnection *cc; | ||
1112 | |||
1113 | /* First, check if message belongs to a connection that ends here. */ | ||
1114 | cc = GCC_lookup (&msg->kx.cid); | ||
1115 | if (NULL != cc) | ||
1116 | { | ||
1117 | /* verify message came from the right direction */ | ||
1118 | unsigned int len; | ||
1119 | struct CadetPeerPath *path = GCC_get_path (cc, &len); | ||
1120 | |||
1121 | if (peer != GCPP_get_peer_at_offset (path, 0)) | ||
1122 | { | ||
1123 | /* received message from unexpected direction, ignore! */ | ||
1124 | GNUNET_break_op (0); | ||
1125 | return; | ||
1126 | } | ||
1127 | GCC_handle_kx_auth (cc, msg); | ||
1128 | return; | ||
1129 | } | ||
1130 | |||
1131 | /* We're just an intermediary peer, route the message along its path */ | ||
1132 | route_message (peer, | ||
1133 | &msg->kx.cid, | ||
1134 | &msg->kx.header, | ||
1135 | GNUNET_MQ_PRIO_CRITICAL_CONTROL | GNUNET_MQ_PREF_LOW_LATENCY); | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | /** | ||
1140 | * Check if the encrypted message has the appropriate size. | ||
1141 | * | ||
1142 | * @param cls Closure (unused). | ||
1143 | * @param msg Message to check. | ||
1144 | * | ||
1145 | * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise. | ||
1146 | */ | ||
1147 | static int | ||
1148 | check_tunnel_encrypted (void *cls, | ||
1149 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
1150 | { | ||
1151 | return GNUNET_YES; | ||
1152 | } | ||
1153 | |||
1154 | |||
1155 | /** | ||
1156 | * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED. | ||
1157 | * | ||
1158 | * @param cls Closure (CadetPeer for neighbor that sent the message). | ||
1159 | * @param msg Message itself. | ||
1160 | */ | ||
1161 | static void | ||
1162 | handle_tunnel_encrypted (void *cls, | ||
1163 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
1164 | { | ||
1165 | struct CadetPeer *peer = cls; | ||
1166 | struct CadetConnection *cc; | ||
1167 | |||
1168 | /* First, check if message belongs to a connection that ends here. */ | ||
1169 | cc = GCC_lookup (&msg->cid); | ||
1170 | if (NULL != cc) | ||
1171 | { | ||
1172 | /* verify message came from the right direction */ | ||
1173 | unsigned int len; | ||
1174 | struct CadetPeerPath *path = GCC_get_path (cc, &len); | ||
1175 | |||
1176 | if (peer != GCPP_get_peer_at_offset (path, 0)) | ||
1177 | { | ||
1178 | /* received message from unexpected direction, ignore! */ | ||
1179 | GNUNET_break_op (0); | ||
1180 | return; | ||
1181 | } | ||
1182 | GCC_handle_encrypted (cc, msg); | ||
1183 | return; | ||
1184 | } | ||
1185 | /* We're just an intermediary peer, route the message along its path */ | ||
1186 | route_message (peer, &msg->cid, &msg->header, GNUNET_MQ_PRIO_BEST_EFFORT); | ||
1187 | } | ||
1188 | |||
1189 | |||
1190 | /** | ||
1191 | * Function called after #GNUNET_CORE_connect has succeeded (or failed | ||
1192 | * for good). Note that the private key of the peer is intentionally | ||
1193 | * not exposed here; if you need it, your process should try to read | ||
1194 | * the private key file directly (which should work if you are | ||
1195 | * authorized...). Implementations of this function must not call | ||
1196 | * #GNUNET_CORE_disconnect (other than by scheduling a new task to | ||
1197 | * do this later). | ||
1198 | * | ||
1199 | * @param cls closure | ||
1200 | * @param my_identity ID of this peer, NULL if we failed | ||
1201 | */ | ||
1202 | static void | ||
1203 | core_init_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity) | ||
1204 | { | ||
1205 | if (NULL == my_identity) | ||
1206 | { | ||
1207 | GNUNET_break (0); | ||
1208 | return; | ||
1209 | } | ||
1210 | GNUNET_break (0 == GNUNET_memcmp (my_identity, &my_full_id)); | ||
1211 | } | ||
1212 | |||
1213 | |||
1214 | /** | ||
1215 | * Method called whenever a given peer connects. | ||
1216 | * | ||
1217 | * @param cls closure | ||
1218 | * @param peer peer identity this notification is about | ||
1219 | */ | ||
1220 | static void * | ||
1221 | core_connect_cb (void *cls, | ||
1222 | const struct GNUNET_PeerIdentity *peer, | ||
1223 | struct GNUNET_MQ_Handle *mq) | ||
1224 | { | ||
1225 | struct CadetPeer *cp; | ||
1226 | |||
1227 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1228 | "CORE connection to peer %s was established.\n", | ||
1229 | GNUNET_i2s (peer)); | ||
1230 | cp = GCP_get (peer, GNUNET_YES); | ||
1231 | GCP_set_mq (cp, mq); | ||
1232 | return cp; | ||
1233 | } | ||
1234 | |||
1235 | |||
1236 | /** | ||
1237 | * Method called whenever a peer disconnects. | ||
1238 | * | ||
1239 | * @param cls closure | ||
1240 | * @param peer peer identity this notification is about | ||
1241 | */ | ||
1242 | static void | ||
1243 | core_disconnect_cb (void *cls, | ||
1244 | const struct GNUNET_PeerIdentity *peer, | ||
1245 | void *peer_cls) | ||
1246 | { | ||
1247 | struct CadetPeer *cp = peer_cls; | ||
1248 | |||
1249 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1250 | "CORE connection to peer %s went down.\n", | ||
1251 | GNUNET_i2s (peer)); | ||
1252 | GCP_set_mq (cp, NULL); | ||
1253 | } | ||
1254 | |||
1255 | |||
1256 | /** | ||
1257 | * Initialize the CORE subsystem. | ||
1258 | * | ||
1259 | * @param c Configuration. | ||
1260 | */ | ||
1261 | void | ||
1262 | GCO_init (const struct GNUNET_CONFIGURATION_Handle *c) | ||
1263 | { | ||
1264 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
1265 | { GNUNET_MQ_hd_var_size (connection_create, | ||
1266 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, | ||
1267 | struct GNUNET_CADET_ConnectionCreateMessage, | ||
1268 | NULL), | ||
1269 | GNUNET_MQ_hd_fixed_size (connection_create_ack, | ||
1270 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK, | ||
1271 | struct GNUNET_CADET_ConnectionCreateAckMessage, | ||
1272 | NULL), | ||
1273 | GNUNET_MQ_hd_fixed_size (connection_broken, | ||
1274 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, | ||
1275 | struct GNUNET_CADET_ConnectionBrokenMessage, | ||
1276 | NULL), | ||
1277 | GNUNET_MQ_hd_fixed_size (connection_destroy, | ||
1278 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, | ||
1279 | struct GNUNET_CADET_ConnectionDestroyMessage, | ||
1280 | NULL), | ||
1281 | GNUNET_MQ_hd_fixed_size (tunnel_kx, | ||
1282 | GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX, | ||
1283 | struct GNUNET_CADET_TunnelKeyExchangeMessage, | ||
1284 | NULL), | ||
1285 | GNUNET_MQ_hd_fixed_size (tunnel_kx_auth, | ||
1286 | GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH, | ||
1287 | struct GNUNET_CADET_TunnelKeyExchangeAuthMessage, | ||
1288 | NULL), | ||
1289 | GNUNET_MQ_hd_var_size (tunnel_encrypted, | ||
1290 | GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED, | ||
1291 | struct GNUNET_CADET_TunnelEncryptedMessage, | ||
1292 | NULL), | ||
1293 | GNUNET_MQ_handler_end () }; | ||
1294 | |||
1295 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c, | ||
1296 | "CADET", | ||
1297 | "MAX_ROUTES", | ||
1298 | &max_routes)) | ||
1299 | max_routes = 5000; | ||
1300 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c, | ||
1301 | "CADET", | ||
1302 | "MAX_MSGS_QUEUE", | ||
1303 | &max_buffers)) | ||
1304 | max_buffers = 10000; | ||
1305 | routes = GNUNET_CONTAINER_multishortmap_create (1024, GNUNET_NO); | ||
1306 | route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1307 | core = GNUNET_CORE_connect (c, | ||
1308 | NULL, | ||
1309 | &core_init_cb, | ||
1310 | &core_connect_cb, | ||
1311 | &core_disconnect_cb, | ||
1312 | handlers); | ||
1313 | } | ||
1314 | |||
1315 | |||
1316 | void | ||
1317 | GCO_shutdown () | ||
1318 | { | ||
1319 | if (NULL != core) | ||
1320 | { | ||
1321 | GNUNET_CORE_disconnect (core); | ||
1322 | core = NULL; | ||
1323 | } | ||
1324 | GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes)); | ||
1325 | GNUNET_CONTAINER_multishortmap_destroy (routes); | ||
1326 | routes = NULL; | ||
1327 | GNUNET_CONTAINER_heap_destroy (route_heap); | ||
1328 | route_heap = NULL; | ||
1329 | if (NULL != timeout_task) | ||
1330 | { | ||
1331 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
1332 | timeout_task = NULL; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | |||
1337 | /* end of gnunet-cadet-service_core.c */ | ||