|
1 | | -use super::{ConnectionId, IpcError, IpcTransport, Message, TransportConfig, TransportState}; |
| 1 | +use super::{ |
| 2 | + get_monotonic_time_ns, ConnectionId, IpcError, IpcTransport, Message, TransportConfig, |
| 3 | + TransportState, |
| 4 | +}; |
2 | 5 | use anyhow::{anyhow, Result}; |
3 | 6 | use async_trait::async_trait; |
4 | 7 | use std::collections::HashMap; |
@@ -69,6 +72,28 @@ impl TcpSocketTransport { |
69 | 72 | Message::from_bytes(&message_data) |
70 | 73 | } |
71 | 74 |
|
| 75 | + /// Read a message and capture a monotonic timestamp immediately after |
| 76 | + /// the raw bytes are read but before deserialization. This excludes |
| 77 | + /// deserialization overhead from one-way latency measurements. |
| 78 | + async fn read_message_timed(stream: &mut TcpStream) -> Result<(Message, u64)> { |
| 79 | + let mut len_bytes = [0u8; 4]; |
| 80 | + stream.read_exact(&mut len_bytes).await?; |
| 81 | + let message_len = u32::from_le_bytes(len_bytes) as usize; |
| 82 | + |
| 83 | + if message_len > 16 * 1024 * 1024 { |
| 84 | + return Err(anyhow!("Message too large: {} bytes", message_len)); |
| 85 | + } |
| 86 | + |
| 87 | + let mut message_data = vec![0u8; message_len]; |
| 88 | + stream.read_exact(&mut message_data).await?; |
| 89 | + |
| 90 | + // Capture timestamp between raw I/O and deserialization |
| 91 | + let receive_time_ns = get_monotonic_time_ns(); |
| 92 | + |
| 93 | + let message = Message::from_bytes(&message_data)?; |
| 94 | + Ok((message, receive_time_ns)) |
| 95 | + } |
| 96 | + |
72 | 97 | /// Write a message to the TCP stream. |
73 | 98 | /// |
74 | 99 | /// Unlike SHM and PMQ, the timestamp is not refreshed |
@@ -340,6 +365,36 @@ impl IpcTransport for TcpSocketTransport { |
340 | 365 | } |
341 | 366 | } |
342 | 367 |
|
| 368 | + async fn receive_timed(&mut self) -> Result<(Message, u64)> { |
| 369 | + if self.state != TransportState::Connected { |
| 370 | + return Err(anyhow!("Transport not connected")); |
| 371 | + } |
| 372 | + |
| 373 | + if self.stream.is_none() { |
| 374 | + if let Some(listener) = self.listener.as_ref() { |
| 375 | + let (stream, client_addr) = listener.accept().await?; |
| 376 | + debug!( |
| 377 | + "TCP Socket server accepted connection from: {}", |
| 378 | + client_addr |
| 379 | + ); |
| 380 | + let std_stream = stream.into_std()?; |
| 381 | + let socket = socket2::Socket::from(std_stream.try_clone()?); |
| 382 | + socket.set_nodelay(true)?; |
| 383 | + socket.set_recv_buffer_size(self.buffer_size)?; |
| 384 | + socket.set_send_buffer_size(self.buffer_size)?; |
| 385 | + self.stream = Some(TcpStream::from_std(std_stream)?); |
| 386 | + } |
| 387 | + } |
| 388 | + |
| 389 | + if let Some(ref mut stream) = self.stream { |
| 390 | + let (message, ts) = Self::read_message_timed(stream).await?; |
| 391 | + debug!("Received message {} via TCP Socket", message.id); |
| 392 | + Ok((message, ts)) |
| 393 | + } else { |
| 394 | + Err(anyhow!("No active stream available")) |
| 395 | + } |
| 396 | + } |
| 397 | + |
343 | 398 | async fn close(&mut self) -> Result<()> { |
344 | 399 | debug!("Closing TCP Socket transport"); |
345 | 400 |
|
|
0 commit comments