Skip to content

Commit 0696c83

Browse files
authored
refactor: defensive styel & move code around (#450)
Some refactors: - Move code around so that helpers structs come after the Connection, kind of more the style and keeps connection code more together. - Use some defensive coding in the spaces impls. Fix a few bugs detected by it
1 parent 5e6ee88 commit 0696c83

2 files changed

Lines changed: 162 additions & 103 deletions

File tree

quinn-proto/src/connection/mod.rs

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -314,57 +314,6 @@ pub struct Connection {
314314
qlog: QlogSink,
315315
}
316316

317-
/// Return value for [`Connection::poll_transmit_path`].
318-
#[derive(Debug)]
319-
enum PollPathStatus {
320-
/// Nothing to send on the path, nothing was written into the [`TransmitBuf`].
321-
NothingToSend {
322-
/// If true there was data to send but congestion control did not allow so.
323-
congestion_blocked: bool,
324-
},
325-
/// The transmit is ready to be sent.
326-
Send(Transmit),
327-
}
328-
329-
/// Return value for [`Connection::poll_transmit_path_space`].
330-
#[derive(Debug)]
331-
enum PollPathSpaceStatus {
332-
/// Nothing to send in the space, nothing was written into the [`TransmitBuf`].
333-
NothingToSend {
334-
/// If true there was data to send but congestion control did not allow so.
335-
congestion_blocked: bool,
336-
},
337-
/// One or more packets have been written into the [`TransmitBuf`].
338-
WrotePacket {
339-
/// The highest packet number.
340-
last_packet_number: u64,
341-
/// Whether to pad an already started datagram in the next packet.
342-
///
343-
/// When packets in Initial, 0-RTT or Handshake packet do not fill the entire
344-
/// datagram they may decide to coalesce with the next packet from a higher
345-
/// encryption level on the same path. But the earlier packet may require specific
346-
/// size requirements for the datagram they are sent in.
347-
///
348-
/// If a space did not complete the datagram, they use this to request the correct
349-
/// padding in the final packet of the datagram so that the final datagram will have
350-
/// the correct size.
351-
///
352-
/// If a space did fill an entire datagram, it leaves this to the default of
353-
/// [`PadDatagram::No`].
354-
pad_datagram: PadDatagram,
355-
},
356-
/// Send the contents of the transmit immediately.
357-
///
358-
/// Packets were written and the GSO batch must end now, regardless from whether higher
359-
/// spaces still have frames to write. This is used when the last datagram written would
360-
/// require too much padding to continue a GSO batch, which would waste space on the
361-
/// wire.
362-
Send {
363-
/// The highest packet number written into the transmit.
364-
last_packet_number: u64,
365-
},
366-
}
367-
368317
impl Connection {
369318
pub(crate) fn new(
370319
endpoint_config: Arc<EndpointConfig>,
@@ -6781,6 +6730,14 @@ impl Connection {
67816730
}
67826731
}
67836732

6733+
impl fmt::Debug for Connection {
6734+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6735+
f.debug_struct("Connection")
6736+
.field("handshake_cid", &self.handshake_cid)
6737+
.finish()
6738+
}
6739+
}
6740+
67846741
/// Hints when the caller identifies a network change.
67856742
pub trait NetworkChangeHint: std::fmt::Debug + 'static {
67866743
/// Inform the connection if a path may recover after a network change.
@@ -6794,12 +6751,55 @@ pub trait NetworkChangeHint: std::fmt::Debug + 'static {
67946751
fn is_path_recoverable(&self, path_id: PathId, network_path: FourTuple) -> bool;
67956752
}
67966753

