Coverage Report

Created: 2025-12-08 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quiche/quiche/src/test_utils.rs
Line
Count
Source
1
// Copyright (C) 2025, Cloudflare, Inc.
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
6
// met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//
11
//     * Redistributions in binary form must reproduce the above copyright
12
//       notice, this list of conditions and the following disclaimer in the
13
//       documentation and/or other materials provided with the distribution.
14
//
15
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27
use super::*;
28
29
use smallvec::smallvec;
30
31
use crate::recovery::Sent;
32
33
pub struct Pipe {
34
    pub client: Connection,
35
    pub server: Connection,
36
}
37
38
impl Pipe {
39
0
    pub fn new(cc_algorithm_name: &str) -> Result<Pipe> {
40
0
        let mut config = Config::new(PROTOCOL_VERSION)?;
41
0
        assert_eq!(config.set_cc_algorithm_name(cc_algorithm_name), Ok(()));
42
0
        config.load_cert_chain_from_pem_file("examples/cert.crt")?;
43
0
        config.load_priv_key_from_pem_file("examples/cert.key")?;
44
0
        config.set_application_protos(&[b"proto1", b"proto2"])?;
45
0
        config.set_initial_max_data(30);
46
0
        config.set_initial_max_stream_data_bidi_local(15);
47
0
        config.set_initial_max_stream_data_bidi_remote(15);
48
0
        config.set_initial_max_stream_data_uni(10);
49
0
        config.set_initial_max_streams_bidi(3);
50
0
        config.set_initial_max_streams_uni(3);
51
0
        config.set_max_idle_timeout(180_000);
52
0
        config.verify_peer(false);
53
0
        config.set_ack_delay_exponent(8);
54
55
0
        Pipe::with_config(&mut config)
56
0
    }
57
58
0
    pub fn client_addr() -> SocketAddr {
59
0
        "127.0.0.1:1234".parse().unwrap()
60
0
    }
61
62
0
    pub fn server_addr() -> SocketAddr {
63
0
        "127.0.0.1:4321".parse().unwrap()
64
0
    }
65
66
0
    pub fn with_config(config: &mut Config) -> Result<Pipe> {
67
0
        let mut client_scid = [0; 16];
68
0
        rand::rand_bytes(&mut client_scid[..]);
69
0
        let client_scid = ConnectionId::from_ref(&client_scid);
70
0
        let client_addr = Pipe::client_addr();
71
72
0
        let mut server_scid = [0; 16];
73
0
        rand::rand_bytes(&mut server_scid[..]);
74
0
        let server_scid = ConnectionId::from_ref(&server_scid);
75
0
        let server_addr = Pipe::server_addr();
76
77
        Ok(Pipe {
78
0
            client: connect(
79
0
                Some("quic.tech"),
80
0
                &client_scid,
81
0
                client_addr,
82
0
                server_addr,
83
0
                config,
84
0
            )?,
85
0
            server: accept(&server_scid, None, server_addr, client_addr, config)?,
86
        })
87
0
    }
88
89
0
    pub fn with_config_and_scid_lengths(
90
0
        config: &mut Config, client_scid_len: usize, server_scid_len: usize,
91
0
    ) -> Result<Pipe> {
92
0
        let mut client_scid = vec![0; client_scid_len];
93
0
        rand::rand_bytes(&mut client_scid[..]);
94
0
        let client_scid = ConnectionId::from_ref(&client_scid);
95
0
        let client_addr = Pipe::client_addr();
96
97
0
        let mut server_scid = vec![0; server_scid_len];
98
0
        rand::rand_bytes(&mut server_scid[..]);
99
0
        let server_scid = ConnectionId::from_ref(&server_scid);
100
0
        let server_addr = Pipe::server_addr();
101
102
        Ok(Pipe {
103
0
            client: connect(
104
0
                Some("quic.tech"),
105
0
                &client_scid,
106
0
                client_addr,
107
0
                server_addr,
108
0
                config,
109
0
            )?,
110
0
            server: accept(&server_scid, None, server_addr, client_addr, config)?,
111
        })
112
0
    }
113
114
0
    pub fn with_client_config(client_config: &mut Config) -> Result<Pipe> {
115
0
        let mut client_scid = [0; 16];
116
0
        rand::rand_bytes(&mut client_scid[..]);
117
0
        let client_scid = ConnectionId::from_ref(&client_scid);
118
0
        let client_addr = Pipe::client_addr();
119
120
0
        let mut server_scid = [0; 16];
121
0
        rand::rand_bytes(&mut server_scid[..]);
122
0
        let server_scid = ConnectionId::from_ref(&server_scid);
123
0
        let server_addr = Pipe::server_addr();
124
125
0
        let mut config = Config::new(PROTOCOL_VERSION)?;
126
0
        config.load_cert_chain_from_pem_file("examples/cert.crt")?;
127
0
        config.load_priv_key_from_pem_file("examples/cert.key")?;
128
0
        config.set_application_protos(&[b"proto1", b"proto2"])?;
129
0
        config.set_initial_max_data(30);
130
0
        config.set_initial_max_stream_data_bidi_local(15);
131
0
        config.set_initial_max_stream_data_bidi_remote(15);
132
0
        config.set_initial_max_streams_bidi(3);
133
0
        config.set_initial_max_streams_uni(3);
134
0
        config.set_ack_delay_exponent(8);
135
136
        Ok(Pipe {
137
0
            client: connect(
138
0
                Some("quic.tech"),
139
0
                &client_scid,
140
0
                client_addr,
141
0
                server_addr,
142
0
                client_config,
143
0
            )?,
144
0
            server: accept(
145
0
                &server_scid,
146
0
                None,
147
0
                server_addr,
148
0
                client_addr,
149
0
                &mut config,
150
0
            )?,
151
        })
152
0
    }
153
154
0
    pub fn with_server_config(server_config: &mut Config) -> Result<Pipe> {
155
0
        let mut client_scid = [0; 16];
156
0
        rand::rand_bytes(&mut client_scid[..]);
157
0
        let client_scid = ConnectionId::from_ref(&client_scid);
158
0
        let client_addr = Pipe::client_addr();
159
160
0
        let mut server_scid = [0; 16];
161
0
        rand::rand_bytes(&mut server_scid[..]);
162
0
        let server_scid = ConnectionId::from_ref(&server_scid);
163
0
        let server_addr = Pipe::server_addr();
164
165
0
        let mut config = Config::new(PROTOCOL_VERSION)?;
166
0
        config.set_application_protos(&[b"proto1", b"proto2"])?;
167
0
        config.set_initial_max_data(30);
168
0
        config.set_initial_max_stream_data_bidi_local(15);
169
0
        config.set_initial_max_stream_data_bidi_remote(15);
170
0
        config.set_initial_max_streams_bidi(3);
171
0
        config.set_initial_max_streams_uni(3);
172
0
        config.set_ack_delay_exponent(8);
173
174
        Ok(Pipe {
175
0
            client: connect(
176
0
                Some("quic.tech"),
177
0
                &client_scid,
178
0
                client_addr,
179
0
                server_addr,
180
0
                &mut config,
181
0
            )?,
182
0
            server: accept(
183
0
                &server_scid,
184
0
                None,
185
0
                server_addr,
186
0
                client_addr,
187
0
                server_config,
188
0
            )?,
189
        })
190
0
    }
191
192
0
    pub fn with_client_and_server_config(
193
0
        client_config: &mut Config, server_config: &mut Config,
194
0
    ) -> Result<Pipe> {
195
0
        let mut client_scid = [0; 16];
196
0
        rand::rand_bytes(&mut client_scid[..]);
197
0
        let client_scid = ConnectionId::from_ref(&client_scid);
198
0
        let client_addr = Pipe::client_addr();
199
200
0
        let mut server_scid = [0; 16];
201
0
        rand::rand_bytes(&mut server_scid[..]);
202
0
        let server_scid = ConnectionId::from_ref(&server_scid);
203
0
        let server_addr = Pipe::server_addr();
204
205
        Ok(Pipe {
206
0
            client: connect(
207
0
                Some("quic.tech"),
208
0
                &client_scid,
209
0
                client_addr,
210
0
                server_addr,
211
0
                client_config,
212
0
            )?,
213
0
            server: accept(
214
0
                &server_scid,
215
0
                None,
216
0
                server_addr,
217
0
                client_addr,
218
0
                server_config,
219
0
            )?,
220
        })
221
0
    }
222
223
0
    pub fn handshake(&mut self) -> Result<()> {
224
0
        while !self.client.is_established() || !self.server.is_established() {
225
0
            let flight = emit_flight(&mut self.client)?;
226
0
            process_flight(&mut self.server, flight)?;
227
228
0
            let flight = emit_flight(&mut self.server)?;
229
0
            process_flight(&mut self.client, flight)?;
230
        }
231
232
0
        Ok(())
233
0
    }
234
235
0
    pub fn advance(&mut self) -> Result<()> {
236
0
        let mut client_done = false;
237
0
        let mut server_done = false;
238
239
0
        while !client_done || !server_done {
240
0
            match emit_flight(&mut self.client) {
241
0
                Ok(flight) => process_flight(&mut self.server, flight)?,
242
243
0
                Err(Error::Done) => client_done = true,
244
245
0
                Err(e) => return Err(e),
246
            };
247
248
0
            match emit_flight(&mut self.server) {
249
0
                Ok(flight) => process_flight(&mut self.client, flight)?,
250
251
0
                Err(Error::Done) => server_done = true,
252
253
0
                Err(e) => return Err(e),
254
            };
255
        }
256
257
0
        Ok(())
258
0
    }
259
260
0
    pub fn client_recv(&mut self, buf: &mut [u8]) -> Result<usize> {
261
0
        let server_path = &self.server.paths.get_active().unwrap();
262
0
        let info = RecvInfo {
263
0
            to: server_path.peer_addr(),
264
0
            from: server_path.local_addr(),
265
0
        };
266
267
0
        self.client.recv(buf, info)
268
0
    }
269
270
0
    pub fn server_recv(&mut self, buf: &mut [u8]) -> Result<usize> {
271
0
        let client_path = &self.client.paths.get_active().unwrap();
272
0
        let info = RecvInfo {
273
0
            to: client_path.peer_addr(),
274
0
            from: client_path.local_addr(),
275
0
        };
276
277
0
        self.server.recv(buf, info)
278
0
    }
279
280
0
    pub fn send_pkt_to_server(
281
0
        &mut self, pkt_type: Type, frames: &[frame::Frame], buf: &mut [u8],
282
0
    ) -> Result<usize> {
283
0
        let written = encode_pkt(&mut self.client, pkt_type, frames, buf)?;
284
0
        recv_send(&mut self.server, buf, written)
285
0
    }
286
287
0
    pub fn client_update_key(&mut self) -> Result<()> {
288
0
        let crypto_ctx = &mut self.client.crypto_ctx[packet::Epoch::Application];
289
290
0
        let open_next = crypto_ctx
291
0
            .crypto_open
292
0
            .as_ref()
293
0
            .unwrap()
294
0
            .derive_next_packet_key()
295
0
            .unwrap();
296
297
0
        let seal_next = crypto_ctx
298
0
            .crypto_seal
299
0
            .as_ref()
300
0
            .unwrap()
301
0
            .derive_next_packet_key()?;
302
303
0
        let open_prev = crypto_ctx.crypto_open.replace(open_next);
304
0
        crypto_ctx.crypto_seal.replace(seal_next);
305
306
0
        crypto_ctx.key_update = Some(packet::KeyUpdate {
307
0
            crypto_open: open_prev.unwrap(),
308
0
            pn_on_update: self.client.next_pkt_num,
309
0
            update_acked: true,
310
0
            timer: Instant::now(),
311
0
        });
312
313
0
        self.client.key_phase = !self.client.key_phase;
314
315
0
        Ok(())
316
0
    }
317
}
318
319
0
pub fn recv_send<F: BufFactory>(
320
0
    conn: &mut Connection<F>, buf: &mut [u8], len: usize,
321
0
) -> Result<usize> {
322
0
    let active_path = conn.paths.get_active()?;
323
0
    let info = RecvInfo {
324
0
        to: active_path.local_addr(),
325
0
        from: active_path.peer_addr(),
326
0
    };
327
328
0
    conn.recv(&mut buf[..len], info)?;
329
330
0
    let mut off = 0;
331
332
0
    match conn.send(&mut buf[off..]) {
333
0
        Ok((write, _)) => off += write,
334
335
0
        Err(Error::Done) => (),
336
337
0
        Err(e) => return Err(e),
338
    }
339
340
0
    Ok(off)
341
0
}
342
343
38.0k
pub fn process_flight(
344
38.0k
    conn: &mut Connection, flight: Vec<(Vec<u8>, SendInfo)>,
345
38.0k
) -> Result<()> {
346
85.6k
    for (mut pkt, si) in flight {
347
47.5k
        let info = RecvInfo {
348
47.5k
            to: si.to,
349
47.5k
            from: si.from,
350
47.5k
        };
351
352
47.5k
        conn.recv(&mut pkt, info)?;
353
    }
354
355
38.0k
    Ok(())
356
38.0k
}
357
358
38.0k
pub fn emit_flight_with_max_buffer(
359
38.0k
    conn: &mut Connection, out_size: usize, from: Option<SocketAddr>,
360
38.0k
    to: Option<SocketAddr>,
361
38.0k
) -> Result<Vec<(Vec<u8>, SendInfo)>> {
362
38.0k
    let mut flight = Vec::new();
363
364
    loop {
365
85.6k
        let mut out = vec![0u8; out_size];
366
367
85.6k
        let info = match conn.send_on_path(&mut out, from, to) {
368
47.5k
            Ok((written, info)) => {
369
47.5k
                out.truncate(written);
370
47.5k
                info
371
            },
372
373
38.0k
            Err(Error::Done) => break,
374
375
0
            Err(e) => return Err(e),
376
        };
377
378
47.5k
        flight.push((out, info));
379
    }
380
381
38.0k
    if flight.is_empty() {
382
0
        return Err(Error::Done);
383
38.0k
    }
384
385
38.0k
    Ok(flight)
386
38.0k
}
387
388
38.0k
pub fn emit_flight_on_path(
389
38.0k
    conn: &mut Connection, from: Option<SocketAddr>, to: Option<SocketAddr>,
390
38.0k
) -> Result<Vec<(Vec<u8>, SendInfo)>> {
391
38.0k
    emit_flight_with_max_buffer(conn, 65535, from, to)
392
38.0k
}
393
394
38.0k
pub fn emit_flight(conn: &mut Connection) -> Result<Vec<(Vec<u8>, SendInfo)>> {
395
38.0k
    emit_flight_on_path(conn, None, None)
396
38.0k
}
397
398
0
pub fn encode_pkt(
399
0
    conn: &mut Connection, pkt_type: Type, frames: &[frame::Frame],
400
0
    buf: &mut [u8],
401
0
) -> Result<usize> {
402
0
    let mut b = octets::OctetsMut::with_slice(buf);
403
404
0
    let epoch = pkt_type.to_epoch()?;
405
406
0
    let crypto_ctx = &mut conn.crypto_ctx[epoch];
407
408
0
    let pn = conn.next_pkt_num;
409
0
    let pn_len = 4;
410
411
0
    let send_path = conn.paths.get_active()?;
412
0
    let active_dcid_seq = send_path
413
0
        .active_dcid_seq
414
0
        .as_ref()
415
0
        .ok_or(Error::InvalidState)?;
416
0
    let active_scid_seq = send_path
417
0
        .active_scid_seq
418
0
        .as_ref()
419
0
        .ok_or(Error::InvalidState)?;
420
421
0
    let hdr = Header {
422
0
        ty: pkt_type,
423
0
        version: conn.version,
424
0
        dcid: ConnectionId::from_ref(
425
0
            conn.ids.get_dcid(*active_dcid_seq)?.cid.as_ref(),
426
        ),
427
0
        scid: ConnectionId::from_ref(
428
0
            conn.ids.get_scid(*active_scid_seq)?.cid.as_ref(),
429
        ),
430
0
        pkt_num: pn,
431
0
        pkt_num_len: pn_len,
432
0
        token: conn.token.clone(),
433
0
        versions: None,
434
0
        key_phase: conn.key_phase,
435
    };
436
437
0
    hdr.to_bytes(&mut b)?;
438
439
0
    let payload_len = frames.iter().fold(0, |acc, x| acc + x.wire_len());
440
441
0
    if pkt_type != Type::Short {
442
0
        let len = pn_len + payload_len + crypto_ctx.crypto_overhead().unwrap();
443
0
        b.put_varint(len as u64)?;
444
0
    }
445
446
    // Always encode packet number in 4 bytes, to allow encoding packets
447
    // with empty payloads.
448
0
    b.put_u32(pn as u32)?;
449
450
0
    let payload_offset = b.off();
451
452
0
    for frame in frames {
453
0
        frame.to_bytes(&mut b)?;
454
    }
455
456
0
    let aead = match crypto_ctx.crypto_seal {
457
0
        Some(ref v) => v,
458
0
        None => return Err(Error::InvalidState),
459
    };
460
461
0
    let written = packet::encrypt_pkt(
462
0
        &mut b,
463
0
        pn,
464
0
        pn_len,
465
0
        payload_len,
466
0
        payload_offset,
467
0
        None,
468
0
        aead,
469
0
    )?;
470
471
0
    conn.next_pkt_num += 1;
472
473
0
    Ok(written)
474
0
}
475
476
0
pub fn decode_pkt(
477
0
    conn: &mut Connection, buf: &mut [u8],
478
0
) -> Result<Vec<frame::Frame>> {
479
0
    let mut b = octets::OctetsMut::with_slice(buf);
480
481
0
    let mut hdr = Header::from_bytes(&mut b, conn.source_id().len()).unwrap();
482
483
0
    let epoch = hdr.ty.to_epoch()?;
484
485
0
    let aead = conn.crypto_ctx[epoch].crypto_open.as_ref().unwrap();
486
487
0
    let payload_len = b.cap();
488
489
0
    packet::decrypt_hdr(&mut b, &mut hdr, aead).unwrap();
490
491
0
    let pn = packet::decode_pkt_num(
492
0
        conn.pkt_num_spaces[epoch].largest_rx_pkt_num,
493
0
        hdr.pkt_num,
494
0
        hdr.pkt_num_len,
495
    );
496
497
0
    let mut payload =
498
0
        packet::decrypt_pkt(&mut b, pn, hdr.pkt_num_len, payload_len, aead)
499
0
            .unwrap();
500
501
0
    let mut frames = Vec::new();
502
503
0
    while payload.cap() > 0 {
504
0
        let frame = frame::Frame::from_bytes(&mut payload, hdr.ty)?;
505
0
        frames.push(frame);
506
    }
507
508
0
    Ok(frames)
509
0
}
510
511
0
pub fn create_cid_and_reset_token(
512
0
    cid_len: usize,
513
0
) -> (ConnectionId<'static>, u128) {
514
0
    let mut cid = vec![0; cid_len];
515
0
    rand::rand_bytes(&mut cid[..]);
516
0
    let cid = ConnectionId::from_ref(&cid).into_owned();
517
518
0
    let mut reset_token = [0; 16];
519
0
    rand::rand_bytes(&mut reset_token);
520
0
    let reset_token = u128::from_be_bytes(reset_token);
521
522
0
    (cid, reset_token)
523
0
}
524
525
0
pub fn helper_packet_sent(pkt_num: u64, now: Instant, size: usize) -> Sent {
526
0
    Sent {
527
0
        pkt_num,
528
0
        frames: smallvec![],
529
0
        time_sent: now,
530
0
        time_acked: None,
531
0
        time_lost: None,
532
0
        size,
533
0
        ack_eliciting: true,
534
0
        in_flight: true,
535
0
        delivered: 0,
536
0
        delivered_time: now,
537
0
        first_sent_time: now,
538
0
        is_app_limited: false,
539
0
        tx_in_flight: 0,
540
0
        lost: 0,
541
0
        has_data: true,
542
0
        is_pmtud_probe: false,
543
0
    }
544
0
}