summaryrefslogtreecommitdiff
path: root/src/cadet/gnunet-service-cadet-new_connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cadet/gnunet-service-cadet-new_connection.c')
-rw-r--r--src/cadet/gnunet-service-cadet-new_connection.c665
1 files changed, 665 insertions, 0 deletions
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c
new file mode 100644
index 000000000..bf88d78e1
--- /dev/null
+++ b/src/cadet/gnunet-service-cadet-new_connection.c
@@ -0,0 +1,665 @@
1
2/*
3 This file is part of GNUnet.
4 Copyright (C) 2001-2017 GNUnet e.V.
5
6 GNUnet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your
9 option) any later version.
10
11 GNUnet is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNUnet; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/**
23 * @file cadet/gnunet-service-cadet-new_connection.c
24 * @brief management of CORE-level end-to-end connections; establishes
25 * end-to-end routes and transmits messages along the route
26 * @author Bartlomiej Polot
27 * @author Christian Grothoff
28 *
29 * TODO:
30 * - keepalive messages
31 * - keep performance metrics (?)
32 */
33#include "platform.h"
34#include "gnunet-service-cadet-new_channel.h"
35#include "gnunet-service-cadet-new_connection.h"
36#include "gnunet-service-cadet-new_paths.h"
37#include "gnunet-service-cadet-new_peer.h"
38#include "gnunet-service-cadet-new_tunnels.h"
39#include "gnunet_cadet_service.h"
40#include "cadet_protocol.h"
41
42
43/**
44 * All the states a connection can be in.
45 */
46enum CadetConnectionState
47{
48 /**
49 * Uninitialized status, we have not yet even gotten the message queue.
50 */
51 CADET_CONNECTION_NEW,
52
53 /**
54 * Connection create message in queue, awaiting transmission by CORE.
55 */
56 CADET_CONNECTION_SENDING_CREATE,
57
58 /**
59 * Connection create message sent, waiting for ACK.
60 */
61 CADET_CONNECTION_SENT,
62
63 /**
64 * We are an inbound connection, and received a CREATE. Need to
65 * send an CREATE_ACK back.
66 */
67 CADET_CONNECTION_CREATE_RECEIVED,
68
69 /**
70 * Connection confirmed, ready to carry traffic.
71 */
72 CADET_CONNECTION_READY
73
74};
75
76
77/**
78 * Low-level connection to a destination.
79 */
80struct CadetConnection
81{
82
83 /**
84 * ID of the connection.
85 */
86 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
87
88 /**
89 * To which peer does this connection go?
90 */
91 struct CadetPeer *destination;
92
93 /**
94 * Which tunnel is using this connection?
95 */
96 struct CadetTConnection *ct;
97
98 /**
99 * Path we are using to our destination.
100 */
101 struct CadetPeerPath *path;
102
103 /**
104 * Pending message, NULL if we are ready to transmit.
105 */
106 struct GNUNET_MQ_Envelope *env;
107
108 /**
109 * Handle for calling #GCP_request_mq_cancel() once we are finished.
110 */
111 struct GCP_MessageQueueManager *mq_man;
112
113 /**
114 * Task for connection maintenance.
115 */
116 struct GNUNET_SCHEDULER_Task *task;
117
118 /**
119 * Function to call once we are ready to transmit.
120 */
121 GCC_ReadyCallback ready_cb;
122
123 /**
124 * Closure for @e ready_cb.
125 */
126 void *ready_cb_cls;
127
128 /**
129 * How long do we wait before we try again with a CREATE message?
130 */
131 struct GNUNET_TIME_Relative retry_delay;
132
133 /**
134 * State of the connection.
135 */
136 enum CadetConnectionState state;
137
138 /**
139 * Offset of our @e destination in @e path.
140 */
141 unsigned int off;
142
143 /**
144 * Are we ready to transmit via @e mq_man right now?
145 */
146 int mqm_ready;
147
148};
149
150
151/**
152 * Destroy a connection.
153 *
154 * @param cc connection to destroy
155 */
156void
157GCC_destroy (struct CadetConnection *cc)
158{
159 struct GNUNET_MQ_Envelope *env = NULL;
160
161 if (CADET_CONNECTION_SENDING_CREATE != cc->state)
162 {
163 struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
164
165 /* Need to notify next hop that we are down. */
166 env = GNUNET_MQ_msg (destroy_msg,
167 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
168 destroy_msg->cid = cc->cid;
169 }
170 GCP_request_mq_cancel (cc->mq_man,
171 env);
172 cc->mq_man = NULL;
173 GCPP_del_connection (cc->path,
174 cc->off,
175 cc);
176 GNUNET_assert (GNUNET_YES ==
177 GNUNET_CONTAINER_multishortmap_remove (connections,
178 &GCC_get_id (cc)->connection_of_tunnel,
179 cc));
180 GNUNET_free (cc);
181}
182
183
184/**
185 * Return the tunnel associated with this connection.
186 *
187 * @param cc connection to query
188 * @return corresponding entry in the tunnel's connection list
189 */
190struct CadetTConnection *
191GCC_get_ct (struct CadetConnection *cc)
192{
193 return cc->ct;
194}
195
196
197/**
198 * A connection ACK was received for this connection, implying
199 * that the end-to-end connection is up. Process it.
200 *
201 * @param cc the connection that got the ACK.
202 */
203void
204GCC_handle_connection_ack (struct CadetConnection *cc)
205{
206 if (NULL != cc->task)
207 {
208 GNUNET_SCHEDULER_cancel (cc->task);
209 cc->task = NULL;
210 }
211#if FIXME_KEEPALIVE
212 cc->task = GNUNET_SCHEDULER_add_delayed (cc->keepalive_period,
213 &send_keepalive,
214 cc);
215#endif
216 cc->state = CADET_CONNECTION_READY;
217 if (GNUNET_YES == cc->mqm_ready)
218 cc->ready_cb (cc->ready_cb_cls,
219 GNUNET_YES);
220}
221
222
223/**
224 * Handle KX message.
225 *
226 * @param cc connection that received encrypted message
227 * @param msg the key exchange message
228 */
229void
230GCC_handle_kx (struct CadetConnection *cc,
231 const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
232{
233 if (CADET_CONNECTION_SENT == cc->state)
234 {
235 /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
236 clearly something is working, so pretend we got an ACK. */
237 GCC_handle_connection_ack (cc);
238 }
239 GCT_handle_kx (cc->ct,
240 msg);
241}
242
243
244/**
245 * Handle encrypted message.
246 *
247 * @param cc connection that received encrypted message
248 * @param msg the encrypted message to decrypt
249 */
250void
251GCC_handle_encrypted (struct CadetConnection *cc,
252 const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
253{
254 if (CADET_CONNECTION_SENT == cc->state)
255 {
256 /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
257 clearly something is working, so pretend we got an ACK. */
258 GCC_handle_connection_ack (cc);
259 }
260 GCT_handle_encrypted (cc->ct,
261 msg);
262}
263
264
265/**
266 * Send a CREATE message to the first hop.
267 *
268 * @param cls the `struct CadetConnection` to initiate
269 */
270static void
271send_create (void *cls)
272{
273 struct CadetConnection *cc = cls;
274 struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
275 struct GNUNET_PeerIdentity *pids;
276 struct GNUNET_MQ_Envelope *env;
277 unsigned int path_length;
278
279 cc->task = NULL;
280 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
281 path_length = GCPP_get_length (cc->path);
282 env = GNUNET_MQ_msg_extra (create_msg,
283 path_length * sizeof (struct GNUNET_PeerIdentity),
284 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
285 create_msg->cid = cc->cid;
286 pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
287 for (unsigned int i=0;i<path_length;i++)
288 pids[i] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
289 i));
290 cc->env = env;
291 cc->mqm_ready = GNUNET_NO;
292 cc->state = CADET_CONNECTION_SENT;
293 GCP_send (cc->mq_man,
294 env);
295}
296
297
298/**
299 * Send a CREATE_ACK message towards the origin.
300 *
301 * @param cls the `struct CadetConnection` to initiate
302 */
303static void
304send_create_ack (void *cls)
305{
306 struct CadetConnection *cc = cls;
307 struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
308 struct GNUNET_PeerIdentity *pids;
309 struct GNUNET_MQ_Envelope *env;
310 unsigned int path_length;
311
312 cc->task = NULL;
313 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
314 path_length = GCPP_get_length (cc->path);
315 env = GNUNET_MQ_msg_extra (create_msg,
316 path_length * sizeof (struct GNUNET_PeerIdentity),
317 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
318 create_msg->cid = cc->cid;
319 pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
320 for (unsigned int i=0;i<path_length;i++)
321 pids[i] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
322 i));
323 cc->env = env;
324 cc->mqm_ready = GNUNET_NO;
325 cc->state = CADET_CONNECTION_READY;
326 GCP_send (cc->mq_man,
327 env);
328}
329
330
331/**
332 * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
333 * connection that we already have. Either our ACK got lost
334 * or something is fishy. Consider retransmitting the ACK.
335 *
336 * @param cc connection that got the duplicate CREATE
337 */
338void
339GCC_handle_duplicate_create (struct CadetConnection *cc)
340{
341 if (GNUNET_YES == cc->mqm_ready)
342 {
343 /* Tell tunnel that we are not ready for transmission anymore
344 (until CREATE_ACK is done) */
345 cc->ready_cb (cc->ready_cb_cls,
346 GNUNET_NO);
347
348 /* Revert back to the state of having only received the 'CREATE',
349 and immediately proceed to send the CREATE_ACK. */
350 cc->state = CADET_CONNECTION_CREATE_RECEIVED;
351 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
352 cc);
353 }
354 else
355 {
356 /* We are currently sending something else back, which
357 can only be an ACK or payload, either of which would
358 do. So actually no need to do anything. */
359 }
360}
361
362
363/**
364 * There has been a change in the message queue existence for our
365 * peer at the first hop. Adjust accordingly.
366 *
367 * @param cls the `struct CadetConnection`
368 * @param available #GNUNET_YES if sending is now possible,
369 * #GNUNET_NO if sending is no longer possible
370 * #GNUNET_SYSERR if sending is no longer possible
371 * and the last envelope was discarded
372 */
373static void
374manage_first_hop_mq (void *cls,
375 int available)
376{
377 struct CadetConnection *cc = cls;
378
379 if (GNUNET_YES != available)
380 {
381 /* Connection is down, for now... */
382 cc->mqm_ready = GNUNET_NO;
383 cc->state = CADET_CONNECTION_NEW;
384 cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
385 if (NULL != cc->task)
386 {
387 GNUNET_SCHEDULER_cancel (cc->task);
388 cc->task = NULL;
389 }
390 cc->ready_cb (cc->ready_cb_cls,
391 GNUNET_NO);
392 return;
393 }
394
395 cc->mqm_ready = GNUNET_YES;
396 switch (cc->state)
397 {
398 case CADET_CONNECTION_NEW:
399 /* Transmit immediately */
400 cc->task = GNUNET_SCHEDULER_add_now (&send_create,
401 cc);
402 break;
403 case CADET_CONNECTION_SENDING_CREATE:
404 /* Should not be possible to be called in this state. */
405 GNUNET_assert (0);
406 break;
407 case CADET_CONNECTION_SENT:
408 /* Retry a bit later... */
409 cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
410 cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
411 &send_create,
412 cc);
413 break;
414 case CADET_CONNECTION_CREATE_RECEIVED:
415 /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
416 cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
417 cc);
418 break;
419 case CADET_CONNECTION_READY:
420 cc->ready_cb (cc->ready_cb_cls,
421 GNUNET_YES);
422 break;
423 }
424}
425
426
427/**
428 * Create a connection to @a destination via @a path and notify @a cb
429 * whenever we are ready for more data. Shared logic independent of
430 * who is initiating the connection.
431 *
432 * @param destination where to go
433 * @param path which path to take (may not be the full path)
434 * @param ct which tunnel uses this connection
435 * @param init_state initial state for the connection
436 * @param ready_cb function to call when ready to transmit
437 * @param ready_cb_cls closure for @a cb
438 * @return handle to the connection
439 */
440static struct CadetConnection *
441connection_create (struct CadetPeer *destination,
442 struct CadetPeerPath *path,
443 struct CadetTConnection *ct,
444 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
445 enum CadetConnectionState init_state,
446 GCC_ReadyCallback ready_cb,
447 void *ready_cb_cls)
448{
449 struct CadetConnection *cc;
450 struct CadetPeer *first_hop;
451 unsigned int off;
452
453 off = GCPP_find_peer (path,
454 destination);
455 GNUNET_assert (UINT_MAX > off);
456 cc = GNUNET_new (struct CadetConnection);
457 cc->state = init_state;
458 cc->ct = ct;
459 cc->cid = *cid;
460 GNUNET_assert (GNUNET_OK ==
461 GNUNET_CONTAINER_multishortmap_put (connections,
462 &GCC_get_id (cc)->connection_of_tunnel,
463 cc,
464 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
465 cc->ready_cb = ready_cb;
466 cc->ready_cb_cls = ready_cb_cls;
467 cc->path = path;
468 cc->off = off;
469 GCPP_add_connection (path,
470 off,
471 cc);
472 for (unsigned int i=0;i<off;i++)
473 GCP_add_connection (GCPP_get_peer_at_offset (path,
474 off),
475 cc);
476
477 first_hop = GCPP_get_peer_at_offset (path,
478 0);
479 cc->mq_man = GCP_request_mq (first_hop,
480 &manage_first_hop_mq,
481 cc);
482 return cc;
483}
484
485
486/**
487 * Create a connection to @a destination via @a path and
488 * notify @a cb whenever we are ready for more data. This
489 * is an inbound tunnel, so we must use the existing @a cid
490 *
491 * @param destination where to go
492 * @param path which path to take (may not be the full path)
493 * @param ct which tunnel uses this connection
494 * @param ready_cb function to call when ready to transmit
495 * @param ready_cb_cls closure for @a cb
496 * @return handle to the connection
497 */
498struct CadetConnection *
499GCC_create_inbound (struct CadetPeer *destination,
500 struct CadetPeerPath *path,
501 struct CadetTConnection *ct,
502 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
503 GCC_ReadyCallback ready_cb,
504 void *ready_cb_cls)
505{
506 return connection_create (destination,
507 path,
508 ct,
509 cid,
510 CADET_CONNECTION_CREATE_RECEIVED,
511 ready_cb,
512 ready_cb_cls);
513}
514
515
516/**
517 * Create a connection to @a destination via @a path and
518 * notify @a cb whenever we are ready for more data.
519 *
520 * @param destination where to go
521 * @param path which path to take (may not be the full path)
522 * @param ct tunnel that uses the connection
523 * @param ready_cb function to call when ready to transmit
524 * @param ready_cb_cls closure for @a cb
525 * @return handle to the connection
526 */
527struct CadetConnection *
528GCC_create (struct CadetPeer *destination,
529 struct CadetPeerPath *path,
530 struct CadetTConnection *ct,
531 GCC_ReadyCallback ready_cb,
532 void *ready_cb_cls)
533{
534 struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
535
536 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
537 &cid,
538 sizeof (cid));
539 return connection_create (destination,
540 path,
541 ct,
542 &cid,
543 CADET_CONNECTION_NEW,
544 ready_cb,
545 ready_cb_cls);
546}
547
548
549/**
550 * Transmit message @a msg via connection @a cc. Must only be called
551 * (once) after the connection has signalled that it is ready via the
552 * `ready_cb`. Clients can also use #GCC_is_ready() to check if the
553 * connection is right now ready for transmission.
554 *
555 * @param cc connection identification
556 * @param env envelope with message to transmit; must NOT
557 * yet have a #GNUNET_MQ_notify_sent() callback attached to it
558 */
559void
560GCC_transmit (struct CadetConnection *cc,
561 struct GNUNET_MQ_Envelope *env)
562{
563 GNUNET_assert (GNUNET_YES == cc->mqm_ready);
564 GNUNET_assert (CADET_CONNECTION_READY == cc->state);
565 cc->mqm_ready = GNUNET_NO;
566 GCP_send (cc->mq_man,
567 env);
568}
569
570
571/**
572 * Obtain the path used by this connection.
573 *
574 * @param cc connection
575 * @return path to @a cc
576 */
577struct CadetPeerPath *
578GCC_get_path (struct CadetConnection *cc)
579{
580 return cc->path;
581}
582
583
584/**
585 * Obtain unique ID for the connection.
586 *
587 * @param cc connection.
588 * @return unique number of the connection
589 */
590const struct GNUNET_CADET_ConnectionTunnelIdentifier *
591GCC_get_id (struct CadetConnection *cc)
592{
593 return &cc->cid;
594}
595
596
597/**
598 * Get a (static) string for a connection.
599 *
600 * @param cc Connection.
601 */
602const char *
603GCC_2s (const struct CadetConnection *cc)
604{
605 static char buf[128];
606
607 if (NULL == cc)
608 return "Connection(NULL)";
609
610 if (NULL != cc->ct)
611 {
612 GNUNET_snprintf (buf,
613 sizeof (buf),
614 "Connection(%s(Tunnel(%s)))",
615 GNUNET_sh2s (&cc->cid.connection_of_tunnel),
616 GCT_2s (cc->ct->t));
617 return buf;
618 }
619 GNUNET_snprintf (buf,
620 sizeof (buf),
621 "Connection(%s(Tunnel(NULL)))",
622 GNUNET_sh2s (&cc->cid.connection_of_tunnel));
623 return buf;
624}
625
626
627#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
628
629
630/**
631 * Log connection info.
632 *
633 * @param cc connection
634 * @param level Debug level to use.
635 */
636void
637GCC_debug (struct CadetConnection *cc,
638 enum GNUNET_ErrorType level)
639{
640 int do_log;
641 char *s;
642
643 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
644 "cadet-con",
645 __FILE__, __FUNCTION__, __LINE__);
646 if (0 == do_log)
647 return;
648 if (NULL == cc)
649 {
650 LOG2 (level,
651 "Connection (NULL)\n");
652 return;
653 }
654 s = GCPP_2s (cc->path);
655 LOG2 (level,
656 "Connection %s to %s via path %s in state %d is %s\n",
657 GCC_2s (cc),
658 GCP_2s (cc->destination),
659 s,
660 cc->state,
661 (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
662 GNUNET_free (s);
663}
664
665/* end of gnunet-service-cadet-new_connection.c */