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