1
//! Parameters influencing all channels in a Tor client
2
//!
3
//! This module contains [`ChannelPaddingInstructions`].
4
//!
5
//! These are instructions about what to do about padding.
6
//! They include information about:
7
//!   * whether padding is to be sent
8
//!   * what timing parameters to use for sending padding
9
//!   * what `PADDING_NEGOTIATE` cell to send
10
//!
11
//! The instructions are, ultimately, instructions to the channel reactor.
12
//! The reactor gets a [`ChannelPaddingInstructionsUpdates`],
13
//! which is a set of *changes* to make.
14
//!
15
//! The producer side is the channel manager,
16
//! which records the current `ChannelPaddingInstructions`
17
//! and makes updates with [`ChannelPaddingInstructionsUpdatesBuilder`]
18
//! (and is assisted by [`Channel::engage_padding_activities`]).
19
//!
20
//! [`Channel::engage_padding_activities`]: super::Channel::engage_padding_activities
21

            
22
use educe::Educe;
23

            
24
use tor_cell::chancell::msg::PaddingNegotiate;
25

            
26
use super::padding;
27

            
28
/// Generate most of the types and methods relating to ChannelPaddingInstructions:
29
/// things which contain or process all instructions fields (or each one)
30
///
31
/// There is one call to this macro, which has as argument
32
/// the body of `struct ChannelPaddingInstructions`, with the following differences:
33
///
34
///  * field visibility specifiers are not specified; they are provided by the macro
35
///  * non-doc attributes that ought to be applied to fields in `ChannelPaddingInstructions`
36
///    are prefixed with `field`, e.g. `#[field educe(Default ...)]`;
37
///    this allows applying doc attributes to other items too.
38
///
39
/// Generates, fairly straightforwardly:
40
///
41
/// ```ignore
42
/// pub struct ChannelPaddingInstructions { ... } // containing the fields as specified
43
/// pub struct ChannelPaddingInstructionsUpdates { ... } // containing `Option` of each field
44
/// pub fn ChannelPaddingInstructions::initial_update(&self) -> ChannelPaddingInstructionsUpdates;
45
/// pub fn ChannelPaddingInstructionsUpdatesBuilder::$field(self, new_value: _) -> Self;
46
/// ```
47
///
48
/// Within the macro body, we indent the per-field `$( )*` with 2 spaces.
49
macro_rules! define_channels_insns_and_automatic_impls { { $(
50
    $( #[doc $($doc_attr:tt)*] )*
51
    $( #[field $other_attr:meta] )*
52
    $field:ident : $ty:ty
53
),* $(,)? } => {
54

            
55
    /// Initial, and, overall, padding instructions for channels
56
    ///
57
    /// This is used both to generate the initial instructions,
58
    /// and to handle updates:
59
    /// when used for handling updates,
60
    /// it contains the last instructions that has been implemented.
61
    ///
62
    /// Central code managing all channels will contain a `ChannelPaddingInstructions`,
63
    /// and use `ChannelPaddingInstructionsUpdatesBuilder` to both update those `Instructions`
64
    /// and generate `ChannelPaddingInstructionsUpdates` messages representing the changes.
65
    ///
66
    /// The channel frontend (methods on `Channel`)
67
    /// processes `ChannelPaddingInstructionsUpdates` from the channel manager,
68
    /// possibly into channel-specific updates.
69
    ///
70
    /// `Default` is a placeholder to use pending availability of a netdir etc.
71
585
    #[derive(Debug, Educe, Clone, Eq, PartialEq)]
72
    #[educe(Default)]
73
    pub struct ChannelPaddingInstructions {
74
      $(
75
        $( #[doc $($doc_attr)*] )*
76
        $( #[$other_attr] )*
77
        pub(crate) $field: $ty,
78
      )*
79
    }
80

            
81
    /// New instructions to the reactor
82
    ///
83
    /// Can contain updates to each of the fields in `ChannelPaddingInstructions`.
84
    /// Constructed via [`ChannelPaddingInstructionsUpdatesBuilder`],
85
    /// which is obtained from [`ChannelPaddingInstructions::start_update`].
86
    ///
87
    /// Sent to all channel implementations, when they ought to change their behaviour.
88
    #[derive(Debug, Default, Clone, Eq, PartialEq)]
89
    pub struct ChannelPaddingInstructionsUpdates {
90
      $(
91
        /// New value, if it has changed.
92
        ///
93
        /// Having this contain `Option` allows the sender of an update to promise
94
        /// that the value hasn't changed, and thereby allows the channel implementation
95
        /// to avoid touching state that it doesn't need to (eg, timers).
96
        pub(crate) $field: Option<$ty>,
97
      )*
98
    }
99

            
100
    impl ChannelPaddingInstructions {
101
        /// Create an update message which sets settings in `self` which
102
        /// are not equal to the initial behaviour of the reactor.
103
        ///
104
        /// Used during channel startup.
105
        #[must_use = "initial_update makes an updates message that must be sent to have effect"]
106
517
        pub fn initial_update(&self) -> Option<ChannelPaddingInstructionsUpdates> {
107
517
            let mut supposed = ChannelPaddingInstructions::default();
108
517

            
109
517
            supposed.start_update()
110
517
              $(
111
517
                .$field(self.$field.clone())
112
517
              )*
113
517
                .finish()
114
517
        }
115
    }
116

            
117
    impl<'c> ChannelPaddingInstructionsUpdatesBuilder<'c> {
118
      $(
119
        $( #[doc $($doc_attr)*] )*
120
        ///
121
        /// (Adds this setting to the update, if it has changed.)
122
7567
        pub fn $field(mut self, new_value: $ty) -> Self {
123
7567
            if &new_value != &self.insns.$field {
124
4230
                self
125
4230
                    .update
126
4282
                    .get_or_insert_with(|| Default::default())
127
4230
                    .$field = Some(new_value.clone());
128
4230
                self.insns.$field = new_value;
129
4230
            }
130
7567
            self
131
7567
        }
132
      )*
133
    }
134

            
135
    impl ChannelPaddingInstructionsUpdates {
136
        /// Combines `more` into `self`
137
        ///
138
        /// Values from `more` override ones in `self`.
139
188
        pub fn combine(&mut self, more: &Self) {
140
          $(
141
188
            if let Some(new_value) = &more.$field {
142
94
                self.$field = Some(new_value.clone());
143
94
            }
144
          )*
145
188
        }
146

            
147
      $(
148
        #[cfg(feature = "testing")]
149
        $( #[doc $($doc_attr)*] )*
150
        ///
151
        /// Accessor.
152
        /// For testing the logic which generates channel padding control instructions.
153
1269
        pub fn $field(&self) -> Option<&$ty> {
154
1269
            self.$field.as_ref()
155
1269
        }
156
      )*
157
    }
158
} }
159

            
160
define_channels_insns_and_automatic_impls! {
161
    /// Whether to send padding
162
    padding_enable: bool,
163

            
164
    /// Padding timing parameters
165
    ///
166
    /// This is in abeyance if `send_padding` is `false`;
167
    /// we still pass it because the usual case is that padding is enabled/disabled
168
    /// rather than the parameters changing,
169
    /// so the padding timer always keeps parameters, even when disabled.
170
    //
171
    // The initial configuration of the padding timer used by the reactor has no
172
    // parameters, so does not send padding.  We need to mirror that here, so that we
173
    // give the reactor an initial set of timing parameters.
174
    #[field educe(Default(expression = "padding::Parameters::disabled()"))]
175
    padding_parameters: padding::Parameters,
176

            
177
    /// Channel padding negotiation cell
178
    ///
179
    /// In `ChannelPaddingInstructions`, and when set via `Builder`,
180
    /// this is the `PADDING_NEGOTIATE` cell which should be used when we want
181
    /// to instruct our peer (the guard) to do padding like we have concluded we want.
182
    ///
183
    /// (An initial `PaddingNegotiate::start_default()` is elided
184
    /// in [`Channel::engage_padding_activities`]
185
    /// since that is what the peer would do anyway.)
186
    ///
187
    /// [`Channel::engage_padding_activities`]: super::Channel::engage_padding_activities
188
    padding_negotiate: PaddingNegotiate,
189
}
190

            
191
/// Builder for a channels padding instructions update
192
///
193
/// Obtain this from `ChannelPaddingInstructions::update`,
194
/// call zero or more setter methods,
195
/// call [`finish`](ChannelPaddingInstructionsUpdatesBuilder::finish),
196
/// and then send the resulting message.
197
///
198
/// # Panics
199
///
200
/// Panics if dropped.  Instead, call `finish`.
201
pub struct ChannelPaddingInstructionsUpdatesBuilder<'c> {
202
    /// Tracking the existing instructions
203
    insns: &'c mut ChannelPaddingInstructions,
204

            
205
    /// The update we are building
206
    ///
207
    /// `None` means nothing has changed yet.
208
    update: Option<ChannelPaddingInstructionsUpdates>,
209

            
210
    /// Make it hard to write code paths that drop this
211
    drop_bomb: bool,
212
}
213

            
214
impl ChannelPaddingInstructions {
215
    /// Start building an update to channel padding instructions
216
    ///
217
    /// The builder **must not be dropped**, once created;
218
    /// instead, [`finish`](ChannelPaddingInstructionsUpdatesBuilder::finish) must be called.
219
    /// So prepare your new values first, perhaps fallibly,
220
    /// and only then create and use the builder and send the update, infallibly.
221
    ///
222
    /// (This is because the builder uses `self: ChannelPaddingInstructions`
223
    /// to track which values have changed,
224
    /// and the values in `self` are updated immediately by the field update methods.)
225
    ///
226
    /// # Panics
227
    ///
228
    /// [`ChannelPaddingInstructionsUpdatesBuilder`] panics if it is dropped.
229
2773
    pub fn start_update(&mut self) -> ChannelPaddingInstructionsUpdatesBuilder {
230
2773
        ChannelPaddingInstructionsUpdatesBuilder {
231
2773
            insns: self,
232
2773
            update: None,
233
2773
            drop_bomb: true,
234
2773
        }
235
2773
    }
236
}
237

            
238
impl<'c> Drop for ChannelPaddingInstructionsUpdatesBuilder<'c> {
239
2773
    fn drop(&mut self) {
240
2773
        assert!(
241
2773
            !self.drop_bomb,
242
            "ChannelPaddingInstructionsUpdatesBuilder dropped"
243
        );
244
2773
    }
245
}
246

            
247
impl<'c> ChannelPaddingInstructionsUpdatesBuilder<'c> {
248
    /// Finalise the update
249
    ///
250
    /// If nothing actually changed, returns `None`.
251
    /// (Tracking this, and returning `None`, allows us to avoid bothering
252
    /// every channel with a null update.)
253
    ///
254
    /// If `Some` is returned, the update **must** be implemented,
255
    /// since the underlying tracking [`ChannelPaddingInstructions`] has already been updated.
256
    #[must_use = "the update from finish() must be sent, to avoid losing insns changes"]
257
2773
    pub fn finish(mut self) -> Option<ChannelPaddingInstructionsUpdates> {
258
2773
        self.drop_bomb = false;
259
2773
        self.update.take()
260
2773
    }
261
}