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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! Events for [`State`](crate::state) transitions.
use serde::{Deserialize, Serialize};
use self::Event::*;
use crate::{MachineId, constants::EVENT_NUM};
use enum_map::Enum;
use std::fmt;
use std::hash::Hash;
use std::slice::Iter;
/// An Event may trigger a [`State`](crate::state) transition.
#[derive(Debug, Enum, Eq, Hash, PartialEq, Clone, Copy, Serialize, Deserialize)]
pub enum Event {
/// NormalRecv is when we received a normal, non-padding packet.
NormalRecv,
/// PaddingRecv is when we received a padding packet.
PaddingRecv,
/// TunnelRecv is when we received a packet in the tunnel: because it is
/// encrypted, we do not know if it is a normal or padding packet yet.
TunnelRecv,
/// NormalSent is when we sent a normal, non-padding packet.
NormalSent,
/// PaddingSent is when we sent a padding packet.
PaddingSent,
/// TunnelSent is when we sent a packet in the tunnel: because it is now
/// encrypted, we do not know if it is a normal or padding packet anymore.
TunnelSent,
/// BlockingBegin is when blocking started.
BlockingBegin,
/// BlockingEnd is when blocking ended.
BlockingEnd,
/// LimitReached is when a limit in a state is reached (internal).
LimitReached,
/// CounterZero is when a machine's counter was decremented to zero.
CounterZero,
/// TimerBegin is when a machine's timer started.
TimerBegin,
/// TimerEnd is when a machine's timer expired.
TimerEnd,
/// Signal is when a machine transitioned to [`STATE_SIGNAL`](crate::constants).
Signal,
}
impl fmt::Display for Event {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl Event {
pub fn iter() -> Iter<'static, Event> {
static EVENTS: [Event; EVENT_NUM] = [
NormalRecv,
PaddingRecv,
TunnelRecv,
NormalSent,
PaddingSent,
TunnelSent,
BlockingBegin,
BlockingEnd,
LimitReached,
CounterZero,
TimerBegin,
TimerEnd,
Signal,
];
EVENTS.iter()
}
// to usize
pub const fn to_usize(&self) -> usize {
*self as usize
}
}
/// Represents an event to be triggered in the framework.
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum TriggerEvent {
/// Received non-padding packet.
///
/// This event should be triggered once for each incoming non-padding
/// packet, after `TunnelRecv`, as soon as we have identified the packet as
/// non-padding.
NormalRecv,
/// Received padding packet.
///
/// This event should be triggered once for each incoming padding packet,
/// after `TunnelRecv`, as soon as we have identified the packet as padding.
PaddingRecv,
/// Received a complete packet in the tunnel.
///
/// This event should be triggered once for each incoming packet of any
/// type, as soon as possible after the packet is received from the network,
/// before the packet is queued, processed, or decrypted.
///
/// (No event should be generated for a partially read packet.)
TunnelRecv,
/// Sent non-padding packet.
///
/// This event should be triggered once for each outgoing non-padding
/// packet, as soon as we have decided put it on any internal queue.
NormalSent,
/// Sent padding packet.
///
/// This event should be triggered once for each outgoing padding packet, as
/// soon as we have decided put it on any internal queue.
PaddingSent { machine: MachineId },
/// Sent packet in the tunnel.
///
/// This event should be triggered once for each outgoing packet of any
/// type, after that packet's `NormalSent` or `PaddingSent` event, as close
/// as possible to the time when it is actually written to the network.
TunnelSent,
/// Blocking of outgoing traffic started by the action from a machine.
///
/// This event should be triggered whenever the action timer for a
/// [`crate::action::TriggerAction::BlockOutgoing`] action expires, whether
/// the blocking timer is adjusted or not.
BlockingBegin { machine: MachineId },
/// Blocking of outgoing traffic has stopped.
///
/// This event should be triggered when the framework-scoped blocking timer
/// expires.
BlockingEnd,
/// A machine's internal timer started, or was changed.
///
/// This event should be triggered any time a new internal timer is started,
/// or whenever the expiration time of an machine's internal timer changes.
TimerBegin { machine: MachineId },
/// A machine's internal timer expired.
///
/// (This event _should not_ be sent in response to a timer being
/// cancelled.)
TimerEnd { machine: MachineId },
}
impl TriggerEvent {
/// Checks if the [`TriggerEvent`] is a particular [`Event`].
pub fn is_event(&self, e: Event) -> bool {
match self {
TriggerEvent::NormalRecv => e == Event::NormalRecv,
TriggerEvent::PaddingRecv => e == Event::PaddingRecv,
TriggerEvent::NormalSent => e == Event::NormalSent,
TriggerEvent::PaddingSent { .. } => e == Event::PaddingSent,
TriggerEvent::BlockingBegin { .. } => e == Event::BlockingBegin,
TriggerEvent::BlockingEnd => e == Event::BlockingEnd,
TriggerEvent::TimerBegin { .. } => e == Event::TimerBegin,
TriggerEvent::TimerEnd { .. } => e == Event::TimerEnd,
TriggerEvent::TunnelSent => e == Event::TunnelSent,
TriggerEvent::TunnelRecv => e == Event::TunnelRecv,
}
}
}
impl fmt::Display for TriggerEvent {
// note that we don't share the private MachineId
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TriggerEvent::NormalRecv => write!(f, "rn"),
TriggerEvent::PaddingRecv => write!(f, "rp"),
TriggerEvent::TunnelRecv => write!(f, "rt"),
TriggerEvent::NormalSent => write!(f, "sn"),
TriggerEvent::PaddingSent { .. } => write!(f, "sp"),
TriggerEvent::TunnelSent => write!(f, "st"),
TriggerEvent::BlockingBegin { .. } => write!(f, "bb"),
TriggerEvent::BlockingEnd => write!(f, "be"),
TriggerEvent::TimerBegin { .. } => write!(f, "tb"),
TriggerEvent::TimerEnd { .. } => write!(f, "te"),
}
}
}
#[cfg(test)]
mod tests {
use crate::event::*;
#[test]
fn v1_events() {
assert_eq!(Event::NormalRecv.to_string(), "NormalRecv");
assert_eq!(Event::PaddingRecv.to_string(), "PaddingRecv");
assert_eq!(Event::NormalSent.to_string(), "NormalSent");
assert_eq!(Event::PaddingSent.to_string(), "PaddingSent");
assert_eq!(Event::BlockingBegin.to_string(), "BlockingBegin");
assert_eq!(Event::BlockingEnd.to_string(), "BlockingEnd");
assert_eq!(Event::LimitReached.to_string(), "LimitReached");
}
#[test]
fn v2_events() {
assert_eq!(Event::CounterZero.to_string(), "CounterZero");
assert_eq!(Event::TimerBegin.to_string(), "TimerBegin");
assert_eq!(Event::TimerEnd.to_string(), "TimerEnd");
assert_eq!(Event::TunnelRecv.to_string(), "TunnelRecv");
assert_eq!(Event::TunnelSent.to_string(), "TunnelSent");
assert_eq!(Event::Signal.to_string(), "Signal");
}
}