]>
Commit | Line | Data |
---|---|---|
487cf647 FG |
1 | //! Interprocess Communication pipes |
2 | //! | |
3 | //! A pipe is a section of shared memory that processes use for communication. | |
4 | //! The process that creates a pipe is the _pipe server_. A process that connects | |
5 | //! to a pipe is a _pipe client_. One process writes information to the pipe, then | |
6 | //! the other process reads the information from the pipe. This overview | |
7 | //! describes how to create, manage, and use pipes. | |
8 | //! | |
9 | //! There are two types of pipes: [anonymous pipes](#fn.anonymous.html) and | |
10 | //! [named pipes](#fn.named.html). Anonymous pipes require less overhead than | |
11 | //! named pipes, but offer limited services. | |
12 | //! | |
13 | //! # Anonymous pipes | |
14 | //! | |
15 | //! An anonymous pipe is an unnamed, one-way pipe that typically transfers data | |
16 | //! between a parent process and a child process. Anonymous pipes are always | |
17 | //! local; they cannot be used for communication over a network. | |
18 | //! | |
19 | //! # Named pipes | |
20 | //! | |
21 | //! A *named pipe* is a named, one-way or duplex pipe for communication between | |
22 | //! the pipe server and one or more pipe clients. All instances of a named pipe | |
23 | //! share the same pipe name, but each instance has its own buffers and handles, | |
24 | //! and provides a separate conduit for client/server communication. The use of | |
25 | //! instances enables multiple pipe clients to use the same named pipe | |
26 | //! simultaneously. | |
27 | //! | |
28 | //! Any process can access named pipes, subject to security checks, making named | |
29 | //! pipes an easy form of communication between related or unrelated processes. | |
30 | //! | |
31 | //! Any process can act as both a server and a client, making peer-to-peer | |
32 | //! communication possible. As used here, the term pipe server refers to a | |
33 | //! process that creates a named pipe, and the term pipe client refers to a | |
34 | //! process that connects to an instance of a named pipe. | |
35 | //! | |
36 | //! Named pipes can be used to provide communication between processes on the | |
37 | //! same computer or between processes on different computers across a network. | |
38 | //! If the server service is running, all named pipes are accessible remotely. If | |
39 | //! you intend to use a named pipe locally only, deny access to NT | |
40 | //! AUTHORITY\\NETWORK or switch to local RPC. | |
41 | //! | |
42 | //! # References | |
43 | //! | |
44 | //! - [win32 pipe docs](https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/ipc/pipes.md) | |
45 | ||
46 | use crate::FALSE; | |
47 | use std::cell::RefCell; | |
48 | use std::ffi::OsStr; | |
49 | use std::fs::{File, OpenOptions}; | |
50 | use std::io; | |
51 | use std::io::{Read, Write}; | |
52 | use std::os::windows::ffi::OsStrExt; | |
53 | use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; | |
54 | use std::time::Duration; | |
55 | ||
56 | use crate::handle::Handle; | |
57 | use crate::overlapped::Overlapped; | |
58 | ||
59 | use windows_sys::Win32::Foundation::{ | |
60 | ERROR_IO_PENDING, ERROR_NO_DATA, ERROR_PIPE_BUSY, ERROR_PIPE_CONNECTED, HANDLE, | |
61 | INVALID_HANDLE_VALUE, | |
62 | }; | |
63 | use windows_sys::Win32::Security::SECURITY_ATTRIBUTES; | |
64 | use windows_sys::Win32::Storage::FileSystem::{ | |
65 | FlushFileBuffers, FILE_FLAG_FIRST_PIPE_INSTANCE, FILE_FLAG_OVERLAPPED, PIPE_ACCESS_DUPLEX, | |
66 | PIPE_ACCESS_INBOUND, PIPE_ACCESS_OUTBOUND, | |
67 | }; | |
68 | use windows_sys::Win32::System::Pipes::{ | |
69 | ConnectNamedPipe, CreateNamedPipeW, CreatePipe, DisconnectNamedPipe, WaitNamedPipeW, | |
70 | PIPE_REJECT_REMOTE_CLIENTS, PIPE_TYPE_BYTE, PIPE_UNLIMITED_INSTANCES, | |
71 | }; | |
72 | use windows_sys::Win32::System::IO::{GetOverlappedResult, OVERLAPPED}; | |
73 | ||
74 | /// Readable half of an anonymous pipe. | |
75 | #[derive(Debug)] | |
76 | pub struct AnonRead(Handle); | |
77 | ||
78 | /// Writable half of an anonymous pipe. | |
79 | #[derive(Debug)] | |
80 | pub struct AnonWrite(Handle); | |
81 | ||
82 | /// A named pipe that can accept connections. | |
83 | #[derive(Debug)] | |
84 | pub struct NamedPipe(Handle); | |
85 | ||
86 | /// A builder structure for creating a new named pipe. | |
87 | #[derive(Debug)] | |
88 | pub struct NamedPipeBuilder { | |
89 | name: Vec<u16>, | |
90 | dwOpenMode: u32, | |
91 | dwPipeMode: u32, | |
92 | nMaxInstances: u32, | |
93 | nOutBufferSize: u32, | |
94 | nInBufferSize: u32, | |
95 | nDefaultTimeOut: u32, | |
96 | } | |
97 | ||
98 | /// Creates a new anonymous in-memory pipe, returning the read/write ends of the | |
99 | /// pipe. | |
100 | /// | |
101 | /// The buffer size for this pipe may also be specified, but the system will | |
102 | /// normally use this as a suggestion and it's not guaranteed that the buffer | |
103 | /// will be precisely this size. | |
104 | pub fn anonymous(buffer_size: u32) -> io::Result<(AnonRead, AnonWrite)> { | |
105 | let mut read = 0 as HANDLE; | |
106 | let mut write = 0 as HANDLE; | |
107 | crate::cvt(unsafe { CreatePipe(&mut read, &mut write, 0 as *mut _, buffer_size) })?; | |
108 | Ok((AnonRead(Handle::new(read)), AnonWrite(Handle::new(write)))) | |
109 | } | |
110 | ||
111 | impl Read for AnonRead { | |
112 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
113 | self.0.read(buf) | |
114 | } | |
115 | } | |
116 | impl<'a> Read for &'a AnonRead { | |
117 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
118 | self.0.read(buf) | |
119 | } | |
120 | } | |
121 | ||
122 | impl AsRawHandle for AnonRead { | |
123 | fn as_raw_handle(&self) -> RawHandle { | |
124 | self.0.raw() as RawHandle | |
125 | } | |
126 | } | |
127 | impl FromRawHandle for AnonRead { | |
128 | unsafe fn from_raw_handle(handle: RawHandle) -> AnonRead { | |
129 | AnonRead(Handle::new(handle as HANDLE)) | |
130 | } | |
131 | } | |
132 | impl IntoRawHandle for AnonRead { | |
133 | fn into_raw_handle(self) -> RawHandle { | |
134 | self.0.into_raw() as RawHandle | |
135 | } | |
136 | } | |
137 | ||
138 | impl Write for AnonWrite { | |
139 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
140 | self.0.write(buf) | |
141 | } | |
142 | fn flush(&mut self) -> io::Result<()> { | |
143 | Ok(()) | |
144 | } | |
145 | } | |
146 | impl<'a> Write for &'a AnonWrite { | |
147 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
148 | self.0.write(buf) | |
149 | } | |
150 | fn flush(&mut self) -> io::Result<()> { | |
151 | Ok(()) | |
152 | } | |
153 | } | |
154 | ||
155 | impl AsRawHandle for AnonWrite { | |
156 | fn as_raw_handle(&self) -> RawHandle { | |
157 | self.0.raw() as RawHandle | |
158 | } | |
159 | } | |
160 | impl FromRawHandle for AnonWrite { | |
161 | unsafe fn from_raw_handle(handle: RawHandle) -> AnonWrite { | |
162 | AnonWrite(Handle::new(handle as HANDLE)) | |
163 | } | |
164 | } | |
165 | impl IntoRawHandle for AnonWrite { | |
166 | fn into_raw_handle(self) -> RawHandle { | |
167 | self.0.into_raw() as RawHandle | |
168 | } | |
169 | } | |
170 | ||
171 | /// A convenience function to connect to a named pipe. | |
172 | /// | |
173 | /// This function will block the calling process until it can connect to the | |
174 | /// pipe server specified by `addr`. This will use `NamedPipe::wait` internally | |
175 | /// to block until it can connect. | |
176 | pub fn connect<A: AsRef<OsStr>>(addr: A) -> io::Result<File> { | |
177 | _connect(addr.as_ref()) | |
178 | } | |
179 | ||
180 | fn _connect(addr: &OsStr) -> io::Result<File> { | |
181 | let mut r = OpenOptions::new(); | |
182 | let mut w = OpenOptions::new(); | |
183 | let mut rw = OpenOptions::new(); | |
184 | r.read(true); | |
185 | w.write(true); | |
186 | rw.read(true).write(true); | |
187 | loop { | |
188 | let res = rw | |
189 | .open(addr) | |
190 | .or_else(|_| r.open(addr)) | |
191 | .or_else(|_| w.open(addr)); | |
192 | match res { | |
193 | Ok(f) => return Ok(f), | |
194 | Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => {} | |
195 | Err(e) => return Err(e), | |
196 | } | |
197 | ||
198 | NamedPipe::wait(addr, Some(Duration::new(20, 0)))?; | |
199 | } | |
200 | } | |
201 | ||
202 | impl NamedPipe { | |
203 | /// Creates a new initial named pipe. | |
204 | /// | |
205 | /// This function is equivalent to: | |
206 | /// | |
207 | /// ``` | |
208 | /// use miow::pipe::NamedPipeBuilder; | |
209 | /// | |
210 | /// # let addr = "foo"; | |
211 | /// NamedPipeBuilder::new(addr) | |
212 | /// .first(true) | |
213 | /// .inbound(true) | |
214 | /// .outbound(true) | |
215 | /// .out_buffer_size(65536) | |
216 | /// .in_buffer_size(65536) | |
217 | /// .create(); | |
218 | /// ``` | |
219 | pub fn new<A: AsRef<OsStr>>(addr: A) -> io::Result<NamedPipe> { | |
220 | NamedPipeBuilder::new(addr).create() | |
221 | } | |
222 | ||
223 | /// Waits until either a time-out interval elapses or an instance of the | |
224 | /// specified named pipe is available for connection. | |
225 | /// | |
226 | /// If this function succeeds the process can create a `File` to connect to | |
227 | /// the named pipe. | |
228 | pub fn wait<A: AsRef<OsStr>>(addr: A, timeout: Option<Duration>) -> io::Result<()> { | |
229 | NamedPipe::_wait(addr.as_ref(), timeout) | |
230 | } | |
231 | ||
232 | fn _wait(addr: &OsStr, timeout: Option<Duration>) -> io::Result<()> { | |
233 | let addr = addr.encode_wide().chain(Some(0)).collect::<Vec<_>>(); | |
234 | let timeout = crate::dur2ms(timeout); | |
235 | crate::cvt(unsafe { WaitNamedPipeW(addr.as_ptr() as _, timeout) }).map(|_| ()) | |
236 | } | |
237 | ||
238 | /// Connects this named pipe to a client, blocking until one becomes | |
239 | /// available. | |
240 | /// | |
241 | /// This function will call the `ConnectNamedPipe` function to await for a | |
242 | /// client to connect. This can be called immediately after the pipe is | |
243 | /// created, or after it has been disconnected from a previous client. | |
244 | pub fn connect(&self) -> io::Result<()> { | |
245 | match crate::cvt(unsafe { ConnectNamedPipe(self.0.raw(), 0 as *mut _) }) { | |
246 | Ok(_) => Ok(()), | |
247 | Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) => Ok(()), | |
248 | Err(e) => Err(e), | |
249 | } | |
250 | } | |
251 | ||
252 | /// Issue a connection request with the specified overlapped operation. | |
253 | /// | |
254 | /// This function will issue a request to connect a client to this server, | |
255 | /// returning immediately after starting the overlapped operation. | |
256 | /// | |
257 | /// If this function immediately succeeds then `Ok(true)` is returned. If | |
258 | /// the overlapped operation is enqueued and pending, then `Ok(false)` is | |
259 | /// returned. Otherwise an error is returned indicating what went wrong. | |
260 | /// | |
261 | /// # Unsafety | |
262 | /// | |
263 | /// This function is unsafe because the kernel requires that the | |
264 | /// `overlapped` pointer is valid until the end of the I/O operation. The | |
265 | /// kernel also requires that `overlapped` is unique for this I/O operation | |
266 | /// and is not in use for any other I/O. | |
267 | /// | |
268 | /// To safely use this function callers must ensure that this pointer is | |
269 | /// valid until the I/O operation is completed, typically via completion | |
270 | /// ports and waiting to receive the completion notification on the port. | |
271 | pub unsafe fn connect_overlapped(&self, overlapped: *mut OVERLAPPED) -> io::Result<bool> { | |
272 | match crate::cvt(ConnectNamedPipe(self.0.raw(), overlapped)) { | |
273 | Ok(_) => Ok(true), | |
274 | Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) => Ok(true), | |
275 | Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) => Ok(false), | |
276 | Err(ref e) if e.raw_os_error() == Some(ERROR_NO_DATA as i32) => Ok(true), | |
277 | Err(e) => Err(e), | |
278 | } | |
279 | } | |
280 | ||
281 | /// Disconnects this named pipe from any connected client. | |
282 | pub fn disconnect(&self) -> io::Result<()> { | |
283 | crate::cvt(unsafe { DisconnectNamedPipe(self.0.raw()) }).map(|_| ()) | |
284 | } | |
285 | ||
286 | /// Issues an overlapped read operation to occur on this pipe. | |
287 | /// | |
288 | /// This function will issue an asynchronous read to occur in an overlapped | |
289 | /// fashion, returning immediately. The `buf` provided will be filled in | |
290 | /// with data and the request is tracked by the `overlapped` function | |
291 | /// provided. | |
292 | /// | |
293 | /// If the operation succeeds immediately, `Ok(Some(n))` is returned where | |
294 | /// `n` is the number of bytes read. If an asynchronous operation is | |
295 | /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred | |
296 | /// it is returned. | |
297 | /// | |
298 | /// When this operation completes (or if it completes immediately), another | |
299 | /// mechanism must be used to learn how many bytes were transferred (such as | |
300 | /// looking at the filed in the IOCP status message). | |
301 | /// | |
302 | /// # Unsafety | |
303 | /// | |
304 | /// This function is unsafe because the kernel requires that the `buf` and | |
305 | /// `overlapped` pointers to be valid until the end of the I/O operation. | |
306 | /// The kernel also requires that `overlapped` is unique for this I/O | |
307 | /// operation and is not in use for any other I/O. | |
308 | /// | |
309 | /// To safely use this function callers must ensure that the pointers are | |
310 | /// valid until the I/O operation is completed, typically via completion | |
311 | /// ports and waiting to receive the completion notification on the port. | |
312 | pub unsafe fn read_overlapped( | |
313 | &self, | |
314 | buf: &mut [u8], | |
315 | overlapped: *mut OVERLAPPED, | |
316 | ) -> io::Result<Option<usize>> { | |
317 | self.0.read_overlapped(buf, overlapped) | |
318 | } | |
319 | ||
320 | /// Issues an overlapped write operation to occur on this pipe. | |
321 | /// | |
322 | /// This function will issue an asynchronous write to occur in an overlapped | |
323 | /// fashion, returning immediately. The `buf` provided will be filled in | |
324 | /// with data and the request is tracked by the `overlapped` function | |
325 | /// provided. | |
326 | /// | |
327 | /// If the operation succeeds immediately, `Ok(Some(n))` is returned where | |
328 | /// `n` is the number of bytes written. If an asynchronous operation is | |
329 | /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred | |
330 | /// it is returned. | |
331 | /// | |
332 | /// When this operation completes (or if it completes immediately), another | |
333 | /// mechanism must be used to learn how many bytes were transferred (such as | |
334 | /// looking at the filed in the IOCP status message). | |
335 | /// | |
336 | /// # Unsafety | |
337 | /// | |
338 | /// This function is unsafe because the kernel requires that the `buf` and | |
339 | /// `overlapped` pointers to be valid until the end of the I/O operation. | |
340 | /// The kernel also requires that `overlapped` is unique for this I/O | |
341 | /// operation and is not in use for any other I/O. | |
342 | /// | |
343 | /// To safely use this function callers must ensure that the pointers are | |
344 | /// valid until the I/O operation is completed, typically via completion | |
345 | /// ports and waiting to receive the completion notification on the port. | |
346 | pub unsafe fn write_overlapped( | |
347 | &self, | |
348 | buf: &[u8], | |
349 | overlapped: *mut OVERLAPPED, | |
350 | ) -> io::Result<Option<usize>> { | |
351 | self.0.write_overlapped(buf, overlapped) | |
352 | } | |
353 | ||
354 | /// Calls the `GetOverlappedResult` function to get the result of an | |
355 | /// overlapped operation for this handle. | |
356 | /// | |
357 | /// This function takes the `OVERLAPPED` argument which must have been used | |
358 | /// to initiate an overlapped I/O operation, and returns either the | |
359 | /// successful number of bytes transferred during the operation or an error | |
360 | /// if one occurred. | |
361 | /// | |
362 | /// # Unsafety | |
363 | /// | |
364 | /// This function is unsafe as `overlapped` must have previously been used | |
365 | /// to execute an operation for this handle, and it must also be a valid | |
366 | /// pointer to an `Overlapped` instance. | |
367 | /// | |
368 | /// # Panics | |
369 | /// | |
370 | /// This function will panic | |
371 | pub unsafe fn result(&self, overlapped: *mut OVERLAPPED) -> io::Result<usize> { | |
372 | let mut transferred = 0; | |
373 | let r = GetOverlappedResult(self.0.raw(), overlapped, &mut transferred, FALSE); | |
374 | if r == 0 { | |
375 | Err(io::Error::last_os_error()) | |
376 | } else { | |
377 | Ok(transferred as usize) | |
378 | } | |
379 | } | |
380 | } | |
381 | ||
382 | thread_local! { | |
383 | static NAMED_PIPE_OVERLAPPED: RefCell<Option<Overlapped>> = RefCell::new(None); | |
384 | } | |
385 | ||
386 | /// Call a function with a threadlocal `Overlapped`. The function `f` should be | |
387 | /// sure that the event is reset, either manually or by a thread being released. | |
388 | fn with_threadlocal_overlapped<F>(f: F) -> io::Result<usize> | |
389 | where | |
390 | F: FnOnce(&Overlapped) -> io::Result<usize>, | |
391 | { | |
392 | NAMED_PIPE_OVERLAPPED.with(|overlapped| { | |
393 | let mut mborrow = overlapped.borrow_mut(); | |
394 | if let None = *mborrow { | |
395 | let op = Overlapped::initialize_with_autoreset_event()?; | |
396 | *mborrow = Some(op); | |
397 | } | |
398 | f(mborrow.as_ref().unwrap()) | |
399 | }) | |
400 | } | |
401 | ||
402 | impl Read for NamedPipe { | |
403 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
404 | // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. | |
405 | with_threadlocal_overlapped(|overlapped| unsafe { | |
406 | self.0 | |
407 | .read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) | |
408 | }) | |
409 | } | |
410 | } | |
411 | impl<'a> Read for &'a NamedPipe { | |
412 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
413 | // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. | |
414 | with_threadlocal_overlapped(|overlapped| unsafe { | |
415 | self.0 | |
416 | .read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) | |
417 | }) | |
418 | } | |
419 | } | |
420 | ||
421 | impl Write for NamedPipe { | |
422 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
423 | // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. | |
424 | with_threadlocal_overlapped(|overlapped| unsafe { | |
425 | self.0 | |
426 | .write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) | |
427 | }) | |
428 | } | |
429 | fn flush(&mut self) -> io::Result<()> { | |
430 | <&NamedPipe as Write>::flush(&mut &*self) | |
431 | } | |
432 | } | |
433 | impl<'a> Write for &'a NamedPipe { | |
434 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
435 | // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. | |
436 | with_threadlocal_overlapped(|overlapped| unsafe { | |
437 | self.0 | |
438 | .write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) | |
439 | }) | |
440 | } | |
441 | fn flush(&mut self) -> io::Result<()> { | |
442 | crate::cvt(unsafe { FlushFileBuffers(self.0.raw()) }).map(|_| ()) | |
443 | } | |
444 | } | |
445 | ||
446 | impl AsRawHandle for NamedPipe { | |
447 | fn as_raw_handle(&self) -> RawHandle { | |
448 | self.0.raw() as RawHandle | |
449 | } | |
450 | } | |
451 | impl FromRawHandle for NamedPipe { | |
452 | unsafe fn from_raw_handle(handle: RawHandle) -> NamedPipe { | |
453 | NamedPipe(Handle::new(handle as HANDLE)) | |
454 | } | |
455 | } | |
456 | impl IntoRawHandle for NamedPipe { | |
457 | fn into_raw_handle(self) -> RawHandle { | |
458 | self.0.into_raw() as RawHandle | |
459 | } | |
460 | } | |
461 | ||
462 | fn flag(slot: &mut u32, on: bool, val: u32) { | |
463 | if on { | |
464 | *slot |= val; | |
465 | } else { | |
466 | *slot &= !val; | |
467 | } | |
468 | } | |
469 | ||
470 | impl NamedPipeBuilder { | |
471 | /// Creates a new named pipe builder with the default settings. | |
472 | pub fn new<A: AsRef<OsStr>>(addr: A) -> NamedPipeBuilder { | |
473 | NamedPipeBuilder { | |
474 | name: addr.as_ref().encode_wide().chain(Some(0)).collect(), | |
475 | dwOpenMode: PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, | |
476 | dwPipeMode: PIPE_TYPE_BYTE, | |
477 | nMaxInstances: PIPE_UNLIMITED_INSTANCES, | |
478 | nOutBufferSize: 65536, | |
479 | nInBufferSize: 65536, | |
480 | nDefaultTimeOut: 0, | |
481 | } | |
482 | } | |
483 | ||
484 | /// Indicates whether data is allowed to flow from the client to the server. | |
485 | pub fn inbound(&mut self, allowed: bool) -> &mut Self { | |
486 | flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_INBOUND); | |
487 | self | |
488 | } | |
489 | ||
490 | /// Indicates whether data is allowed to flow from the server to the client. | |
491 | pub fn outbound(&mut self, allowed: bool) -> &mut Self { | |
492 | flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_OUTBOUND); | |
493 | self | |
494 | } | |
495 | ||
496 | /// Indicates that this pipe must be the first instance. | |
497 | /// | |
498 | /// If set to true, then creation will fail if there's already an instance | |
499 | /// elsewhere. | |
500 | pub fn first(&mut self, first: bool) -> &mut Self { | |
501 | flag(&mut self.dwOpenMode, first, FILE_FLAG_FIRST_PIPE_INSTANCE); | |
502 | self | |
503 | } | |
504 | ||
505 | /// Indicates whether this server can accept remote clients or not. | |
506 | pub fn accept_remote(&mut self, accept: bool) -> &mut Self { | |
507 | flag(&mut self.dwPipeMode, !accept, PIPE_REJECT_REMOTE_CLIENTS); | |
508 | self | |
509 | } | |
510 | ||
511 | /// Specifies the maximum number of instances of the server pipe that are | |
512 | /// allowed. | |
513 | /// | |
514 | /// The first instance of a pipe can specify this value. A value of 255 | |
515 | /// indicates that there is no limit to the number of instances. | |
516 | pub fn max_instances(&mut self, instances: u8) -> &mut Self { | |
517 | self.nMaxInstances = instances as u32; | |
518 | self | |
519 | } | |
520 | ||
521 | /// Specifies the number of bytes to reserver for the output buffer | |
522 | pub fn out_buffer_size(&mut self, buffer: u32) -> &mut Self { | |
523 | self.nOutBufferSize = buffer as u32; | |
524 | self | |
525 | } | |
526 | ||
527 | /// Specifies the number of bytes to reserver for the input buffer | |
528 | pub fn in_buffer_size(&mut self, buffer: u32) -> &mut Self { | |
529 | self.nInBufferSize = buffer as u32; | |
530 | self | |
531 | } | |
532 | ||
533 | /// Using the options in this builder, attempt to create a new named pipe. | |
534 | /// | |
535 | /// This function will call the `CreateNamedPipe` function and return the | |
536 | /// result. | |
537 | pub fn create(&mut self) -> io::Result<NamedPipe> { | |
538 | unsafe { self.with_security_attributes(::std::ptr::null_mut()) } | |
539 | } | |
540 | ||
541 | /// Using the options in the builder and the provided security attributes, attempt to create a | |
542 | /// new named pipe. This function has to be called with a valid pointer to a | |
543 | /// `SECURITY_ATTRIBUTES` struct that will stay valid for the lifetime of this function or a | |
544 | /// null pointer. | |
545 | /// | |
546 | /// This function will call the `CreateNamedPipe` function and return the | |
547 | /// result. | |
548 | pub unsafe fn with_security_attributes( | |
549 | &mut self, | |
550 | attrs: *mut SECURITY_ATTRIBUTES, | |
551 | ) -> io::Result<NamedPipe> { | |
552 | let h = CreateNamedPipeW( | |
553 | self.name.as_mut_ptr(), | |
554 | self.dwOpenMode, | |
555 | self.dwPipeMode, | |
556 | self.nMaxInstances, | |
557 | self.nOutBufferSize, | |
558 | self.nInBufferSize, | |
559 | self.nDefaultTimeOut, | |
560 | attrs, | |
561 | ); | |
562 | ||
563 | if h == INVALID_HANDLE_VALUE { | |
564 | Err(io::Error::last_os_error()) | |
565 | } else { | |
566 | Ok(NamedPipe(Handle::new(h))) | |
567 | } | |
568 | } | |
569 | } | |
570 | ||
571 | #[cfg(test)] | |
572 | mod tests { | |
573 | use std::fs::{File, OpenOptions}; | |
574 | use std::io::prelude::*; | |
575 | use std::sync::mpsc::channel; | |
576 | use std::thread; | |
577 | use std::time::Duration; | |
578 | ||
579 | use rand::{distributions::Alphanumeric, thread_rng, Rng}; | |
580 | ||
581 | use super::{anonymous, NamedPipe, NamedPipeBuilder}; | |
582 | use crate::iocp::CompletionPort; | |
583 | use crate::Overlapped; | |
584 | ||
585 | fn name() -> String { | |
586 | let name = thread_rng() | |
587 | .sample_iter(Alphanumeric) | |
588 | .take(30) | |
589 | .map(char::from) | |
590 | .collect::<String>(); | |
591 | format!(r"\\.\pipe\{}", name) | |
592 | } | |
593 | ||
594 | #[test] | |
595 | fn anon() { | |
596 | let (mut read, mut write) = t!(anonymous(256)); | |
597 | assert_eq!(t!(write.write(&[1, 2, 3])), 3); | |
598 | let mut b = [0; 10]; | |
599 | assert_eq!(t!(read.read(&mut b)), 3); | |
600 | assert_eq!(&b[..3], &[1, 2, 3]); | |
601 | } | |
602 | ||
603 | #[test] | |
604 | fn named_not_first() { | |
605 | let name = name(); | |
606 | let _a = t!(NamedPipe::new(&name)); | |
607 | assert!(NamedPipe::new(&name).is_err()); | |
608 | ||
609 | t!(NamedPipeBuilder::new(&name).first(false).create()); | |
610 | } | |
611 | ||
612 | #[test] | |
613 | fn named_connect() { | |
614 | let name = name(); | |
615 | let a = t!(NamedPipe::new(&name)); | |
616 | ||
617 | let t = thread::spawn(move || { | |
618 | t!(File::open(name)); | |
619 | }); | |
620 | ||
621 | t!(a.connect()); | |
622 | t!(a.disconnect()); | |
623 | t!(t.join()); | |
624 | } | |
625 | ||
626 | #[test] | |
627 | fn named_wait() { | |
628 | let name = name(); | |
629 | let a = t!(NamedPipe::new(&name)); | |
630 | ||
631 | let (tx, rx) = channel(); | |
632 | let t = thread::spawn(move || { | |
633 | t!(NamedPipe::wait(&name, None)); | |
634 | t!(File::open(&name)); | |
635 | assert!(NamedPipe::wait(&name, Some(Duration::from_millis(1))).is_err()); | |
636 | t!(tx.send(())); | |
637 | }); | |
638 | ||
639 | t!(a.connect()); | |
640 | t!(rx.recv()); | |
641 | t!(a.disconnect()); | |
642 | t!(t.join()); | |
643 | } | |
644 | ||
645 | #[test] | |
646 | fn named_connect_overlapped() { | |
647 | let name = name(); | |
648 | let a = t!(NamedPipe::new(&name)); | |
649 | ||
650 | let t = thread::spawn(move || { | |
651 | t!(File::open(name)); | |
652 | }); | |
653 | ||
654 | let cp = t!(CompletionPort::new(1)); | |
655 | t!(cp.add_handle(2, &a)); | |
656 | ||
657 | let over = Overlapped::zero(); | |
658 | unsafe { | |
659 | t!(a.connect_overlapped(over.raw())); | |
660 | } | |
661 | ||
662 | let status = t!(cp.get(None)); | |
663 | assert_eq!(status.bytes_transferred(), 0); | |
664 | assert_eq!(status.token(), 2); | |
665 | assert_eq!(status.overlapped(), over.raw()); | |
666 | t!(t.join()); | |
667 | } | |
668 | ||
669 | #[test] | |
670 | fn named_read_write() { | |
671 | let name = name(); | |
672 | let mut a = t!(NamedPipe::new(&name)); | |
673 | ||
674 | let t = thread::spawn(move || { | |
675 | let mut f = t!(OpenOptions::new().read(true).write(true).open(name)); | |
676 | t!(f.write_all(&[1, 2, 3])); | |
677 | let mut b = [0; 10]; | |
678 | assert_eq!(t!(f.read(&mut b)), 3); | |
679 | assert_eq!(&b[..3], &[1, 2, 3]); | |
680 | }); | |
681 | ||
682 | t!(a.connect()); | |
683 | let mut b = [0; 10]; | |
684 | assert_eq!(t!(a.read(&mut b)), 3); | |
685 | assert_eq!(&b[..3], &[1, 2, 3]); | |
686 | t!(a.write_all(&[1, 2, 3])); | |
687 | t!(a.flush()); | |
688 | t!(a.disconnect()); | |
689 | t!(t.join()); | |
690 | } | |
691 | ||
692 | #[test] | |
693 | fn named_read_write_multi() { | |
694 | for _ in 0..5 { | |
695 | named_read_write() | |
696 | } | |
697 | } | |
698 | ||
699 | #[test] | |
700 | fn named_read_write_multi_same_thread() { | |
701 | let name1 = name(); | |
702 | let mut a1 = t!(NamedPipe::new(&name1)); | |
703 | let name2 = name(); | |
704 | let mut a2 = t!(NamedPipe::new(&name2)); | |
705 | ||
706 | let t = thread::spawn(move || { | |
707 | let mut f = t!(OpenOptions::new().read(true).write(true).open(name1)); | |
708 | t!(f.write_all(&[1, 2, 3])); | |
709 | let mut b = [0; 10]; | |
710 | assert_eq!(t!(f.read(&mut b)), 3); | |
711 | assert_eq!(&b[..3], &[1, 2, 3]); | |
712 | ||
713 | let mut f = t!(OpenOptions::new().read(true).write(true).open(name2)); | |
714 | t!(f.write_all(&[1, 2, 3])); | |
715 | let mut b = [0; 10]; | |
716 | assert_eq!(t!(f.read(&mut b)), 3); | |
717 | assert_eq!(&b[..3], &[1, 2, 3]); | |
718 | }); | |
719 | ||
720 | t!(a1.connect()); | |
721 | let mut b = [0; 10]; | |
722 | assert_eq!(t!(a1.read(&mut b)), 3); | |
723 | assert_eq!(&b[..3], &[1, 2, 3]); | |
724 | t!(a1.write_all(&[1, 2, 3])); | |
725 | t!(a1.flush()); | |
726 | t!(a1.disconnect()); | |
727 | ||
728 | t!(a2.connect()); | |
729 | let mut b = [0; 10]; | |
730 | assert_eq!(t!(a2.read(&mut b)), 3); | |
731 | assert_eq!(&b[..3], &[1, 2, 3]); | |
732 | t!(a2.write_all(&[1, 2, 3])); | |
733 | t!(a2.flush()); | |
734 | t!(a2.disconnect()); | |
735 | ||
736 | t!(t.join()); | |
737 | } | |
738 | ||
739 | #[test] | |
740 | fn named_read_overlapped() { | |
741 | let name = name(); | |
742 | let a = t!(NamedPipe::new(&name)); | |
743 | ||
744 | let t = thread::spawn(move || { | |
745 | let mut f = t!(File::create(name)); | |
746 | t!(f.write_all(&[1, 2, 3])); | |
747 | }); | |
748 | ||
749 | let cp = t!(CompletionPort::new(1)); | |
750 | t!(cp.add_handle(3, &a)); | |
751 | t!(a.connect()); | |
752 | ||
753 | let mut b = [0; 10]; | |
754 | let over = Overlapped::zero(); | |
755 | unsafe { | |
756 | t!(a.read_overlapped(&mut b, over.raw())); | |
757 | } | |
758 | let status = t!(cp.get(None)); | |
759 | assert_eq!(status.bytes_transferred(), 3); | |
760 | assert_eq!(status.token(), 3); | |
761 | assert_eq!(status.overlapped(), over.raw()); | |
762 | assert_eq!(&b[..3], &[1, 2, 3]); | |
763 | ||
764 | t!(t.join()); | |
765 | } | |
766 | ||
767 | #[test] | |
768 | fn named_write_overlapped() { | |
769 | let name = name(); | |
770 | let a = t!(NamedPipe::new(&name)); | |
771 | ||
772 | let t = thread::spawn(move || { | |
773 | let mut f = t!(super::connect(name)); | |
774 | let mut b = [0; 10]; | |
775 | assert_eq!(t!(f.read(&mut b)), 3); | |
776 | assert_eq!(&b[..3], &[1, 2, 3]) | |
777 | }); | |
778 | ||
779 | let cp = t!(CompletionPort::new(1)); | |
780 | t!(cp.add_handle(3, &a)); | |
781 | t!(a.connect()); | |
782 | ||
783 | let over = Overlapped::zero(); | |
784 | unsafe { | |
785 | t!(a.write_overlapped(&[1, 2, 3], over.raw())); | |
786 | } | |
787 | ||
788 | let status = t!(cp.get(None)); | |
789 | assert_eq!(status.bytes_transferred(), 3); | |
790 | assert_eq!(status.token(), 3); | |
791 | assert_eq!(status.overlapped(), over.raw()); | |
792 | ||
793 | t!(t.join()); | |
794 | } | |
795 | } |