interprocess_docfix/os/windows/named_pipe/mod.rs
1//! Support for named pipes on Windows.
2//!
3//! ## Windows named pipes are not Unix named pipes
4//! The term "named pipe" refers to completely different things in Unix and Windows. For this reason, Unix named pipes are referred to as "FIFO files" to avoid confusion with the more powerful Windows named pipes. In fact, the only common features for those two is that they both can be located using filesystem paths and they both use a stream interface. The differences can be summed up like this:
5//! - Windows named pipes are located on a separate filesystem (NPFS – **N**amed **P**ipe **F**ile**s**ystem), while Unix FIFO files live in the shared filesystem tree together with all other files
6//! - On Linux, the implementation of Unix domain sockets exposes a similar feature: by setting the first byte in the socket file path to `NULL` (`\0`), the socket is placed into a separate namespace instead of being placed on the filesystem; this is a non-standard extension to POSIX and is not available on other Unix systems
7//! - Windows named pipes have a server and an arbitrary number of clients, meaning that the separate processes connecting to a named pipe have separate connections to the server, while Unix FIFO files don't have the notion of a server or client and thus mix all data written into one sink from which the data is read by one process
8//! - Windows named pipes can be used over the network, while a Unix FIFO file is still local even if created in a directory which is a mounted network filesystem
9//! - Windows named pipes can maintain datagram boundaries, allowing both sides of the connection to operate on separate messages rather than on a byte stream, while FIFO files, like any other type of file, expose only a byte stream interface
10//!
11//! If you carefully read through this list, you'd notice how Windows named pipes are similar to Unix domain sockets. For this reason, the implementation of "local sockets" in the `local_socket` module of this crate uses named pipes on Windows and Ud-sockets on Unix.
12
13// TODO improve docs
14// TODO add examples
15// TODO get rid of the dumbass autoflush, literally no reason for me to have added it now that i
16// actually write proper examples for this
17// FIXME message streams should have methods instead of I/O traits
18
19mod enums;
20mod listener;
21mod pipeops;
22#[macro_use]
23mod stream;
24pub use enums::*;
25pub use listener::*;
26pub use stream::*;
27
28#[cfg(any(doc, feature = "tokio_support"))]
29#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "tokio_support")))]
30#[cfg_attr(not(feature = "tokio_support"), allow(unused_imports))]
31pub mod tokio;
32
33use pipeops::*;
34use {
35 super::imports::*,
36 std::{
37 ffi::{OsStr, OsString},
38 io, ptr,
39 },
40};
41
42fn convert_path(pipe_name: &OsStr, hostname: Option<&OsStr>) -> Vec<u16> {
43 static PREFIX_LITERAL: &str = r"\\";
44 static PIPEFS_LITERAL: &str = r"\pipe\";
45
46 let hostname = hostname.unwrap_or_else(|| OsStr::new("."));
47
48 let mut path = OsString::with_capacity(
49 PREFIX_LITERAL.len() + hostname.len() + PIPEFS_LITERAL.len() + pipe_name.len(),
50 );
51 path.push(PREFIX_LITERAL);
52 path.push(hostname);
53 path.push(PIPEFS_LITERAL);
54 path.push(pipe_name);
55
56 let mut path = path.encode_wide().collect::<Vec<u16>>();
57 path.push(0); // encode_wide does not include the terminating NULL, so we have to add it ourselves
58 path
59}
60#[cfg(windows)]
61unsafe fn set_nonblocking_for_stream(
62 handle: HANDLE,
63 read_mode: Option<PipeMode>,
64 nonblocking: bool,
65) -> io::Result<()> {
66 let read_mode: u32 = read_mode.map_or(0, PipeMode::to_readmode);
67 // Bitcast the boolean without additional transformations since
68 // the flag is in the first bit.
69 let mut mode: u32 = read_mode | nonblocking as u32;
70 let success = unsafe {
71 SetNamedPipeHandleState(
72 handle,
73 &mut mode as *mut _,
74 ptr::null_mut(),
75 ptr::null_mut(),
76 )
77 } != 0;
78 if success {
79 Ok(())
80 } else {
81 Err(io::Error::last_os_error())
82 }
83}