liminal_protocol/outcome/keepalive.rs
1use alloc::string::String;
2
3/// Signed platform descriptor used in keepalive certification failures.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct PlatformName(String);
6
7impl PlatformName {
8 /// Creates a platform descriptor from its signed name.
9 #[must_use]
10 pub const fn new(name: String) -> Self {
11 Self(name)
12 }
13
14 /// Borrows the signed platform name.
15 #[must_use]
16 pub fn as_str(&self) -> &str {
17 &self.0
18 }
19
20 /// Returns the owned signed platform name.
21 #[must_use]
22 pub fn into_string(self) -> String {
23 self.0
24 }
25}
26
27/// Numeric keepalive configuration field.
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum KeepaliveField {
30 /// Idle seconds before the first probe.
31 IdleSeconds,
32 /// Seconds between probes.
33 IntervalSeconds,
34 /// Probe count before connection failure.
35 ProbeCount,
36}
37
38/// Socket option selected by certification.
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub enum KeepaliveOption {
41 /// Boolean `SO_KEEPALIVE` enablement.
42 SoKeepalive,
43 /// Platform idle-time option.
44 Idle,
45 /// Platform probe-interval option.
46 Interval,
47 /// Platform probe-count option.
48 Count,
49}
50
51/// Phase in which keepalive certification failed.
52#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub enum KeepalivePhase {
54 /// Listener startup configuration validation.
55 StartupConfiguration,
56 /// Configuration of one accepted participant socket.
57 AcceptedSocket,
58}
59
60/// Type-safe read-back mismatch body.
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
62pub enum KeepaliveReadbackMismatch {
63 /// Boolean `SO_KEEPALIVE` mismatch.
64 SoKeepalive {
65 /// Requested enablement.
66 requested: bool,
67 /// Effective enablement.
68 effective: bool,
69 },
70 /// Numeric keepalive-option mismatch.
71 Numeric {
72 /// Idle, interval, or count option; `SO_KEEPALIVE` is absent by type.
73 option: NumericKeepaliveOption,
74 /// Requested unsigned value.
75 requested: u64,
76 /// Effective unsigned value.
77 effective: u64,
78 },
79}
80
81/// Numeric socket options; boolean `SO_KEEPALIVE` is deliberately absent.
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83pub enum NumericKeepaliveOption {
84 /// Platform idle-time option.
85 Idle,
86 /// Platform probe-interval option.
87 Interval,
88 /// Platform probe-count option.
89 Count,
90}
91
92/// Startup-only keepalive validation or support failure.
93#[derive(Clone, Debug, PartialEq, Eq)]
94pub enum StartupKeepaliveReason {
95 /// A required numeric value was zero.
96 Zero {
97 /// First zero field in certification order.
98 field: KeepaliveField,
99 /// Requested value, which is zero for this variant.
100 requested: u64,
101 /// Required minimum, which is one for this variant.
102 required_minimum: u64,
103 },
104 /// Requested value is outside the signed platform range.
105 OutOfRange {
106 /// First out-of-range field in certification order.
107 field: KeepaliveField,
108 /// Requested value.
109 requested: u64,
110 /// Inclusive signed platform minimum.
111 supported_min: u64,
112 /// Inclusive signed platform maximum.
113 supported_max: u64,
114 /// Signed target-platform descriptor.
115 platform: PlatformName,
116 },
117 /// Requested value cannot be represented at platform granularity.
118 GranularityMismatch {
119 /// First mismatched field in certification order.
120 field: KeepaliveField,
121 /// Requested value.
122 requested: u64,
123 /// Signed platform granularity.
124 granularity: u64,
125 /// Signed target-platform descriptor.
126 platform: PlatformName,
127 },
128 /// No signed keepalive descriptor exists for the platform.
129 UnsupportedPlatform {
130 /// Unsupported target-platform descriptor.
131 platform: PlatformName,
132 },
133 /// A required option is absent from the signed descriptor.
134 UnsupportedOption {
135 /// First unsupported option in certification order.
136 option: KeepaliveOption,
137 /// Signed target-platform descriptor.
138 platform: PlatformName,
139 },
140}
141
142/// Accepted-socket-only set or read-back certification failure.
143#[derive(Clone, Debug, PartialEq, Eq)]
144pub enum AcceptedSocketKeepaliveReason {
145 /// Setting a required option failed.
146 SetFailed {
147 /// First option whose set failed.
148 option: KeepaliveOption,
149 /// Signed target-platform descriptor.
150 platform: PlatformName,
151 /// Raw operating-system error code.
152 os_error: i32,
153 },
154 /// Reading back a required option failed.
155 ReadbackFailed {
156 /// First option whose read-back failed.
157 option: KeepaliveOption,
158 /// Signed target-platform descriptor.
159 platform: PlatformName,
160 /// Raw operating-system error code.
161 os_error: i32,
162 },
163 /// Read-back value differs from the exact requested value.
164 ReadbackMismatch {
165 /// Exact option-specific requested/effective pair.
166 mismatch: KeepaliveReadbackMismatch,
167 /// Signed target-platform descriptor.
168 platform: PlatformName,
169 },
170}
171
172/// Keepalive startup or accepted-socket certification failed.
173///
174/// The phase is encoded by the outer variant, so startup-only and
175/// accepted-socket-only reasons cannot be combined with the wrong phase.
176#[derive(Clone, Debug, PartialEq, Eq)]
177pub enum KeepaliveCertificationFailed {
178 /// Startup configuration failed before opening the participant listener.
179 StartupConfiguration(StartupKeepaliveReason),
180 /// One accepted socket failed before participant negotiation.
181 AcceptedSocket(AcceptedSocketKeepaliveReason),
182}
183
184impl KeepaliveCertificationFailed {
185 /// Returns the phase fixed by this outcome's reason family.
186 #[must_use]
187 pub const fn phase(&self) -> KeepalivePhase {
188 match self {
189 Self::StartupConfiguration(_) => KeepalivePhase::StartupConfiguration,
190 Self::AcceptedSocket(_) => KeepalivePhase::AcceptedSocket,
191 }
192 }
193}