aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-communicator-quic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/gnunet-communicator-quic.c')
-rw-r--r--src/transport/gnunet-communicator-quic.c1796
1 files changed, 1796 insertions, 0 deletions
diff --git a/src/transport/gnunet-communicator-quic.c b/src/transport/gnunet-communicator-quic.c
new file mode 100644
index 000000000..1225a3817
--- /dev/null
+++ b/src/transport/gnunet-communicator-quic.c
@@ -0,0 +1,1796 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018, 2019 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 transport/gnunet-communicator-quic.c
23 * @brief Transport plugin using QUIC.
24 * @author Marshall Stone
25 * @author Martin Schanzenbach
26 *
27 * TODO:
28 * - Automatically generate self-signed x509 certificates and load from config
29 * - Figure out MTU and how we have to handle fragmentation in Quiche.
30 * - Mandate timeouts
31 * - Setup stats handler properly
32 * - Doxygen documentation of methods
33 * - Refactor code shared with UDP and TCP communicator
34 * - Performance testing
35 * - Check for memory leaks with coverity/valgrind
36 */
37#include "gnunet_common.h"
38#include "gnunet_util_lib.h"
39#include "gnunet_core_service.h"
40#include "quiche.h"
41#include "platform.h"
42#include "gnunet_protocols.h"
43#include "gnunet_signatures.h"
44#include "gnunet_constants.h"
45#include "gnunet_statistics_service.h"
46#include "gnunet_transport_application_service.h"
47#include "gnunet_transport_communication_service.h"
48#include "gnunet_nt_lib.h"
49#include "gnunet_nat_service.h"
50#include "stdint.h"
51#include "inttypes.h"
52
53#define COMMUNICATOR_CONFIG_SECTION "communicator-quic"
54#define COMMUNICATOR_ADDRESS_PREFIX "quic"
55#define MAX_DATAGRAM_SIZE 1350
56
57
58/* FIXME: Review all static lengths/contents below. Maybe this can be done smarter */
59/* Currently equivalent to QUICHE_MAX_CONN_ID_LEN */
60#define LOCAL_CONN_ID_LEN 20
61#define MAX_TOKEN_LEN \
62 sizeof("quiche") - 1 \
63 + sizeof(struct sockaddr_storage) \
64 + QUICHE_MAX_CONN_ID_LEN
65#define CID_LEN sizeof(uint8_t) * QUICHE_MAX_CONN_ID_LEN
66#define TOKEN_LEN sizeof (uint8_t) * MAX_TOKEN_LEN
67
68
69/* FIXME: Why 4?
70 Generic, bidirectional, client-initiated quic stream id */
71#define STREAMID_BI 4
72
73/**
74 * How long do we believe our addresses to remain up (before
75 * the other peer should revalidate).
76 */
77#define ADDRESS_VALIDITY_PERIOD GNUNET_TIME_UNIT_HOURS
78
79/**
80 * Map of DCID (uint8_t) -> quic_conn for quickly retrieving connections to other peers.
81 */
82struct GNUNET_CONTAINER_MultiHashMap *conn_map;
83
84/**
85 * Map of sockaddr -> struct PeerAddress
86 */
87struct GNUNET_CONTAINER_MultiHashMap *addr_map;
88
89/**
90 * Handle to the config
91 */
92static const struct GNUNET_CONFIGURATION_Handle *cfg;
93
94/**
95 * FIXME undocumented
96 */
97static struct GNUNET_TIME_Relative rekey_interval;
98
99/**
100 * FIXME undocumented
101 */
102static struct GNUNET_NETWORK_Handle *udp_sock;
103
104/**
105 * FIXME undocumented
106 */
107static struct GNUNET_SCHEDULER_Task *read_task;
108
109/**
110 * FIXME undocumented
111 */
112static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
113
114/**
115 * FIXME undocumented
116 */
117static struct GNUNET_TRANSPORT_ApplicationHandle *ah;
118
119/**
120 * FIXME undocumented
121 */
122static int have_v6_socket;
123
124/**
125 * FIXME undocumented
126 */
127static uint16_t my_port;
128
129/**
130 * FIXME undocumented
131 */
132static unsigned long long rekey_max_bytes;
133
134/**
135 * FIXME undocumented
136 */
137static quiche_config *config = NULL;
138
139/**
140 * Our peer identity
141*/
142struct GNUNET_PeerIdentity my_identity;
143
144/**
145 * Our private key.
146 */
147static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
148
149/**
150 * Connection to NAT service.
151 */
152static struct GNUNET_NAT_Handle *nat;
153
154/**
155 * Information we track per peer we have recently been in contact with.
156 *
157 * (Since quiche handles crypto, handshakes, etc. we don't differentiate
158 * between SenderAddress and ReceiverAddress)
159 * FIXME: But we do a handshake as well. The flag in this struct seems to
160 * indicate this. Update comment!
161 */
162struct PeerAddress
163{
164 /**
165 * To whom are we talking to.
166 */
167 struct GNUNET_PeerIdentity target;
168
169 /**
170 * Flag to indicate whether we know the PeerIdentity (target) yet
171 */
172 int id_rcvd;
173
174 /**
175 * Flag to indicate whether we have sent OUR PeerIdentity to this peer
176 */
177 int id_sent;
178
179 /**
180 * Flag to indicate if we are the initiator of the connection
181 */
182 int is_receiver;
183
184 /**
185 * Address of the receiver in the human-readable format
186 * with the #COMMUNICATOR_ADDRESS_PREFIX.
187 */
188 char *foreign_addr;
189
190 /**
191 * Address of the other peer.
192 */
193 struct sockaddr *address;
194
195 /**
196 * Length of the address.
197 */
198 socklen_t address_len;
199
200 /**
201 * The QUIC connection associated with this peer
202 */
203 struct quic_conn *conn;
204
205 /**
206 * Default message queue we are providing for the #ch.
207 */
208 struct GNUNET_MQ_Handle *d_mq;
209
210 /**
211 * handle for default queue with the #ch.
212 */
213 struct GNUNET_TRANSPORT_QueueHandle *d_qh;
214
215 /**
216 * Timeout for this peer address.
217 */
218 struct GNUNET_TIME_Absolute timeout;
219
220 /**
221 * MTU we allowed transport for this peer's default queue.
222 * FIXME: MTU from quiche
223 */
224 size_t d_mtu;
225
226 /**
227 * Which network type does this queue use?
228 */
229 enum GNUNET_NetworkType nt;
230
231 /**
232 * receiver_destroy already called on receiver.
233 */
234 int peer_destroy_called;
235
236 /**
237 * FIXME implementation missing
238 * Entry in sender expiration heap.
239 */
240 // struct GNUNET_CONTAINER_HeapNode *hn;
241};
242
243// /**
244// * FIXME: Implementation missing
245// * Expiration heap for peers (contains `struct PeerAddress`)
246// */
247// static struct GNUNET_CONTAINER_Heap *peers_heap;
248
249/**
250 * ID of timeout task
251 */
252static struct GNUNET_SCHEDULER_Task *timeout_task;
253
254/**
255 * Network scanner to determine network types.
256 */
257static struct GNUNET_NT_InterfaceScanner *is;
258
259/**
260 * For logging statistics.
261 */
262static struct GNUNET_STATISTICS_Handle *stats;
263
264/**
265 * QUIC connection object. A connection has a unique SCID/DCID pair. Here we store our SCID
266 * (incoming packet DCID field == outgoing packet SCID field) for a given connection. This
267 * is hashed for each unique quic_conn.
268*/
269struct quic_conn
270{
271 uint8_t cid[LOCAL_CONN_ID_LEN];
272
273 quiche_conn *conn;
274};
275
276/**
277 * QUIC_header is used to store information received from an incoming QUIC packet
278*/
279struct QUIC_header
280{
281 uint8_t type;
282 uint32_t version;
283
284 uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
285 size_t scid_len;
286
287 uint8_t dcid[QUICHE_MAX_CONN_ID_LEN];
288 size_t dcid_len;
289
290 uint8_t odcid[QUICHE_MAX_CONN_ID_LEN];
291 size_t odcid_len;
292
293 uint8_t token[MAX_TOKEN_LEN];
294 size_t token_len;
295};
296
297
298/**
299 * Given a PeerAddress, receive data from streams after doing connection logic.
300 * ASSUMES: connection is established to peer
301*/
302static void
303recv_from_streams (struct PeerAddress *peer)
304{
305 char stream_buf[UINT16_MAX];
306 size_t buf_size = UINT16_MAX;
307 char *buf_ptr = stream_buf;
308 struct GNUNET_MessageHeader *hdr;
309
310 uint64_t s = 0;
311 quiche_stream_iter *readable;
312 bool fin;
313 ssize_t recv_len;
314
315 readable = quiche_conn_readable (peer->conn->conn);
316 while (quiche_stream_iter_next (readable, &s))
317 {
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stream %" PRIu64 " is readable\n",
319 s);
320 fin = false;
321 recv_len = quiche_conn_stream_recv (peer->conn->conn, s,
322 (uint8_t *) stream_buf, buf_size,
323 &fin);
324 if (recv_len < 0)
325 {
326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327 "error while receiving data from stream %" PRIu64 "\n", s);
328 break;
329 }
330 /**
331 * FIXME: Do not use implicit booleans. Use GNUNET_YES, GNUNET_NO, GNUNET_SYSERR
332 * and check for that.
333 *
334 * Initial packet should contain peerid if they are the initiator
335 */
336 if (! peer->is_receiver && GNUNET_NO == peer->id_rcvd)
337 {
338 if (recv_len < sizeof(struct GNUNET_PeerIdentity))
339 {
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341 "message recv len of %zd less than length of peer identity\n",
342 recv_len);
343 return;
344 }
345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
346 "received peer identity\n");
347 struct GNUNET_PeerIdentity *pid = (struct
348 GNUNET_PeerIdentity *) stream_buf;
349 peer->target = *pid;
350 peer->id_rcvd = GNUNET_YES;
351 buf_ptr += sizeof(struct GNUNET_PeerIdentity);
352 recv_len -= sizeof(struct GNUNET_PeerIdentity);
353 }
354 /**
355 * Parse messages to pass to communicator
356 */
357 while (recv_len >= sizeof(struct GNUNET_MessageHeader))
358 {
359 hdr = (struct GNUNET_MessageHeader *) buf_ptr;
360 if (ntohs (hdr->size) > recv_len)
361 {
362 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
363 "message size stated (%d) is greater than length of rcvd data (%zd)!\n",
364 ntohs (hdr->size), recv_len);
365 return;
366 }
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "passing %zd bytes to core\n",
368 recv_len);
369 GNUNET_TRANSPORT_communicator_receive (ch, &peer->target, hdr,
370 ADDRESS_VALIDITY_PERIOD, NULL,
371 NULL);
372 recv_len -= ntohs (hdr->size);
373 buf_ptr += ntohs (hdr->size);
374 }
375 /**
376 * Check for leftover bytes
377 */
378 if (0 != recv_len)
379 {
380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
381 "message recv len of %zd less than length of message header\n",
382 recv_len);
383 }
384 /**
385 * FIXME: comment useless
386 * fin
387 */
388 if (fin)
389 {
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "fin received, closing connection\n");
392 if (0 > quiche_conn_close (peer->conn->conn, true, 0, NULL, 0))
393 {
394 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
395 "quiche failed to close connection to peer\n");
396 }
397 }
398 }
399 quiche_stream_iter_free (readable);
400}
401
402
403/**
404 * FIXME: review token generation, assure tokens are generated properly. doxygen
405 */
406static void
407mint_token (const uint8_t *dcid, size_t dcid_len,
408 struct sockaddr_storage *addr, socklen_t addr_len,
409 uint8_t *token, size_t *token_len)
410{
411 GNUNET_memcpy (token, "quiche", sizeof("quiche") - 1);
412 GNUNET_memcpy (token + sizeof("quiche") - 1, addr, addr_len);
413 GNUNET_memcpy (token + sizeof("quiche") - 1 + addr_len, dcid, dcid_len);
414
415 *token_len = sizeof("quiche") - 1 + addr_len + dcid_len;
416}
417
418
419static enum GNUNET_GenericReturnValue
420validate_token (const uint8_t *token, size_t token_len,
421 struct sockaddr_storage *addr, socklen_t addr_len,
422 uint8_t *odcid, size_t *odcid_len)
423{
424 if ((token_len < sizeof("quiche") - 1) ||
425 memcmp (token, "quiche", sizeof("quiche") - 1))
426 {
427 return GNUNET_NO;
428 }
429
430 token += sizeof("quiche") - 1;
431 token_len -= sizeof("quiche") - 1;
432
433 if ((token_len < addr_len) || memcmp (token, addr, addr_len))
434 {
435 return GNUNET_NO;
436 }
437
438 token += addr_len;
439 token_len -= addr_len;
440
441 if (*odcid_len < token_len)
442 {
443 return GNUNET_NO;
444 }
445
446 memcpy (odcid, token, token_len);
447 *odcid_len = token_len;
448
449 return GNUNET_OK;
450}
451
452
453static struct quic_conn*
454create_conn (uint8_t *scid, size_t scid_len,
455 uint8_t *odcid, size_t odcid_len,
456 struct sockaddr *local_addr,
457 socklen_t local_addr_len,
458 struct sockaddr_storage *peer_addr,
459 socklen_t peer_addr_len)
460{
461 struct quic_conn *conn;
462 quiche_conn *q_conn;
463 conn = GNUNET_new (struct quic_conn);
464 if (scid_len != LOCAL_CONN_ID_LEN)
465 {
466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
467 "error while creating connection, scid length too short: %zu\n",
468 scid_len);
469 return NULL;
470 }
471
472 GNUNET_memcpy (conn->cid, scid, LOCAL_CONN_ID_LEN);
473 q_conn = quiche_accept (conn->cid, LOCAL_CONN_ID_LEN,
474 odcid, odcid_len,
475 local_addr,
476 local_addr_len,
477 (struct sockaddr *) peer_addr,
478 peer_addr_len,
479 config);
480 if (NULL == q_conn)
481 {
482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
483 "quiche failed to create connection after call to quiche_accept\n");
484 return NULL;
485 }
486 conn->conn = q_conn;
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new quic connection created\n");
488 return conn;
489}
490
491
492static void
493flush_egress (struct quic_conn *conn)
494{
495 static uint8_t out[MAX_DATAGRAM_SIZE];
496 quiche_send_info send_info;
497
498 ssize_t written;
499 ssize_t sent;
500
501 while (1)
502 {
503 written = quiche_conn_send (conn->conn, out, sizeof(out), &send_info);
504 if (QUICHE_ERR_DONE == written)
505 {
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done writing quic packets\n");
507 break;
508 }
509 if (0 > written)
510 {
511 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
512 "quiche failed to create packet. quiche error: %zd\n",
513 written);
514 return;
515 }
516 sent = GNUNET_NETWORK_socket_sendto (udp_sock, out, written,
517 (struct sockaddr *) &send_info.to,
518 send_info.to_len);
519 if (sent != written)
520 {
521 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
522 "quiche failed to send data to peer\n");
523 return;
524 }
525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent %zd bytes\n", sent);
526 }
527}
528
529
530/**
531 * Increment receiver timeout due to activity.
532 *
533 * @param receiver address for which the timeout should be rescheduled
534 */
535static void
536reschedule_peer_timeout (struct PeerAddress *peer)
537{
538 peer->timeout =
539 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
540 // GNUNET_CONTAINER_heap_update_cost (peer->hn,
541 // peer->timeout.abs_value_us);
542}
543
544
545/**
546 * Destroys a receiving state due to timeout or shutdown.
547 *
548 * @param receiver entity to close down
549 */
550static void
551peer_destroy (struct PeerAddress *peer)
552{
553 struct GNUNET_HashCode addr_key;
554
555 peer->peer_destroy_called = GNUNET_YES;
556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557 "Disconnecting peer for peer `%s'\n",
558 GNUNET_i2s (&peer->target));
559 if (NULL != peer->d_qh)
560 {
561 GNUNET_TRANSPORT_communicator_mq_del (peer->d_qh);
562 peer->d_qh = NULL;
563 }
564 // GNUNET_assert (peer == GNUNET_CONTAINER_heap_remove_node (peer->hn));
565 /**
566 * Remove peer from hashmap
567 */
568 GNUNET_CRYPTO_hash (peer->address, peer->address_len, &addr_key);
569 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (addr_map, &addr_key,
570 peer))
571 {
572 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573 "tried to remove non-existent peer from addr map\n");
574 return;
575 }
576 GNUNET_STATISTICS_set (stats,
577 "# peers active",
578 GNUNET_CONTAINER_multihashmap_size (addr_map),
579 GNUNET_NO);
580 quiche_conn_free (peer->conn->conn);
581 GNUNET_free (peer->address);
582 GNUNET_free (peer->foreign_addr);
583 GNUNET_free (peer->conn);
584 GNUNET_free (peer);
585}
586
587
588/**
589 * Iterator over all peers to clean up.
590 *
591 * @param cls NULL
592 * @param key peer->address
593 * @param value the peer to destroy
594 * @return #GNUNET_OK to continue to iterate
595 */
596static int
597get_peer_delete_it (void *cls,
598 const struct GNUNET_HashCode *key,
599 void *value)
600{
601 struct PeerAddress *peer = value;
602 (void) cls;
603 (void) key;
604 peer_destroy (peer);
605 return GNUNET_OK;
606}
607
608
609/**
610 * Signature of functions implementing the sending functionality of a
611 * message queue.
612 *
613 * @param mq the message queue
614 * @param msg the message to send
615 * @param impl_state our `struct PeerAddress`
616 */
617static void
618mq_send_d (struct GNUNET_MQ_Handle *mq,
619 const struct GNUNET_MessageHeader *msg,
620 void *impl_state)
621{
622 struct PeerAddress *peer = impl_state;
623 uint16_t msize = ntohs (msg->size);
624 ssize_t send_len;
625
626 if (NULL == peer->conn->conn)
627 {
628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
629 "peer never established quic connection\n");
630 return;
631 }
632
633 GNUNET_assert (mq == peer->d_mq);
634 if (msize > peer->d_mtu)
635 {
636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
637 "msize: %u, mtu: %lu\n",
638 msize,
639 peer->d_mtu);
640 GNUNET_break (0);
641 if (GNUNET_YES != peer->peer_destroy_called)
642 {
643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
644 "peer destroy called, destroying peer\n");
645 peer_destroy (peer);
646 }
647 return;
648 }
649 reschedule_peer_timeout (peer);
650
651 send_len = quiche_conn_stream_send (peer->conn->conn, 4, (uint8_t *) msg,
652 msize, false);
653 if (send_len != msize)
654 {
655 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
656 "tried to send message and quiche returned %zd", send_len);
657 return;
658 }
659 flush_egress (peer->conn);
660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
661 "sent a message of %zd bytes\n", send_len);
662 GNUNET_MQ_impl_send_continue (mq);
663}
664
665
666/**
667 * Signature of functions implementing the destruction of a message
668 * queue. Implementations must not free @a mq, but should take care
669 * of @a impl_state.
670 *
671 * @param mq the message queue to destroy
672 * @param impl_state our `struct PeerAddress`
673 */
674static void
675mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state)
676{
677 struct PeerAddress *peer = impl_state;
678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679 "Default MQ destroyed\n");
680 if (mq == peer->d_mq)
681 {
682 peer->d_mq = NULL;
683 if (GNUNET_YES != peer->peer_destroy_called)
684 peer_destroy (peer);
685 }
686}
687
688
689/**
690 * Implementation function that cancels the currently sent message.
691 *
692 * @param mq message queue
693 * @param impl_state our `struct PeerAddress`
694 */
695static void
696mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
697{
698 /* Cancellation is impossible with QUIC; bail */
699 GNUNET_assert (0);
700}
701
702
703/**
704 * Generic error handler, called with the appropriate
705 * error code and the same closure specified at the creation of
706 * the message queue.
707 * Not every message queue implementation supports an error handler.
708 *
709 * @param cls our `struct ReceiverAddress`
710 * @param error error code
711 */
712static void
713mq_error (void *cls, enum GNUNET_MQ_Error error)
714{
715 struct PeerAddress *peer = cls;
716
717 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
718 "MQ error in queue to %s: %d\n",
719 GNUNET_i2s (&peer->target),
720 (int) error);
721 peer_destroy (peer);
722}
723
724
725/**
726 * Convert UDP bind specification to a `struct sockaddr *`
727 *
728 * @param bindto bind specification to convert
729 * @param[out] sock_len set to the length of the address
730 * @return converted bindto specification
731 */
732static struct sockaddr *
733udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
734{
735 struct sockaddr *in;
736 unsigned int port;
737 char dummy[2];
738 char *colon;
739 char *cp;
740
741 if (1 == sscanf (bindto, "%u%1s", &port, dummy))
742 {
743 /* interpreting value as just a PORT number */
744 if (port > UINT16_MAX)
745 {
746 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
747 "BINDTO specification `%s' invalid: value too large for port\n",
748 bindto);
749 return NULL;
750 }
751 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
752 (GNUNET_YES ==
753 GNUNET_CONFIGURATION_get_value_yesno (cfg,
754 COMMUNICATOR_CONFIG_SECTION,
755 "DISABLE_V6")))
756 {
757 struct sockaddr_in *i4;
758
759 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
760 i4->sin_family = AF_INET;
761 i4->sin_port = htons ((uint16_t) port);
762 *sock_len = sizeof(struct sockaddr_in);
763 in = (struct sockaddr *) i4;
764 }
765 else
766 {
767 struct sockaddr_in6 *i6;
768
769 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
770 i6->sin6_family = AF_INET6;
771 i6->sin6_port = htons ((uint16_t) port);
772 *sock_len = sizeof(struct sockaddr_in6);
773 in = (struct sockaddr *) i6;
774 }
775 return in;
776 }
777 cp = GNUNET_strdup (bindto);
778 colon = strrchr (cp, ':');
779 if (NULL != colon)
780 {
781 /* interpret value after colon as port */
782 *colon = '\0';
783 colon++;
784 if (1 == sscanf (colon, "%u%1s", &port, dummy))
785 {
786 /* interpreting value as just a PORT number */
787 if (port > UINT16_MAX)
788 {
789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790 "BINDTO specification `%s' invalid: value too large for port\n",
791 bindto);
792 GNUNET_free (cp);
793 return NULL;
794 }
795 }
796 else
797 {
798 GNUNET_log (
799 GNUNET_ERROR_TYPE_ERROR,
800 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
801 bindto);
802 GNUNET_free (cp);
803 return NULL;
804 }
805 }
806 else
807 {
808 /* interpret missing port as 0, aka pick any free one */
809 port = 0;
810 }
811 {
812 /* try IPv4 */
813 struct sockaddr_in v4;
814
815 memset (&v4, 0, sizeof(v4));
816 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
817 {
818 v4.sin_family = AF_INET;
819 v4.sin_port = htons ((uint16_t) port);
820#if HAVE_SOCKADDR_IN_SIN_LEN
821 v4.sin_len = sizeof(struct sockaddr_in);
822#endif
823 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
824 *sock_len = sizeof(struct sockaddr_in);
825 GNUNET_free (cp);
826 return in;
827 }
828 }
829 {
830 /* try IPv6 */
831 struct sockaddr_in6 v6;
832 const char *start;
833
834 memset (&v6, 0, sizeof(v6));
835 start = cp;
836 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
837 {
838 start++; /* skip over '[' */
839 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
840 }
841 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
842 {
843 v6.sin6_family = AF_INET6;
844 v6.sin6_port = htons ((uint16_t) port);
845#if HAVE_SOCKADDR_IN_SIN_LEN
846 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
847#endif
848 in = GNUNET_memdup (&v6, sizeof(v6));
849 *sock_len = sizeof(v6);
850 GNUNET_free (cp);
851 return in;
852 }
853 }
854 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
855 GNUNET_free (cp);
856 return NULL;
857}
858
859
860/**
861 * Setup the MQ for the @a peer. If a queue exists,
862 * the existing one is destroyed. Then the MTU is
863 * recalculated and a fresh queue is initialized.
864 *
865 * @param peer peer to setup MQ for
866 */
867static void
868setup_peer_mq (struct PeerAddress *peer)
869{
870 size_t base_mtu;
871
872 switch (peer->address->sa_family)
873 {
874 case AF_INET:
875 base_mtu = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
876 - sizeof(struct GNUNET_TUN_IPv4Header) /* 20 */
877 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
878 break;
879
880 case AF_INET6:
881 base_mtu = 1280 /* Minimum MTU required by IPv6 */
882 - sizeof(struct GNUNET_TUN_IPv6Header) /* 40 */
883 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
884 break;
885
886 default:
887 GNUNET_assert (0);
888 break;
889 }
890 /* MTU == base_mtu */
891 peer->d_mtu = base_mtu;
892
893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
894 "Setting up MQs and QHs\n");
895 /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
896 1404 (IPv4 + Box) bytes, depending on circumstances... */
897
898 if (NULL == peer->d_mq)
899 peer->d_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_d,
900 &mq_destroy_d,
901 &mq_cancel,
902 peer,
903 NULL,
904 &mq_error,
905 peer);
906 peer->d_qh =
907 GNUNET_TRANSPORT_communicator_mq_add (ch,
908 &peer->target,
909 peer->foreign_addr,
910 1000,
911 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
912 0, /* Priority */
913 peer->nt,
914 GNUNET_TRANSPORT_CS_OUTBOUND,
915 peer->d_mq);
916}
917
918
919/**
920 * Taken from: UDP communicator
921 * Converts @a address to the address string format used by this
922 * communicator in HELLOs.
923 *
924 * @param address the address to convert, must be AF_INET or AF_INET6.
925 * @param address_len number of bytes in @a address
926 * @return string representation of @a address
927 */
928static char *
929sockaddr_to_udpaddr_string (const struct sockaddr *address,
930 socklen_t address_len)
931{
932 char *ret;
933
934 switch (address->sa_family)
935 {
936 case AF_INET:
937 GNUNET_asprintf (&ret,
938 "%s-%s",
939 COMMUNICATOR_ADDRESS_PREFIX,
940 GNUNET_a2s (address, address_len));
941 break;
942
943 case AF_INET6:
944 GNUNET_asprintf (&ret,
945 "%s-%s",
946 COMMUNICATOR_ADDRESS_PREFIX,
947 GNUNET_a2s (address, address_len));
948 break;
949
950 default:
951 GNUNET_assert (0);
952 }
953 return ret;
954}
955
956
957/**
958 * Function called when the transport service has received a
959 * backchannel message for this communicator (!) via a different return
960 * path. Should be an acknowledgement.
961 *
962 * @param cls closure, NULL
963 * @param sender which peer sent the notification
964 * @param msg payload
965 */
966static void
967notify_cb (void *cls,
968 const struct GNUNET_PeerIdentity *sender,
969 const struct GNUNET_MessageHeader *msg)
970{
971 // const struct UDPAck *ack;
972
973 // (void) cls;
974 // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975 // "Storing UDPAck received from backchannel from %s\n",
976 // GNUNET_i2s_full (sender));
977 // if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK) ||
978 // (ntohs (msg->size) != sizeof(struct UDPAck)))
979 // {
980 // GNUNET_break_op (0);
981 // return;
982 // }
983 // ack = (const struct UDPAck *) msg;
984 // GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
985 // sender,
986 // &handle_ack,
987 // (void *) ack);
988}
989
990
991/**
992 * Task run to check #receiver_heap and #sender_heap for timeouts.
993 *
994 * @param cls unused, NULL
995 */
996static void
997check_timeouts (void *cls)
998{
999 // struct GNUNET_TIME_Relative st;
1000 // struct GNUNET_TIME_Relative rt;
1001 // struct GNUNET_TIME_Relative delay;
1002 // struct ReceiverAddress *receiver;
1003 // struct SenderAddress *sender;
1004
1005 // (void) cls;
1006 // timeout_task = NULL;
1007 // rt = GNUNET_TIME_UNIT_FOREVER_REL;
1008 // while (NULL != (receiver = GNUNET_CONTAINER_heap_peek (receivers_heap)))
1009 // {
1010 // /* if (GNUNET_YES != receiver->receiver_destroy_called) */
1011 // /* { */
1012 // rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout);
1013 // if (0 != rt.rel_value_us)
1014 // break;
1015 // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 // "Receiver timed out\n");
1017 // receiver_destroy (receiver);
1018 // // }
1019 // }
1020 // st = GNUNET_TIME_UNIT_FOREVER_REL;
1021 // while (NULL != (sender = GNUNET_CONTAINER_heap_peek (senders_heap)))
1022 // {
1023 // if (GNUNET_YES != sender->sender_destroy_called)
1024 // {
1025 // st = GNUNET_TIME_absolute_get_remaining (sender->timeout);
1026 // if (0 != st.rel_value_us)
1027 // break;
1028 // sender_destroy (sender);
1029 // }
1030 // }
1031 // delay = GNUNET_TIME_relative_min (rt, st);
1032 // if (delay.rel_value_us < GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1033 // timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &check_timeouts, NULL);
1034}
1035
1036
1037/**
1038 * Function called by the transport service to initialize a
1039 * message queue given address information about another peer.
1040 * If and when the communication channel is established, the
1041 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
1042 * to notify the service that the channel is now up. It is
1043 * the responsibility of the communicator to manage sane
1044 * retries and timeouts for any @a peer/@a address combination
1045 * provided by the transport service. Timeouts and retries
1046 * do not need to be signalled to the transport service.
1047 *
1048 * @param cls closure
1049 * @param peer identity of the other peer
1050 * @param address where to send the message, human-readable
1051 * communicator-specific format, 0-terminated, UTF-8
1052 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
1053 * invalid
1054 */
1055static int
1056mq_init (void *cls, const struct GNUNET_PeerIdentity *peer_id, const
1057 char *address)
1058{
1059 struct PeerAddress *peer;
1060 const char *path;
1061 struct sockaddr *in;
1062 socklen_t in_len;
1063 struct GNUNET_HashCode addr_key;
1064 uint8_t scid[LOCAL_CONN_ID_LEN];
1065
1066 struct quic_conn *q_conn;
1067 char *bindto;
1068 socklen_t local_in_len;
1069 struct sockaddr *local_addr;
1070
1071 if (GNUNET_OK !=
1072 GNUNET_CONFIGURATION_get_value_string (cfg,
1073 COMMUNICATOR_CONFIG_SECTION,
1074 "BINDTO",
1075 &bindto))
1076 {
1077 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1078 COMMUNICATOR_CONFIG_SECTION,
1079 "BINDTO");
1080 return GNUNET_SYSERR;
1081 }
1082 local_addr = udp_address_to_sockaddr (bindto, &local_in_len);
1083
1084 if (0 != strncmp (address,
1085 COMMUNICATOR_ADDRESS_PREFIX "-",
1086 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
1087 {
1088 GNUNET_break_op (0);
1089 return GNUNET_SYSERR;
1090 }
1091 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
1092 in = udp_address_to_sockaddr (path, &in_len);
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mq_init in_len length before: %d\n",
1094 in_len);
1095 /**
1096 * If we already have a queue with this peer, ignore
1097 */
1098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address string in mq_init: %s\n",
1099 address);
1100 GNUNET_CRYPTO_hash (address, strlen (address), &addr_key);
1101 peer = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key);
1102 if (NULL != peer)
1103 {
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "ignoring transport service mq request, we already have an mq with this peer (address)\n");
1106 return GNUNET_SYSERR;
1107 }
1108 peer = GNUNET_new (struct PeerAddress);
1109 peer->address = in;
1110 peer->address_len = in_len;
1111 peer->target = *peer_id;
1112 peer->id_rcvd = GNUNET_YES;
1113 peer->is_receiver = GNUNET_YES;
1114 peer->nt = GNUNET_NT_scanner_get_type (is, in, in_len);
1115 peer->timeout =
1116 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1117 GNUNET_STATISTICS_set (stats,
1118 "# peers active",
1119 GNUNET_CONTAINER_multihashmap_size (addr_map),
1120 GNUNET_NO);
1121 peer->foreign_addr =
1122 sockaddr_to_udpaddr_string (peer->address, peer->address_len);
1123 /**
1124 * Insert peer into hashmap
1125 */
1126 GNUNET_CONTAINER_multihashmap_put (addr_map, &addr_key,
1127 peer,
1128 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1130 "mq_init added new peer to the addr map\n");
1131 /**
1132 * Before setting up peer mq, initiate a quic connection to the target (perform handshake w/ quiche)
1133 */
1134 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, scid,
1135 LOCAL_CONN_ID_LEN);
1136 q_conn = GNUNET_new (struct quic_conn);
1137 GNUNET_memcpy (q_conn->cid, scid, LOCAL_CONN_ID_LEN);
1138 peer->conn = q_conn;
1139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1140 "attempting to perform QUIC handshake with peer\n");
1141 q_conn->conn = quiche_connect (peer->foreign_addr, scid, LOCAL_CONN_ID_LEN,
1142 local_addr,
1143 local_in_len, peer->address, peer->address_len,
1144 config);
1145 flush_egress (peer->conn);
1146 GNUNET_free (local_addr);
1147 return GNUNET_OK;
1148 /**
1149 * TODO: handle this
1150 */
1151 // if (NULL == timeout_task)
1152 // timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
1153}
1154
1155
1156static void
1157try_connection_reversal (void *cls,
1158 const struct sockaddr *addr,
1159 socklen_t addrlen)
1160{
1161 /* FIXME: support reversal: #5529 */
1162 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1163 "No connection reversal implemented!");
1164}
1165
1166
1167/**
1168 * Signature of the callback passed to #GNUNET_NAT_register() for
1169 * a function to call whenever our set of 'valid' addresses changes.
1170 *
1171 * @param cls closure
1172 * @param app_ctx[in,out] location where the app can store stuff
1173 * on add and retrieve it on remove
1174 * @param add_remove #GNUNET_YES to add a new public IP address,
1175 * #GNUNET_NO to remove a previous (now invalid) one
1176 * @param ac address class the address belongs to
1177 * @param addr either the previous or the new public IP address
1178 * @param addrlen actual length of the @a addr
1179 */
1180static void
1181nat_address_cb (void *cls,
1182 void **app_ctx,
1183 int add_remove,
1184 enum GNUNET_NAT_AddressClass ac,
1185 const struct sockaddr *addr,
1186 socklen_t addrlen)
1187{
1188 char *my_addr;
1189 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
1190
1191 if (GNUNET_YES == add_remove)
1192 {
1193 enum GNUNET_NetworkType nt;
1194
1195 GNUNET_asprintf (&my_addr,
1196 "%s-%s",
1197 COMMUNICATOR_ADDRESS_PREFIX,
1198 GNUNET_a2s (addr, addrlen));
1199 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
1200 ai =
1201 GNUNET_TRANSPORT_communicator_address_add (ch,
1202 my_addr,
1203 nt,
1204 GNUNET_TIME_UNIT_FOREVER_REL);
1205 GNUNET_free (my_addr);
1206 *app_ctx = ai;
1207 }
1208 else
1209 {
1210 ai = *app_ctx;
1211 GNUNET_TRANSPORT_communicator_address_remove (ai);
1212 *app_ctx = NULL;
1213 }
1214}
1215
1216
1217/**
1218 * Shutdown the QUIC communicator.
1219 *
1220 * @param cls NULL (always)
1221 */
1222static void
1223do_shutdown (void *cls)
1224{
1225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1226 "do_shutdown\n");
1227 GNUNET_CONTAINER_multihashmap_iterate (addr_map, &get_peer_delete_it, NULL);
1228 GNUNET_CONTAINER_multihashmap_destroy (addr_map);
1229 quiche_config_free (config);
1230
1231 if (NULL != timeout_task)
1232 {
1233 GNUNET_SCHEDULER_cancel (timeout_task);
1234 timeout_task = NULL;
1235 }
1236 if (NULL != read_task)
1237 {
1238 GNUNET_SCHEDULER_cancel (read_task);
1239 read_task = NULL;
1240 }
1241 if (NULL != udp_sock)
1242 {
1243 GNUNET_break (GNUNET_OK ==
1244 GNUNET_NETWORK_socket_close (udp_sock));
1245 udp_sock = NULL;
1246 }
1247 if (NULL != ch)
1248 {
1249 GNUNET_TRANSPORT_communicator_disconnect (ch);
1250 ch = NULL;
1251 }
1252 if (NULL != ah)
1253 {
1254 GNUNET_TRANSPORT_application_done (ah);
1255 ah = NULL;
1256 }
1257 if (NULL != my_private_key)
1258 {
1259 GNUNET_free (my_private_key);
1260 my_private_key = NULL;
1261 }
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263 "do_shutdown finished\n");
1264}
1265
1266
1267static void
1268sock_read (void *cls)
1269{
1270 struct sockaddr_storage sa;
1271 struct sockaddr_in *addr_verify;
1272 socklen_t salen = sizeof(sa);
1273 uint8_t buf[UINT16_MAX];
1274 uint8_t out[MAX_DATAGRAM_SIZE];
1275 ssize_t rcvd;
1276
1277 ssize_t process_pkt;
1278 struct QUIC_header quic_header;
1279 uint8_t new_cid[LOCAL_CONN_ID_LEN];
1280
1281 struct PeerAddress *peer;
1282 struct GNUNET_HashCode addr_key;
1283
1284 (void) cls;
1285 quic_header.scid_len = sizeof(quic_header.scid);
1286 quic_header.dcid_len = sizeof(quic_header.dcid);
1287 quic_header.odcid_len = sizeof(quic_header.odcid);
1288 quic_header.token_len = sizeof(quic_header.token);
1289 /**
1290 * Get local_addr, in_len for quiche
1291 */
1292 char *bindto;
1293 socklen_t in_len;
1294 if (GNUNET_OK !=
1295 GNUNET_CONFIGURATION_get_value_string (cfg,
1296 COMMUNICATOR_CONFIG_SECTION,
1297 "BINDTO",
1298 &bindto))
1299 {
1300 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1301 COMMUNICATOR_CONFIG_SECTION,
1302 "BINDTO");
1303 return;
1304 }
1305 struct sockaddr *local_addr = udp_address_to_sockaddr (bindto, &in_len);
1306
1307 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1308 udp_sock,
1309 &sock_read,
1310 NULL);
1311 while (1)
1312 {
1313 rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock,
1314 buf,
1315 sizeof(buf),
1316 (struct sockaddr *) &sa,
1317 &salen);
1318 if (-1 == rcvd)
1319 {
1320 if (EAGAIN == errno)
1321 break; // We are done reading data
1322 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1323 return;
1324 }
1325
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327 "Read %lu bytes\n", rcvd);
1328
1329 if (-1 == rcvd)
1330 {
1331 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1332 return;
1333 }
1334 /**
1335 * FIXME: hashing address string vs ip/port. It is not ideal that
1336 * we hash the string, instead of the binary representation, but
1337 * for now it is certainly less code.
1338 * Note that simply hashing the sockaddr does NOT work because the
1339 * the struct is not portable.
1340 */
1341 const char *addr_string = sockaddr_to_udpaddr_string ((const struct
1342 sockaddr *) &sa,
1343 salen);
1344 GNUNET_CRYPTO_hash (addr_string, strlen (addr_string),
1345 &addr_key);
1346 GNUNET_free (addr_string);
1347 peer = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key);
1348
1349 if (NULL == peer)
1350 {
1351 /**
1352 * Create new PeerAddress (receiver) with id_rcvd = false
1353 */
1354 peer = GNUNET_new (struct PeerAddress);
1355 peer->address = GNUNET_memdup (&sa, salen);
1356 peer->address_len = salen;
1357 peer->id_rcvd = GNUNET_NO;
1358 peer->id_sent = GNUNET_NO;
1359 peer->is_receiver = GNUNET_NO;
1360 peer->conn = NULL;
1361 peer->foreign_addr = sockaddr_to_udpaddr_string (peer->address,
1362 peer->address_len);
1363 /**
1364 * TODO: after connection established
1365 */
1366 // setup_peer_mq (peer);
1367 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (addr_map,
1368 &addr_key,
1369 peer,
1370 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1371 {
1372 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1373 "tried to add duplicate address into address map\n");
1374 return;
1375 }
1376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1377 "sock_read added new peer to address map\n");
1378 }
1379
1380 /**
1381 * Parse QUIC info
1382 */
1383 int rc = quiche_header_info (buf, rcvd, LOCAL_CONN_ID_LEN,
1384 &quic_header.version,
1385 &quic_header.type, quic_header.scid,
1386 &quic_header.scid_len, quic_header.dcid,
1387 &quic_header.dcid_len,
1388 quic_header.token, &quic_header.token_len);
1389 if (0 > rc)
1390 {
1391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1392 "failed to parse quic header: %d\n",
1393 rc);
1394 return;
1395 }
1396
1397 /**
1398 * New QUIC connection with peer
1399 */
1400 if (NULL == peer->conn)
1401 {
1402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1403 "attempting to create new connection\n");
1404 if (0 == quiche_version_is_supported (quic_header.version))
1405 {
1406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1407 "quic version negotiation initiated\n");
1408 /**
1409 * FIXME variables are redeclared often. Refactor either
1410 * to declare variables once in the beginning or refactor into
1411 * method.
1412 *
1413 * Write a version negotiation packet to "out"
1414 */
1415 ssize_t written = quiche_negotiate_version (quic_header.scid,
1416 quic_header.scid_len,
1417 quic_header.dcid,
1418 quic_header.dcid_len,
1419 out, sizeof(out));
1420 if (0 > written)
1421 {
1422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1423 "quiche failed to generate version negotiation packet\n");
1424 return;
1425 }
1426 ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock,
1427 out,
1428 written,
1429 (struct sockaddr*) &sa,
1430 salen);
1431 if (sent != written)
1432 {
1433 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1434 "failed to send version negotiation packet to peer\n");
1435 return;
1436 }
1437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1438 "sent %zd bytes to peer during version negotiation\n",
1439 sent);
1440 return;
1441 }
1442
1443 if (0 == quic_header.token_len)
1444 {
1445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "quic stateless retry\n");
1446 mint_token (quic_header.dcid, quic_header.dcid_len, &sa, salen,
1447 quic_header.token, &quic_header.token_len);
1448
1449 uint8_t new_cid[LOCAL_CONN_ID_LEN];
1450 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, new_cid,
1451 LOCAL_CONN_ID_LEN);
1452
1453 ssize_t written = quiche_retry (quic_header.scid, quic_header.scid_len,
1454 quic_header.dcid, quic_header.dcid_len,
1455 new_cid, LOCAL_CONN_ID_LEN,
1456 quic_header.token,
1457 quic_header.token_len,
1458 quic_header.version, out, sizeof(out));
1459 if (0 > written)
1460 {
1461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1462 "quiche failed to write retry packet\n");
1463 return;
1464 }
1465 ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock,
1466 out,
1467 written,
1468 (struct sockaddr*) &sa,
1469 salen);
1470 if (written != sent)
1471 {
1472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failed to send retry packet\n");
1473 return;
1474 }
1475
1476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent %zd bytes\n", sent);
1477 continue;
1478 }
1479
1480 if (GNUNET_OK != validate_token (quic_header.token, quic_header.token_len,
1481 &sa, salen,
1482 quic_header.odcid,
1483 &quic_header.odcid_len))
1484 {
1485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1486 "invalid address validation token created\n");
1487 return;
1488 }
1489 peer->conn = create_conn (quic_header.dcid, quic_header.dcid_len,
1490 quic_header.odcid, quic_header.odcid_len,
1491 local_addr, in_len,
1492 &sa, salen);
1493 if (NULL == peer->conn)
1494 {
1495 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1496 "failed to create quic connection with peer\n");
1497 return;
1498 }
1499 } // null connection
1500
1501 quiche_recv_info recv_info = {
1502 (struct sockaddr *) &sa,
1503 salen,
1504
1505 local_addr,
1506 in_len,
1507 };
1508 /**
1509 * Send our PeerIdentity if the connection is established now
1510 */
1511 if (quiche_conn_is_established (peer->conn->conn) && ! peer->id_sent &&
1512 peer->is_receiver)
1513 {
1514 ssize_t send_len;
1515
1516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1517 "handshake established with peer, sending our peer id\n");
1518 send_len = quiche_conn_stream_send (peer->conn->conn, STREAMID_BI,
1519 (const uint8_t *) &my_identity,
1520 sizeof(my_identity),
1521 false);
1522 if (0 > send_len)
1523 {
1524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1525 "failed to write peer identity packet. quiche error: %zd\n",
1526 send_len);
1527 return;
1528 }
1529 flush_egress (peer->conn);
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer identity sent to peer\n");
1531 peer->id_sent = GNUNET_YES;
1532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "setting up peer mq\n");
1533 setup_peer_mq (peer);
1534 /**
1535 * After this, we should be all good to send/recv data
1536 */
1537 }
1538 process_pkt = quiche_conn_recv (peer->conn->conn, buf, rcvd, &recv_info);
1539 if (0 > process_pkt)
1540 {
1541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1542 "quiche failed to process received packet: %zd\n",
1543 process_pkt);
1544 return;
1545 }
1546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1547 "quiche processed %zd bytes\n", process_pkt);
1548 // Check for data on all available streams if the connection is established
1549 if (GNUNET_YES == quiche_conn_is_established (peer->conn->conn))
1550 {
1551 recv_from_streams (peer);
1552 }
1553 /**
1554 * TODO: Should we use a list instead of hashmap?
1555 * Overhead for hashing function, O(1) retrieval vs O(n) iteration with n=30?
1556 *
1557 * TODO: Is iteration necessary as in the quiche server example?
1558 */
1559 quiche_stats stats;
1560 quiche_path_stats path_stats;
1561
1562 flush_egress (peer->conn);
1563
1564 if (quiche_conn_is_closed (peer->conn->conn))
1565 {
1566 quiche_conn_stats (peer->conn->conn, &stats);
1567 quiche_conn_path_stats (peer->conn->conn, 0, &path_stats);
1568
1569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570 "connection closed. quiche stats: sent=%zu, recv=%zu\n",
1571 stats.sent, stats.recv);
1572 peer_destroy (peer);
1573 }
1574 }
1575 GNUNET_free (local_addr);
1576}
1577
1578
1579/**
1580 * Setup communicator and launch network interactions.
1581 *
1582 * @param cls NULL (always)
1583 * @param args remaining command-line arguments
1584 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1585 * @param c configuration
1586 */
1587static void
1588run (void *cls,
1589 char *const *args,
1590 const char *cfgfile,
1591 const struct GNUNET_CONFIGURATION_Handle *c)
1592{
1593 char *bindto;
1594 struct sockaddr *in;
1595 socklen_t in_len;
1596 struct sockaddr_storage in_sto;
1597 socklen_t sto_len;
1598
1599 (void) cls;
1600 cfg = c;
1601
1602 if (GNUNET_OK !=
1603 GNUNET_CONFIGURATION_get_value_string (cfg,
1604 COMMUNICATOR_CONFIG_SECTION,
1605 "BINDTO",
1606 &bindto))
1607 {
1608 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1609 COMMUNICATOR_CONFIG_SECTION,
1610 "BINDTO");
1611 return;
1612 }
1613
1614 in = udp_address_to_sockaddr (bindto, &in_len);
1615
1616 if (NULL == in)
1617 {
1618 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1619 "Failed to setup UDP socket address with path `%s'\n",
1620 bindto);
1621 GNUNET_free (bindto);
1622 return;
1623 }
1624 udp_sock =
1625 GNUNET_NETWORK_socket_create (in->sa_family,
1626 SOCK_DGRAM,
1627 IPPROTO_UDP);
1628 if (NULL == udp_sock)
1629 {
1630 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1631 GNUNET_free (in);
1632 GNUNET_free (bindto);
1633 return;
1634 }
1635 if (AF_INET6 == in->sa_family)
1636 have_v6_socket = GNUNET_YES;
1637 if (GNUNET_OK !=
1638 GNUNET_NETWORK_socket_bind (udp_sock,
1639 in,
1640 in_len))
1641 {
1642 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1643 "bind",
1644 bindto);
1645 GNUNET_NETWORK_socket_close (udp_sock);
1646 udp_sock = NULL;
1647 GNUNET_free (in);
1648 GNUNET_free (bindto);
1649 return;
1650 }
1651 sto_len = sizeof(in_sto);
1652 if (0 != getsockname (GNUNET_NETWORK_get_fd (udp_sock),
1653 (struct sockaddr *) &in_sto,
1654 &sto_len))
1655 {
1656 memcpy (&in_sto, in, in_len);
1657 sto_len = in_len;
1658 }
1659 GNUNET_free (in);
1660 GNUNET_free (bindto);
1661 in = (struct sockaddr *) &in_sto;
1662 in_len = sto_len;
1663 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1664 "transport",
1665 "Bound to `%s'\n",
1666 GNUNET_a2s ((const struct sockaddr *) &in_sto,
1667 sto_len));
1668 switch (in->sa_family)
1669 {
1670 case AF_INET:
1671 my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
1672 break;
1673
1674 case AF_INET6:
1675 my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
1676 break;
1677
1678 default:
1679 GNUNET_break (0);
1680 my_port = 0;
1681 }
1682 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1683 /**
1684 * Setup QUICHE configuration
1685 */
1686 config = quiche_config_new (QUICHE_PROTOCOL_VERSION);
1687 quiche_config_verify_peer (config, false);
1688 /**
1689 * TODO: configure TLS cert
1690 */
1691 quiche_config_load_cert_chain_from_pem_file (config, "./cert.crt");
1692 quiche_config_load_priv_key_from_pem_file (config, "./cert.key");
1693 quiche_config_set_application_protos (config,
1694 (uint8_t *)
1695 "\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9",
1696 38);
1697 quiche_config_set_max_idle_timeout (config, 5000);
1698 quiche_config_set_max_recv_udp_payload_size (config, 1200);
1699 quiche_config_set_max_send_udp_payload_size (config, 1200);
1700 quiche_config_set_initial_max_data (config, 10000000);
1701 quiche_config_set_initial_max_stream_data_bidi_local (config, 1000000);
1702 quiche_config_set_initial_max_stream_data_bidi_remote (config, 1000000);
1703 quiche_config_set_initial_max_stream_data_uni (config, 1000000);
1704 quiche_config_set_initial_max_streams_bidi (config, 100);
1705 quiche_config_set_initial_max_streams_uni (config, 100);
1706 quiche_config_set_cc_algorithm (config, QUICHE_CC_RENO);
1707 quiche_config_set_disable_active_migration (config, true);
1708 addr_map = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
1709 /**
1710 * Get our public key for initial packet
1711 */
1712 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1713 if (NULL == my_private_key)
1714 {
1715 GNUNET_log (
1716 GNUNET_ERROR_TYPE_ERROR,
1717 _ (
1718 "Transport service is lacking key configuration settings. Exiting.\n"));
1719 GNUNET_SCHEDULER_shutdown ();
1720 return;
1721 }
1722 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1723 /* start reading */
1724 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1725 udp_sock,
1726 &sock_read,
1727 NULL);
1728 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1729 COMMUNICATOR_CONFIG_SECTION,
1730 COMMUNICATOR_ADDRESS_PREFIX,
1731 GNUNET_TRANSPORT_CC_RELIABLE,
1732 &mq_init,
1733 NULL,
1734 &notify_cb,
1735 NULL);
1736 is = GNUNET_NT_scanner_init ();
1737 nat = GNUNET_NAT_register (cfg,
1738 COMMUNICATOR_CONFIG_SECTION,
1739 IPPROTO_UDP,
1740 1 /* one address */,
1741 (const struct sockaddr **) &in,
1742 &in_len,
1743 &nat_address_cb,
1744 try_connection_reversal,
1745 NULL /* closure */);
1746 if (NULL == ch)
1747 {
1748 GNUNET_break (0);
1749 GNUNET_SCHEDULER_shutdown ();
1750 return;
1751 }
1752 ah = GNUNET_TRANSPORT_application_init (cfg);
1753 if (NULL == ah)
1754 {
1755 GNUNET_break (0);
1756 GNUNET_SCHEDULER_shutdown ();
1757 return;
1758 }
1759
1760 /* start broadcasting */
1761 // if (GNUNET_YES !=
1762 // GNUNET_CONFIGURATION_get_value_yesno (cfg,
1763 // COMMUNICATOR_CONFIG_SECTION,
1764 // "DISABLE_BROADCAST"))
1765 // {
1766 // broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, NULL);
1767 // }
1768}
1769
1770
1771int
1772main (int argc, char *const *argv)
1773{
1774 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1775 GNUNET_GETOPT_OPTION_END
1776 };
1777 int ret;
1778
1779 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1780 "transport",
1781 "Starting quic communicator\n");
1782 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1783 return 2;
1784
1785 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
1786 argv,
1787 "gnunet-communicator-quic",
1788 _ ("GNUnet QUIC communicator"),
1789 options,
1790 &run,
1791 NULL))
1792 ? 0
1793 : 1;
1794 GNUNET_free_nz ((void *) argv);
1795 return ret;
1796}