6797-
impl fmt::Debug for Connection {
6798-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6799-
f.debug_struct("Connection")
6800-
.field("handshake_cid", &self.handshake_cid)
6801-
.finish()
6802-
}
6754+
/// Return value for [`Connection::poll_transmit_path`].
6755+
#[derive(Debug)]
6756+
enum PollPathStatus {
6757+
/// Nothing to send on the path, nothing was written into the [`TransmitBuf`].
6758+
NothingToSend {
6759+
/// If true there was data to send but congestion control did not allow so.
6760+
congestion_blocked: bool,
6761+
},
6762+
/// The transmit is ready to be sent.
6763+
Send(Transmit),
6764+
}
6765+
6766+
/// Return value for [`Connection::poll_transmit_path_space`].
6767+
#[derive(Debug)]
6768+
enum PollPathSpaceStatus {
6769+
/// Nothing to send in the space, nothing was written into the [`TransmitBuf`].
6770+
NothingToSend {
6771+
/// If true there was data to send but congestion control did not allow so.
6772+
congestion_blocked: bool,
6773+
},
6774+
/// One or more packets have been written into the [`TransmitBuf`].
6775+
WrotePacket {
6776+
/// The highest packet number.
6777+
last_packet_number: u64,
6778+
/// Whether to pad an already started datagram in the next packet.
6779+
///
6780+
/// When packets in Initial, 0-RTT or Handshake packet do not fill the entire
6781+
/// datagram they may decide to coalesce with the next packet from a higher
6782+
/// encryption level on the same path. But the earlier packet may require specific
6783+
/// size requirements for the datagram they are sent in.
6784+
///
6785+
/// If a space did not complete the datagram, they use this to request the correct
6786+
/// padding in the final packet of the datagram so that the final datagram will have
6787+
/// the correct size.
6788+
///
6789+
/// If a space did fill an entire datagram, it leaves this to the default of
6790+
/// [`PadDatagram::No`].
6791+
pad_datagram: PadDatagram,
6792+
},
6793+
/// Send the contents of the transmit immediately.
6794+
///
6795+
/// Packets were written and the GSO batch must end now, regardless from whether higher
6796+
/// spaces still have frames to write. This is used when the last datagram written would
6797+
/// require too much padding to continue a GSO batch, which would waste space on the
6798+
/// wire.
6799+
Send {
6800+
/// The highest packet number written into the transmit.
6801+
last_packet_number: u64,
6802+
},
68036803
}
68046804

68056805
#[derive(Debug, Copy, Clone, PartialEq, Eq)]

quinn-proto/src/connection/spaces.rs

