Skip to content

Commit 23b7f72

Browse files
committed
issue 469: TQUIC tools支持报文丢失
1 parent d648bbe commit 23b7f72

6 files changed

Lines changed: 422 additions & 4 deletions

File tree

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,7 @@ pub use crate::endpoint::Endpoint;
12251225
pub use crate::error::Error;
12261226
pub use crate::multipath_scheduler::MultipathAlgorithm;
12271227
pub use crate::packet::PacketHeader;
1228+
pub use crate::packet::PacketType;
12281229
pub use crate::tls::TlsConfig;
12291230
pub use crate::tls::TlsConfigSelector;
12301231

src/packet.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const RETRY_INTEGRITY_NONCE_V1: [u8; aead::NONCE_LEN] = [
7676
];
7777

7878
/// QUIC packet type.
79-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
79+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8080
pub enum PacketType {
8181
/// The Version Negotiation packet is a response to a client packet that
8282
/// contains a version that is not supported by the server.

tools/src/bin/tquic_client.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ use tquic::PacketInfo;
6666
use tquic::TlsConfig;
6767
use tquic::TransportHandler;
6868
use tquic_tools::ApplicationProto;
69+
use tquic_tools::LossPacketType;
70+
use tquic_tools::PacketLossConfig;
6971
use tquic_tools::QuicSocket;
7072
use tquic_tools::Result;
7173

@@ -334,6 +336,40 @@ pub struct ClientOpt {
334336
/// The range of the request, like "0-1023".
335337
#[clap(long, value_name = "RANGE", help_heading = "Protocol")]
336338
pub range: Option<String>,
339+
/// Packet loss rate (0.0 to 1.0) for testing.
340+
#[clap(
341+
long,
342+
default_value = "0.0",
343+
value_name = "RATE",
344+
help_heading = "Packet Loss"
345+
)]
346+
pub packet_loss_rate: f64,
347+
348+
/// Specific packet numbers to drop (comma-separated).
349+
#[clap(
350+
long,
351+
value_delimiter = ',',
352+
value_name = "NUMBERS",
353+
help_heading = "Packet Loss"
354+
)]
355+
pub packet_loss_numbers: Vec<u64>,
356+
357+
/// Packet types to drop.
358+
#[clap(
359+
long,
360+
value_delimiter = ',',
361+
value_name = "TYPES",
362+
help_heading = "Packet Loss"
363+
)]
364+
pub packet_loss_types: Vec<LossPacketType>,
365+
366+
/// Apply packet loss to incoming packets.
367+
#[clap(long, help_heading = "Packet Loss")]
368+
pub packet_loss_incoming: bool,
369+
370+
/// Apply packet loss to outgoing packets.
371+
#[clap(long, help_heading = "Packet Loss")]
372+
pub packet_loss_outgoing: bool,
337373
}
338374

339375
const MAX_BUF_SIZE: usize = 65536;
@@ -572,7 +608,32 @@ impl Worker {
572608
false => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
573609
}
574610
};
575-
let mut sock = QuicSocket::new(&local, registry)?;
611+
612+
// Create packet loss configuration if needed
613+
let packet_loss_config = if option.packet_loss_rate > 0.0
614+
|| !option.packet_loss_numbers.is_empty()
615+
|| !option.packet_loss_types.is_empty()
616+
{
617+
let mut config = PacketLossConfig::new()
618+
.with_loss_rate(option.packet_loss_rate)
619+
.with_drop_packet_numbers(option.packet_loss_numbers.clone())
620+
.with_drop_incoming(option.packet_loss_incoming)
621+
.with_drop_outgoing(option.packet_loss_outgoing);
622+
623+
let packet_types: Vec<_> = option
624+
.packet_loss_types
625+
.iter()
626+
.map(|t| t.to_packet_type())
627+
.collect();
628+
config = config.with_drop_packet_types(packet_types);
629+
630+
Some(config)
631+
} else {
632+
None
633+
};
634+
635+
let mut sock =
636+
QuicSocket::with_packet_loss(&local, registry, packet_loss_config, option.cid_len)?;
576637

577638
let mut assigned_addrs = Vec::new();
578639
assigned_addrs.push(sock.local_addr());

tools/src/bin/tquic_server.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ use tquic::PacketInfo;
4545
use tquic::TlsConfig;
4646
use tquic::TransportHandler;
4747
use tquic_tools::ApplicationProto;
48+
use tquic_tools::LossPacketType;
49+
use tquic_tools::PacketLossConfig;
4850
use tquic_tools::QuicSocket;
4951
use tquic_tools::Result;
5052

@@ -250,6 +252,41 @@ pub struct ServerOpt {
250252
/// Disable encryption on 1-RTT packets.
251253
#[clap(long, help_heading = "Misc")]
252254
pub disable_encryption: bool,
255+
256+
/// Packet loss rate (0.0 to 1.0) for testing.
257+
#[clap(
258+
long,
259+
default_value = "0.0",
260+
value_name = "RATE",
261+
help_heading = "Packet Loss"
262+
)]
263+
pub packet_loss_rate: f64,
264+
265+
/// Specific packet numbers to drop (comma-separated).
266+
#[clap(
267+
long,
268+
value_delimiter = ',',
269+
value_name = "NUMBERS",
270+
help_heading = "Packet Loss"
271+
)]
272+
pub packet_loss_numbers: Vec<u64>,
273+
274+
/// Packet types to drop.
275+
#[clap(
276+
long,
277+
value_delimiter = ',',
278+
value_name = "TYPES",
279+
help_heading = "Packet Loss"
280+
)]
281+
pub packet_loss_types: Vec<LossPacketType>,
282+
283+
/// Apply packet loss to incoming packets.
284+
#[clap(long, help_heading = "Packet Loss")]
285+
pub packet_loss_incoming: bool,
286+
287+
/// Apply packet loss to outgoing packets.
288+
#[clap(long, help_heading = "Packet Loss")]
289+
pub packet_loss_outgoing: bool,
253290
}
254291

