179 lines
6.4 KiB
Rust
179 lines
6.4 KiB
Rust
use libremetaverse::packets::{
|
|
AgentThrottlePacket, Header, Packet, PacketType, UseCircuitCodePacket,
|
|
};
|
|
use libremetaverse::{Error, Helpers, PacketFrequency};
|
|
use libremetaverse_types::UUID;
|
|
|
|
fn header(frequency: PacketFrequency, id: u16) -> Header {
|
|
Header {
|
|
ack_list: None,
|
|
appended_acks: false,
|
|
frequency,
|
|
id,
|
|
reliable: true,
|
|
resent: false,
|
|
sequence: 0x0102_0304,
|
|
zerocoded: false,
|
|
}
|
|
}
|
|
|
|
fn header_bytes(header: &Header) -> Vec<u8> {
|
|
let length = match header.frequency {
|
|
PacketFrequency::High => 7,
|
|
PacketFrequency::Medium => 8,
|
|
PacketFrequency::Low => 10,
|
|
};
|
|
let mut bytes = vec![0_u8; length];
|
|
let mut position = 0;
|
|
header
|
|
.to_bytes(&mut bytes, &mut position)
|
|
.expect("encode header");
|
|
assert_eq!(usize::try_from(position).unwrap(), bytes.len());
|
|
bytes
|
|
}
|
|
|
|
#[test]
|
|
fn header_frequencies_match_the_reference_wire_bytes() {
|
|
// Golden source: codegen/inputs/message_template.msg frequency rules and
|
|
// LibreMetaverse.Tests/PacketTests.cs::HeaderFlags (translated in
|
|
// tests/compat/tests/wire_semantics.rs::packet_header_flags).
|
|
assert_eq!(
|
|
header_bytes(&header(PacketFrequency::High, 0x2a)),
|
|
[0x40, 1, 2, 3, 4, 0, 0x2a]
|
|
);
|
|
assert_eq!(
|
|
header_bytes(&header(PacketFrequency::Medium, 0x2a)),
|
|
[0x40, 1, 2, 3, 4, 0, 0xff, 0x2a]
|
|
);
|
|
assert_eq!(
|
|
header_bytes(&header(PacketFrequency::Low, 0x1234)),
|
|
[0x40, 1, 2, 3, 4, 0, 0xff, 0xff, 0x12, 0x34]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn appended_acks_are_big_endian_and_removed_from_the_payload_boundary() {
|
|
let mut value = header(PacketFrequency::High, 0x2a);
|
|
value.appended_acks = true;
|
|
value.ack_list = Some(vec![0x0102_0304, 0xa0b0_c0d0]);
|
|
let mut bytes = header_bytes(&value);
|
|
let mut ack_bytes = [0_u8; 9];
|
|
let mut ack_position = 0;
|
|
value
|
|
.acks_to_bytes(&mut ack_bytes, &mut ack_position)
|
|
.expect("encode ACKs");
|
|
assert_eq!(ack_bytes, [1, 2, 3, 4, 0xa0, 0xb0, 0xc0, 0xd0, 2]);
|
|
bytes.extend_from_slice(&ack_bytes);
|
|
|
|
let mut position = 0;
|
|
let mut packet_end = i32::try_from(bytes.len()).unwrap() - 1;
|
|
let decoded = Header::build_header(bytes, &mut position, &mut packet_end).expect("decode");
|
|
assert!(decoded.appended_acks);
|
|
assert_eq!(decoded.ack_list, value.ack_list);
|
|
assert_eq!(position, 7);
|
|
assert_eq!(packet_end, 6);
|
|
}
|
|
|
|
#[test]
|
|
fn use_circuit_code_matches_the_reference_golden_packet() {
|
|
// Golden schema: codegen/inputs/message_template.msg::UseCircuitCode
|
|
// (Low 3, CircuitCode/U32 + SessionID/LLUUID + ID/LLUUID). Header behavior
|
|
// is linked to the translated HeaderFlags test above.
|
|
let session = (0_u8..16).collect::<Vec<_>>();
|
|
let agent = (16_u8..32).collect::<Vec<_>>();
|
|
let mut packet = UseCircuitCodePacket::new_with_constructor().expect("packet constructor");
|
|
packet.circuit_code.code = 0x1122_3344;
|
|
packet.circuit_code.session_id =
|
|
UUID::new_with_bytes_int32(session.clone(), 0).expect("session UUID");
|
|
packet.circuit_code.id = UUID::new_with_bytes_int32(agent.clone(), 0).expect("agent UUID");
|
|
|
|
let encoded = packet.to_bytes_with_method().expect("encode packet");
|
|
let mut expected = vec![
|
|
0x40, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 3, 0x44, 0x33, 0x22, 0x11,
|
|
];
|
|
expected.extend_from_slice(&session);
|
|
expected.extend_from_slice(&agent);
|
|
assert_eq!(encoded, expected);
|
|
|
|
let mut position = 0;
|
|
let decoded =
|
|
UseCircuitCodePacket::new_with_bytes_int32(encoded.clone(), &mut position).expect("decode");
|
|
assert_eq!(usize::try_from(position).unwrap(), encoded.len());
|
|
assert_eq!(decoded.circuit_code.code, 0x1122_3344);
|
|
assert_eq!(
|
|
decoded.circuit_code.session_id.get_bytes().unwrap(),
|
|
session
|
|
);
|
|
assert_eq!(decoded.circuit_code.id.get_bytes().unwrap(), agent);
|
|
assert_eq!(decoded.to_bytes_with_method().unwrap(), encoded);
|
|
}
|
|
|
|
#[test]
|
|
fn malformed_and_unknown_packets_return_errors_without_panicking() {
|
|
let valid = [0x40, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 3];
|
|
for length in 0..valid.len() {
|
|
let bytes = valid[..length].to_vec();
|
|
let outcome = std::panic::catch_unwind(|| {
|
|
let mut end = i32::try_from(bytes.len()).unwrap() - 1;
|
|
Packet::build_packet_with_bytes_int32_bytes(bytes.clone(), &mut end, vec![0; 64])
|
|
});
|
|
assert!(outcome.is_ok(), "truncation at {length} panicked");
|
|
assert!(
|
|
outcome.unwrap().is_err(),
|
|
"truncation at {length} was accepted"
|
|
);
|
|
}
|
|
|
|
let missing_payload = valid.to_vec();
|
|
let mut end = i32::try_from(missing_payload.len()).unwrap() - 1;
|
|
assert!(
|
|
Packet::build_packet_with_bytes_int32_bytes(missing_payload, &mut end, vec![0; 64])
|
|
.is_err()
|
|
);
|
|
|
|
let unknown = vec![0x40, 0, 0, 0, 0, 0, 0xfe];
|
|
let mut end = i32::try_from(unknown.len()).unwrap() - 1;
|
|
let Err(error) = Packet::build_packet_with_bytes_int32_bytes(unknown, &mut end, vec![0; 64])
|
|
else {
|
|
panic!("unknown packet ID was accepted");
|
|
};
|
|
assert!(matches!(error, Error::Parse { .. }));
|
|
}
|
|
|
|
#[test]
|
|
fn packet_factory_decodes_zerocoded_payloads() {
|
|
let mut packet = AgentThrottlePacket::new_with_constructor().expect("packet constructor");
|
|
packet.agent_data.circuit_code = 0x1122_3344;
|
|
packet.throttle.gen_counter = 0x5566_7788;
|
|
packet.throttle.throttles = vec![1, 0, 0, 2, 3];
|
|
let raw = packet.to_bytes_with_method().expect("raw packet");
|
|
let mut encoded = vec![0_u8; raw.len() * 2 + 2];
|
|
let encoded_length = Helpers::zero_encode(
|
|
Some(&raw),
|
|
i32::try_from(raw.len()).unwrap(),
|
|
Some(&mut encoded),
|
|
)
|
|
.expect("zero encode");
|
|
encoded.truncate(usize::try_from(encoded_length).unwrap());
|
|
|
|
let mut end = encoded_length - 1;
|
|
let built =
|
|
Packet::build_packet_with_bytes_int32_bytes(encoded, &mut end, vec![0_u8; raw.len()])
|
|
.expect("packet factory");
|
|
assert_eq!(built.type_, PacketType::AgentThrottle);
|
|
assert_eq!(end, i32::try_from(raw.len()).unwrap() - 1);
|
|
}
|
|
|
|
#[test]
|
|
fn packet_id_dispatch_covers_known_and_unknown_ids() {
|
|
assert_eq!(
|
|
Packet::get_type(3, PacketFrequency::Low).expect("packet type"),
|
|
PacketType::UseCircuitCode
|
|
);
|
|
assert_eq!(
|
|
Packet::get_type(u16::MAX, PacketFrequency::High).expect("unknown type"),
|
|
PacketType::Default
|
|
);
|
|
assert_eq!(Helpers::MSG_RELIABLE, 0x40);
|
|
}
|