new namedpipe

This commit is contained in:
rustdesk 2021-06-26 00:47:45 +08:00
parent 2d515815ed
commit 6f796db523
5 changed files with 63 additions and 145 deletions

View File

@ -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;
} }
} }

View File

@ -1,6 +1,5 @@
use futures::StreamExt as _;
use tokio::{ use tokio::{
prelude::*, io::*,
self, self,
io::split, io::split,
}; };

View File

@ -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());

View File

@ -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;

View File

@ -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");
} }
} }