running_process/broker/server/handoff/
windows.rs1use super::{
8 HandoffAttemptDecision, HandoffAttemptFailure, HandoffFallbackDecision, HandoffFallbackReason,
9 HandoffToken,
10};
11
12pub const DUPLICATE_HANDLE_TRANSPORT_SUPPORTED: bool =
14 running_process_platform_internal::LEGACY_DUPLICATE_HANDLE_TRANSPORT_SUPPORTED;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
18pub struct WindowsHandleValue(usize);
19
20impl WindowsHandleValue {
21 pub fn new(value: usize) -> Self {
23 Self(value)
24 }
25
26 pub fn get(self) -> usize {
28 self.0
29 }
30}
31
32#[derive(Clone, Debug, PartialEq, Eq)]
34pub struct DuplicateHandleAttempt {
35 pub pipe_handle: WindowsHandleValue,
37 pub backend_pid: u32,
39 pub handoff_token: HandoffToken,
41}
42
43impl DuplicateHandleAttempt {
44 pub fn new(
46 pipe_handle: WindowsHandleValue,
47 backend_pid: u32,
48 handoff_token: HandoffToken,
49 ) -> Self {
50 Self {
51 pipe_handle,
52 backend_pid,
53 handoff_token,
54 }
55 }
56}
57
58#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct DuplicateHandleSuccess {
61 pub duplicated_handle: WindowsHandleValue,
63 pub backend_pid: u32,
65 pub handoff_token: HandoffToken,
67}
68
69impl DuplicateHandleSuccess {
70 pub fn new(
72 duplicated_handle: WindowsHandleValue,
73 backend_pid: u32,
74 handoff_token: HandoffToken,
75 ) -> Self {
76 Self {
77 duplicated_handle,
78 backend_pid,
79 handoff_token,
80 }
81 }
82}
83
84pub type DuplicateHandleResult = Result<DuplicateHandleSuccess, DuplicateHandleError>;
86
87pub fn try_duplicate_handle(attempt: &DuplicateHandleAttempt) -> DuplicateHandleResult {
94 let duplicated = running_process_platform_internal::legacy_duplicate_handle(
95 attempt.pipe_handle.get(),
96 attempt.backend_pid,
97 )
98 .map_err(|error| legacy_error(attempt.backend_pid, error))?;
99 Ok(DuplicateHandleSuccess::new(
100 WindowsHandleValue::new(duplicated),
101 attempt.backend_pid,
102 attempt.handoff_token,
103 ))
104}
105
106fn legacy_error(
107 backend_pid: u32,
108 error: running_process_platform_internal::LegacyHandoffError,
109) -> DuplicateHandleError {
110 use running_process_platform_internal::platform::ipc::HandoffTransferErrorKind;
111
112 match error.kind() {
113 HandoffTransferErrorKind::Unsupported => DuplicateHandleError::UnsupportedPlatform,
114 HandoffTransferErrorKind::PermissionDenied => {
115 DuplicateHandleError::PermissionDenied { backend_pid }
116 }
117 HandoffTransferErrorKind::BackendUnavailable => {
118 DuplicateHandleError::CannotOpenBackend { backend_pid }
119 }
120 HandoffTransferErrorKind::WouldBlock | HandoffTransferErrorKind::Failed => {
121 DuplicateHandleError::DuplicateFailed {
122 backend_pid,
123 raw_os_error: error.raw_os_error(),
124 }
125 }
126 }
127}
128
129#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
131pub enum DuplicateHandleError {
132 #[error("DuplicateHandle handoff transport is unsupported on this platform")]
134 UnsupportedPlatform,
135 #[error("cannot open backend process {backend_pid} for DuplicateHandle")]
137 CannotOpenBackend {
138 backend_pid: u32,
140 },
141 #[error("permission denied duplicating handle into backend process {backend_pid}")]
143 PermissionDenied {
144 backend_pid: u32,
146 },
147 #[error("DuplicateHandle failed for backend process {backend_pid}")]
149 DuplicateFailed {
150 backend_pid: u32,
152 raw_os_error: Option<i32>,
154 },
155 #[error("integrity mismatch duplicating handle into backend process {backend_pid}")]
157 IntegrityMismatch {
158 backend_pid: u32,
160 },
161 #[error("backend process {backend_pid} did not acknowledge duplicated handle")]
163 BackendAckTimeout {
164 backend_pid: u32,
166 },
167}
168
169impl DuplicateHandleError {
170 pub fn attempt_failure(&self) -> Option<HandoffAttemptFailure> {
172 match self {
173 Self::UnsupportedPlatform => None,
174 Self::CannotOpenBackend { .. }
175 | Self::PermissionDenied { .. }
176 | Self::DuplicateFailed { .. } => Some(HandoffAttemptFailure::PermissionDenied),
177 Self::IntegrityMismatch { .. } => Some(HandoffAttemptFailure::IntegrityMismatch),
178 Self::BackendAckTimeout { .. } => Some(HandoffAttemptFailure::BackendAckTimeout),
179 }
180 }
181
182 pub fn fallback_reason(&self) -> HandoffFallbackReason {
184 match self.attempt_failure() {
185 Some(failure) => failure.into(),
186 None => HandoffFallbackReason::ServicePolicyDisabled,
187 }
188 }
189
190 pub fn fallback_decision(&self) -> HandoffFallbackDecision {
192 HandoffFallbackDecision::new(self.fallback_reason())
193 }
194
195 pub fn fallback_attempt_decision(&self) -> HandoffAttemptDecision {
197 HandoffAttemptDecision::FallbackToReconnect(self.fallback_decision())
198 }
199
200 pub fn is_fallback_safe(&self) -> bool {
202 let fallback = self.fallback_decision();
203 fallback.uses_backend_reconnect() && !fallback.sends_client_error()
204 }
205}