net-wire 0.1.0

Allocation-free no_std wire views and codecs for network protocols.
Documentation
use net_wire::ParseError;
use net_wire::tcp::{TcpFlags, TcpSegment, TcpSegmentBuildError, TcpSegmentBuilder, TcpSegmentMut};

fn build_with_local_options(buffer: &mut [u8]) -> TcpSegmentMut<'_> {
    let options = [1, 2, 3, 4];
    TcpSegmentBuilder::new(buffer, 1)
        .source_port(1)
        .destination_port(2)
        .options(&options)
        .sequence_number(3)
        .acknowledgment_number(4)
        .flags(TcpFlags::SYN)
        .window_size(5)
        .checksum(0xbeef)
        .urgent_pointer(6)
        .build()
        .unwrap()
}

#[test]
fn layout_all_accessors_mutators_flags_and_builder_errors() {
    assert_eq!(
        TcpSegment::parse(&[0; 19]),
        Err(ParseError::Truncated {
            minimum: 20,
            available: 19
        })
    );
    let mut short = [0; 20];
    short[12] = 0x40;
    assert_eq!(
        TcpSegment::parse(&short),
        Err(ParseError::InvalidHeaderLength {
            minimum: 20,
            actual: 16
        })
    );
    short[12] = 0x60;
    assert_eq!(
        TcpSegment::parse(&short),
        Err(ParseError::Truncated {
            minimum: 24,
            available: 20
        })
    );
    let bytes = [
        0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0x65, 0xa5, 0, 9, 0x12, 0x34, 0, 7, 1, 2, 3, 4, 9,
    ];
    let p = TcpSegment::parse(&bytes).unwrap();
    assert_eq!(p.source_port(), 1);
    assert_eq!(p.destination_port(), 2);
    assert_eq!(p.sequence_number(), 3);
    assert_eq!(p.acknowledgment_number(), 4);
    assert_eq!(p.data_offset(), 6);
    assert_eq!(p.header_length(), 24);
    assert_eq!(p.reserved(), 5);
    assert_eq!(p.flags().raw(), 0xa5);
    assert_eq!(p.window_size(), 9);
    assert_eq!(p.checksum(), 0x1234);
    assert_eq!(p.urgent_pointer(), 7);
    assert_eq!(p.options(), &[1, 2, 3, 4]);
    assert_eq!(p.payload(), &[9]);
    assert_eq!(p.as_bytes(), &bytes);
    let flags = TcpFlags::SYN.union(TcpFlags::ACK);
    assert!(flags.contains(TcpFlags::SYN | TcpFlags::ACK));
    assert_eq!(flags.raw(), 0x12);
    assert_eq!((TcpFlags::FIN | TcpFlags::CWR).raw(), 0x81);
    assert_eq!(TcpFlags::new(0xff).raw(), 0xff);
    let mut bytes = bytes;
    let mut p = TcpSegmentMut::parse(&mut bytes).unwrap();
    p.set_source_port(9);
    p.set_destination_port(10);
    p.set_sequence_number(11);
    p.set_acknowledgment_number(12);
    p.set_flags(flags);
    assert_eq!(&p.as_bytes()[12..14], &[0x65, 0x12]);
    p.set_window_size(13);
    p.set_checksum(0xbeef);
    p.set_urgent_pointer(14);
    p.options_mut()[0] = 8;
    p.payload_mut()[0] = 7;
    assert_eq!(
        (
            p.source_port(),
            p.destination_port(),
            p.sequence_number(),
            p.acknowledgment_number(),
            p.reserved(),
            p.flags().raw(),
            p.window_size(),
            p.checksum(),
            p.urgent_pointer(),
            p.options(),
            p.payload()
        ),
        (
            9,
            10,
            11,
            12,
            5,
            0x12,
            13,
            0xbeef,
            14,
            &[8, 2, 3, 4][..],
            &[7][..]
        )
    );
    let mut output = [0xa5; 26];
    output[24] = 9;
    let built = build_with_local_options(&mut output);
    assert_eq!(built.options(), &[1, 2, 3, 4]);
    assert_eq!(built.payload(), &[9]);
    assert_eq!(built.checksum(), 0xbeef);
    assert_eq!(&built.as_bytes()[12..14], &[0x60, 0x02]);
    assert_eq!(built.flags(), TcpFlags::SYN);
    assert_eq!(built.reserved(), 0);
    assert_eq!(&output[25..], &[0xa5]);
    let mut buffer = [0xa5; 25];
    let before = buffer;
    assert_eq!(
        TcpSegmentBuilder::new(&mut buffer, 0).build(),
        Err(TcpSegmentBuildError::MissingSourcePort)
    );
    assert_eq!(buffer, before);
    assert_eq!(
        TcpSegmentBuilder::new(&mut buffer, 0)
            .source_port(1)
            .build(),
        Err(TcpSegmentBuildError::MissingDestinationPort)
    );
    assert_eq!(buffer, before);
    assert_eq!(
        TcpSegmentBuilder::new(&mut buffer, 0)
            .source_port(1)
            .destination_port(2)
            .options(&[1])
            .build(),
        Err(TcpSegmentBuildError::InvalidOptionsLength)
    );
    assert_eq!(buffer, before);
    assert_eq!(
        TcpSegmentBuilder::new(&mut buffer, 0)
            .source_port(1)
            .destination_port(2)
            .options(&[0; 44])
            .build(),
        Err(TcpSegmentBuildError::InvalidOptionsLength)
    );
    assert_eq!(buffer, before);
    assert_eq!(
        TcpSegmentBuilder::new(&mut buffer, usize::MAX)
            .source_port(1)
            .destination_port(2)
            .build(),
        Err(TcpSegmentBuildError::SegmentLengthTooLarge)
    );
    assert_eq!(buffer, before);
    assert_eq!(
        TcpSegmentBuilder::new(&mut buffer, 6)
            .source_port(1)
            .destination_port(2)
            .build(),
        Err(TcpSegmentBuildError::BufferTooShort {
            required: 26,
            available: 25
        })
    );
    assert_eq!(buffer, before);
}