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}
120
121#[derive(Debug, Clone)]
123pub enum NamedPipeChange {
124 Appeared(NamedPipeInfo),
126 Removed(NamedPipeInfo),
128}
129
130pub(crate) fn filetime_to_system_time(filetime: i64) -> Option<SystemTime> {
131 const FILETIME_TO_UNIX_EPOCH: i64 = 116_444_736_000_000_000;
132
133 if filetime <= 0 {
134 return None;
135 }
136
137 let intervals_since_unix = filetime.saturating_sub(FILETIME_TO_UNIX_EPOCH);
138 let seconds = intervals_since_unix.div_euclid(10_000_000) as u64;
139 let nanos = (intervals_since_unix.rem_euclid(10_000_000) as u32) * 100;
140
141 Some(SystemTime::UNIX_EPOCH + Duration::new(seconds, nanos))
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum NamedPipeOpenMode {
147 Inbound,
149 Outbound,
151 Duplex,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum NamedPipeType {
158 Byte,
160 Message,
162}
163
164#[derive(Debug, Clone)]
166pub struct PipeSecurityOptions {
167 pub inherit_handle: bool,
169 pub security_descriptor: Option<SecurityDescriptor>,
171}
172
173impl PipeSecurityOptions {
174 pub fn new() -> Self {
176 Self {
177 inherit_handle: false,
178 security_descriptor: None,
179 }
180 }
181
182 pub fn inherit_handle(mut self, inherit_handle: bool) -> Self {
184 self.inherit_handle = inherit_handle;
185 self
186 }
187
188 pub fn security_descriptor(mut self, security_descriptor: SecurityDescriptor) -> Self {
190 self.security_descriptor = Some(security_descriptor);
191 self
192 }
193}
194
195impl Default for PipeSecurityOptions {
196 fn default() -> Self {
197 Self::new()
198 }
199}
200
201#[derive(Debug)]
203pub struct PipeServerEndpoint {
204 handle: OwnedHandle,
205 pipe_name: PipeName,
206 open_mode: NamedPipeOpenMode,
207 pipe_type: NamedPipeType,
208}
209
210impl PipeServerEndpoint {
211 pub(crate) fn from_raw(
213 handle: HANDLE,
214 close_on_drop: bool,
215 pipe_name: PipeName,
216 open_mode: NamedPipeOpenMode,
217 pipe_type: NamedPipeType,
218 ) -> Self {
219 Self {
220 handle: OwnedHandle::with_ownership(handle, close_on_drop),
221 pipe_name,
222 open_mode,
223 pipe_type,
224 }
225 }
226
227 pub fn raw_handle(&self) -> HANDLE {
229 self.handle.raw()
230 }
231
232 pub fn pipe_name(&self) -> &PipeName {
234 &self.pipe_name
235 }
236
237 pub fn open_mode(&self) -> NamedPipeOpenMode {
239 self.open_mode
240 }
241
242 pub fn pipe_type(&self) -> NamedPipeType {
244 self.pipe_type
245 }
246
247 pub fn set_close_on_drop(&mut self, close_on_drop: bool) {
249 self.handle.set_close_on_drop(close_on_drop);
250 }
251}
252
253#[derive(Debug)]
255pub struct PipeClientEndpoint {
256 handle: OwnedHandle,
257 pipe_name: PipeName,
258 open_mode: NamedPipeOpenMode,
259}
260
261impl PipeClientEndpoint {
262 pub(crate) fn from_raw(
264 handle: HANDLE,
265 close_on_drop: bool,
266 pipe_name: PipeName,
267 open_mode: NamedPipeOpenMode,
268 ) -> Self {
269 Self {
270 handle: OwnedHandle::with_ownership(handle, close_on_drop),
271 pipe_name,
272 open_mode,
273 }
274 }
275
276 pub fn raw_handle(&self) -> HANDLE {
278 self.handle.raw()
279 }
280
281 pub fn pipe_name(&self) -> &PipeName {
283 &self.pipe_name
284 }
285
286 pub fn open_mode(&self) -> NamedPipeOpenMode {
288 self.open_mode
289 }
290
291 pub fn set_close_on_drop(&mut self, close_on_drop: bool) {
293 self.handle.set_close_on_drop(close_on_drop);
294 }
295}
296
297pub(crate) fn to_cow_pipe_name(pipe_name: Option<&PipeName>) -> Cow<'static, str> {
298 match pipe_name {
299 Some(name) => Cow::Owned(name.to_string()),
300 None => Cow::Borrowed("<unnamed pipe>"),
301 }
302}