-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: provide NamedPipe{Client, Server} types and builders (#3760)
This builds on tokio-rs/mio#1351 and introduces the tokio::net::windows::named_pipe module which provides low level types for building and communicating asynchronously over windows named pipes. Named pipes require the `net` feature flag to be enabled on Windows. Co-authored-by: Alice Ryhl <alice@ryhl.io>
- Loading branch information
Showing
13 changed files
with
1,740 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use std::io; | ||
|
||
#[cfg(windows)] | ||
async fn windows_main() -> io::Result<()> { | ||
use std::time::Duration; | ||
use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions}; | ||
use tokio::time; | ||
use winapi::shared::winerror; | ||
|
||
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-multi-client"; | ||
const N: usize = 10; | ||
|
||
// The first server needs to be constructed early so that clients can | ||
// be correctly connected. Otherwise a waiting client will error. | ||
// | ||
// Here we also make use of `first_pipe_instance`, which will ensure | ||
// that there are no other servers up and running already. | ||
let mut server = ServerOptions::new() | ||
.first_pipe_instance(true) | ||
.create(PIPE_NAME)?; | ||
|
||
let server = tokio::spawn(async move { | ||
// Artificial workload. | ||
time::sleep(Duration::from_secs(1)).await; | ||
|
||
for _ in 0..N { | ||
// Wait for client to connect. | ||
server.connect().await?; | ||
let mut inner = server; | ||
|
||
// Construct the next server to be connected before sending the one | ||
// we already have of onto a task. This ensures that the server | ||
// isn't closed (after it's done in the task) before a new one is | ||
// available. Otherwise the client might error with | ||
// `io::ErrorKind::NotFound`. | ||
server = ServerOptions::new().create(PIPE_NAME)?; | ||
|
||
let _ = tokio::spawn(async move { | ||
let mut buf = vec![0u8; 4]; | ||
inner.read_exact(&mut buf).await?; | ||
inner.write_all(b"pong").await?; | ||
Ok::<_, io::Error>(()) | ||
}); | ||
} | ||
|
||
Ok::<_, io::Error>(()) | ||
}); | ||
|
||
let mut clients = Vec::new(); | ||
|
||
for _ in 0..N { | ||
clients.push(tokio::spawn(async move { | ||
// This showcases a generic connect loop. | ||
// | ||
// We immediately try to create a client, if it's not found or | ||
// the pipe is busy we use the specialized wait function on the | ||
// client builder. | ||
let mut client = loop { | ||
match ClientOptions::new().open(PIPE_NAME) { | ||
Ok(client) => break client, | ||
Err(e) if e.raw_os_error() == Some(winerror::ERROR_PIPE_BUSY as i32) => (), | ||
Err(e) => return Err(e), | ||
} | ||
|
||
time::sleep(Duration::from_millis(5)).await; | ||
}; | ||
|
||
let mut buf = [0u8; 4]; | ||
client.write_all(b"ping").await?; | ||
client.read_exact(&mut buf).await?; | ||
Ok::<_, io::Error>(buf) | ||
})); | ||
} | ||
|
||
for client in clients { | ||
let result = client.await?; | ||
assert_eq!(&result?[..], b"pong"); | ||
} | ||
|
||
server.await??; | ||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> io::Result<()> { | ||
#[cfg(windows)] | ||
{ | ||
windows_main().await?; | ||
} | ||
|
||
#[cfg(not(windows))] | ||
{ | ||
println!("Named pipes are only supported on Windows!"); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use std::io; | ||
|
||
#[cfg(windows)] | ||
async fn windows_main() -> io::Result<()> { | ||
use tokio::io::AsyncWriteExt; | ||
use tokio::io::{AsyncBufReadExt, BufReader}; | ||
use tokio::net::windows::named_pipe::{ClientOptions, ServerOptions}; | ||
|
||
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-single-client"; | ||
|
||
let server = ServerOptions::new().create(PIPE_NAME)?; | ||
|
||
let server = tokio::spawn(async move { | ||
// Note: we wait for a client to connect. | ||
server.connect().await?; | ||
|
||
let mut server = BufReader::new(server); | ||
|
||
let mut buf = String::new(); | ||
server.read_line(&mut buf).await?; | ||
server.write_all(b"pong\n").await?; | ||
Ok::<_, io::Error>(buf) | ||
}); | ||
|
||
let client = tokio::spawn(async move { | ||
// There's no need to use a connect loop here, since we know that the | ||
// server is already up - `open` was called before spawning any of the | ||
// tasks. | ||
let client = ClientOptions::new().open(PIPE_NAME)?; | ||
|
||
let mut client = BufReader::new(client); | ||
|
||
let mut buf = String::new(); | ||
client.write_all(b"ping\n").await?; | ||
client.read_line(&mut buf).await?; | ||
Ok::<_, io::Error>(buf) | ||
}); | ||
|
||
let (server, client) = tokio::try_join!(server, client)?; | ||
|
||
assert_eq!(server?, "ping\n"); | ||
assert_eq!(client?, "pong\n"); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> io::Result<()> { | ||
#[cfg(windows)] | ||
{ | ||
windows_main().await?; | ||
} | ||
|
||
#[cfg(not(windows))] | ||
{ | ||
println!("Named pipes are only supported on Windows!"); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
//! Types which are documented locally in the Tokio crate, but does not actually | ||
//! live here. | ||
//! | ||
//! **Note** this module is only visible on docs.rs, you cannot use it directly | ||
//! in your own code. | ||
/// The name of a type which is not defined here. | ||
/// | ||
/// This is typically used as an alias for another type, like so: | ||
/// | ||
/// ```rust,ignore | ||
/// /// See [some::other::location](https://example.com). | ||
/// type DEFINED_ELSEWHERE = crate::doc::NotDefinedHere; | ||
/// ``` | ||
/// | ||
/// This type is uninhabitable like the [`never` type] to ensure that no one | ||
/// will ever accidentally use it. | ||
/// | ||
/// [`never` type]: https://doc.rust-lang.org/std/primitive.never.html | ||
pub enum NotDefinedHere {} | ||
|
||
pub mod os; | ||
pub mod winapi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//! See [std::os](https://doc.rust-lang.org/std/os/index.html). | ||
/// Platform-specific extensions to `std` for Windows. | ||
/// | ||
/// See [std::os::windows](https://doc.rust-lang.org/std/os/windows/index.html). | ||
pub mod windows { | ||
/// Windows-specific extensions to general I/O primitives. | ||
/// | ||
/// See [std::os::windows::io](https://doc.rust-lang.org/std/os/windows/io/index.html). | ||
pub mod io { | ||
/// See [std::os::windows::io::RawHandle](https://doc.rust-lang.org/std/os/windows/io/type.RawHandle.html) | ||
pub type RawHandle = crate::doc::NotDefinedHere; | ||
|
||
/// See [std::os::windows::io::AsRawHandle](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html) | ||
pub trait AsRawHandle { | ||
/// See [std::os::windows::io::FromRawHandle::from_raw_handle](https://doc.rust-lang.org/std/os/windows/io/trait.AsRawHandle.html#tymethod.as_raw_handle) | ||
fn as_raw_handle(&self) -> RawHandle; | ||
} | ||
|
||
/// See [std::os::windows::io::FromRawHandle](https://doc.rust-lang.org/std/os/windows/io/trait.FromRawHandle.html) | ||
pub trait FromRawHandle { | ||
/// See [std::os::windows::io::FromRawHandle::from_raw_handle](https://doc.rust-lang.org/std/os/windows/io/trait.FromRawHandle.html#tymethod.from_raw_handle) | ||
unsafe fn from_raw_handle(handle: RawHandle) -> Self; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
//! See [winapi]. | ||
//! | ||
//! [winapi]: https://docs.rs/winapi | ||
/// See [winapi::shared](https://docs.rs/winapi/*/winapi/shared/index.html). | ||
pub mod shared { | ||
/// See [winapi::shared::winerror](https://docs.rs/winapi/*/winapi/shared/winerror/index.html). | ||
#[allow(non_camel_case_types)] | ||
pub mod winerror { | ||
/// See [winapi::shared::winerror::ERROR_ACCESS_DENIED][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/shared/winerror/constant.ERROR_ACCESS_DENIED.html | ||
pub type ERROR_ACCESS_DENIED = crate::doc::NotDefinedHere; | ||
|
||
/// See [winapi::shared::winerror::ERROR_PIPE_BUSY][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/shared/winerror/constant.ERROR_PIPE_BUSY.html | ||
pub type ERROR_PIPE_BUSY = crate::doc::NotDefinedHere; | ||
|
||
/// See [winapi::shared::winerror::ERROR_MORE_DATA][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/shared/winerror/constant.ERROR_MORE_DATA.html | ||
pub type ERROR_MORE_DATA = crate::doc::NotDefinedHere; | ||
} | ||
} | ||
|
||
/// See [winapi::um](https://docs.rs/winapi/*/winapi/um/index.html). | ||
pub mod um { | ||
/// See [winapi::um::winbase](https://docs.rs/winapi/*/winapi/um/winbase/index.html). | ||
#[allow(non_camel_case_types)] | ||
pub mod winbase { | ||
/// See [winapi::um::winbase::PIPE_TYPE_MESSAGE][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/um/winbase/constant.PIPE_TYPE_MESSAGE.html | ||
pub type PIPE_TYPE_MESSAGE = crate::doc::NotDefinedHere; | ||
|
||
/// See [winapi::um::winbase::PIPE_TYPE_BYTE][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/um/winbase/constant.PIPE_TYPE_BYTE.html | ||
pub type PIPE_TYPE_BYTE = crate::doc::NotDefinedHere; | ||
|
||
/// See [winapi::um::winbase::PIPE_CLIENT_END][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/um/winbase/constant.PIPE_CLIENT_END.html | ||
pub type PIPE_CLIENT_END = crate::doc::NotDefinedHere; | ||
|
||
/// See [winapi::um::winbase::PIPE_SERVER_END][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/um/winbase/constant.PIPE_SERVER_END.html | ||
pub type PIPE_SERVER_END = crate::doc::NotDefinedHere; | ||
|
||
/// See [winapi::um::winbase::SECURITY_IDENTIFICATION][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/um/winbase/constant.SECURITY_IDENTIFICATION.html | ||
pub type SECURITY_IDENTIFICATION = crate::doc::NotDefinedHere; | ||
} | ||
|
||
/// See [winapi::um::minwinbase](https://docs.rs/winapi/*/winapi/um/minwinbase/index.html). | ||
#[allow(non_camel_case_types)] | ||
pub mod minwinbase { | ||
/// See [winapi::um::minwinbase::SECURITY_ATTRIBUTES][winapi] | ||
/// | ||
/// [winapi]: https://docs.rs/winapi/*/winapi/um/minwinbase/constant.SECURITY_ATTRIBUTES.html | ||
pub type SECURITY_ATTRIBUTES = crate::doc::NotDefinedHere; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
//! Windows specific network types. | ||
pub mod named_pipe; |
Oops, something went wrong.