compio_fs::named_pipe

Struct ServerOptions

Source
pub struct ServerOptions { /* private fields */ }
Available on Windows only.
Expand description

A builder structure for construct a named pipe with named pipe-specific options. This is required to use for named pipe servers who wants to modify pipe-related options.

See ServerOptions::create.

Implementations§

Source§

impl ServerOptions

Source

pub fn new() -> ServerOptions

Creates a new named pipe builder with the default settings.

use compio_fs::named_pipe::ServerOptions;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-new";

let server = ServerOptions::new().create(PIPE_NAME).unwrap();
Source

pub fn pipe_mode(&mut self, pipe_mode: PipeMode) -> &mut Self

The pipe mode.

The default pipe mode is PipeMode::Byte. See PipeMode for documentation of what each mode means.

This corresponds to specifying PIPE_TYPE_ and PIPE_READMODE_ in dwPipeMode.

Source

pub fn access_inbound(&mut self, allowed: bool) -> &mut Self

The flow of data in the pipe goes from client to server only.

This corresponds to setting PIPE_ACCESS_INBOUND.

§Errors

Server side prevents connecting by denying inbound access, client errors with std::io::ErrorKind::PermissionDenied when attempting to create the connection.

use std::io;

use compio_fs::named_pipe::{ClientOptions, ServerOptions};

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-access-inbound-err1";

let _server = ServerOptions::new()
    .access_inbound(false)
    .create(PIPE_NAME)
    .unwrap();

let e = ClientOptions::new().open(PIPE_NAME).await.unwrap_err();

assert_eq!(e.kind(), io::ErrorKind::PermissionDenied);

Disabling writing allows a client to connect, but errors with std::io::ErrorKind::PermissionDenied if a write is attempted.

use std::io;

use compio_fs::named_pipe::{ClientOptions, ServerOptions};
use compio_io::AsyncWrite;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-access-inbound-err2";

let server = ServerOptions::new()
    .access_inbound(false)
    .create(PIPE_NAME)
    .unwrap();

let mut client = ClientOptions::new()
    .write(false)
    .open(PIPE_NAME)
    .await
    .unwrap();

server.connect().await.unwrap();

let e = client.write("ping").await.0.unwrap_err();
assert_eq!(e.kind(), io::ErrorKind::PermissionDenied);
§Examples

A unidirectional named pipe that only supports server-to-client communication.

use std::io;

use compio_buf::BufResult;
use compio_fs::named_pipe::{ClientOptions, ServerOptions};
use compio_io::{AsyncReadExt, AsyncWriteExt};

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-access-inbound";

let mut server = ServerOptions::new()
    .access_inbound(false)
    .create(PIPE_NAME)
    .unwrap();

let mut client = ClientOptions::new()
    .write(false)
    .open(PIPE_NAME)
    .await
    .unwrap();

server.connect().await.unwrap();

let write = server.write_all("ping");

let buf = Vec::with_capacity(4);
let read = client.read_exact(buf);

let (BufResult(write, _), BufResult(read, buf)) = futures_util::join!(write, read);
write.unwrap();
read.unwrap();

assert_eq!(&buf[..], b"ping");
Source

pub fn access_outbound(&mut self, allowed: bool) -> &mut Self

The flow of data in the pipe goes from server to client only.

This corresponds to setting PIPE_ACCESS_OUTBOUND.

§Errors

Server side prevents connecting by denying outbound access, client errors with std::io::ErrorKind::PermissionDenied when attempting to create the connection.

use std::io;

use compio_fs::named_pipe::{ClientOptions, ServerOptions};

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-access-outbound-err1";

let server = ServerOptions::new()
    .access_outbound(false)
    .create(PIPE_NAME)
    .unwrap();

let e = ClientOptions::new().open(PIPE_NAME).await.unwrap_err();

assert_eq!(e.kind(), io::ErrorKind::PermissionDenied);

Disabling reading allows a client to connect, but attempting to read will error with std::io::ErrorKind::PermissionDenied.

use std::io;

use compio_fs::named_pipe::{ClientOptions, ServerOptions};
use compio_io::AsyncRead;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-access-outbound-err2";

