1use std::{
2 collections::{HashMap, hash_map},
3 convert::TryFrom,
4 fmt, mem,
5 net::{IpAddr, SocketAddr},
6 ops::{Index, IndexMut},
7 sync::Arc,
8};
9
10use bytes::{BufMut, Bytes, BytesMut};
11use rand::{
12 Rng, RngExt, SeedableRng,
13 rngs::{StdRng, SysRng},
14};
15use rustc_hash::FxHashMap;
16use slab::Slab;
17use thiserror::Error;
18use tracing::{debug, error, trace, warn};
19
20use crate::{
21 Duration, INITIAL_MTU, Instant, MAX_CID_SIZE, MIN_INITIAL_SIZE, RESET_TOKEN_SIZE, ResetToken,
22 Side, Transmit, TransportConfig, TransportError,
23 cid_generator::ConnectionIdGenerator,
24 coding::BufMutExt,
25 config::{ClientConfig, EndpointConfig, ServerConfig},
26 connection::{Connection, ConnectionError, SideArgs},
27 crypto::{self, Keys, UnsupportedVersion},
28 frame,
29 packet::{
30 FixedLengthConnectionIdParser, Header, InitialHeader, InitialPacket, PacketDecodeError,
31 PacketNumber, PartialDecode, ProtectedInitialHeader,
32 },
33 shared::{
34 ConnectionEvent, ConnectionEventInner, ConnectionId, DatagramConnectionEvent, EcnCodepoint,
35 EndpointEvent, EndpointEventInner, IssuedCid,
36 },
37 token::{IncomingToken, InvalidRetryTokenError, Token, TokenPayload},
38 transport_parameters::{PreferredAddress, TransportParameters},
39};
40
41pub struct Endpoint {
46 rng: StdRng,
47 index: ConnectionIndex,
48 connections: Slab<ConnectionMeta>,
49 local_cid_generator: Box<dyn ConnectionIdGenerator>,
50 config: Arc<EndpointConfig>,
51 server_config: Option<Arc<ServerConfig>>,
52 allow_mtud: bool,
54 last_stateless_reset: Option<Instant>,
56 incoming_buffers: Slab<IncomingBuffer>,
58 all_incoming_buffers_total_bytes: u64,
59}
60
61impl Endpoint {
62 pub fn new(
73 config: Arc<EndpointConfig>,
74 server_config: Option<Arc<ServerConfig>>,
75 allow_mtud: bool,
76 rng_seed: Option<[u8; 32]>,
77 ) -> Self {
78 Self {
79 rng: match rng_seed.or(config.rng_seed) {
80 Some(seed) => StdRng::from_seed(seed),
81 None => StdRng::try_from_rng(&mut SysRng)
82 .expect("failed to seed random number generator from system"),
83 },
84 index: ConnectionIndex::default(),
85 connections: Slab::new(),
86 local_cid_generator: (config.connection_id_generator_factory.as_ref())(),
87 config,
88 server_config,
89 allow_mtud,
90 last_stateless_reset: None,
91 incoming_buffers: Slab::new(),
92 all_incoming_buffers_total_bytes: 0,
93 }
94 }
95
96 pub fn set_server_config(&mut self, server_config: Option<Arc<ServerConfig>>) {
100 self.server_config = server_config;
101 }
102
103 pub fn handle_event(
107 &mut self,
108 ch: ConnectionHandle,
109 event: EndpointEvent,
110 ) -> Option<ConnectionEvent> {
111 use EndpointEventInner::*;
112 match event.0 {
113 NeedIdentifiers(now, n) => {
114 return Some(self.send_new_identifiers(now, ch, n));
115 }
116 ResetToken(remote, token) => {
117 if let Some(old) = self.connections[ch].reset_token.replace((remote, token)) {
118 self.index.connection_reset_tokens.remove(old.0, old.1);
119 }
120 if self.index.connection_reset_tokens.insert(remote, token, ch) {
121 warn!("duplicate reset token");
122 }
123 }
124 RetireConnectionId(now, seq, allow_more_cids) => {
125 if let Some(cid) = self.connections[ch].loc_cids.remove(&seq) {
126 trace!("peer retired CID {}: {}", seq, cid);
127 self.index.retire(cid);
128 if allow_more_cids {
129 return Some(self.send_new_identifiers(now, ch, 1));
130 }
131 }
132 }
133 Drained => {
134 if let Some(conn) = self.connections.try_remove(ch.0) {
135 self.index.remove(&conn);
136 } else {
137 error!(id = ch.0, "unknown connection drained");
141 }
142 }
143 }
144 None
145 }
146
147 pub fn handle(
149 &mut self,
150 now: Instant,
151 remote: SocketAddr,
152 local_ip: Option<IpAddr>,
153 ecn: Option<EcnCodepoint>,
154 data: BytesMut,
155 buf: &mut Vec<u8>,
156 ) -> Option<DatagramEvent> {
157 let datagram_len = data.len();
159 let event = match PartialDecode::new(
160 data,
161 &FixedLengthConnectionIdParser::new(self.local_cid_generator.cid_len()),
162 &self.config.supported_versions,
163 self.config.grease_quic_bit,
164 ) {
165 Ok((first_decode, remaining)) => DatagramConnectionEvent {
166 now,
167 remote,
168 ecn,
169 first_decode,
170 remaining,
171 },
172 Err(PacketDecodeError::UnsupportedVersion {
173 src_cid,
174 dst_cid,
175 version,
176 }) => {
177 if self.server_config.is_none() {
178 debug!("dropping packet with unsupported version");
179 return None;
180 }
181 if datagram_len < MIN_INITIAL_SIZE as usize {
185 debug!("dropping short packet with unsupported version");
186 return None;
187 }
188 trace!("sending version negotiation");
189 Header::VersionNegotiate {
191 random: self.rng.random::<u8>() | 0x40,
192 src_cid: dst_cid,
193 dst_cid: src_cid,
194 }
195 .encode(buf);
196 buf.write::<u32>(match version {
198 0x0a1a_2a3a => 0x0a1a_2a4a,
199 _ => 0x0a1a_2a3a,
200 });
201 for &version in &self.config.supported_versions {
202 buf.write(version);
203 }
204 return Some(DatagramEvent::Response(Transmit {
205 destination: remote,
206 ecn: None,
207 size: buf.len(),
208 segment_size: None,
209 src_ip: local_ip,
210 }));
211 }
212 Err(e) => {
213 trace!("malformed header: {}", e);
214 return None;
215 }
216 };
217
218 let addresses = FourTuple { remote, local_ip };
219 let dst_cid = event.first_decode.dst_cid();
220
221 if let Some(route_to) = self.index.get(&addresses, &event.first_decode) {
222 match route_to {
224 RouteDatagramTo::Incoming(incoming_idx) => {
225 let incoming_buffer = &mut self.incoming_buffers[incoming_idx];
226 let config = &incoming_buffer.server_config;
227
228 if incoming_buffer
229 .total_bytes
230 .checked_add(datagram_len as u64)
231 .is_some_and(|n| n <= config.incoming_buffer_size)
232 && self
233 .all_incoming_buffers_total_bytes
234 .checked_add(datagram_len as u64)
235 .is_some_and(|n| n <= config.incoming_buffer_size_total)
236 {
237 incoming_buffer.datagrams.push(event);
238 incoming_buffer.total_bytes += datagram_len as u64;
239 self.all_incoming_buffers_total_bytes += datagram_len as u64;
240 }
241
242 None
243 }
244 RouteDatagramTo::Connection(ch) => Some(DatagramEvent::ConnectionEvent(
245 ch,
246 ConnectionEvent(ConnectionEventInner::Datagram(event)),
247 )),
248 }
249 } else if event.first_decode.initial_header().is_some() {
250 self.handle_first_packet(datagram_len, event, addresses, buf)
253 } else if event.first_decode.has_long_header() {
254 debug!(
255 "ignoring non-initial packet for unknown connection {}",
256 dst_cid
257 );
258 None
259 } else if !event.first_decode.is_initial()
260 && self.local_cid_generator.validate(dst_cid).is_err()
261 {
262 debug!("dropping packet with invalid CID");
263 None
264 } else if dst_cid.is_empty() {
265 trace!("dropping unrecognized short packet without ID");
266 None
267 } else {
268 self.stateless_reset(now, datagram_len, addresses, *dst_cid, buf)
271 .map(DatagramEvent::Response)
272 }
273 }
274
275 fn stateless_reset(
276 &mut self,
277 now: Instant,
278 inciting_dgram_len: usize,
279 addresses: FourTuple,
280 dst_cid: ConnectionId,
281 buf: &mut Vec<u8>,
282 ) -> Option<Transmit> {
283 if self
284 .last_stateless_reset
285 .is_some_and(|last| last + self.config.min_reset_interval > now)
286 {
287 debug!("ignoring unexpected packet within minimum stateless reset interval");
288 return None;
289 }
290
291 const MIN_PADDING_LEN: usize = 5;
293
294 let max_padding_len = match inciting_dgram_len.checked_sub(RESET_TOKEN_SIZE) {
297 Some(headroom) if headroom > MIN_PADDING_LEN => headroom - 1,
298 _ => {
299 debug!(
300 "ignoring unexpected {} byte packet: not larger than minimum stateless reset size",
301 inciting_dgram_len
302 );
303 return None;
304 }
305 };
306
307 debug!(
308 "sending stateless reset for {} to {}",
309 dst_cid, addresses.remote
310 );
311 self.last_stateless_reset = Some(now);
312 const IDEAL_MIN_PADDING_LEN: usize = MIN_PADDING_LEN + MAX_CID_SIZE;
314 let padding_len = if max_padding_len <= IDEAL_MIN_PADDING_LEN {
315 max_padding_len
316 } else {
317 self.rng
318 .random_range(IDEAL_MIN_PADDING_LEN..max_padding_len)
319 };
320 buf.reserve(padding_len + RESET_TOKEN_SIZE);
321 buf.resize(padding_len, 0);
322 self.rng.fill_bytes(&mut buf[0..padding_len]);
323 buf[0] = 0b0100_0000 | (buf[0] >> 2);
324 buf.extend_from_slice(&ResetToken::new(&*self.config.reset_key, dst_cid));
325
326 debug_assert!(buf.len() < inciting_dgram_len);
327
328 Some(Transmit {
329 destination: addresses.remote,
330 ecn: None,
331 size: buf.len(),
332 segment_size: None,
333 src_ip: addresses.local_ip,
334 })
335 }
336
337 pub fn connect(
339 &mut self,
340 now: Instant,
341 config: ClientConfig,
342 remote: SocketAddr,
343 server_name: &str,
344 ) -> Result<(ConnectionHandle, Connection), ConnectError> {
345 if self.cids_exhausted() {
346 return Err(ConnectError::CidsExhausted);
347 }
348 if remote.port() == 0 || remote.ip().is_unspecified() {
349 return Err(ConnectError::InvalidRemoteAddress(remote));
350 }
351 if !self.config.supported_versions.contains(&config.version) {
352 return Err(ConnectError::UnsupportedVersion);
353 }
354
355 let remote_id = (config.initial_dst_cid_provider)();
356 trace!(initial_dcid = %remote_id);
357
358 let ch = ConnectionHandle(self.connections.vacant_key());
359 let loc_cid = self.new_cid(ch);
360 let params = TransportParameters::new(
361 &config.transport,
362 &self.config,
363 self.local_cid_generator.as_ref(),
364 loc_cid,
365 None,
366 &mut self.rng,
367 );
368 let tls = config
369 .crypto
370 .start_session(config.version, server_name, ¶ms)
371 .inspect_err(|_| {
372 self.index.connection_ids.remove(&loc_cid);
374 })?;
375
376 let conn = self.add_connection(
377 ch,
378 config.version,
379 remote_id,
380 loc_cid,
381 remote_id,
382 FourTuple {
383 remote,
384 local_ip: None,
385 },
386 now,
387 tls,
388 config.transport,
389 SideArgs::Client {
390 token_store: config.token_store,
391 server_name: server_name.into(),
392 },
393 );
394 Ok((ch, conn))
395 }
396
397 fn send_new_identifiers(
398 &mut self,
399 now: Instant,
400 ch: ConnectionHandle,
401 num: u64,
402 ) -> ConnectionEvent {
403 let mut ids = vec![];
404 for _ in 0..num {
405 let id = self.new_cid(ch);
406 let meta = &mut self.connections[ch];
407 let sequence = meta.cids_issued;
408 meta.cids_issued += 1;
409 meta.loc_cids.insert(sequence, id);
410 ids.push(IssuedCid {
411 sequence,
412 id,
413 reset_token: ResetToken::new(&*self.config.reset_key, id),
414 });
415 }
416 ConnectionEvent(ConnectionEventInner::NewIdentifiers(ids, now))
417 }
418
419 fn new_cid(&mut self, ch: ConnectionHandle) -> ConnectionId {
421 loop {
422 let cid = self.local_cid_generator.generate_cid();
423 if cid.is_empty() {
424 debug_assert_eq!(self.local_cid_generator.cid_len(), 0);
426 return cid;
427 }
428 if let hash_map::Entry::Vacant(e) = self.index.connection_ids.entry(cid) {
429 e.insert(ch);
430 break cid;
431 }
432 }
433 }
434
435 fn handle_first_packet(
436 &mut self,
437 datagram_len: usize,
438 event: DatagramConnectionEvent,
439 addresses: FourTuple,
440 buf: &mut Vec<u8>,
441 ) -> Option<DatagramEvent> {
442 let dst_cid = event.first_decode.dst_cid();
443 let header = event.first_decode.initial_header().unwrap();
444
445 let Some(server_config) = &self.server_config else {
446 debug!("packet for unrecognized connection {}", dst_cid);
447 return self
448 .stateless_reset(event.now, datagram_len, addresses, *dst_cid, buf)
449 .map(DatagramEvent::Response);
450 };
451
452 if datagram_len < MIN_INITIAL_SIZE as usize {
453 debug!("ignoring short initial for connection {}", dst_cid);
454 return None;
455 }
456
457 if self.cids_exhausted() || self.incoming_buffers.len() >= server_config.max_incoming {
460 debug!(
461 "ignoring initial for connection {} due to saturation",
462 dst_cid
463 );
464 return None;
465 }
466
467 let crypto = match server_config.crypto.initial_keys(header.version, dst_cid) {
468 Ok(keys) => keys,
469 Err(UnsupportedVersion) => {
470 debug!(
473 "ignoring initial packet version {:#x} unsupported by cryptographic layer",
474 header.version
475 );
476 return None;
477 }
478 };
479
480 if let Err(reason) = self.early_validate_first_packet(header) {
481 return Some(DatagramEvent::Response(self.initial_close(
482 header.version,
483 addresses,
484 &crypto,
485 &header.src_cid,
486 reason,
487 buf,
488 )));
489 }
490
491 let packet = match event.first_decode.finish(Some(&*crypto.header.remote)) {
492 Ok(packet) => packet,
493 Err(e) => {
494 trace!("unable to decode initial packet: {}", e);
495 return None;
496 }
497 };
498
499 if !packet.reserved_bits_valid() {
500 debug!("dropping connection attempt with invalid reserved bits");
501 return None;
502 }
503
504 let Header::Initial(header) = packet.header else {
505 panic!("non-initial packet in handle_first_packet()");
506 };
507
508 let server_config = self.server_config.as_ref().unwrap().clone();
509
510 let token = match IncomingToken::from_header(&header, &server_config, addresses.remote) {
511 Ok(token) => token,
512 Err(InvalidRetryTokenError) => {
513 debug!("rejecting invalid retry token");
514 return Some(DatagramEvent::Response(self.initial_close(
515 header.version,
516 addresses,
517 &crypto,
518 &header.src_cid,
519 TransportError::INVALID_TOKEN(""),
520 buf,
521 )));
522 }
523 };
524
525 let incoming_idx = self.incoming_buffers.insert(IncomingBuffer {
526 server_config,
527 datagrams: Vec::new(),
528 total_bytes: 0,
529 });
530 self.index
531 .insert_initial_incoming(header.dst_cid, incoming_idx);
532
533 Some(DatagramEvent::NewConnection(Incoming {
534 received_at: event.now,
535 addresses,
536 ecn: event.ecn,
537 packet: InitialPacket {
538 header,
539 header_data: packet.header_data,
540 payload: packet.payload,
541 },
542 rest: event.remaining,
543 crypto,
544 token,
545 incoming_idx,
546 improper_drop_warner: IncomingImproperDropWarner,
547 }))
548 }
549
550 #[allow(clippy::result_large_err)]
553 pub fn accept(
554 &mut self,
555 mut incoming: Incoming,
556 now: Instant,
557 buf: &mut Vec<u8>,
558 server_config: Option<Arc<ServerConfig>>,
559 ) -> Result<(ConnectionHandle, Connection), AcceptError> {
560 let remote_address_validated = incoming.remote_address_validated();
561 incoming.improper_drop_warner.dismiss();
562 let incoming_buffer = self.incoming_buffers.remove(incoming.incoming_idx);
563 self.all_incoming_buffers_total_bytes -= incoming_buffer.total_bytes;
564
565 let packet_number = incoming.packet.header.number.expand(0);
566 let InitialHeader {
567 src_cid,
568 dst_cid,
569 version,
570 ..
571 } = incoming.packet.header;
572 let server_config = server_config.unwrap_or_else(|| incoming_buffer.server_config.clone());
573
574 if server_config
575 .transport
576 .max_idle_timeout
577 .is_some_and(|timeout| {
578 incoming.received_at + Duration::from_millis(timeout.into()) <= now
579 })
580 {
581 debug!("abandoning accept of stale initial");
582 self.index.remove_initial(dst_cid);
583 return Err(AcceptError {
584 cause: ConnectionError::TimedOut,
585 response: None,
586 });
587 }
588
589 if self.cids_exhausted() {
590 debug!("refusing connection");
591 self.index.remove_initial(dst_cid);
592 return Err(AcceptError {
593 cause: ConnectionError::CidsExhausted,
594 response: Some(self.initial_close(
595 version,
596 incoming.addresses,
597 &incoming.crypto,
598 &src_cid,
599 TransportError::CONNECTION_REFUSED(""),
600 buf,
601 )),
602 });
603 }
604
605 if incoming
606 .crypto
607 .packet
608 .remote
609 .decrypt(
610 packet_number,
611 &incoming.packet.header_data,
612 &mut incoming.packet.payload,
613 )
614 .is_err()
615 {
616 debug!(packet_number, "failed to authenticate initial packet");
617 self.index.remove_initial(dst_cid);
618 return Err(AcceptError {
619 cause: TransportError::PROTOCOL_VIOLATION("authentication failed").into(),
620 response: None,
621 });
622 };
623
624 let ch = ConnectionHandle(self.connections.vacant_key());
625 let loc_cid = self.new_cid(ch);
626 let mut params = TransportParameters::new(
627 &server_config.transport,
628 &self.config,
629 self.local_cid_generator.as_ref(),
630 loc_cid,
631 Some(&server_config),
632 &mut self.rng,
633 );
634 params.stateless_reset_token = Some(ResetToken::new(&*self.config.reset_key, loc_cid));
635 params.original_dst_cid = Some(incoming.token.orig_dst_cid);
636 params.retry_src_cid = incoming.token.retry_src_cid;
637 let mut pref_addr_cid = None;
638 if server_config.has_preferred_address() {
639 let cid = self.new_cid(ch);
640 pref_addr_cid = Some(cid);
641 params.preferred_address = Some(PreferredAddress {
642 address_v4: server_config.preferred_address_v4,
643 address_v6: server_config.preferred_address_v6,
644 connection_id: cid,
645 stateless_reset_token: ResetToken::new(&*self.config.reset_key, cid),
646 });
647 }
648
649 let tls = server_config.crypto.clone().start_session(version, ¶ms);
650 let transport_config = server_config.transport.clone();
651 let mut conn = self.add_connection(
652 ch,
653 version,
654 dst_cid,
655 loc_cid,
656 src_cid,
657 incoming.addresses,
658 incoming.received_at,
659 tls,
660 transport_config,
661 SideArgs::Server {
662 server_config,
663 pref_addr_cid,
664 path_validated: remote_address_validated,
665 },
666 );
667 self.index.insert_initial(dst_cid, ch);
668
669 match conn.handle_first_packet(
670 incoming.received_at,
671 incoming.addresses.remote,
672 incoming.ecn,
673 packet_number,
674 incoming.packet,
675 incoming.rest,
676 ) {
677 Ok(()) => {
678 trace!(id = ch.0, icid = %dst_cid, "new connection");
679
680 for event in incoming_buffer.datagrams {
681 conn.handle_event(ConnectionEvent(ConnectionEventInner::Datagram(event)))
682 }
683
684 Ok((ch, conn))
685 }
686 Err(e) => {
687 debug!("handshake failed: {}", e);
688 self.handle_event(ch, EndpointEvent(EndpointEventInner::Drained));
689 let response = match e {
690 ConnectionError::TransportError(ref e) => Some(self.initial_close(
691 version,
692 incoming.addresses,
693 &incoming.crypto,
694 &src_cid,
695 e.clone(),
696 buf,
697 )),
698 _ => None,
699 };
700 Err(AcceptError { cause: e, response })
701 }
702 }
703 }
704
705 fn early_validate_first_packet(
707 &mut self,
708 header: &ProtectedInitialHeader,
709 ) -> Result<(), TransportError> {
710 if header.dst_cid.len() < 8
715 && (header.token_pos.is_empty()
716 || header.dst_cid.len() != self.local_cid_generator.cid_len())
717 {
718 debug!(
719 "rejecting connection due to invalid DCID length {}",
720 header.dst_cid.len()
721 );
722 return Err(TransportError::PROTOCOL_VIOLATION(
723 "invalid destination CID length",
724 ));
725 }
726
727 Ok(())
728 }
729
730 pub fn refuse(&mut self, incoming: Incoming, buf: &mut Vec<u8>) -> Transmit {
732 self.clean_up_incoming(&incoming);
733 incoming.improper_drop_warner.dismiss();
734
735 self.initial_close(
736 incoming.packet.header.version,
737 incoming.addresses,
738 &incoming.crypto,
739 &incoming.packet.header.src_cid,
740 TransportError::CONNECTION_REFUSED(""),
741 buf,
742 )
743 }
744
745 pub fn retry(&mut self, incoming: Incoming, buf: &mut Vec<u8>) -> Result<Transmit, RetryError> {
749 if !incoming.may_retry() {
750 return Err(RetryError(Box::new(incoming)));
751 }
752
753 let server_config = self.incoming_buffers[incoming.incoming_idx]
754 .server_config
755 .clone();
756 self.clean_up_incoming(&incoming);
757 incoming.improper_drop_warner.dismiss();
758
759 let loc_cid = self.local_cid_generator.generate_cid();
766
767 let payload = TokenPayload::Retry {
768 address: incoming.addresses.remote,
769 orig_dst_cid: incoming.packet.header.dst_cid,
770 issued: server_config.time_source.now(),
771 };
772 let token = Token::new(payload, &mut self.rng).encode(&*server_config.token_key);
773
774 let header = Header::Retry {
775 src_cid: loc_cid,
776 dst_cid: incoming.packet.header.src_cid,
777 version: incoming.packet.header.version,
778 };
779
780 let encode = header.encode(buf);
781 buf.put_slice(&token);
782 buf.extend_from_slice(&server_config.crypto.retry_tag(
783 incoming.packet.header.version,
784 &incoming.packet.header.dst_cid,
785 buf,
786 ));
787 encode.finish(buf, &*incoming.crypto.header.local, None);
788
789 Ok(Transmit {
790 destination: incoming.addresses.remote,
791 ecn: None,
792 size: buf.len(),
793 segment_size: None,
794 src_ip: incoming.addresses.local_ip,
795 })
796 }
797
798 pub fn ignore(&mut self, incoming: Incoming) {
803 self.clean_up_incoming(&incoming);
804 incoming.improper_drop_warner.dismiss();
805 }
806
807 fn clean_up_incoming(&mut self, incoming: &Incoming) {
809 self.index.remove_initial(incoming.packet.header.dst_cid);
810 let incoming_buffer = self.incoming_buffers.remove(incoming.incoming_idx);
811 self.all_incoming_buffers_total_bytes -= incoming_buffer.total_bytes;
812 }
813
814 fn add_connection(
815 &mut self,
816 ch: ConnectionHandle,
817 version: u32,
818 init_cid: ConnectionId,
819 loc_cid: ConnectionId,
820 rem_cid: ConnectionId,
821 addresses: FourTuple,
822 now: Instant,
823 tls: Box<dyn crypto::Session>,
824 transport_config: Arc<TransportConfig>,
825 side_args: SideArgs,
826 ) -> Connection {
827 let mut rng_seed = [0; 32];
828 self.rng.fill_bytes(&mut rng_seed);
829 let side = side_args.side();
830 let pref_addr_cid = side_args.pref_addr_cid();
831 let conn = Connection::new(
832 self.config.clone(),
833 transport_config,
834 init_cid,
835 loc_cid,
836 rem_cid,
837 addresses.remote,
838 addresses.local_ip,
839 tls,
840 self.local_cid_generator.as_ref(),
841 now,
842 version,
843 self.allow_mtud,
844 rng_seed,
845 side_args,
846 );
847
848 let mut cids_issued = 0;
849 let mut loc_cids = FxHashMap::default();
850
851 loc_cids.insert(cids_issued, loc_cid);
852 cids_issued += 1;
853
854 if let Some(cid) = pref_addr_cid {
855 debug_assert_eq!(cids_issued, 1, "preferred address cid seq must be 1");
856 loc_cids.insert(cids_issued, cid);
857 cids_issued += 1;
858 }
859
860 let id = self.connections.insert(ConnectionMeta {
861 init_cid,
862 cids_issued,
863 loc_cids,
864 addresses,
865 side,
866 reset_token: None,
867 });
868 debug_assert_eq!(id, ch.0, "connection handle allocation out of sync");
869
870 self.index.insert_conn(addresses, loc_cid, ch, side);
871
872 conn
873 }
874
875 fn initial_close(
876 &mut self,
877 version: u32,
878 addresses: FourTuple,
879 crypto: &Keys,
880 remote_id: &ConnectionId,
881 reason: TransportError,
882 buf: &mut Vec<u8>,
883 ) -> Transmit {
884 let local_id = self.local_cid_generator.generate_cid();
888 let number = PacketNumber::U8(0);
889 let header = Header::Initial(InitialHeader {
890 dst_cid: *remote_id,
891 src_cid: local_id,
892 number,
893 token: Bytes::new(),
894 version,
895 });
896
897 let partial_encode = header.encode(buf);
898 let max_len =
899 INITIAL_MTU as usize - partial_encode.header_len - crypto.packet.local.tag_len();
900 frame::Close::from(reason).encode(buf, max_len);
901 buf.resize(buf.len() + crypto.packet.local.tag_len(), 0);
902 partial_encode.finish(buf, &*crypto.header.local, Some((0, &*crypto.packet.local)));
903 Transmit {
904 destination: addresses.remote,
905 ecn: None,
906 size: buf.len(),
907 segment_size: None,
908 src_ip: addresses.local_ip,
909 }
910 }
911
912 pub fn config(&self) -> &EndpointConfig {
914 &self.config
915 }
916
917 pub fn open_connections(&self) -> usize {
919 self.connections.len()
920 }
921
922 pub fn incoming_buffer_bytes(&self) -> u64 {
925 self.all_incoming_buffers_total_bytes
926 }
927
928 #[cfg(test)]
929 pub(crate) fn known_connections(&self) -> usize {
930 let x = self.connections.len();
931 debug_assert_eq!(x, self.index.connection_ids_initial.len());
932 debug_assert!(x >= self.index.connection_reset_tokens.0.len());
934 debug_assert!(x >= self.index.incoming_connection_remotes.len());
936 debug_assert!(x >= self.index.outgoing_connection_remotes.len());
937 x
938 }
939
940 #[cfg(test)]
941 pub(crate) fn known_cids(&self) -> usize {
942 self.index.connection_ids.len()
943 }
944
945 fn cids_exhausted(&self) -> bool {
950 self.local_cid_generator.cid_len() <= 4
951 && self.local_cid_generator.cid_len() != 0
952 && (2usize.pow(self.local_cid_generator.cid_len() as u32 * 8)
953 - self.index.connection_ids.len())
954 < 2usize.pow(self.local_cid_generator.cid_len() as u32 * 8 - 2)
955 }
956}
957
958impl fmt::Debug for Endpoint {
959 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
960 fmt.debug_struct("Endpoint")
961 .field("rng", &self.rng)
962 .field("index", &self.index)
963 .field("connections", &self.connections)
964 .field("config", &self.config)
965 .field("server_config", &self.server_config)
966 .field("incoming_buffers.len", &self.incoming_buffers.len())
968 .field(
969 "all_incoming_buffers_total_bytes",
970 &self.all_incoming_buffers_total_bytes,
971 )
972 .finish()
973 }
974}
975
976struct IncomingBuffer {
978 server_config: Arc<ServerConfig>,
979 datagrams: Vec<DatagramConnectionEvent>,
980 total_bytes: u64,
981}
982
983#[derive(Copy, Clone, Debug)]
985enum RouteDatagramTo {
986 Incoming(usize),
987 Connection(ConnectionHandle),
988}
989
990#[derive(Default, Debug)]
992struct ConnectionIndex {
993 connection_ids_initial: HashMap<ConnectionId, RouteDatagramTo>,
999 connection_ids: FxHashMap<ConnectionId, ConnectionHandle>,
1003 incoming_connection_remotes: HashMap<FourTuple, ConnectionHandle>,
1007 outgoing_connection_remotes: HashMap<SocketAddr, ConnectionHandle>,
1016 connection_reset_tokens: ResetTokenTable,
1021}
1022
1023impl ConnectionIndex {
1024 fn insert_initial_incoming(&mut self, dst_cid: ConnectionId, incoming_key: usize) {
1026 if dst_cid.is_empty() {
1027 return;
1028 }
1029 self.connection_ids_initial
1030 .insert(dst_cid, RouteDatagramTo::Incoming(incoming_key));
1031 }
1032
1033 fn remove_initial(&mut self, dst_cid: ConnectionId) {
1035 if dst_cid.is_empty() {
1036 return;
1037 }
1038 let removed = self.connection_ids_initial.remove(&dst_cid);
1039 debug_assert!(removed.is_some());
1040 }
1041
1042 fn insert_initial(&mut self, dst_cid: ConnectionId, connection: ConnectionHandle) {
1044 if dst_cid.is_empty() {
1045 return;
1046 }
1047 self.connection_ids_initial
1048 .insert(dst_cid, RouteDatagramTo::Connection(connection));
1049 }
1050
1051 fn insert_conn(
1054 &mut self,
1055 addresses: FourTuple,
1056 dst_cid: ConnectionId,
1057 connection: ConnectionHandle,
1058 side: Side,
1059 ) {
1060 match dst_cid.len() {
1061 0 => match side {
1062 Side::Server => {
1063 self.incoming_connection_remotes
1064 .insert(addresses, connection);
1065 }
1066 Side::Client => {
1067 self.outgoing_connection_remotes
1068 .insert(addresses.remote, connection);
1069 }
1070 },
1071 _ => {
1072 self.connection_ids.insert(dst_cid, connection);
1073 }
1074 }
1075 }
1076
1077 fn retire(&mut self, dst_cid: ConnectionId) {
1079 self.connection_ids.remove(&dst_cid);
1080 }
1081
1082 fn remove(&mut self, conn: &ConnectionMeta) {
1084 if conn.side.is_server() {
1085 self.remove_initial(conn.init_cid);
1086 }
1087 for cid in conn.loc_cids.values() {
1088 self.connection_ids.remove(cid);
1089 }
1090 self.incoming_connection_remotes.remove(&conn.addresses);
1091 self.outgoing_connection_remotes
1092 .remove(&conn.addresses.remote);
1093 if let Some((remote, token)) = conn.reset_token {
1094 self.connection_reset_tokens.remove(remote, token);
1095 }
1096 }
1097
1098 fn get(&self, addresses: &FourTuple, datagram: &PartialDecode) -> Option<RouteDatagramTo> {
1100 if !datagram.dst_cid().is_empty() {
1101 if let Some(&ch) = self.connection_ids.get(datagram.dst_cid()) {
1102 return Some(RouteDatagramTo::Connection(ch));
1103 }
1104 }
1105 if datagram.is_initial() || datagram.is_0rtt() {
1106 if let Some(&ch) = self.connection_ids_initial.get(datagram.dst_cid()) {
1107 return Some(ch);
1108 }
1109 }
1110 if datagram.dst_cid().is_empty() {
1111 if let Some(&ch) = self.incoming_connection_remotes.get(addresses) {
1112 return Some(RouteDatagramTo::Connection(ch));
1113 }
1114 if let Some(&ch) = self.outgoing_connection_remotes.get(&addresses.remote) {
1115 return Some(RouteDatagramTo::Connection(ch));
1116 }
1117 }
1118 let data = datagram.data();
1119 if data.len() < RESET_TOKEN_SIZE {
1120 return None;
1121 }
1122 self.connection_reset_tokens
1123 .get(addresses.remote, &data[data.len() - RESET_TOKEN_SIZE..])
1124 .cloned()
1125 .map(RouteDatagramTo::Connection)
1126 }
1127}
1128
1129#[derive(Debug)]
1130pub(crate) struct ConnectionMeta {
1131 init_cid: ConnectionId,
1132 cids_issued: u64,
1134 loc_cids: FxHashMap<u64, ConnectionId>,
1135 addresses: FourTuple,
1140 side: Side,
1141 reset_token: Option<(SocketAddr, ResetToken)>,
1144}
1145
1146#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
1148pub struct ConnectionHandle(pub usize);
1149
1150impl From<ConnectionHandle> for usize {
1151 fn from(x: ConnectionHandle) -> Self {
1152 x.0
1153 }
1154}
1155
1156impl Index<ConnectionHandle> for Slab<ConnectionMeta> {
1157 type Output = ConnectionMeta;
1158 fn index(&self, ch: ConnectionHandle) -> &ConnectionMeta {
1159 &self[ch.0]
1160 }
1161}
1162
1163impl IndexMut<ConnectionHandle> for Slab<ConnectionMeta> {
1164 fn index_mut(&mut self, ch: ConnectionHandle) -> &mut ConnectionMeta {
1165 &mut self[ch.0]
1166 }
1167}
1168
1169pub enum DatagramEvent {
1171 ConnectionEvent(ConnectionHandle, ConnectionEvent),
1173 NewConnection(Incoming),
1175 Response(Transmit),
1177}
1178
1179pub struct Incoming {
1181 received_at: Instant,
1182 addresses: FourTuple,
1183 ecn: Option<EcnCodepoint>,
1184 packet: InitialPacket,
1185 rest: Option<BytesMut>,
1186 crypto: Keys,
1187 token: IncomingToken,
1188 incoming_idx: usize,
1189 improper_drop_warner: IncomingImproperDropWarner,
1190}
1191
1192impl Incoming {
1193 pub fn local_ip(&self) -> Option<IpAddr> {
1197 self.addresses.local_ip
1198 }
1199
1200 pub fn remote_address(&self) -> SocketAddr {
1202 self.addresses.remote
1203 }
1204
1205 pub fn remote_address_validated(&self) -> bool {
1213 self.token.validated
1214 }
1215
1216 pub fn may_retry(&self) -> bool {
1221 self.token.retry_src_cid.is_none()
1222 }
1223
1224 pub fn orig_dst_cid(&self) -> &ConnectionId {
1226 &self.token.orig_dst_cid
1227 }
1228}
1229
1230impl fmt::Debug for Incoming {
1231 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1232 f.debug_struct("Incoming")
1233 .field("addresses", &self.addresses)
1234 .field("ecn", &self.ecn)
1235 .field("token", &self.token)
1238 .field("incoming_idx", &self.incoming_idx)
1239 .finish_non_exhaustive()
1241 }
1242}
1243
1244struct IncomingImproperDropWarner;
1245
1246impl IncomingImproperDropWarner {
1247 fn dismiss(self) {
1248 mem::forget(self);
1249 }
1250}
1251
1252impl Drop for IncomingImproperDropWarner {
1253 fn drop(&mut self) {
1254 warn!(
1255 "quinn_proto::Incoming dropped without passing to Endpoint::accept/refuse/retry/ignore \
1256 (may cause memory leak and eventual inability to accept new connections)"
1257 );
1258 }
1259}
1260
1261#[derive(Debug, Error, Clone, PartialEq, Eq)]
1265pub enum ConnectError {
1266 #[error("endpoint stopping")]
1270 EndpointStopping,
1271 #[error("CIDs exhausted")]
1275 CidsExhausted,
1276 #[error("invalid server name: {0}")]
1278 InvalidServerName(String),
1279 #[error("invalid remote address: {0}")]
1283 InvalidRemoteAddress(SocketAddr),
1284 #[error("no default client config")]
1288 NoDefaultClientConfig,
1289 #[error("unsupported QUIC version")]
1291 UnsupportedVersion,
1292}
1293
1294#[derive(Debug)]
1296pub struct AcceptError {
1297 pub cause: ConnectionError,
1299 pub response: Option<Transmit>,
1301}
1302
1303#[derive(Debug, Error)]
1305#[error("retry() with validated Incoming")]
1306pub struct RetryError(Box<Incoming>);
1307
1308impl RetryError {
1309 pub fn into_incoming(self) -> Incoming {
1311 *self.0
1312 }
1313}
1314
1315#[derive(Default, Debug)]
1320struct ResetTokenTable(HashMap<SocketAddr, HashMap<ResetToken, ConnectionHandle>>);
1321
1322impl ResetTokenTable {
1323 fn insert(&mut self, remote: SocketAddr, token: ResetToken, ch: ConnectionHandle) -> bool {
1324 self.0
1325 .entry(remote)
1326 .or_default()
1327 .insert(token, ch)
1328 .is_some()
1329 }
1330
1331 fn remove(&mut self, remote: SocketAddr, token: ResetToken) {
1332 use std::collections::hash_map::Entry;
1333 match self.0.entry(remote) {
1334 Entry::Vacant(_) => {}
1335 Entry::Occupied(mut e) => {
1336 e.get_mut().remove(&token);
1337 if e.get().is_empty() {
1338 e.remove_entry();
1339 }
1340 }
1341 }
1342 }
1343
1344 fn get(&self, remote: SocketAddr, token: &[u8]) -> Option<&ConnectionHandle> {
1345 let token = ResetToken::from(<[u8; RESET_TOKEN_SIZE]>::try_from(token).ok()?);
1346 self.0.get(&remote)?.get(&token)
1347 }
1348}
1349
1350#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
1355struct FourTuple {
1356 remote: SocketAddr,
1357 local_ip: Option<IpAddr>,
1359}