Lines changed: 105 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -554,58 +554,104 @@ pub struct Retransmits {
554554

555555
impl Retransmits {
556556
pub(super) fn is_empty(&self, streams: &StreamsState) -> bool {
557-
!self.max_data
558-
&& !self.max_stream_id.into_iter().any(|x| x)
559-
&& self.reset_stream.is_empty()
560-
&& self.stop_sending.is_empty()
561-
&& self
562-
.max_stream_data
557+
let Self {
558+
max_data,
559+
max_stream_id,
560+
reset_stream,
561+
stop_sending,
562+
max_stream_data,
563+
crypto,
564+
new_cids,
565+
retire_cids,
566+
ack_frequency,
567+
handshake_done,
568+
observed_addr,
569+
max_path_id,
570+
paths_blocked,
571+
new_tokens,
572+
path_abandon,
573+
path_status,
574+
path_cids_blocked,
575+
add_address,
576+
remove_address,
577+
reach_out,
578+
} = &self;
579+
!max_data
580+
&& !max_stream_id.iter().any(|x| *x)
581+
&& reset_stream.is_empty()
582+
&& stop_sending.is_empty()
583+
&& max_stream_data
563584
.iter()
564585
.all(|&id| !streams.can_send_flow_control(id))
565-
&& self.crypto.is_empty()
566-
&& self.new_cids.is_empty()
567-
&& self.retire_cids.is_empty()
568-
&& !self.ack_frequency
569-
&& !self.handshake_done
570-
&& !self.observed_addr
571-
&& self.new_tokens.is_empty()
572-
&& self.path_abandon.is_empty()
573-
&& self.path_status.is_empty()
574-
&& !self.max_path_id
575-
&& !self.paths_blocked
576-
&& self.add_address.is_empty()
577-
&& self.remove_address.is_empty()
578-
&& self.reach_out.is_none()
586+
&& crypto.is_empty()
587+
&& new_cids.is_empty()
588+
&& retire_cids.is_empty()
589+
&& !ack_frequency
590+
&& !handshake_done
591+
&& !observed_addr
592+
&& !max_path_id
593+
&& !paths_blocked
594+
&& new_tokens.is_empty()
595+
&& path_abandon.is_empty()
596+
&& path_status.is_empty()
597+
&& path_cids_blocked.is_empty()
598+
&& add_address.is_empty()
599+
&& remove_address.is_empty()
600+
&& reach_out.is_none()
579601
}
580602
}
581603

582604
impl ::std::ops::BitOrAssign for Retransmits {
583-
fn bitor_assign(&mut self, mut rhs: Self) {
605+
fn bitor_assign(&mut self, rhs: Self) {
606+
let Self {
607+
max_data,
608+
max_stream_id,
609+
reset_stream,
610+
stop_sending,
611+
max_stream_data,
612+
crypto,
613+
new_cids,
614+
retire_cids,
615+
ack_frequency,
616+
handshake_done,
617+
observed_addr,
618+
max_path_id,
619+
paths_blocked,
620+
new_tokens,
621+
mut path_abandon,
622+
mut path_status,
623+
mut path_cids_blocked,
624+
add_address,
625+
remove_address,
626+
reach_out,
627+
} = rhs;
628+
584629
// We reduce in-stream head-of-line blocking by queueing retransmits before other data for
585630
// STREAM and CRYPTO frames.
586-
self.max_data |= rhs.max_data;
631+
self.max_data |= max_data;
587632
for dir in Dir::iter() {
588-
self.max_stream_id[dir as usize] |= rhs.max_stream_id[dir as usize];
633+
self.max_stream_id[dir as usize] |= max_stream_id[dir as usize];
589634
}
590-
self.reset_stream.extend_from_slice(&rhs.reset_stream);
591-
self.stop_sending.extend_from_slice(&rhs.stop_sending);
592-
self.max_stream_data.extend(&rhs.max_stream_data);
593-
for crypto in rhs.crypto.into_iter().rev() {
635+
self.reset_stream.extend_from_slice(&reset_stream);
636+
self.stop_sending.extend_from_slice(&stop_sending);
637+
self.max_stream_data.extend(&max_stream_data);
638+
for crypto in crypto.into_iter().rev() {
594639
self.crypto.push_front(crypto);
595640
}
596-
self.new_cids.extend(&rhs.new_cids);
597-
self.retire_cids.extend(rhs.retire_cids);
598-
self.ack_frequency |= rhs.ack_frequency;
599-
self.handshake_done |= rhs.handshake_done;
600-
self.observed_addr |= rhs.observed_addr;
601-
self.new_tokens.extend_from_slice(&rhs.new_tokens);
602-
self.path_abandon.append(&mut rhs.path_abandon);
603-
self.max_path_id |= rhs.max_path_id;
604-
self.paths_blocked |= rhs.paths_blocked;
605-
self.add_address.extend(rhs.add_address.iter().copied());
606-
self.remove_address
607-
.extend(rhs.remove_address.iter().copied());
608-
if let Some((rhs_round, rhs_addrs)) = rhs.reach_out {
641+
self.new_cids.extend(&new_cids);
642+
self.retire_cids.extend(retire_cids);
643+
self.ack_frequency |= ack_frequency;
644+
self.handshake_done |= handshake_done;
645+
self.observed_addr |= observed_addr;
646+
self.max_path_id |= max_path_id;
647+
self.paths_blocked |= paths_blocked;
648+
self.new_tokens.extend_from_slice(&new_tokens);
649+
self.path_abandon.append(&mut path_abandon);
650+
self.path_status.append(&mut path_status);
651+
self.path_cids_blocked.append(&mut path_cids_blocked);
652+
self.add_address.extend(add_address.iter().copied());
653+
self.remove_address.extend(remove_address.iter().copied());
654+
if let Some((rhs_round, rhs_addrs)) = reach_out {
609655
match self.reach_out.as_mut() {
610656
// Use RHS if there is no recorded round.
611657
None => self.reach_out = Some((rhs_round, rhs_addrs)),
@@ -626,7 +672,8 @@ impl ::std::ops::BitOrAssign for Retransmits {
626672

627673
impl ::std::ops::BitOrAssign<ThinRetransmits> for Retransmits {
628674
fn bitor_assign(&mut self, rhs: ThinRetransmits) {
629-
if let Some(retransmits) = rhs.retransmits {
675+
let ThinRetransmits { retransmits } = rhs;
676+
if let Some(retransmits) = retransmits {
630677
self.bitor_assign(*retransmits)
631678
}
632679
}
@@ -841,16 +888,28 @@ impl SendableFrames {
841888

842889
/// Whether no data is sendable
843890
pub(super) fn is_empty(&self) -> bool {
844-
!self.acks && !self.other && !self.close && !self.path_exclusive
891+
let Self {
892+
acks,
893+
other,
894+
close,
895+
path_exclusive,
896+
} = *self;
897+
!acks && !other && !close && !path_exclusive
845898
}
846899
}
847900

848901
impl ::std::ops::BitOrAssign for SendableFrames {
849902
fn bitor_assign(&mut self, rhs: Self) {
850-
self.acks |= rhs.acks;
851-
self.other |= rhs.other;
852-
self.close |= rhs.close;
853-
self.path_exclusive |= rhs.path_exclusive;
903+
let Self {
904+
acks,
905+
other,
906+
close,
907+
path_exclusive,
908+
} = rhs;
909+
self.acks |= acks;
910+
self.other |= other;
911+
self.close |= close;
912+
self.path_exclusive |= path_exclusive;
854913
}
855914
}
856915

0 commit comments

Comments
 (0)