diff options
Diffstat (limited to 'src/cadet/gnunet-service-cadet_connection.c')
-rw-r--r-- | src/cadet/gnunet-service-cadet_connection.c | 1091 |
1 files changed, 1091 insertions, 0 deletions
diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c new file mode 100644 index 000000000..7b66f61a2 --- /dev/null +++ b/src/cadet/gnunet-service-cadet_connection.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2001-2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file cadet/gnunet-service-cadet_connection.c | ||
23 | * @brief management of CORE-level end-to-end connections; establishes | ||
24 | * end-to-end routes and transmits messages along the route | ||
25 | * @author Bartlomiej Polot | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet-service-cadet_connection.h" | ||
30 | #include "gnunet-service-cadet_channel.h" | ||
31 | #include "gnunet-service-cadet_paths.h" | ||
32 | #include "gnunet-service-cadet_tunnels.h" | ||
33 | #include "gnunet_cadet_service.h" | ||
34 | #include "gnunet_statistics_service.h" | ||
35 | #include "cadet_protocol.h" | ||
36 | |||
37 | |||
38 | #define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__) | ||
39 | |||
40 | |||
41 | /** | ||
42 | * All the states a connection can be in. | ||
43 | */ | ||
44 | enum CadetConnectionState | ||
45 | { | ||
46 | /** | ||
47 | * Uninitialized status, we have not yet even gotten the message queue. | ||
48 | */ | ||
49 | CADET_CONNECTION_NEW, | ||
50 | |||
51 | /** | ||
52 | * Connection create message in queue, awaiting transmission by CORE. | ||
53 | */ | ||
54 | CADET_CONNECTION_SENDING_CREATE, | ||
55 | |||
56 | /** | ||
57 | * Connection create message sent, waiting for ACK. | ||
58 | */ | ||
59 | CADET_CONNECTION_SENT, | ||
60 | |||
61 | /** | ||
62 | * We are an inbound connection, and received a CREATE. Need to | ||
63 | * send an CREATE_ACK back. | ||
64 | */ | ||
65 | CADET_CONNECTION_CREATE_RECEIVED, | ||
66 | |||
67 | /** | ||
68 | * Connection confirmed, ready to carry traffic. | ||
69 | */ | ||
70 | CADET_CONNECTION_READY | ||
71 | |||
72 | }; | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Low-level connection to a destination. | ||
77 | */ | ||
78 | struct CadetConnection | ||
79 | { | ||
80 | |||
81 | /** | ||
82 | * ID of the connection. | ||
83 | */ | ||
84 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
85 | |||
86 | /** | ||
87 | * To which peer does this connection go? | ||
88 | */ | ||
89 | struct CadetPeer *destination; | ||
90 | |||
91 | /** | ||
92 | * Which tunnel is using this connection? | ||
93 | */ | ||
94 | struct CadetTConnection *ct; | ||
95 | |||
96 | /** | ||
97 | * Path we are using to our destination. | ||
98 | */ | ||
99 | struct CadetPeerPath *path; | ||
100 | |||
101 | /** | ||
102 | * Pending message, NULL if we are ready to transmit. | ||
103 | */ | ||
104 | struct GNUNET_MQ_Envelope *env; | ||
105 | |||
106 | /** | ||
107 | * Handle for calling #GCP_request_mq_cancel() once we are finished. | ||
108 | */ | ||
109 | struct GCP_MessageQueueManager *mq_man; | ||
110 | |||
111 | /** | ||
112 | * Task for connection maintenance. | ||
113 | */ | ||
114 | struct GNUNET_SCHEDULER_Task *task; | ||
115 | |||
116 | /** | ||
117 | * Queue entry for keepalive messages. | ||
118 | */ | ||
119 | struct CadetTunnelQueueEntry *keepalive_qe; | ||
120 | |||
121 | /** | ||
122 | * Function to call once we are ready to transmit. | ||
123 | */ | ||
124 | GCC_ReadyCallback ready_cb; | ||
125 | |||
126 | /** | ||
127 | * Closure for @e ready_cb. | ||
128 | */ | ||
129 | void *ready_cb_cls; | ||
130 | |||
131 | /** | ||
132 | * How long do we wait before we try again with a CREATE message? | ||
133 | */ | ||
134 | struct GNUNET_TIME_Relative retry_delay; | ||
135 | |||
136 | /** | ||
137 | * Performance metrics for this connection. | ||
138 | */ | ||
139 | struct CadetConnectionMetrics metrics; | ||
140 | |||
141 | /** | ||
142 | * State of the connection. | ||
143 | */ | ||
144 | enum CadetConnectionState state; | ||
145 | |||
146 | /** | ||
147 | * Options for the route, control buffering. | ||
148 | */ | ||
149 | enum GNUNET_CADET_ChannelOption options; | ||
150 | |||
151 | /** | ||
152 | * How many latency observations did we make for this connection? | ||
153 | */ | ||
154 | unsigned int latency_datapoints; | ||
155 | |||
156 | /** | ||
157 | * Offset of our @e destination in @e path. | ||
158 | */ | ||
159 | unsigned int off; | ||
160 | |||
161 | /** | ||
162 | * Are we ready to transmit via @e mq_man right now? | ||
163 | */ | ||
164 | int mqm_ready; | ||
165 | |||
166 | }; | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Lookup a connection by its identifier. | ||
171 | * | ||
172 | * @param cid identifier to resolve | ||
173 | * @return NULL if connection was not found | ||
174 | */ | ||
175 | struct CadetConnection * | ||
176 | GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
177 | { | ||
178 | return GNUNET_CONTAINER_multishortmap_get (connections, | ||
179 | &cid->connection_of_tunnel); | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Update the connection state. Also triggers the necessary | ||
185 | * MQM notifications. | ||
186 | * | ||
187 | * @param cc connection to update the state for | ||
188 | * @param new_state new state for @a cc | ||
189 | * @param new_mqm_ready new `mqm_ready` state for @a cc | ||
190 | */ | ||
191 | static void | ||
192 | update_state (struct CadetConnection *cc, | ||
193 | enum CadetConnectionState new_state, | ||
194 | int new_mqm_ready) | ||
195 | { | ||
196 | int old_ready; | ||
197 | int new_ready; | ||
198 | |||
199 | if ( (new_state == cc->state) && | ||
200 | (new_mqm_ready == cc->mqm_ready) ) | ||
201 | return; /* no change, nothing to do */ | ||
202 | old_ready = ( (CADET_CONNECTION_READY == cc->state) && | ||
203 | (GNUNET_YES == cc->mqm_ready) ); | ||
204 | new_ready = ( (CADET_CONNECTION_READY == new_state) && | ||
205 | (GNUNET_YES == new_mqm_ready) ); | ||
206 | cc->state = new_state; | ||
207 | cc->mqm_ready = new_mqm_ready; | ||
208 | if (old_ready != new_ready) | ||
209 | cc->ready_cb (cc->ready_cb_cls, | ||
210 | new_ready); | ||
211 | } | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Destroy a connection, part of the internal implementation. Called | ||
216 | * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel(). | ||
217 | * | ||
218 | * @param cc connection to destroy | ||
219 | */ | ||
220 | static void | ||
221 | GCC_destroy (struct CadetConnection *cc) | ||
222 | { | ||
223 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
224 | "Destroying %s\n", | ||
225 | GCC_2s (cc)); | ||
226 | if (NULL != cc->mq_man) | ||
227 | { | ||
228 | GCP_request_mq_cancel (cc->mq_man, | ||
229 | NULL); | ||
230 | cc->mq_man = NULL; | ||
231 | } | ||
232 | if (NULL != cc->task) | ||
233 | { | ||
234 | GNUNET_SCHEDULER_cancel (cc->task); | ||
235 | cc->task = NULL; | ||
236 | } | ||
237 | if (NULL != cc->keepalive_qe) | ||
238 | { | ||
239 | GCT_send_cancel (cc->keepalive_qe); | ||
240 | cc->keepalive_qe = NULL; | ||
241 | } | ||
242 | GCPP_del_connection (cc->path, | ||
243 | cc->off, | ||
244 | cc); | ||
245 | for (unsigned int i=0;i<cc->off;i++) | ||
246 | GCP_remove_connection (GCPP_get_peer_at_offset (cc->path, | ||
247 | i), | ||
248 | cc); | ||
249 | GNUNET_assert (GNUNET_YES == | ||
250 | GNUNET_CONTAINER_multishortmap_remove (connections, | ||
251 | &GCC_get_id (cc)->connection_of_tunnel, | ||
252 | cc)); | ||
253 | GNUNET_free (cc); | ||
254 | } | ||
255 | |||
256 | |||
257 | |||
258 | /** | ||
259 | * Destroy a connection, called when the CORE layer is already done | ||
260 | * (i.e. has received a BROKEN message), but if we still have to | ||
261 | * communicate the destruction of the connection to the tunnel (if one | ||
262 | * exists). | ||
263 | * | ||
264 | * @param cc connection to destroy | ||
265 | */ | ||
266 | void | ||
267 | GCC_destroy_without_core (struct CadetConnection *cc) | ||
268 | { | ||
269 | if (NULL != cc->ct) | ||
270 | { | ||
271 | GCT_connection_lost (cc->ct); | ||
272 | cc->ct = NULL; | ||
273 | } | ||
274 | GCC_destroy (cc); | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Destroy a connection, called if the tunnel association with the | ||
280 | * connection was already broken, but we still need to notify the CORE | ||
281 | * layer about the breakage. | ||
282 | * | ||
283 | * @param cc connection to destroy | ||
284 | */ | ||
285 | void | ||
286 | GCC_destroy_without_tunnel (struct CadetConnection *cc) | ||
287 | { | ||
288 | cc->ct = NULL; | ||
289 | if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) && | ||
290 | (NULL != cc->mq_man) ) | ||
291 | { | ||
292 | struct GNUNET_MQ_Envelope *env; | ||
293 | struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg; | ||
294 | |||
295 | /* Need to notify next hop that we are down. */ | ||
296 | env = GNUNET_MQ_msg (destroy_msg, | ||
297 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); | ||
298 | destroy_msg->cid = cc->cid; | ||
299 | GCP_request_mq_cancel (cc->mq_man, | ||
300 | env); | ||
301 | cc->mq_man = NULL; | ||
302 | } | ||
303 | GCC_destroy (cc); | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Return the tunnel associated with this connection. | ||
309 | * | ||
310 | * @param cc connection to query | ||
311 | * @return corresponding entry in the tunnel's connection list | ||
312 | */ | ||
313 | struct CadetTConnection * | ||
314 | GCC_get_ct (struct CadetConnection *cc) | ||
315 | { | ||
316 | return cc->ct; | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
321 | * Obtain performance @a metrics from @a cc. | ||
322 | * | ||
323 | * @param cc connection to query | ||
324 | * @return the metrics | ||
325 | */ | ||
326 | const struct CadetConnectionMetrics * | ||
327 | GCC_get_metrics (struct CadetConnection *cc) | ||
328 | { | ||
329 | return &cc->metrics; | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the | ||
335 | * tunnel to prevent it from timing out. | ||
336 | * | ||
337 | * @param cls the `struct CadetConnection` to keep alive. | ||
338 | */ | ||
339 | static void | ||
340 | send_keepalive (void *cls); | ||
341 | |||
342 | |||
343 | /** | ||
344 | * Keepalive was transmitted. Remember this, and possibly | ||
345 | * schedule the next one. | ||
346 | * | ||
347 | * @param cls the `struct CadetConnection` to keep alive. | ||
348 | * @param cid identifier of the connection within the tunnel, NULL | ||
349 | * if transmission failed | ||
350 | */ | ||
351 | static void | ||
352 | keepalive_done (void *cls, | ||
353 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
354 | { | ||
355 | struct CadetConnection *cc = cls; | ||
356 | |||
357 | cc->keepalive_qe = NULL; | ||
358 | if ( (GNUNET_YES == cc->mqm_ready) && | ||
359 | (NULL == cc->task) ) | ||
360 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
361 | &send_keepalive, | ||
362 | cc); | ||
363 | } | ||
364 | |||
365 | |||
366 | /** | ||
367 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the | ||
368 | * tunnel to prevent it from timing out. | ||
369 | * | ||
370 | * @param cls the `struct CadetConnection` to keep alive. | ||
371 | */ | ||
372 | static void | ||
373 | send_keepalive (void *cls) | ||
374 | { | ||
375 | struct CadetConnection *cc = cls; | ||
376 | struct GNUNET_MessageHeader msg; | ||
377 | |||
378 | cc->task = NULL; | ||
379 | if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t)) | ||
380 | { | ||
381 | /* Tunnel not yet ready, wait with keepalives... */ | ||
382 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
383 | &send_keepalive, | ||
384 | cc); | ||
385 | return; | ||
386 | } | ||
387 | GNUNET_assert (NULL != cc->ct); | ||
388 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
389 | GNUNET_assert (NULL == cc->keepalive_qe); | ||
390 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
391 | "Sending KEEPALIVE on behalf of %s via %s\n", | ||
392 | GCC_2s (cc), | ||
393 | GCT_2s (cc->ct->t)); | ||
394 | GNUNET_STATISTICS_update (stats, | ||
395 | "# keepalives sent", | ||
396 | 1, | ||
397 | GNUNET_NO); | ||
398 | msg.size = htons (sizeof (msg)); | ||
399 | msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE); | ||
400 | |||
401 | cc->keepalive_qe | ||
402 | = GCT_send (cc->ct->t, | ||
403 | &msg, | ||
404 | &keepalive_done, | ||
405 | cc); | ||
406 | } | ||
407 | |||
408 | |||
409 | /** | ||
410 | * We sent a message for which we expect to receive an ACK via | ||
411 | * the connection identified by @a cti. | ||
412 | * | ||
413 | * @param cid connection identifier where we expect an ACK | ||
414 | */ | ||
415 | void | ||
416 | GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
417 | { | ||
418 | struct CadetConnection *cc; | ||
419 | |||
420 | cc = GCC_lookup (cid); | ||
421 | if (NULL == cc) | ||
422 | return; /* whopise, connection alredy down? */ | ||
423 | cc->metrics.num_acked_transmissions++; | ||
424 | } | ||
425 | |||
426 | |||
427 | /** | ||
428 | * We observed an ACK for a message that was originally sent via | ||
429 | * the connection identified by @a cti. | ||
430 | * | ||
431 | * @param cti connection identifier where we got an ACK for a message | ||
432 | * that was originally sent via this connection (the ACK | ||
433 | * may have gotten back to us via a different connection). | ||
434 | */ | ||
435 | void | ||
436 | GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid) | ||
437 | { | ||
438 | struct CadetConnection *cc; | ||
439 | |||
440 | cc = GCC_lookup (cid); | ||
441 | if (NULL == cc) | ||
442 | return; /* whopise, connection alredy down? */ | ||
443 | cc->metrics.num_successes++; | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | * We observed some the given @a latency on the connection | ||
449 | * identified by @a cti. (The same connection was taken | ||
450 | * in both directions.) | ||
451 | * | ||
452 | * @param cid connection identifier where we measured latency | ||
453 | * @param latency the observed latency | ||
454 | */ | ||
455 | void | ||
456 | GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
457 | struct GNUNET_TIME_Relative latency) | ||
458 | { | ||
459 | struct CadetConnection *cc; | ||
460 | double weight; | ||
461 | double result; | ||
462 | |||
463 | cc = GCC_lookup (cid); | ||
464 | if (NULL == cc) | ||
465 | return; /* whopise, connection alredy down? */ | ||
466 | GNUNET_STATISTICS_update (stats, | ||
467 | "# latencies observed", | ||
468 | 1, | ||
469 | GNUNET_NO); | ||
470 | cc->latency_datapoints++; | ||
471 | if (cc->latency_datapoints >= 7) | ||
472 | weight = 7.0; | ||
473 | else | ||
474 | weight = cc->latency_datapoints; | ||
475 | /* Compute weighted average, giving at MOST weight 7 to the | ||
476 | existing values, or less if that value is based on fewer than 7 | ||
477 | measurements. */ | ||
478 | result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us; | ||
479 | result /= (weight + 1.0); | ||
480 | cc->metrics.aged_latency.rel_value_us = (uint64_t) result; | ||
481 | } | ||
482 | |||
483 | |||
484 | /** | ||
485 | * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying | ||
486 | * that the end-to-end connection is up. Process it. | ||
487 | * | ||
488 | * @param cc the connection that got the ACK. | ||
489 | */ | ||
490 | void | ||
491 | GCC_handle_connection_create_ack (struct CadetConnection *cc) | ||
492 | { | ||
493 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
494 | "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n", | ||
495 | GCC_2s (cc), | ||
496 | cc->state, | ||
497 | (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy"); | ||
498 | if (CADET_CONNECTION_READY == cc->state) | ||
499 | return; /* Duplicate ACK, ignore */ | ||
500 | if (NULL != cc->task) | ||
501 | { | ||
502 | GNUNET_SCHEDULER_cancel (cc->task); | ||
503 | cc->task = NULL; | ||
504 | } | ||
505 | cc->metrics.age = GNUNET_TIME_absolute_get (); | ||
506 | update_state (cc, | ||
507 | CADET_CONNECTION_READY, | ||
508 | cc->mqm_ready); | ||
509 | if ( (NULL == cc->keepalive_qe) && | ||
510 | (GNUNET_YES == cc->mqm_ready) && | ||
511 | (NULL == cc->task) ) | ||
512 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
513 | &send_keepalive, | ||
514 | cc); | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Handle KX message. | ||
520 | * | ||
521 | * @param cc connection that received encrypted message | ||
522 | * @param msg the key exchange message | ||
523 | */ | ||
524 | void | ||
525 | GCC_handle_kx (struct CadetConnection *cc, | ||
526 | const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) | ||
527 | { | ||
528 | if (CADET_CONNECTION_SENT == cc->state) | ||
529 | { | ||
530 | /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine, | ||
531 | clearly something is working, so pretend we got an ACK. */ | ||
532 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
533 | "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n", | ||
534 | GCC_2s (cc)); | ||
535 | GCC_handle_connection_create_ack (cc); | ||
536 | } | ||
537 | GCT_handle_kx (cc->ct, | ||
538 | msg); | ||
539 | } | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Handle KX_AUTH message. | ||
544 | * | ||
545 | * @param cc connection that received encrypted message | ||
546 | * @param msg the key exchange message | ||
547 | */ | ||
548 | void | ||
549 | GCC_handle_kx_auth (struct CadetConnection *cc, | ||
550 | const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg) | ||
551 | { | ||
552 | if (CADET_CONNECTION_SENT == cc->state) | ||
553 | { | ||
554 | /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine, | ||
555 | clearly something is working, so pretend we got an ACK. */ | ||
556 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
557 | "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n", | ||
558 | GCC_2s (cc)); | ||
559 | GCC_handle_connection_create_ack (cc); | ||
560 | } | ||
561 | GCT_handle_kx_auth (cc->ct, | ||
562 | msg); | ||
563 | } | ||
564 | |||
565 | |||
566 | /** | ||
567 | * Handle encrypted message. | ||
568 | * | ||
569 | * @param cc connection that received encrypted message | ||
570 | * @param msg the encrypted message to decrypt | ||
571 | */ | ||
572 | void | ||
573 | GCC_handle_encrypted (struct CadetConnection *cc, | ||
574 | const struct GNUNET_CADET_TunnelEncryptedMessage *msg) | ||
575 | { | ||
576 | if (CADET_CONNECTION_SENT == cc->state) | ||
577 | { | ||
578 | /* We didn't get the CREATE_ACK, but instead got payload. That's fine, | ||
579 | clearly something is working, so pretend we got an ACK. */ | ||
580 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
581 | "Faking connection ACK for %s due to ENCRYPTED payload\n", | ||
582 | GCC_2s (cc)); | ||
583 | GCC_handle_connection_create_ack (cc); | ||
584 | } | ||
585 | cc->metrics.last_use = GNUNET_TIME_absolute_get (); | ||
586 | GCT_handle_encrypted (cc->ct, | ||
587 | msg); | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the | ||
593 | * first hop. | ||
594 | * | ||
595 | * @param cls the `struct CadetConnection` to initiate | ||
596 | */ | ||
597 | static void | ||
598 | send_create (void *cls) | ||
599 | { | ||
600 | struct CadetConnection *cc = cls; | ||
601 | struct GNUNET_CADET_ConnectionCreateMessage *create_msg; | ||
602 | struct GNUNET_PeerIdentity *pids; | ||
603 | struct GNUNET_MQ_Envelope *env; | ||
604 | unsigned int path_length; | ||
605 | |||
606 | cc->task = NULL; | ||
607 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
608 | path_length = GCPP_get_length (cc->path); | ||
609 | env = GNUNET_MQ_msg_extra (create_msg, | ||
610 | (1 + path_length) * sizeof (struct GNUNET_PeerIdentity), | ||
611 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); | ||
612 | create_msg->options = htonl ((uint32_t) cc->options); | ||
613 | create_msg->cid = cc->cid; | ||
614 | pids = (struct GNUNET_PeerIdentity *) &create_msg[1]; | ||
615 | pids[0] = my_full_id; | ||
616 | for (unsigned int i=0;i<path_length;i++) | ||
617 | pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path, | ||
618 | i)); | ||
619 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
620 | "Sending CADET_CONNECTION_CREATE message for %s\n", | ||
621 | GCC_2s (cc)); | ||
622 | cc->env = env; | ||
623 | update_state (cc, | ||
624 | CADET_CONNECTION_SENT, | ||
625 | GNUNET_NO); | ||
626 | GCP_send (cc->mq_man, | ||
627 | env); | ||
628 | } | ||
629 | |||
630 | |||
631 | /** | ||
632 | * Send a CREATE_ACK message towards the origin. | ||
633 | * | ||
634 | * @param cls the `struct CadetConnection` to initiate | ||
635 | */ | ||
636 | static void | ||
637 | send_create_ack (void *cls) | ||
638 | { | ||
639 | struct CadetConnection *cc = cls; | ||
640 | struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg; | ||
641 | struct GNUNET_MQ_Envelope *env; | ||
642 | |||
643 | cc->task = NULL; | ||
644 | GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state); | ||
645 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
646 | "Sending CONNECTION_CREATE_ACK message for %s\n", | ||
647 | GCC_2s (cc)); | ||
648 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
649 | env = GNUNET_MQ_msg (ack_msg, | ||
650 | GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK); | ||
651 | ack_msg->cid = cc->cid; | ||
652 | cc->env = env; | ||
653 | update_state (cc, | ||
654 | CADET_CONNECTION_READY, | ||
655 | GNUNET_NO); | ||
656 | GCP_send (cc->mq_man, | ||
657 | env); | ||
658 | } | ||
659 | |||
660 | |||
661 | /** | ||
662 | * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a | ||
663 | * connection that we already have. Either our ACK got lost | ||
664 | * or something is fishy. Consider retransmitting the ACK. | ||
665 | * | ||
666 | * @param cc connection that got the duplicate CREATE | ||
667 | */ | ||
668 | void | ||
669 | GCC_handle_duplicate_create (struct CadetConnection *cc) | ||
670 | { | ||
671 | if (GNUNET_YES == cc->mqm_ready) | ||
672 | { | ||
673 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
674 | "Got duplicate CREATE for %s, scheduling another ACK (%s)\n", | ||
675 | GCC_2s (cc), | ||
676 | (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy"); | ||
677 | /* Revert back to the state of having only received the 'CREATE', | ||
678 | and immediately proceed to send the CREATE_ACK. */ | ||
679 | update_state (cc, | ||
680 | CADET_CONNECTION_CREATE_RECEIVED, | ||
681 | cc->mqm_ready); | ||
682 | if (NULL != cc->task) | ||
683 | GNUNET_SCHEDULER_cancel (cc->task); | ||
684 | cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, | ||
685 | cc); | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | /* We are currently sending something else back, which | ||
690 | can only be an ACK or payload, either of which would | ||
691 | do. So actually no need to do anything. */ | ||
692 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
693 | "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n", | ||
694 | GCC_2s (cc)); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | |||
699 | /** | ||
700 | * There has been a change in the message queue existence for our | ||
701 | * peer at the first hop. Adjust accordingly. | ||
702 | * | ||
703 | * @param cls the `struct CadetConnection` | ||
704 | * @param available #GNUNET_YES if sending is now possible, | ||
705 | * #GNUNET_NO if sending is no longer possible | ||
706 | * #GNUNET_SYSERR if sending is no longer possible | ||
707 | * and the last envelope was discarded | ||
708 | */ | ||
709 | static void | ||
710 | manage_first_hop_mq (void *cls, | ||
711 | int available) | ||
712 | { | ||
713 | struct CadetConnection *cc = cls; | ||
714 | |||
715 | if (GNUNET_YES != available) | ||
716 | { | ||
717 | /* Connection is down, for now... */ | ||
718 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
719 | "Core MQ for %s went down\n", | ||
720 | GCC_2s (cc)); | ||
721 | update_state (cc, | ||
722 | CADET_CONNECTION_NEW, | ||
723 | GNUNET_NO); | ||
724 | cc->retry_delay = GNUNET_TIME_UNIT_ZERO; | ||
725 | if (NULL != cc->task) | ||
726 | { | ||
727 | GNUNET_SCHEDULER_cancel (cc->task); | ||
728 | cc->task = NULL; | ||
729 | } | ||
730 | return; | ||
731 | } | ||
732 | |||
733 | update_state (cc, | ||
734 | cc->state, | ||
735 | GNUNET_YES); | ||
736 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
737 | "Core MQ for %s became available in state %d\n", | ||
738 | GCC_2s (cc), | ||
739 | cc->state); | ||
740 | switch (cc->state) | ||
741 | { | ||
742 | case CADET_CONNECTION_NEW: | ||
743 | /* Transmit immediately */ | ||
744 | cc->task = GNUNET_SCHEDULER_add_now (&send_create, | ||
745 | cc); | ||
746 | break; | ||
747 | case CADET_CONNECTION_SENDING_CREATE: | ||
748 | /* Should not be possible to be called in this state. */ | ||
749 | GNUNET_assert (0); | ||
750 | break; | ||
751 | case CADET_CONNECTION_SENT: | ||
752 | /* Retry a bit later... */ | ||
753 | cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay); | ||
754 | cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay, | ||
755 | &send_create, | ||
756 | cc); | ||
757 | break; | ||
758 | case CADET_CONNECTION_CREATE_RECEIVED: | ||
759 | /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */ | ||
760 | cc->metrics.age = GNUNET_TIME_absolute_get (); | ||
761 | cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack, | ||
762 | cc); | ||
763 | break; | ||
764 | case CADET_CONNECTION_READY: | ||
765 | if ( (NULL == cc->keepalive_qe) && | ||
766 | (GNUNET_YES == cc->mqm_ready) && | ||
767 | (NULL == cc->task) ) | ||
768 | { | ||
769 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
770 | "Scheduling keepalive for %s in %s\n", | ||
771 | GCC_2s (cc), | ||
772 | GNUNET_STRINGS_relative_time_to_string (keepalive_period, | ||
773 | GNUNET_YES)); | ||
774 | cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period, | ||
775 | &send_keepalive, | ||
776 | cc); | ||
777 | } | ||
778 | break; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | |||
783 | /** | ||
784 | * Create a connection to @a destination via @a path and notify @a cb | ||
785 | * whenever we are ready for more data. Shared logic independent of | ||
786 | * who is initiating the connection. | ||
787 | * | ||
788 | * @param destination where to go | ||
789 | * @param path which path to take (may not be the full path) | ||
790 | * @param off offset of @a destination on @a path | ||
791 | * @param options options for the connection | ||
792 | * @param ct which tunnel uses this connection | ||
793 | * @param init_state initial state for the connection | ||
794 | * @param ready_cb function to call when ready to transmit | ||
795 | * @param ready_cb_cls closure for @a cb | ||
796 | * @return handle to the connection | ||
797 | */ | ||
798 | static struct CadetConnection * | ||
799 | connection_create (struct CadetPeer *destination, | ||
800 | struct CadetPeerPath *path, | ||
801 | unsigned int off, | ||
802 | enum GNUNET_CADET_ChannelOption options, | ||
803 | struct CadetTConnection *ct, | ||
804 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
805 | enum CadetConnectionState init_state, | ||
806 | GCC_ReadyCallback ready_cb, | ||
807 | void *ready_cb_cls) | ||
808 | { | ||
809 | struct CadetConnection *cc; | ||
810 | struct CadetPeer *first_hop; | ||
811 | |||
812 | cc = GNUNET_new (struct CadetConnection); | ||
813 | cc->options = options; | ||
814 | cc->state = init_state; | ||
815 | cc->ct = ct; | ||
816 | cc->cid = *cid; | ||
817 | GNUNET_assert (GNUNET_OK == | ||
818 | GNUNET_CONTAINER_multishortmap_put (connections, | ||
819 | &GCC_get_id (cc)->connection_of_tunnel, | ||
820 | cc, | ||
821 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
822 | cc->ready_cb = ready_cb; | ||
823 | cc->ready_cb_cls = ready_cb_cls; | ||
824 | cc->path = path; | ||
825 | cc->off = off; | ||
826 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
827 | "Creating %s using path %s\n", | ||
828 | GCC_2s (cc), | ||
829 | GCPP_2s (path)); | ||
830 | GCPP_add_connection (path, | ||
831 | off, | ||
832 | cc); | ||
833 | for (unsigned int i=0;i<off;i++) | ||
834 | GCP_add_connection (GCPP_get_peer_at_offset (path, | ||
835 | i), | ||
836 | cc); | ||
837 | |||
838 | first_hop = GCPP_get_peer_at_offset (path, | ||
839 | 0); | ||
840 | cc->mq_man = GCP_request_mq (first_hop, | ||
841 | &manage_first_hop_mq, | ||
842 | cc); | ||
843 | return cc; | ||
844 | } | ||
845 | |||
846 | |||
847 | /** | ||
848 | * Create a connection to @a destination via @a path and | ||
849 | * notify @a cb whenever we are ready for more data. This | ||
850 | * is an inbound tunnel, so we must use the existing @a cid | ||
851 | * | ||
852 | * @param destination where to go | ||
853 | * @param path which path to take (may not be the full path) | ||
854 | * @param options options for the connection | ||
855 | * @param ct which tunnel uses this connection | ||
856 | * @param ready_cb function to call when ready to transmit | ||
857 | * @param ready_cb_cls closure for @a cb | ||
858 | * @return handle to the connection, NULL if we already have | ||
859 | * a connection that takes precedence on @a path | ||
860 | */ | ||
861 | struct CadetConnection * | ||
862 | GCC_create_inbound (struct CadetPeer *destination, | ||
863 | struct CadetPeerPath *path, | ||
864 | enum GNUNET_CADET_ChannelOption options, | ||
865 | struct CadetTConnection *ct, | ||
866 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, | ||
867 | GCC_ReadyCallback ready_cb, | ||
868 | void *ready_cb_cls) | ||
869 | { | ||
870 | struct CadetConnection *cc; | ||
871 | unsigned int off; | ||
872 | |||
873 | off = GCPP_find_peer (path, | ||
874 | destination); | ||
875 | GNUNET_assert (UINT_MAX != off); | ||
876 | cc = GCPP_get_connection (path, | ||
877 | destination, | ||
878 | off); | ||
879 | if (NULL != cc) | ||
880 | { | ||
881 | int cmp; | ||
882 | |||
883 | cmp = memcmp (cid, | ||
884 | &cc->cid, | ||
885 | sizeof (*cid)); | ||
886 | if (0 == cmp) | ||
887 | { | ||
888 | /* Two peers picked the SAME random connection identifier at the | ||
889 | same time for the same path? Must be malicious. Drop | ||
890 | connection (existing and inbound), even if it is the only | ||
891 | one. */ | ||
892 | GNUNET_break_op (0); | ||
893 | GCT_connection_lost (cc->ct); | ||
894 | GCC_destroy_without_tunnel (cc); | ||
895 | return NULL; | ||
896 | } | ||
897 | if (0 < cmp) | ||
898 | { | ||
899 | /* drop existing */ | ||
900 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
901 | "Got two connections on %s, dropping my existing %s\n", | ||
902 | GCPP_2s (path), | ||
903 | GCC_2s (cc)); | ||
904 | GCT_connection_lost (cc->ct); | ||
905 | GCC_destroy_without_tunnel (cc); | ||
906 | } | ||
907 | else | ||
908 | { | ||
909 | /* keep existing */ | ||
910 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
911 | "Got two connections on %s, keeping my existing %s\n", | ||
912 | GCPP_2s (path), | ||
913 | GCC_2s (cc)); | ||
914 | return NULL; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | return connection_create (destination, | ||
919 | path, | ||
920 | off, | ||
921 | options, | ||
922 | ct, | ||
923 | cid, | ||
924 | CADET_CONNECTION_CREATE_RECEIVED, | ||
925 | ready_cb, | ||
926 | ready_cb_cls); | ||
927 | } | ||
928 | |||
929 | |||
930 | /** | ||
931 | * Create a connection to @a destination via @a path and | ||
932 | * notify @a cb whenever we are ready for more data. | ||
933 | * | ||
934 | * @param destination where to go | ||
935 | * @param path which path to take (may not be the full path) | ||
936 | * @param off offset of @a destination on @a path | ||
937 | * @param options options for the connection | ||
938 | * @param ct tunnel that uses the connection | ||
939 | * @param ready_cb function to call when ready to transmit | ||
940 | * @param ready_cb_cls closure for @a cb | ||
941 | * @return handle to the connection | ||
942 | */ | ||
943 | struct CadetConnection * | ||
944 | GCC_create (struct CadetPeer *destination, | ||
945 | struct CadetPeerPath *path, | ||
946 | unsigned int off, | ||
947 | enum GNUNET_CADET_ChannelOption options, | ||
948 | struct CadetTConnection *ct, | ||
949 | GCC_ReadyCallback ready_cb, | ||
950 | void *ready_cb_cls) | ||
951 | { | ||
952 | struct GNUNET_CADET_ConnectionTunnelIdentifier cid; | ||
953 | |||
954 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, | ||
955 | &cid, | ||
956 | sizeof (cid)); | ||
957 | return connection_create (destination, | ||
958 | path, | ||
959 | off, | ||
960 | options, | ||
961 | ct, | ||
962 | &cid, | ||
963 | CADET_CONNECTION_NEW, | ||
964 | ready_cb, | ||
965 | ready_cb_cls); | ||
966 | } | ||
967 | |||
968 | |||
969 | /** | ||
970 | * Transmit message @a msg via connection @a cc. Must only be called | ||
971 | * (once) after the connection has signalled that it is ready via the | ||
972 | * `ready_cb`. Clients can also use #GCC_is_ready() to check if the | ||
973 | * connection is right now ready for transmission. | ||
974 | * | ||
975 | * @param cc connection identification | ||
976 | * @param env envelope with message to transmit; must NOT | ||
977 | * yet have a #GNUNET_MQ_notify_sent() callback attached to it | ||
978 | */ | ||
979 | void | ||
980 | GCC_transmit (struct CadetConnection *cc, | ||
981 | struct GNUNET_MQ_Envelope *env) | ||
982 | { | ||
983 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
984 | "Scheduling message for transmission on %s\n", | ||
985 | GCC_2s (cc)); | ||
986 | GNUNET_assert (GNUNET_YES == cc->mqm_ready); | ||
987 | GNUNET_assert (CADET_CONNECTION_READY == cc->state); | ||
988 | cc->metrics.last_use = GNUNET_TIME_absolute_get (); | ||
989 | cc->mqm_ready = GNUNET_NO; | ||
990 | if (NULL != cc->task) | ||
991 | { | ||
992 | GNUNET_SCHEDULER_cancel (cc->task); | ||
993 | cc->task = NULL; | ||
994 | } | ||
995 | GCP_send (cc->mq_man, | ||
996 | env); | ||
997 | } | ||
998 | |||
999 | |||
1000 | /** | ||
1001 | * Obtain the path used by this connection. | ||
1002 | * | ||
1003 | * @param cc connection | ||
1004 | * @return path to @a cc | ||
1005 | */ | ||
1006 | struct CadetPeerPath * | ||
1007 | GCC_get_path (struct CadetConnection *cc) | ||
1008 | { | ||
1009 | return cc->path; | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | /** | ||
1014 | * Obtain unique ID for the connection. | ||
1015 | * | ||
1016 | * @param cc connection. | ||
1017 | * @return unique number of the connection | ||
1018 | */ | ||
1019 | const struct GNUNET_CADET_ConnectionTunnelIdentifier * | ||
1020 | GCC_get_id (struct CadetConnection *cc) | ||
1021 | { | ||
1022 | return &cc->cid; | ||
1023 | } | ||
1024 | |||
1025 | |||
1026 | /** | ||
1027 | * Get a (static) string for a connection. | ||
1028 | * | ||
1029 | * @param cc Connection. | ||
1030 | */ | ||
1031 | const char * | ||
1032 | GCC_2s (const struct CadetConnection *cc) | ||
1033 | { | ||
1034 | static char buf[128]; | ||
1035 | |||
1036 | if (NULL == cc) | ||
1037 | return "Connection(NULL)"; | ||
1038 | |||
1039 | if (NULL != cc->ct) | ||
1040 | { | ||
1041 | GNUNET_snprintf (buf, | ||
1042 | sizeof (buf), | ||
1043 | "Connection %s (%s)", | ||
1044 | GNUNET_sh2s (&cc->cid.connection_of_tunnel), | ||
1045 | GCT_2s (cc->ct->t)); | ||
1046 | return buf; | ||
1047 | } | ||
1048 | GNUNET_snprintf (buf, | ||
1049 | sizeof (buf), | ||
1050 | "Connection %s", | ||
1051 | GNUNET_sh2s (&cc->cid.connection_of_tunnel)); | ||
1052 | return buf; | ||
1053 | } | ||
1054 | |||
1055 | |||
1056 | #define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__) | ||
1057 | |||
1058 | |||
1059 | /** | ||
1060 | * Log connection info. | ||
1061 | * | ||
1062 | * @param cc connection | ||
1063 | * @param level Debug level to use. | ||
1064 | */ | ||
1065 | void | ||
1066 | GCC_debug (struct CadetConnection *cc, | ||
1067 | enum GNUNET_ErrorType level) | ||
1068 | { | ||
1069 | int do_log; | ||
1070 | |||
1071 | do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), | ||
1072 | "cadet-con", | ||
1073 | __FILE__, __FUNCTION__, __LINE__); | ||
1074 | if (0 == do_log) | ||
1075 | return; | ||
1076 | if (NULL == cc) | ||
1077 | { | ||
1078 | LOG2 (level, | ||
1079 | "Connection (NULL)\n"); | ||
1080 | return; | ||
1081 | } | ||
1082 | LOG2 (level, | ||
1083 | "%s to %s via path %s in state %d is %s\n", | ||
1084 | GCC_2s (cc), | ||
1085 | GCP_2s (cc->destination), | ||
1086 | GCPP_2s (cc->path), | ||
1087 | cc->state, | ||
1088 | (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy"); | ||
1089 | } | ||
1090 | |||
1091 | /* end of gnunet-service-cadet-new_connection.c */ | ||