diff --git a/Makefile b/Makefile index b2ed055..f7880bd 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,8 @@ all: release-build debug-build: cargo build + cp ./target/debug/hptp-recv ./3700recv + cp ./target/debug/hptp-send ./3700send release-build: cargo build --release diff --git a/hptp/src/encoding.rs b/hptp/src/encoding.rs index e3ea8d9..2b55260 100644 --- a/hptp/src/encoding.rs +++ b/hptp/src/encoding.rs @@ -7,16 +7,16 @@ lazy_static! { static WRAP_SIZE: usize = 60; -pub fn can_be_encoded(data: &[u8]) -> bool { - ENCODING_DETECTOR.is_match(data) -} - #[derive(Clone)] pub struct MeowCoder { line_index: usize, } impl MeowCoder { + pub fn can_be_encoded(data: &[u8]) -> bool { + ENCODING_DETECTOR.is_match(data) + } + pub fn new() -> MeowCoder { MeowCoder{line_index: 0} } @@ -43,7 +43,7 @@ impl MeowCoder { (LOOKUP[first as usize], LOOKUP[second as usize]) } - pub fn encode(input: &Vec) -> Vec { + pub fn encode(input: &Vec) -> (Vec, bool) { let mut out: Vec = Vec::new(); let mut prev_char: u8 = 0; let mut pair_first = false; @@ -61,15 +61,23 @@ impl MeowCoder { pair_first = false; } } - out + // trailing byte specifies whether this was cut or not + if pair_first { + out.push(MeowCoder::hex_to_nibble(prev_char) * 16); + (out, true) + } else { + (out, false) + } } - pub fn decode(&mut self, input: &Vec) -> Vec { + pub fn decode(&mut self, input: &Vec, was_cut: bool) -> Vec { let mut out: Vec = Vec::new(); - for byte in input { + for (pos, byte) in input.iter().enumerate() { let (first, second) = MeowCoder::u8_to_hex(*byte); out.push(first); - out.push(second); + if pos < input.len() - 1 || !was_cut { + out.push(second); + } self.line_index += 2; if self.line_index == WRAP_SIZE { self.line_index = 0; @@ -86,27 +94,43 @@ mod tests { #[test] fn test_match() { - assert_eq!(can_be_encoded(b"abcd1234"), true); - assert_eq!(can_be_encoded(b"abcXd1234"), false); - assert_eq!(can_be_encoded(b"012345678901234567890123456789012345678901234567890123456789\nabcdef"), true); - assert_eq!(can_be_encoded(b"01234567890123456789012345678901234567890123456789012345678\nabcdef"), false); - assert_eq!(can_be_encoded(b"\x12\xab\x45\n"), false); + assert_eq!(MeowCoder::can_be_encoded(b"abcd1234"), true); + assert_eq!(MeowCoder::can_be_encoded(b"abcXd1234"), false); + assert_eq!(MeowCoder::can_be_encoded(b"012345678901234567890123456789012345678901234567890123456789\nabcdef"), true); + assert_eq!(MeowCoder::can_be_encoded(b"01234567890123456789012345678901234567890123456789012345678\nabcdef"), false); + assert_eq!(MeowCoder::can_be_encoded(b"\x12\xab\x45\n"), false); } #[test] fn test_encode() { let vec = vec!['a' as u8, '4' as u8, 'c' as u8, 'd' as u8, '\n' as u8, 'e' as u8, 'f' as u8]; - assert_eq!(MeowCoder::encode(&vec), vec![0xa4, 0xcd, 0xef]); + assert_eq!(MeowCoder::encode(&vec), (vec![0xa4, 0xcd, 0xef], false)); + + let vec2 = vec!['a' as u8, '4' as u8, 'c' as u8, 'd' as u8, + '\n' as u8, 'e' as u8, 'f' as u8, '9' as u8]; + assert_eq!(MeowCoder::encode(&vec2), (vec![0xa4, 0xcd, 0xef, 0x90], true)); } #[test] fn test_encode_decode() { let hex_str: &[u8] = b"012345678901234567890123456789012345678901234567890123456789\nabcdef"; let vec: Vec = Vec::from(hex_str); - let vec2 = MeowCoder::encode(&vec); + let (vec2, was_cut) = MeowCoder::encode(&vec); + assert_eq!(was_cut, false); let mut coder = MeowCoder::new(); - let out = coder.decode(&vec2); + let out = coder.decode(&vec2, was_cut); + assert_eq!(out, vec); + } + + #[test] + fn test_encode_decode_cut() { + let hex_str: &[u8] = b"012345678901234567890123456789012345678901234567890123456789\nabcdef3"; + let vec: Vec = Vec::from(hex_str); + let (vec2, was_cut) = MeowCoder::encode(&vec); + assert_eq!(was_cut, true); + let mut coder = MeowCoder::new(); + let out = coder.decode(&vec2, was_cut); assert_eq!(out, vec); } } diff --git a/hptp/src/msg.rs b/hptp/src/msg.rs index da14c5d..386f9f9 100644 --- a/hptp/src/msg.rs +++ b/hptp/src/msg.rs @@ -31,6 +31,7 @@ pub trait SerDes: Sized { type BO = byteorder::LE; const LAST_SEG_MASK: u32 = 1 << 31; +const MEOW_CODED_MASK: u32 = 1 << 30; impl SerDes for UpMsg { fn des(buf: &[u8]) -> Result { @@ -39,11 +40,11 @@ impl SerDes for UpMsg { } else { let hdr = BO::read_u32(&buf[0..4]); Ok(UpMsg::Data { - seg_idx: hdr & !LAST_SEG_MASK, + seg_idx: hdr & !LAST_SEG_MASK & !MEOW_CODED_MASK, payload: SegData { bytes: buf[4..].into(), is_last_segment: (hdr & LAST_SEG_MASK) != 0, - is_meow_encoded: false, + is_meow_encoded: (hdr & MEOW_CODED_MASK) != 0, }, }) } @@ -60,7 +61,8 @@ impl SerDes for UpMsg { }, seg_idx, } => { - let hdr = *seg_idx | if *is_last_segment { LAST_SEG_MASK } else { 0 }; + let hdr = *seg_idx | if *is_last_segment { LAST_SEG_MASK } else { 0 } + | if *is_meow_encoded { MEOW_CODED_MASK } else { 0 }; BO::write_u32(&mut buf[0..4], hdr); let len = bytes.len(); buf[4..4 + len].copy_from_slice(&bytes[..]); diff --git a/hptp/src/seg.rs b/hptp/src/seg.rs index 3319788..e2a8b0e 100644 --- a/hptp/src/seg.rs +++ b/hptp/src/seg.rs @@ -50,7 +50,7 @@ pub struct SegmentSet { #[derive(Clone)] pub struct SegData { - pub(crate) bytes: Vec, + pub bytes: Vec, pub is_last_segment: bool, pub is_meow_encoded: bool, } diff --git a/scripts/create-net-ns.sh b/scripts/create-net-ns.sh index a304a9b..f071126 100755 --- a/scripts/create-net-ns.sh +++ b/scripts/create-net-ns.sh @@ -8,5 +8,5 @@ sudo unshare -n capsh --caps="cap_net_admin+eip cap_setpcap,cap_setuid,cap_setgi -- -c "export PATH=$PWD/.netsim:\$PATH; export HOME=$PWD; /usr/bin/ip link set lo up; netsim; \ export PERL5LIB=\"/home/$USER/perl5/lib/perl5\${PERL5LIB:+:\${PERL5LIB}}\" \ export PERL_LOCAL_LIB_ROOT=\"/home/$USER/perl5\${PERL_LOCAL_LIB_ROOT:+:\${PERL_LOCAL_LIB_ROOT}}\" \ - tc qdisc show dev lo; /bin/bash --init-file <(echo unset HISTFILE)" + tc qdisc show dev lo; cd .netsim; /bin/bash --init-file <(echo unset HISTFILE)" true