let server = ServerOptions::new()
    .access_outbound(false)
    .create(PIPE_NAME)
    .unwrap();

let mut client = ClientOptions::new()
    .read(false)
    .open(PIPE_NAME)
    .await
    .unwrap();

server.connect().await.unwrap();

let buf = Vec::with_capacity(4);
let e = client.read(buf).await.0.unwrap_err();
assert_eq!(e.kind(), io::ErrorKind::PermissionDenied);
§Examples

A unidirectional named pipe that only supports client-to-server communication.

use compio_buf::BufResult;
use compio_fs::named_pipe::{ClientOptions, ServerOptions};
use compio_io::{AsyncReadExt, AsyncWriteExt};

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-access-outbound";

let mut server = ServerOptions::new()
    .access_outbound(false)
    .create(PIPE_NAME)
    .unwrap();

let mut client = ClientOptions::new()
    .read(false)
    .open(PIPE_NAME)
    .await
    .unwrap();

server.connect().await.unwrap();

let write = client.write_all("ping");

let buf = Vec::with_capacity(4);
let read = server.read_exact(buf);

let (BufResult(write, _), BufResult(read, buf)) = futures_util::join!(write, read);
write.unwrap();
read.unwrap();

println!("done reading and writing");

assert_eq!(&buf[..], b"ping");
Source

pub fn first_pipe_instance(&mut self, first: bool) -> &mut Self

If you attempt to create multiple instances of a pipe with this flag set, creation of the first server instance succeeds, but creation of any subsequent instances will fail with std::io::ErrorKind::PermissionDenied.

This option is intended to be used with servers that want to ensure that they are the only process listening for clients on a given named pipe. This is accomplished by enabling it for the first server instance created in a process.

This corresponds to setting FILE_FLAG_FIRST_PIPE_INSTANCE.

§Errors

If this option is set and more than one instance of the server for a given named pipe exists, calling create will fail with std::io::ErrorKind::PermissionDenied.

use std::io;

use compio_fs::named_pipe::ServerOptions;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-first-instance-error";

let server1 = ServerOptions::new()
    .first_pipe_instance(true)
    .create(PIPE_NAME)
    .unwrap();

// Second server errs, since it's not the first instance.
let e = ServerOptions::new()
    .first_pipe_instance(true)
    .create(PIPE_NAME)
    .unwrap_err();

assert_eq!(e.kind(), io::ErrorKind::PermissionDenied);
§Examples
use std::io;

use compio_fs::named_pipe::ServerOptions;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-first-instance";

let mut builder = ServerOptions::new();
builder.first_pipe_instance(true);

let server = builder.create(PIPE_NAME).unwrap();
let e = builder.create(PIPE_NAME).unwrap_err();
assert_eq!(e.kind(), io::ErrorKind::PermissionDenied);
drop(server);

// OK: since, we've closed the other instance.
let _server2 = builder.create(PIPE_NAME).unwrap();
Source

pub fn write_dac(&mut self, requested: bool) -> &mut Self

Requests permission to modify the pipe’s discretionary access control list.

This corresponds to setting WRITE_DAC in dwOpenMode.

§Examples
use std::{io, ptr};

use compio_driver::AsRawFd;
use compio_fs::named_pipe::ServerOptions;
use windows_sys::Win32::{
    Foundation::ERROR_SUCCESS,
    Security::{
        Authorization::{SE_KERNEL_OBJECT, SetSecurityInfo},
        DACL_SECURITY_INFORMATION,
    },
};

const PIPE_NAME: &str = r"\\.\pipe\write_dac_pipe";

let mut pipe_template = ServerOptions::new();
pipe_template.write_dac(true);
let pipe = pipe_template.create(PIPE_NAME).unwrap();

unsafe {
    assert_eq!(
        ERROR_SUCCESS,
        SetSecurityInfo(
            pipe.as_raw_fd() as _,
            SE_KERNEL_OBJECT,
            DACL_SECURITY_INFORMATION,
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
        )
    );
}
use std::{io, ptr};

