Connection

Struct Connection 

Source
pub struct Connection { /* private fields */ }
Expand description

Contains the state information and implements the logic for a minimalist TCP connection.

One particular thing is that whenever the connection sends a RST segment, it will also stop working itself. This is just a design decision for our envisioned use cases; improvements/changes may happen in the future (this also goes for other aspects of the current implementation).

A Connection object can only be created via passive open, and will not recognize/use any TCP options except MSS during the handshake. The associated state machine is similar to how TCP normally functions, but there are some differences:

  • Since only passive opens are supported, a Connection can only be instantiated in response to an incoming SYN segment. If the segment is valid, it will start directly in a state called SYN_RECEIVED. The valid events at this point are receiving a retransmission of the previous SYN (which does nothing), and getting the chance to write a SYNACK, which also moves the connection to the SYNACK_SENT state. Any incoming segment which is not a copy of the previous SYN will reset the connection.
  • In the SYNACK_SENT state, the connection awaits an ACK for the SYNACK. A retransmission of the original SYN moves the state back to SYN_RECEIVED. A valid ACK advances the state to ESTABLISHED. Any unexpected/invalid segment resets the connection.
  • While ESTABLISHED, the connection will only reset if it receives a RST or a SYN. Invalid segments are simply ignored. FIN handling is simplifed: when close is invoked the connection records the FIN sequence number, and starts setting the FIN flag (when possible) on outgoing segments. A FIN from the other endpoint is only taken into consideration if it has the next expected sequence number. When the connection has both sent and received a FIN, it marks itself as being done. There’s no equivalent for the TIME_WAIT TCP state.

The current implementation does not do any kind of congestion control, expects segments to arrive in order, triggers a retransmission after the first duplicate ACK, and relies on the user to supply an opaque u64 timestamp value when invoking send or receive functionality. The timestamps must be non-decreasing, and are mainly used for retransmission timeouts.

See mmds-design for why we are able to make these simplifications. Specifically, we want to stress that no traffic handled by dumbo ever leaves a microVM.

Implementations§

Source§

impl Connection

Source

pub fn passive_open<T: NetworkBytes + Debug>( segment: &TcpSegment<'_, T>, local_rwnd_size: u32, rto_period: NonZeroU64, rto_count_max: NonZeroU16, ) -> Result<Self, PassiveOpenError>

Attempts to create a new Connection in response to an incoming SYN segment.

§Arguments
  • segment - The incoming SYN.
  • local_rwnd_size - Initial size of the local receive window.
  • rto_period - How long the connection waits before a retransmission timeout fires for the first segment which has not been acknowledged yet. This uses an opaque time unit.
  • rto_count_max - How many consecutive timeout-based retransmission may occur before the connection resets itself.
Source

pub fn close(&mut self)

Closes this half of the connection.

Subsequent calls after the first one do not have any effect. The sequence number of the FIN is the first sequence number not yet sent at this point.

Source

pub fn make_rst_config(&self) -> RstConfig

Returns a valid configuration for a RST segment, which can be sent to the other endpoint to signal the connection should be reset.

Source

pub fn reset(&mut self)

Specifies that a RST segment should be sent to the other endpoint, and then the connection should be destroyed.

Source

pub fn is_established(&self) -> bool

Returns true if the connection is past the ESTABLISHED point.

Source

pub fn fin_received(&self) -> bool

Returns true if a FIN has been received.

Source

pub fn is_done(&self) -> bool

Returns true if the connection is done communicating with the other endpoint.

Maybe it would be a good idea to return true only after our FIN has also been ACKed? Otherwise, when using the TCP handler there’s pretty much always going to be an ACK for the FIN that’s going to trigger a gratuitous RST (best case), or can even be considered valid if a new connection is created meanwhile using the same tuple and we get very unlucky (worst case, extremely unlikely though).

Source

pub fn first_not_sent(&self) -> Wrapping<u32>

Returns the first sequence number which has not been sent yet for the current window.

Source

pub fn highest_ack_received(&self) -> Wrapping<u32>

Returns the highest acknowledgement number received for the current window.

Source

pub fn advance_local_rwnd_edge(&mut self, value: u32)

Advances the right edge of the local receive window.

This is effectively allowing the other endpoint to send more data, because no byte can be sent unless its sequence number falls into the receive window.

Source

pub fn remote_rwnd_edge(&self) -> Wrapping<u32>

Returns the right edge of the receive window advertised by the other endpoint.

Source

pub fn dup_ack_pending(&self) -> bool

Returns true if a retransmission caused by the reception of a duplicate ACK is pending.

Source

pub fn control_segment_or_timeout_status(&self) -> NextSegmentStatus

Describes whether a control segment can be sent immediately, a retransmission is pending, or there’s nothing to transmit until more segments are received.

This function does not tell whether any data segments can/will be sent, because the Connection itself does not control the send buffer. Thus the information returned here only pertains to control segments and timeout expiry. Data segment related status will be reported by higher level components, which also manage the contents of the send buffer.

Source

pub fn receive_segment<T: NetworkBytes + Debug>( &mut self, s: &TcpSegment<'_, T>, buf: &mut [u8], now: u64, ) -> Result<(Option<NonZeroUsize>, RecvStatusFlags), RecvError>

Handles an incoming segment.

When no errors occur, returns a pair consisting of how many bytes (if any) were received, and whether any unusual conditions arose while processing the segment. Since a Connection does not have its own internal buffer, buf is required to store any data carried by incoming segments.

§Arguments
  • s - The incoming segment.
  • buf - The receive buffer where payload data (if any) from s is going to be written.
  • now - An opaque timestamp representing the current moment in time.
Source

pub fn write_next_segment<'a, R: ByteBuffer + ?Sized + Debug>( &mut self, buf: &'a mut [u8], mss_reserved: u16, payload_src: PayloadSource<'_, R>, now: u64, ) -> Result<Option<Incomplete<TcpSegment<'a, &'a mut [u8]>>>, WriteNextError>

Writes a new segment (if available) to the specified buffer.

The payload_src argument is required because the Connection does not have an internal send buffer. If the payload source is present, the data referenced therein must not amount to more than MAX_WINDOW_SIZE.

§Arguments
  • buf - The buffer where the segment is written.
  • mss_reserved - How much (if anything) of the MSS value has been already used at the lower layers (by IP options, for example). This will be zero most of the time.
  • payload_src - References a buffer which contains data to send, and also specifies the sequence number associated with the first byte from that buffer.
  • now - An opaque timestamp representing the current moment in time.

Trait Implementations§

Source§

impl Clone for Connection

Source§

fn clone(&self) -> Connection

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Connection

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AsAny for T
where T: Any,

Source§

fn as_any(&self) -> &(dyn Any + 'static)

Return the immutable any encapsulated object.
Source§

fn as_mut_any(&mut self) -> &mut (dyn Any + 'static)

Return the mutable encapsulated any object.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> Conv for T

§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
§

impl<T> FmtForward for T

§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pipe for T
where T: ?Sized,

§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
§

impl<T> Tap for T

§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T> TryConv for T

§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V