new namedpipe
This commit is contained in:
parent
2d515815ed
commit
6f796db523
@ -1,4 +1,4 @@
|
|||||||
use tokio::{self, prelude::*};
|
use tokio::{self, io::*};
|
||||||
use parity_tokio_ipc::Endpoint;
|
use parity_tokio_ipc::Endpoint;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -19,6 +19,6 @@ async fn main() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::time::delay_for(std::time::Duration::from_secs(2)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use futures::StreamExt as _;
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
prelude::*,
|
io::*,
|
||||||
self,
|
self,
|
||||||
io::split,
|
io::split,
|
||||||
};
|
};
|
||||||
|
@ -31,9 +31,9 @@ mod unix;
|
|||||||
/// }
|
/// }
|
||||||
///```
|
///```
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub use win::{SecurityAttributes, Endpoint, Connection, Incoming};
|
pub use win::{SecurityAttributes, Endpoint, Connection, ConnectionClient, Incoming};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub use unix::{SecurityAttributes, Endpoint, Connection, Incoming};
|
pub use unix::{SecurityAttributes, Endpoint, Connection, ConnectionClient, Incoming};
|
||||||
|
|
||||||
/// For testing/examples
|
/// For testing/examples
|
||||||
pub fn dummy_endpoint() -> String {
|
pub fn dummy_endpoint() -> String {
|
||||||
@ -47,13 +47,14 @@ pub fn dummy_endpoint() -> String {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use tokio::prelude::*;
|
use futures::{channel::oneshot, FutureExt as _};
|
||||||
use futures::{channel::oneshot, StreamExt as _, FutureExt as _};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
self,
|
self,
|
||||||
io::split,
|
io::split,
|
||||||
};
|
};
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
use super::{dummy_endpoint, Endpoint, SecurityAttributes};
|
use super::{dummy_endpoint, Endpoint, SecurityAttributes};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -100,12 +101,12 @@ mod tests {
|
|||||||
});
|
});
|
||||||
tokio::spawn(server);
|
tokio::spawn(server);
|
||||||
|
|
||||||
tokio::time::delay_for(Duration::from_secs(2)).await;
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
|
|
||||||
println!("Connecting to client 0...");
|
println!("Connecting to client 0...");
|
||||||
let mut client_0 = Endpoint::connect(&path).await
|
let mut client_0 = Endpoint::connect(&path).await
|
||||||
.expect("failed to open client_0");
|
.expect("failed to open client_0");
|
||||||
tokio::time::delay_for(Duration::from_secs(2)).await;
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
println!("Connecting to client 1...");
|
println!("Connecting to client 1...");
|
||||||
let mut client_1 = Endpoint::connect(&path).await
|
let mut client_1 = Endpoint::connect(&path).await
|
||||||
.expect("failed to open client_1");
|
.expect("failed to open client_1");
|
||||||
@ -125,7 +126,7 @@ mod tests {
|
|||||||
// shutdown server
|
// shutdown server
|
||||||
if let Ok(()) = shutdown_tx.send(()) {
|
if let Ok(()) = shutdown_tx.send(()) {
|
||||||
// wait one second for the file to be deleted.
|
// wait one second for the file to be deleted.
|
||||||
tokio::time::delay_for(Duration::from_secs(1)).await;
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
let path = Path::new(&path);
|
let path = Path::new(&path);
|
||||||
// assert that it has
|
// assert that it has
|
||||||
assert!(!path.exists());
|
assert!(!path.exists());
|
||||||
|
@ -156,3 +156,5 @@ impl AsyncWrite for Connection {
|
|||||||
Pin::new(&mut this.inner).poll_shutdown(ctx)
|
Pin::new(&mut this.inner).poll_shutdown(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ConnectionClient = Connection;
|
||||||
|
@ -9,17 +9,12 @@ use winapi::um::winnt::*;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::marker;
|
use std::marker;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
|
||||||
use futures::Stream;
|
|
||||||
use tokio::prelude::*;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tokio::io::PollEvented;
|
use std::ptr;
|
||||||
|
use tokio::net::windows::named_pipe::*;
|
||||||
|
|
||||||
type NamedPipe = PollEvented<mio_named_pipes::NamedPipe>;
|
pub type ConnectionClient = NamedPipeClient;
|
||||||
|
pub type Connection = NamedPipeServer;
|
||||||
const PIPE_AVAILABILITY_TIMEOUT: u64 = 5000;
|
|
||||||
|
|
||||||
/// Endpoint implementation for windows
|
/// Endpoint implementation for windows
|
||||||
pub struct Endpoint {
|
pub struct Endpoint {
|
||||||
@ -27,6 +22,18 @@ pub struct Endpoint {
|
|||||||
security_attributes: SecurityAttributes,
|
security_attributes: SecurityAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_server(path: &str, first: bool, attr: *mut libc::c_void) -> io::Result<NamedPipeServer> {
|
||||||
|
unsafe {
|
||||||
|
ServerOptions::new()
|
||||||
|
.access_inbound(true)
|
||||||
|
.access_outbound(true)
|
||||||
|
.out_buffer_size(65536)
|
||||||
|
.in_buffer_size(65536)
|
||||||
|
.first_pipe_instance(first)
|
||||||
|
.create_with_security_attributes_raw(path, attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
/// Stream of incoming connections
|
/// Stream of incoming connections
|
||||||
pub fn incoming(mut self) -> io::Result<Incoming> {
|
pub fn incoming(mut self) -> io::Result<Incoming> {
|
||||||
@ -42,23 +49,8 @@ impl Endpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Inner platform-dependant state of the endpoint
|
/// Inner platform-dependant state of the endpoint
|
||||||
fn inner(&mut self) -> io::Result<NamedPipe> {
|
fn inner(&mut self) -> io::Result<NamedPipeServer> {
|
||||||
use miow::pipe::NamedPipeBuilder;
|
unsafe { create_server(&self.path, true, self.security_attributes.as_ptr() as _) }
|
||||||
use std::os::windows::io::*;
|
|
||||||
|
|
||||||
let raw_handle = unsafe {
|
|
||||||
NamedPipeBuilder::new(&self.path)
|
|
||||||
.first(true)
|
|
||||||
.inbound(true)
|
|
||||||
.outbound(true)
|
|
||||||
.out_buffer_size(65536)
|
|
||||||
.in_buffer_size(65536)
|
|
||||||
.with_security_attributes(self.security_attributes.as_ptr())?
|
|
||||||
.into_raw_handle()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mio_pipe = unsafe { mio_named_pipes::NamedPipe::from_raw_handle(raw_handle) };
|
|
||||||
NamedPipe::new(mio_pipe)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set security attributes for the connection
|
/// Set security attributes for the connection
|
||||||
@ -72,30 +64,25 @@ impl Endpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make new connection using the provided path and running event pool.
|
/// Make new connection using the provided path and running event pool.
|
||||||
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Connection> {
|
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<ConnectionClient> {
|
||||||
Ok(Connection::wrap(Self::connect_inner(path.as_ref())?))
|
Self::connect_inner(path.as_ref()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_inner(path: &Path) -> io::Result<NamedPipe> {
|
async fn connect_inner(path: &Path) -> io::Result<NamedPipeClient> {
|
||||||
use std::fs::OpenOptions;
|
let client = loop {
|
||||||
use std::os::windows::fs::OpenOptionsExt;
|
match ClientOptions::new().read(true).write(true).open(path) {
|
||||||
use std::os::windows::io::{FromRawHandle, IntoRawHandle};
|
Ok(client) => break client,
|
||||||
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
Err(e)
|
||||||
|
if e.raw_os_error()
|
||||||
// Wait for the pipe to become available or fail after 5 seconds.
|
== Some(winapi::shared::winerror::ERROR_PIPE_BUSY as i32) =>
|
||||||
miow::pipe::NamedPipe::wait(
|
{
|
||||||
path,
|
()
|
||||||
Some(std::time::Duration::from_millis(PIPE_AVAILABILITY_TIMEOUT)),
|
}
|
||||||
)?;
|
Err(e) => return Err(e),
|
||||||
let file = OpenOptions::new()
|
}
|
||||||
.read(true)
|
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
|
||||||
.write(true)
|
};
|
||||||
.custom_flags(FILE_FLAG_OVERLAPPED)
|
Ok(client)
|
||||||
.open(path)?;
|
|
||||||
let mio_pipe =
|
|
||||||
unsafe { mio_named_pipes::NamedPipe::from_raw_handle(file.into_raw_handle()) };
|
|
||||||
let pipe = NamedPipe::new(mio_pipe)?;
|
|
||||||
Ok(pipe)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New IPC endpoint at the given path
|
/// New IPC endpoint at the given path
|
||||||
@ -109,31 +96,10 @@ impl Endpoint {
|
|||||||
|
|
||||||
struct NamedPipeSupport {
|
struct NamedPipeSupport {
|
||||||
path: String,
|
path: String,
|
||||||
pipe: NamedPipe,
|
pipe: NamedPipeServer,
|
||||||
security_attributes: SecurityAttributes,
|
security_attributes: SecurityAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NamedPipeSupport {
|
|
||||||
fn replacement_pipe(&mut self) -> io::Result<NamedPipe> {
|
|
||||||
use miow::pipe::NamedPipeBuilder;
|
|
||||||
use std::os::windows::io::*;
|
|
||||||
|
|
||||||
let raw_handle = unsafe {
|
|
||||||
NamedPipeBuilder::new(&self.path)
|
|
||||||
.first(false)
|
|
||||||
.inbound(true)
|
|
||||||
.outbound(true)
|
|
||||||
.out_buffer_size(65536)
|
|
||||||
.in_buffer_size(65536)
|
|
||||||
.with_security_attributes(self.security_attributes.as_ptr())?
|
|
||||||
.into_raw_handle()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mio_pipe = unsafe { mio_named_pipes::NamedPipe::from_raw_handle(raw_handle) };
|
|
||||||
NamedPipe::new(mio_pipe)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stream of incoming connections
|
/// Stream of incoming connections
|
||||||
pub struct Incoming {
|
pub struct Incoming {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -141,70 +107,20 @@ pub struct Incoming {
|
|||||||
inner: NamedPipeSupport,
|
inner: NamedPipeSupport,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for Incoming {
|
impl Incoming {
|
||||||
type Item = tokio::io::Result<Connection>;
|
async fn next_(&mut self) -> io::Result<NamedPipeServer> {
|
||||||
|
self.inner.pipe.connect().await?;
|
||||||
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
let new_listener = unsafe {
|
||||||
match self.inner.pipe.get_ref().connect() {
|
create_server(
|
||||||
Ok(()) => {
|
&self.inner.path,
|
||||||
log::trace!("Incoming connection polled successfully");
|
false,
|
||||||
let new_listener = self.inner.replacement_pipe()?;
|
self.inner.security_attributes.as_ptr() as _,
|
||||||
Poll::Ready(
|
)?
|
||||||
Some(Ok(Connection::wrap(std::mem::replace(&mut self.inner.pipe, new_listener))))
|
};
|
||||||
)
|
Ok(std::mem::replace(&mut self.inner.pipe, new_listener))
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
|
||||||
self.inner.pipe.clear_write_ready(ctx);
|
|
||||||
Poll::Pending
|
|
||||||
} else {
|
|
||||||
Poll::Ready(Some(Err(e)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
pub async fn next(&mut self) -> Option<io::Result<NamedPipeServer>> {
|
||||||
|
Some(self.next_().await)
|
||||||
/// IPC connection.
|
|
||||||
pub struct Connection {
|
|
||||||
inner: NamedPipe,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Connection {
|
|
||||||
pub fn wrap(pipe: NamedPipe) -> Self {
|
|
||||||
Self { inner: pipe }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsyncRead for Connection {
|
|
||||||
fn poll_read(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
ctx: &mut Context<'_>,
|
|
||||||
buf: &mut tokio::io::ReadBuf<'_>,
|
|
||||||
) -> Poll<io::Result<()>> {
|
|
||||||
let this = Pin::into_inner(self);
|
|
||||||
Pin::new(&mut this.inner).poll_read(ctx, buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsyncWrite for Connection {
|
|
||||||
fn poll_write(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
ctx: &mut Context<'_>,
|
|
||||||
buf: &[u8],
|
|
||||||
) -> Poll<Result<usize>> {
|
|
||||||
let this = Pin::into_inner(self);
|
|
||||||
Pin::new(&mut this.inner).poll_write(ctx, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Result<()>> {
|
|
||||||
let this = Pin::into_inner(self);
|
|
||||||
Pin::new(&mut this.inner).poll_flush(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_shutdown(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Result<()>> {
|
|
||||||
let this = Pin::into_inner(self);
|
|
||||||
Pin::new(&mut this.inner).poll_shutdown(ctx)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,6 +175,7 @@ struct Sid {
|
|||||||
impl Sid {
|
impl Sid {
|
||||||
fn everyone_sid() -> io::Result<Sid> {
|
fn everyone_sid() -> io::Result<Sid> {
|
||||||
let mut sid_ptr = ptr::null_mut();
|
let mut sid_ptr = ptr::null_mut();
|
||||||
|
#[allow(const_item_mutation)]
|
||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
AllocateAndInitializeSid(
|
AllocateAndInitializeSid(
|
||||||
SECURITY_WORLD_SID_AUTHORITY.as_mut_ptr() as *mut _,
|
SECURITY_WORLD_SID_AUTHORITY.as_mut_ptr() as *mut _,
|
||||||
@ -479,5 +396,4 @@ mod test {
|
|||||||
.allow_everyone_connect()
|
.allow_everyone_connect()
|
||||||
.expect("failed to create security attributes that allow everyone to read and write to/from a pipe");
|
.expect("failed to create security attributes that allow everyone to read and write to/from a pipe");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user