255292
const MAX_BUF_SIZE: usize = 65536;
@@ -315,7 +352,36 @@ impl Server {
315352
let registry = poll.registry();
316353

317354
let handlers = ServerHandler::new(option)?;
318-
let sock = Rc::new(QuicSocket::new(&option.listen, registry)?);
355+
356+
// Create packet loss configuration if needed
357+
let packet_loss_config = if option.packet_loss_rate > 0.0
358+
|| !option.packet_loss_numbers.is_empty()
359+
|| !option.packet_loss_types.is_empty()
360+
{
361+
let mut config = PacketLossConfig::new()
362+
.with_loss_rate(option.packet_loss_rate)
363+
.with_drop_packet_numbers(option.packet_loss_numbers.clone())
364+
.with_drop_incoming(option.packet_loss_incoming)
365+
.with_drop_outgoing(option.packet_loss_outgoing);
366+
367+
let packet_types: Vec<_> = option
368+
.packet_loss_types
369+
.iter()
370+
.map(|t| t.to_packet_type())
371+
.collect();
372+
config = config.with_drop_packet_types(packet_types);
373+
374+
Some(config)
375+
} else {
376+
None
377+
};
378+
379+
let sock = Rc::new(QuicSocket::with_packet_loss(
380+
&option.listen,
381+
registry,
382+
packet_loss_config,
383+
option.cid_len,
384+
)?);
319385

320386
Ok(Server {
321387
endpoint: Endpoint::new(Box::new(config), true, Box::new(handlers), sock.clone()),

tools/src/common.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::cell::RefCell;
1516
use std::io::ErrorKind;
1617
use std::net::SocketAddr;
1718

@@ -29,6 +30,9 @@ use slab::Slab;
2930
use tquic::PacketInfo;
3031
use tquic::PacketSendHandler;
3132

33+
pub mod packet_loss;
34+
pub use packet_loss::{LossPacketType, PacketLossConfig, PacketLossSimulator};
35+
3236
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
3337

3438
/// Supported application protocols.
@@ -98,10 +102,25 @@ pub struct QuicSocket {
98102

99103
/// Local address of the initial socket.
100104
local_addr: SocketAddr,
105+
106+
/// Packet loss simulator for testing
107+
packet_loss: RefCell<Option<PacketLossSimulator>>,
108+
109+
/// Connection ID length for packet parsing
110+
dcid_len: usize,
101111
}
102112

103113
impl QuicSocket {
104114
pub fn new(local: &SocketAddr, registry: &Registry) -> Result<Self> {
115+
Self::with_packet_loss(local, registry, None, 8)
116+
}
117+
118+
pub fn with_packet_loss(
119+
local: &SocketAddr,
120+
registry: &Registry,
121+
packet_loss_config: Option<PacketLossConfig>,
122+
dcid_len: usize,
123+
) -> Result<Self> {
105124
let mut socks = Slab::new();
106125
let mut addrs = FxHashMap::default();
107126

@@ -113,10 +132,14 @@ impl QuicSocket {
113132
let socket = socks.get_mut(sid).unwrap();
114133
registry.register(socket, Token(sid), Interest::READABLE)?;
115134

135+
let packet_loss = RefCell::new(packet_loss_config.map(PacketLossSimulator::new));
136+
116137
Ok(Self {
117138
socks,
118139
addrs,
119140
local_addr,
141+
packet_loss,
142+
dcid_len,
120143
})
121144
}
122145

@@ -166,14 +189,38 @@ impl QuicSocket {
166189
};
167190

168191
match socket.recv_from(buf) {
169-
Ok((len, remote)) => Ok((len, socket.local_addr()?, remote)),
192+
Ok((len, remote)) => {
193+
// Check if packet should be dropped due to loss simulation
194+
if let Ok(mut packet_loss) = self.packet_loss.try_borrow_mut() {
195+
if let Some(ref mut simulator) = *packet_loss {
196+
if simulator.should_drop_incoming(&buf[..len], self.dcid_len) {
197+
debug!("Simulating incoming packet loss - dropping packet");
198+
return Err(std::io::Error::new(
199+
ErrorKind::WouldBlock,
200+
"simulated packet loss",
201+
));
202+
}
203+
}
204+
}
205+
Ok((len, socket.local_addr()?, remote))
206+
}
170207
Err(e) => Err(e),
171208
}
172209
}
173210

174211
/// Send data on the socket to the given address.
175212
/// Note: packets with unknown src address are dropped.
176213
pub fn send_to(&self, buf: &[u8], src: SocketAddr, dst: SocketAddr) -> std::io::Result<usize> {
214+
// Check if packet should be dropped due to loss simulation
215+
if let Ok(mut packet_loss) = self.packet_loss.try_borrow_mut() {
216+
if let Some(ref mut simulator) = *packet_loss {
217+
if simulator.should_drop_outgoing(buf, self.dcid_len) {
218+
debug!("Simulating outgoing packet loss - dropping packet");
219+
return Ok(buf.len()); // Pretend we sent it
220+
}
221+
}
222+
}
223+
177224
let sid = match self.addrs.get(&src) {
178225
Some(sid) => sid,
179226
None => {

0 commit comments

Comments
 (0)