Skip to content

Commit db91679

Browse files
committed
issue 469: TQUIC tools支持报文丢失
1 parent fd70a16 commit db91679

6 files changed

Lines changed: 423 additions & 4 deletions

File tree

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,7 @@ pub use crate::endpoint::Endpoint;
12221222
pub use crate::error::Error;
12231223
pub use crate::multipath_scheduler::MultipathAlgorithm;
12241224
pub use crate::packet::PacketHeader;
1225+
pub use crate::packet::PacketType;
12251226
pub use crate::tls::TlsConfig;
12261227
pub use crate::tls::TlsConfigSelector;
12271228

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: 63 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

@@ -330,6 +332,41 @@ pub struct ClientOpt {
330332
help_heading = "Misc"
331333
)]
332334
pub max_sample: usize,
335+
336+
/// Packet loss rate (0.0 to 1.0) for testing.
337+
#[clap(
338+
long,
339+
default_value = "0.0",
340+
value_name = "RATE",
341+
help_heading = "Packet Loss"
342+
)]
343+
pub packet_loss_rate: f64,
344+
345+
/// Specific packet numbers to drop (comma-separated).
346+
#[clap(
347+
long,
348+
value_delimiter = ',',
349+
value_name = "NUMBERS",
350+
help_heading = "Packet Loss"
351+
)]
352+
pub packet_loss_numbers: Vec<u64>,
353+
354+
/// Packet types to drop.
355+
#[clap(
356+
long,
357+
value_delimiter = ',',
358+
value_name = "TYPES",
359+
help_heading = "Packet Loss"
360+
)]
361+
pub packet_loss_types: Vec<LossPacketType>,
362+
363+
/// Apply packet loss to incoming packets.
364+
#[clap(long, help_heading = "Packet Loss")]
365+
pub packet_loss_incoming: bool,
366+
367+
/// Apply packet loss to outgoing packets.
368+
#[clap(long, help_heading = "Packet Loss")]
369+
pub packet_loss_outgoing: bool,
333370
}
334371

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

573635
let mut assigned_addrs = Vec::new();
574636
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
@@ -43,6 +43,8 @@ use tquic::PacketInfo;
4343
use tquic::TlsConfig;
4444
use tquic::TransportHandler;
4545
use tquic_tools::ApplicationProto;
46+
use tquic_tools::LossPacketType;
47+
use tquic_tools::PacketLossConfig;
4648
use tquic_tools::QuicSocket;
4749
use tquic_tools::Result;
4850

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

253290
const MAX_BUF_SIZE: usize = 65536;
@@ -313,7 +350,36 @@ impl Server {
313350
let registry = poll.registry();
314351

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

318384
Ok(Server {
319385
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)