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