use compio_driver::AsRawFd;
use compio_fs::named_pipe::ServerOptions;
use windows_sys::Win32::{
    Foundation::ERROR_ACCESS_DENIED,
    Security::{
        Authorization::{SE_KERNEL_OBJECT, SetSecurityInfo},
        DACL_SECURITY_INFORMATION,
    },
};

const PIPE_NAME: &str = r"\\.\pipe\write_dac_pipe_fail";

let mut pipe_template = ServerOptions::new();
pipe_template.write_dac(false);
let pipe = pipe_template.create(PIPE_NAME).unwrap();

unsafe {
    assert_eq!(
        ERROR_ACCESS_DENIED,
        SetSecurityInfo(
            pipe.as_raw_fd() as _,
            SE_KERNEL_OBJECT,
            DACL_SECURITY_INFORMATION,
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
            ptr::null_mut(),
        )
    );
}
Source

pub fn write_owner(&mut self, requested: bool) -> &mut Self

Requests permission to modify the pipe’s owner.

This corresponds to setting WRITE_OWNER in dwOpenMode.

Source

pub fn access_system_security(&mut self, requested: bool) -> &mut Self

Requests permission to modify the pipe’s system access control list.

This corresponds to setting ACCESS_SYSTEM_SECURITY in dwOpenMode.

Source

pub fn reject_remote_clients(&mut self, reject: bool) -> &mut Self

Indicates whether this server can accept remote clients or not. Remote clients are disabled by default.

This corresponds to setting PIPE_REJECT_REMOTE_CLIENTS.

Source

pub fn max_instances(&mut self, instances: usize) -> &mut Self

The maximum number of instances that can be created for this pipe. The first instance of the pipe can specify this value; the same number must be specified for other instances of the pipe. Acceptable values are in the range 1 through 254. The default value is unlimited.

This corresponds to specifying nMaxInstances.

§Errors

The same numbers of max_instances have to be used by all servers. Any additional servers trying to be built which uses a mismatching value might error.

use std::io;

use compio_fs::named_pipe::{ClientOptions, ServerOptions};
use windows_sys::Win32::Foundation::ERROR_PIPE_BUSY;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-max-instances";

let mut server = ServerOptions::new();
server.max_instances(2);

let s1 = server.create(PIPE_NAME).unwrap();
let c1 = ClientOptions::new().open(PIPE_NAME).await.unwrap();

let s2 = server.create(PIPE_NAME).unwrap();
let c2 = ClientOptions::new().open(PIPE_NAME).await.unwrap();

// Too many servers!
let e = server.create(PIPE_NAME).unwrap_err();
assert_eq!(e.raw_os_error(), Some(ERROR_PIPE_BUSY as i32));

// Still too many servers even if we specify a higher value!
let e = server.max_instances(100).create(PIPE_NAME).unwrap_err();
assert_eq!(e.raw_os_error(), Some(ERROR_PIPE_BUSY as i32));
§Panics

This function will panic if more than 254 instances are specified. If you do not wish to set an instance limit, leave it unspecified.

use compio_fs::named_pipe::ServerOptions;

let builder = ServerOptions::new().max_instances(255);
Source

pub fn out_buffer_size(&mut self, buffer: u32) -> &mut Self

The number of bytes to reserve for the output buffer.

This corresponds to specifying nOutBufferSize.

Source

pub fn in_buffer_size(&mut self, buffer: u32) -> &mut Self

The number of bytes to reserve for the input buffer.

This corresponds to specifying nInBufferSize.

Source

pub fn create(&self, addr: impl AsRef<OsStr>) -> Result<NamedPipeServer>

Creates the named pipe identified by addr for use as a server.

This uses the CreateNamedPipe function.

§Examples
use compio_fs::named_pipe::ServerOptions;

const PIPE_NAME: &str = r"\\.\pipe\compio-named-pipe-create";

let server = ServerOptions::new().create(PIPE_NAME).unwrap();

Trait Implementations§

Source§

impl Clone for ServerOptions

Source§

fn clone(&self) -> ServerOptions

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ServerOptions

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ServerOptions

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more