1use std::borrow::Cow;
2use std::time::{Duration, SystemTime};
3
4use windows::Win32::Foundation::HANDLE;
5
6use crate::error::InvalidParameterError;
7use crate::security::SecurityDescriptor;
8use crate::utils::OwnedHandle;
9use crate::{Error, Result};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct PipeName(String);
14
15impl PipeName {
16 pub const PREFIX: &'static str = r"\\.\pipe\";
18
19 pub fn new(path: impl Into<String>) -> Result<Self> {
21 let path = path.into();
22 if path.is_empty() {
23 return Err(Error::InvalidParameter(InvalidParameterError::new(
24 "path",
25 "Pipe name cannot be empty",
26 )));
27 }
28 if !path.starts_with(Self::PREFIX) {
29 return Err(Error::InvalidParameter(InvalidParameterError::new(
30 "path",
31 "Pipe name must start with \\\\.\\pipe\\",
32 )));
33 }
34 if path == Self::PREFIX {
35 return Err(Error::InvalidParameter(InvalidParameterError::new(
36 "path",
37 "Pipe name must include a segment after \\\\.\\pipe\\",
38 )));
39 }
40
41 Ok(Self(path))
42 }
43
44 pub fn as_str(&self) -> &str {
46 &self.0
47 }
48
49 pub fn from_relative_name(name: impl AsRef<str>) -> Result<Self> {
51 let name = name.as_ref();
52 Self::new(format!("{}{}", Self::PREFIX, name))
53 }
54}
55
56impl std::fmt::Display for PipeName {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 write!(f, "{}", self.0)
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct NamedPipeInfo {
65 pub pipe_name: PipeName,
67 pub relative_name: String,
69 pub creation_time: Option<SystemTime>,
71 pub last_access_time: Option<SystemTime>,
73 pub last_write_time: Option<SystemTime>,
75 pub change_time: Option<SystemTime>,
77 pub end_of_file: i64,
79 pub allocation_size: i64,
81 pub file_attributes: u32,
83 pub file_index: u32,
85 pub local_info: Option<NamedPipeLocalInfo>,
87}
88
89impl NamedPipeInfo {
90 pub fn pipe_name(&self) -> &PipeName {
92 &self.pipe_name
93 }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub struct NamedPipeLocalInfo {
99 pub named_pipe_type: u32,
101 pub named_pipe_configuration: u32,
103 pub maximum_instances: u32,
105 pub current_instances: u32,
107 pub inbound_quota: u32,
109 pub read_data_available: u32,
111 pub outbound_quota: u32,
113 pub write_quota_available: u32,
115 pub named_pipe_state: u32,
117 pub named_pipe_end: u32,
119 pub server_process_id: Option<crate::types::ProcessId>,
121}
122
123#[derive(Debug, Clone)]
125pub enum NamedPipeChange {
126 Appeared(NamedPipeInfo),
128 Removed(NamedPipeInfo),
130}
131
132pub(crate) fn filetime_to_system_time(filetime: i64) -> Option<SystemTime> {
133 const FILETIME_TO_UNIX_EPOCH: i64 = 116_444_736_000_000_000;
134
135 if filetime <= 0 {
136 return None;
137 }
138
139 let intervals_since_unix = filetime.saturating_sub(FILETIME_TO_UNIX_EPOCH);
140 let seconds = intervals_since_unix.div_euclid(10_000_000) as u64;
141 let nanos = (intervals_since_unix.rem_euclid(10_000_000) as u32) * 100;
142
143 Some(SystemTime::UNIX_EPOCH + Duration::new(seconds, nanos))
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148pub enum NamedPipeOpenMode {
149 Inbound,
151 Outbound,
153 Duplex,
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159pub enum NamedPipeType {
160 Byte,
162 Message,
164}
165
166#[derive(Debug, Clone)]
168pub struct PipeSecurityOptions {
169 pub inherit_handle: bool,
171 pub security_descriptor: Option<SecurityDescriptor>,
173}
174
175impl PipeSecurityOptions {
176 pub fn new() -> Self {
178 Self {
179 inherit_handle: false,
180 security_descriptor: None,
181 }
182 }
183
184 pub fn inherit_handle(mut self, inherit_handle: bool) -> Self {
186 self.inherit_handle = inherit_handle;
187 self
188 }
189
190 pub fn security_descriptor(mut self, security_descriptor: SecurityDescriptor) -> Self {
192 self.security_descriptor = Some(security_descriptor);
193 self
194 }
195}
196
197impl Default for PipeSecurityOptions {
198 fn default() -> Self {
199 Self::new()
200 }
201}
202
203#[derive(Debug)]
205pub struct PipeServerEndpoint {
206 handle: OwnedHandle,
207 pipe_name: PipeName,
208 open_mode: NamedPipeOpenMode,
209 pipe_type: NamedPipeType,
210}
211
212impl PipeServerEndpoint {
213 pub(crate) fn from_raw(
215 handle: HANDLE,
216 close_on_drop: bool,
217 pipe_name: PipeName,
218 open_mode: NamedPipeOpenMode,
219 pipe_type: NamedPipeType,
220 ) -> Self {
221 Self {
222 handle: OwnedHandle::with_ownership(handle, close_on_drop),
223 pipe_name,
224 open_mode,
225 pipe_type,
226 }
227 }
228
229 pub fn raw_handle(&self) -> HANDLE {
231 self.handle.raw()
232 }
233
234 pub fn pipe_name(&self) -> &PipeName {
236 &self.pipe_name
237 }
238
239 pub fn open_mode(&self) -> NamedPipeOpenMode {
241 self.open_mode
242 }
243
244 pub fn pipe_type(&self) -> NamedPipeType {
246 self.pipe_type
247 }
248
249 pub fn set_close_on_drop(&mut self, close_on_drop: bool) {
251 self.handle.set_close_on_drop(close_on_drop);
252 }
253}
254
255#[derive(Debug)]
257pub struct PipeClientEndpoint {
258 handle: OwnedHandle,
259 pipe_name: PipeName,
260 open_mode: NamedPipeOpenMode,
261}
262
263impl PipeClientEndpoint {
264 pub(crate) fn from_raw(
266 handle: HANDLE,
267 close_on_drop: bool,
268 pipe_name: PipeName,
269 open_mode: NamedPipeOpenMode,
270 ) -> Self {
271 Self {
272 handle: OwnedHandle::with_ownership(handle, close_on_drop),
273 pipe_name,
274 open_mode,
275 }
276 }
277
278 pub fn raw_handle(&self) -> HANDLE {
280 self.handle.raw()
281 }
282
283 pub fn pipe_name(&self) -> &PipeName {
285 &self.pipe_name
286 }
287
288 pub fn open_mode(&self) -> NamedPipeOpenMode {
290 self.open_mode
291 }
292
293 pub fn set_close_on_drop(&mut self, close_on_drop: bool) {
295 self.handle.set_close_on_drop(close_on_drop);
296 }
297}
298
299pub(crate) fn to_cow_pipe_name(pipe_name: Option<&PipeName>) -> Cow<'static, str> {
300 match pipe_name {
301 Some(name) => Cow::Owned(name.to_string()),
302 None => Cow::Borrowed("<unnamed pipe>"),
303 }
304}