summaryrefslogtreecommitdiffstats
path: root/third_party/rust/neqo-transport/src/connection/saved.rs
blob: 368a859f5d5395b5f967e2a66d5c3756dc0cf646 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem;
use std::time::Instant;

use crate::crypto::CryptoSpace;
use neqo_common::{qdebug, qinfo, Datagram};

/// The number of datagrams that are saved during the handshake when
/// keys to decrypt them are not yet available.
const MAX_SAVED_DATAGRAMS: usize = 4;

pub struct SavedDatagram {
    /// The datagram.
    pub d: Datagram,
    /// The time that the datagram was received.
    pub t: Instant,
}

#[derive(Default)]
pub struct SavedDatagrams {
    handshake: Vec<SavedDatagram>,
    application_data: Vec<SavedDatagram>,
    available: Option<CryptoSpace>,
}

impl SavedDatagrams {
    fn store(&mut self, cspace: CryptoSpace) -> &mut Vec<SavedDatagram> {
        match cspace {
            CryptoSpace::Handshake => &mut self.handshake,
            CryptoSpace::ApplicationData => &mut self.application_data,
            _ => panic!("unexpected space"),
        }
    }

    pub fn save(&mut self, cspace: CryptoSpace, d: Datagram, t: Instant) {
        let store = self.store(cspace);

        if store.len() < MAX_SAVED_DATAGRAMS {
            qdebug!("saving datagram of {} bytes", d.len());
            store.push(SavedDatagram { d, t });
        } else {
            qinfo!("not saving datagram of {} bytes", d.len());
        }
    }

    pub fn make_available(&mut self, cspace: CryptoSpace) {
        debug_assert_ne!(cspace, CryptoSpace::ZeroRtt);
        debug_assert_ne!(cspace, CryptoSpace::Initial);
        if !self.store(cspace).is_empty() {
            self.available = Some(cspace);
        }
    }

    pub fn available(&self) -> Option<CryptoSpace> {
        self.available
    }

    pub fn take_saved(&mut self) -> Vec<SavedDatagram> {
        self.available
            .take()
            .map_or_else(Vec::new, |cspace| mem::take(self.store(cspace)))
    }
}