Implement native PacketDump capture (#87)
Some checks failed
Native Rust workspace compile / compile (push) Has been cancelled
Some checks failed
Native Rust workspace compile / compile (push) Has been cancelled
This commit is contained in:
@@ -293,6 +293,7 @@ impl<T: 'static> EventRegistry<T> {
|
||||
pub struct PacketReceivedEventArgs {
|
||||
packet: Packet,
|
||||
simulator: Simulator,
|
||||
raw_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -304,7 +305,19 @@ pub(crate) struct RawPacketReceivedEventArgs {
|
||||
|
||||
impl PacketReceivedEventArgs {
|
||||
pub fn new(packet: Packet, simulator: Simulator) -> Result<Self, Error> {
|
||||
Ok(Self { packet, simulator })
|
||||
Self::new_with_raw_data(packet, simulator, None)
|
||||
}
|
||||
|
||||
pub fn new_with_raw_data(
|
||||
packet: Packet,
|
||||
simulator: Simulator,
|
||||
raw_data: Option<Vec<u8>>,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
packet,
|
||||
simulator,
|
||||
raw_data,
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -316,6 +329,13 @@ impl PacketReceivedEventArgs {
|
||||
pub fn simulator(&self) -> Simulator {
|
||||
self.simulator.clone()
|
||||
}
|
||||
|
||||
/// Returns the original datagram when this event came from the native UDP
|
||||
/// receive path. Synthetic decoded events intentionally return `None`.
|
||||
#[must_use]
|
||||
pub fn raw_data(&self) -> Option<Vec<u8>> {
|
||||
self.raw_data.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -552,6 +572,7 @@ struct AsyncPacketBatch {
|
||||
specific_handlers: Vec<EventHandler<PacketReceivedEventArgs>>,
|
||||
packet: Packet,
|
||||
simulator: Simulator,
|
||||
raw_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
enum PacketWorkerCommand {
|
||||
@@ -674,7 +695,19 @@ impl PacketEventDictionary {
|
||||
packet: Packet,
|
||||
simulator: Simulator,
|
||||
) -> Result<(), Error> {
|
||||
self.raise_event(packet_type, packet, simulator)
|
||||
self.raise_event(packet_type, packet, simulator, None)
|
||||
}
|
||||
|
||||
/// Dispatches a decoded packet together with its original wire datagram.
|
||||
/// This is primarily useful to deterministic packet-capture fixtures.
|
||||
pub fn invoke_raise_event_with_raw_data(
|
||||
&self,
|
||||
packet_type: PacketType,
|
||||
packet: Packet,
|
||||
simulator: Simulator,
|
||||
raw_data: Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
self.raise_event(packet_type, packet, simulator, Some(raw_data))
|
||||
}
|
||||
|
||||
fn raise_event(
|
||||
@@ -682,6 +715,7 @@ impl PacketEventDictionary {
|
||||
packet_type: PacketType,
|
||||
packet: Packet,
|
||||
simulator: Simulator,
|
||||
raw_data: Option<Vec<u8>>,
|
||||
) -> Result<(), Error> {
|
||||
let (defaults, specific) = {
|
||||
let table = mutex(&self.state.callbacks);
|
||||
@@ -692,7 +726,11 @@ impl PacketEventDictionary {
|
||||
};
|
||||
let default_async = defaults.is_async;
|
||||
let specific_async = specific.is_async;
|
||||
let args = PacketReceivedEventArgs::new(packet.clone(), simulator.clone())?;
|
||||
let args = PacketReceivedEventArgs::new_with_raw_data(
|
||||
packet.clone(),
|
||||
simulator.clone(),
|
||||
raw_data.clone(),
|
||||
)?;
|
||||
|
||||
if !default_async {
|
||||
for handler in &defaults.handlers {
|
||||
@@ -731,6 +769,7 @@ impl PacketEventDictionary {
|
||||
specific_handlers,
|
||||
packet,
|
||||
simulator,
|
||||
raw_data,
|
||||
}))
|
||||
.map_err(|_| Error::InvalidOperation)
|
||||
}
|
||||
@@ -740,7 +779,11 @@ fn packet_event_worker(receiver: Receiver<PacketWorkerCommand>, state: Weak<Pack
|
||||
while state.strong_count() != 0 {
|
||||
match receiver.recv_timeout(Duration::from_millis(100)) {
|
||||
Ok(PacketWorkerCommand::Dispatch(batch)) => {
|
||||
let Ok(args) = PacketReceivedEventArgs::new(batch.packet, batch.simulator) else {
|
||||
let Ok(args) = PacketReceivedEventArgs::new_with_raw_data(
|
||||
batch.packet,
|
||||
batch.simulator,
|
||||
batch.raw_data,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
for handler in batch
|
||||
@@ -2090,7 +2133,7 @@ impl NetworkManagerInner {
|
||||
continue;
|
||||
};
|
||||
inner.process_internal_packet(&packet, &simulator, raw_data.as_deref());
|
||||
if let Some(data) = raw_data {
|
||||
if let Some(data) = raw_data.as_ref() {
|
||||
inner.events.raw_packet_received.emit_with(|| {
|
||||
RawPacketReceivedEventArgs {
|
||||
packet_type: packet.type_,
|
||||
@@ -2099,10 +2142,12 @@ impl NetworkManagerInner {
|
||||
}
|
||||
});
|
||||
}
|
||||
let _ =
|
||||
inner
|
||||
.packet_events
|
||||
.raise_event(packet.type_, packet, simulator);
|
||||
let _ = inner.packet_events.raise_event(
|
||||
packet.type_,
|
||||
packet,
|
||||
simulator,
|
||||
raw_data,
|
||||
);
|
||||
}
|
||||
Err(RecvTimeoutError::Timeout) => {}
|
||||
Err(RecvTimeoutError::Disconnected) => break,
|
||||
|
||||
@@ -183,6 +183,42 @@ fn packet_callbacks_preserve_filtering_order_async_policy_and_reentrancy() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoded_packet_callbacks_preserve_optional_raw_datagrams() {
|
||||
let client = GridClient::new().expect("client");
|
||||
let sim = simulator(&client);
|
||||
let events = PacketEventDictionary::new(client).expect("packet events");
|
||||
let observed = Arc::new(Mutex::new(None));
|
||||
let captured = Arc::clone(&observed);
|
||||
events
|
||||
.register_event(
|
||||
PacketType::Default,
|
||||
Arc::new(move |event| *captured.lock().unwrap() = event.raw_data()),
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let raw = vec![0x40, 0, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0];
|
||||
events
|
||||
.invoke_raise_event_with_raw_data(
|
||||
PacketType::StartPingCheck,
|
||||
base_packet(PacketType::StartPingCheck),
|
||||
sim.clone(),
|
||||
raw.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(*observed.lock().unwrap(), Some(raw));
|
||||
|
||||
*observed.lock().unwrap() = Some(vec![1]);
|
||||
events
|
||||
.invoke_raise_event(
|
||||
PacketType::StartPingCheck,
|
||||
base_packet(PacketType::StartPingCheck),
|
||||
sim,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(*observed.lock().unwrap(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn synchronous_specific_dispatch_suppresses_default_async_chain_like_reference() {
|
||||
let mixed_events = PacketEventDictionary::new(GridClient::new().unwrap()).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user