tor_proto/channel/
params.rs

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
22use educe::Educe;
23
24use tor_cell::chancell::msg::PaddingNegotiate;
25
26use 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.
49macro_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    #[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        pub fn initial_update(&self) -> Option<ChannelPaddingInstructionsUpdates> {
107            let mut supposed = ChannelPaddingInstructions::default();
108
109            supposed.start_update()
110              $(
111                .$field(self.$field.clone())
112              )*
113                .finish()
114        }
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        pub fn $field(mut self, new_value: $ty) -> Self {
123            if &new_value != &self.insns.$field {
124                self
125                    .update
126                    .get_or_insert_with(|| Default::default())
127                    .$field = Some(new_value.clone());
128                self.insns.$field = new_value;
129            }
130            self
131        }
132      )*
133    }
134
135    impl ChannelPaddingInstructionsUpdates {
136        /// Combines `more` into `self`
137        ///
138        /// Values from `more` override ones in `self`.
139        pub fn combine(&mut self, more: &Self) {
140          $(
141            if let Some(new_value) = &more.$field {
142                self.$field = Some(new_value.clone());
143            }
144          )*
145        }
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        pub fn $field(&self) -> Option<&$ty> {
154            self.$field.as_ref()
155        }
156      )*
157    }
158} }
159
160define_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`.
201pub 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
214impl 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    pub fn start_update(&mut self) -> ChannelPaddingInstructionsUpdatesBuilder {
230        ChannelPaddingInstructionsUpdatesBuilder {
231            insns: self,
232            update: None,
233            drop_bomb: true,
234        }
235    }
236}
237
238impl<'c> Drop for ChannelPaddingInstructionsUpdatesBuilder<'c> {
239    fn drop(&mut self) {
240        assert!(
241            !self.drop_bomb,
242            "ChannelPaddingInstructionsUpdatesBuilder dropped"
243        );
244    }
245}
246
247impl<'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    pub fn finish(mut self) -> Option<ChannelPaddingInstructionsUpdates> {
258        self.drop_bomb = false;
259        self.update.take()
260    }
261}