mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-06 19:41:28 +03:00
source code
This commit is contained in:
3
libs/parity-tokio-ipc/.gitignore
vendored
Normal file
3
libs/parity-tokio-ipc/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
target
|
||||
Cargo.lock
|
||||
.idea
|
||||
20
libs/parity-tokio-ipc/.travis.yml
Normal file
20
libs/parity-tokio-ipc/.travis.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
after_success:
|
||||
- |-
|
||||
[ $TRAVIS_BRANCH = master ] &&
|
||||
[ $TRAVIS_PULL_REQUEST = false ] &&
|
||||
cargo doc --all --no-deps &&
|
||||
echo '<meta http-equiv=refresh content=0;url=parity_tokio_ipc/index.html>' > target/doc/index.html &&
|
||||
pip install --user ghp-import &&
|
||||
/home/travis/.local/bin/ghp-import -n target/doc &&
|
||||
git push -fq https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages
|
||||
env:
|
||||
global:
|
||||
secure: eUHPLjVMSVclRcEgwgybIKZQJTBW8QDjcjgIsEhOHZn7Kpzw0+rwJVoKkvr/uqyJwyY7pHy36mWX31J8YDSbSiM3W8jXeI97sk+FTUkleqUffPzXnbnR1D4kHZlKndFIbcuO5Z+rtVgsAv5E/u1w9XR+mvgK2lfaIEay+26gBl6dl/1TxWvrwDBeMvfq1JGVDQH4Etubncpi3LSWhbRkie1AKnVnsDIY9sUYVKSnIqjxx0qW6Z7EiCdwZ8gf04LNnqyIoKDpyldotL+nJ67ZlVI2O2DrbOOt55nliFHsH4BcWZIZOyIAM4PxIwhDl8g9E55FLkkUX9VUpVtqjTu9RWkVl7rzyrSxLoBUEjguIPrpFWBwLo0FSDvplB2XCXt8x035Io5PEg6m5dVxx5iytTIbI6HQwcA0ESTuDPuAdRJMNvJS/9e2UzPukdYYaaxF6g8wSmiIQjLuZU/nGBdmAl7Uw6cFlQnyLc/GXQg0oZ+B/J8sc4W2C/Z64oB8jK72RLNTKeeWs/XSOt8NxQiNkWeFIhGqiYOPJgjBiTCLSKJPY3CUTiBT8QpAcpj1x1gsWi+5fRoXYxNig/CmeTwZjuxKNxfQIu3J+lJbNdt44x7whnwhZ/AKVuLFPNNiC2OBNpa738UY60VYDoNZyhomWSdBnz3E6i1VtdiSnujFFnc=
|
||||
24
libs/parity-tokio-ipc/Cargo.toml
Normal file
24
libs/parity-tokio-ipc/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "parity-tokio-ipc"
|
||||
version = "0.7.2"
|
||||
edition = "2018"
|
||||
authors = ["NikVolf <nikvolf@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nikvolf/parity-tokio-ipc"
|
||||
homepage = "https://github.com/nikvolf/parity-tokio-ipc"
|
||||
description = """
|
||||
Interprocess communication library for tokio.
|
||||
"""
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
mio-named-pipes = "0.1"
|
||||
miow = "0.3"
|
||||
rand = "0.7"
|
||||
tokio = { version = "0.2", features = ["io-driver", "io-util", "uds", "stream", "rt-core", "macros", "time"] }
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["winbase", "winnt", "accctrl", "aclapi", "securitybaseapi", "minwinbase", "winbase"] }
|
||||
201
libs/parity-tokio-ipc/LICENSE-APACHE
Normal file
201
libs/parity-tokio-ipc/LICENSE-APACHE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
libs/parity-tokio-ipc/LICENSE-MIT
Normal file
25
libs/parity-tokio-ipc/LICENSE-MIT
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2017 Nikolay Volf
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
28
libs/parity-tokio-ipc/README.md
Normal file
28
libs/parity-tokio-ipc/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# parity-tokio-ipc
|
||||
|
||||
[](https://travis-ci.org/NikVolf/parity-tokio-ipc)
|
||||
|
||||
[Documentation](https://nikvolf.github.io/parity-tokio-ipc)
|
||||
|
||||
This crate abstracts interprocess transport for UNIX/Windows. On UNIX it utilizes unix sockets (`tokio_uds` crate) and named pipe on windows (experimental `tokio-named-pipes` crate).
|
||||
|
||||
Endpoint is transport-agnostic interface for incoming connections:
|
||||
```rust
|
||||
let endpoint = Endpoint::new(endpoint_addr, handle).unwrap();
|
||||
endpoint.incoming().for_each(|_| println!("Connection received!"));
|
||||
```
|
||||
|
||||
And IpcStream is transport-agnostic io:
|
||||
```rust
|
||||
let endpoint = Endpoint::new(endpoint_addr, handle).unwrap();
|
||||
endpoint.incoming().for_each(|(ipc_stream: IpcStream, _)| io::write_all(ipc_stream, b"Hello!"));
|
||||
```
|
||||
|
||||
|
||||
# License
|
||||
|
||||
`parity-tokio-ipc` is primarily distributed under the terms of both the MIT
|
||||
license and the Apache License (Version 2.0), with portions covered by various
|
||||
BSD-like licenses.
|
||||
|
||||
See LICENSE-APACHE, and LICENSE-MIT for details.
|
||||
16
libs/parity-tokio-ipc/appveyor.yml
Normal file
16
libs/parity-tokio-ipc/appveyor.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
|
||||
install:
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host %TARGET%
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\MinGW\bin
|
||||
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test
|
||||
24
libs/parity-tokio-ipc/examples/client.rs
Normal file
24
libs/parity-tokio-ipc/examples/client.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use tokio::{self, prelude::*};
|
||||
use parity_tokio_ipc::Endpoint;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let path = std::env::args().nth(1).expect("Run it with server path to connect as argument");
|
||||
|
||||
let mut client = Endpoint::connect(&path).await
|
||||
.expect("Failed to connect client.");
|
||||
|
||||
loop {
|
||||
let mut buf = [0u8; 4];
|
||||
println!("SEND: PING");
|
||||
client.write_all(b"ping").await.expect("Unable to write message to client");
|
||||
client.read_exact(&mut buf[..]).await.expect("Unable to read buffer");
|
||||
if let Ok("pong") = std::str::from_utf8(&buf[..]) {
|
||||
println!("RECEIVED: PONG");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
tokio::time::delay_for(std::time::Duration::from_secs(2)).await;
|
||||
}
|
||||
}
|
||||
47
libs/parity-tokio-ipc/examples/server.rs
Normal file
47
libs/parity-tokio-ipc/examples/server.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use futures::StreamExt as _;
|
||||
use tokio::{
|
||||
prelude::*,
|
||||
self,
|
||||
io::split,
|
||||
};
|
||||
|
||||
use parity_tokio_ipc::{Endpoint, SecurityAttributes};
|
||||
|
||||
async fn run_server(path: String) {
|
||||
let mut endpoint = Endpoint::new(path);
|
||||
endpoint.set_security_attributes(SecurityAttributes::allow_everyone_create().unwrap());
|
||||
|
||||
let mut incoming = endpoint.incoming().expect("failed to open new socket");
|
||||
|
||||
while let Some(result) = incoming.next().await
|
||||
{
|
||||
match result {
|
||||
Ok(stream) => {
|
||||
let (mut reader, mut writer) = split(stream);
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
let mut buf = [0u8; 4];
|
||||
let pong_buf = b"pong";
|
||||
if let Err(_) = reader.read_exact(&mut buf).await {
|
||||
println!("Closing socket");
|
||||
break;
|
||||
}
|
||||
if let Ok("ping") = std::str::from_utf8(&buf[..]) {
|
||||
println!("RECIEVED: PING");
|
||||
writer.write_all(pong_buf).await.expect("unable to write to socket");
|
||||
println!("SEND: PONG");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => unreachable!("ideally")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let path = std::env::args().nth(1).expect("Run it with server path as argument");
|
||||
run_server(path).await
|
||||
}
|
||||
7
libs/parity-tokio-ipc/examples/spam-clients.sh
Executable file
7
libs/parity-tokio-ipc/examples/spam-clients.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Spawning 100 processes"
|
||||
for i in {1..100} ;
|
||||
do
|
||||
( cargo run --example client -- /tmp/test.ipc & )
|
||||
done
|
||||
154
libs/parity-tokio-ipc/src/lib.rs
Normal file
154
libs/parity-tokio-ipc/src/lib.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
//! Tokio IPC transport. Under the hood uses Unix Domain Sockets for Linux/Mac
|
||||
//! and Named Pipes for Windows.
|
||||
|
||||
//#![warn(missing_docs)]
|
||||
//#![deny(rust_2018_idioms)]
|
||||
|
||||
#[cfg(windows)]
|
||||
mod win;
|
||||
#[cfg(not(windows))]
|
||||
mod unix;
|
||||
|
||||
/// Endpoint for IPC transport
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use parity_tokio_ipc::{Endpoint, dummy_endpoint};
|
||||
/// use futures::{future, Future, Stream, StreamExt};
|
||||
/// use tokio::runtime::Runtime;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut runtime = Runtime::new().unwrap();
|
||||
/// let mut endpoint = Endpoint::new(dummy_endpoint());
|
||||
/// let server = endpoint.incoming()
|
||||
/// .expect("failed to open up a new pipe/socket")
|
||||
/// .for_each(|_stream| {
|
||||
/// println!("Connection received");
|
||||
/// futures::future::ready(())
|
||||
/// });
|
||||
/// runtime.block_on(server)
|
||||
/// }
|
||||
///```
|
||||
#[cfg(windows)]
|
||||
pub use win::{SecurityAttributes, Endpoint, Connection, Incoming};
|
||||
#[cfg(unix)]
|
||||
pub use unix::{SecurityAttributes, Endpoint, Connection, Incoming};
|
||||
|
||||
/// For testing/examples
|
||||
pub fn dummy_endpoint() -> String {
|
||||
let num: u64 = rand::Rng::gen(&mut rand::thread_rng());
|
||||
if cfg!(windows) {
|
||||
format!(r"\\.\pipe\my-pipe-{}", num)
|
||||
} else {
|
||||
format!(r"/tmp/my-uds-{}", num)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tokio::prelude::*;
|
||||
use futures::{channel::oneshot, StreamExt as _, FutureExt as _};
|
||||
use std::time::Duration;
|
||||
use tokio::{
|
||||
self,
|
||||
io::split,
|
||||
};
|
||||
|
||||
use super::{dummy_endpoint, Endpoint, SecurityAttributes};
|
||||
use std::path::Path;
|
||||
use futures::future::{Either, select, ready};
|
||||
|
||||
async fn run_server(path: String) {
|
||||
let path = path.to_owned();
|
||||
let mut endpoint = Endpoint::new(path);
|
||||
|
||||
endpoint.set_security_attributes(
|
||||
SecurityAttributes::empty()
|
||||
.set_mode(0o777)
|
||||
.unwrap()
|
||||
);
|
||||
let mut incoming = endpoint.incoming().expect("failed to open up a new socket");
|
||||
|
||||
while let Some(result) = incoming.next().await {
|
||||
match result {
|
||||
Ok(stream) => {
|
||||
let (mut reader, mut writer) = split(stream);
|
||||
let mut buf = [0u8; 5];
|
||||
reader.read_exact(&mut buf).await.expect("unable to read from socket");
|
||||
writer.write_all(&buf[..]).await.expect("unable to write to socket");
|
||||
}
|
||||
_ => unreachable!("ideally")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn smoke_test() {
|
||||
let path = dummy_endpoint();
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
|
||||
let server = select(Box::pin(run_server(path.clone())), shutdown_rx)
|
||||
.then(|either| {
|
||||
match either {
|
||||
Either::Right((_, server)) => {
|
||||
drop(server);
|
||||
}
|
||||
_ => unreachable!("also ideally")
|
||||
};
|
||||
ready(())
|
||||
});
|
||||
tokio::spawn(server);
|
||||
|
||||
tokio::time::delay_for(Duration::from_secs(2)).await;
|
||||
|
||||
println!("Connecting to client 0...");
|
||||
let mut client_0 = Endpoint::connect(&path).await
|
||||
.expect("failed to open client_0");
|
||||
tokio::time::delay_for(Duration::from_secs(2)).await;
|
||||
println!("Connecting to client 1...");
|
||||
let mut client_1 = Endpoint::connect(&path).await
|
||||
.expect("failed to open client_1");
|
||||
let msg = b"hello";
|
||||
|
||||
let mut rx_buf = vec![0u8; msg.len()];
|
||||
client_0.write_all(msg).await.expect("Unable to write message to client");
|
||||
client_0.read_exact(&mut rx_buf).await.expect("Unable to read message from client");
|
||||
|
||||
let mut rx_buf2 = vec![0u8; msg.len()];
|
||||
client_1.write_all(msg).await.expect("Unable to write message to client");
|
||||
client_1.read_exact(&mut rx_buf2).await.expect("Unable to read message from client");
|
||||
|
||||
assert_eq!(rx_buf, msg);
|
||||
assert_eq!(rx_buf2, msg);
|
||||
|
||||
// shutdown server
|
||||
if let Ok(()) = shutdown_tx.send(()) {
|
||||
// wait one second for the file to be deleted.
|
||||
tokio::time::delay_for(Duration::from_secs(1)).await;
|
||||
let path = Path::new(&path);
|
||||
// assert that it has
|
||||
assert!(!path.exists());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn create_pipe_with_permissions(attr: SecurityAttributes) -> ::std::io::Result<()> {
|
||||
let path = dummy_endpoint();
|
||||
|
||||
let mut endpoint = Endpoint::new(path);
|
||||
endpoint.set_security_attributes(attr);
|
||||
endpoint.incoming().map(|_| ())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tokio::test]
|
||||
async fn test_pipe_permissions() {
|
||||
create_pipe_with_permissions(SecurityAttributes::empty())
|
||||
.expect("failed with no attributes");
|
||||
create_pipe_with_permissions(SecurityAttributes::allow_everyone_create().unwrap())
|
||||
.expect("failed with attributes for creating");
|
||||
create_pipe_with_permissions(SecurityAttributes::empty().allow_everyone_connect().unwrap())
|
||||
.expect("failed with attributes for connecting");
|
||||
}
|
||||
}
|
||||
163
libs/parity-tokio-ipc/src/unix.rs
Normal file
163
libs/parity-tokio-ipc/src/unix.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use libc::chmod;
|
||||
use std::ffi::CString;
|
||||
use std::io::{self, Error};
|
||||
use tokio::prelude::*;
|
||||
use tokio::net::{UnixListener, UnixStream};
|
||||
use std::path::Path;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
/// Socket permissions and ownership on UNIX
|
||||
pub struct SecurityAttributes {
|
||||
// read/write permissions for owner, group and others in unix octal.
|
||||
mode: Option<u16>
|
||||
}
|
||||
|
||||
impl SecurityAttributes {
|
||||
/// New default security attributes.
|
||||
pub fn empty() -> Self {
|
||||
SecurityAttributes {
|
||||
mode: None
|
||||
}
|
||||
}
|
||||
|
||||
/// New security attributes that allow everyone to connect.
|
||||
pub fn allow_everyone_connect(mut self) -> io::Result<Self> {
|
||||
self.mode = Some(0o777);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Set a custom permission on the socket
|
||||
pub fn set_mode(mut self, mode: u16) -> io::Result<Self> {
|
||||
self.mode = Some(mode);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// New security attributes that allow everyone to create.
|
||||
pub fn allow_everyone_create() -> io::Result<Self> {
|
||||
Ok(SecurityAttributes {
|
||||
mode: None
|
||||
})
|
||||
}
|
||||
|
||||
/// called in unix, after server socket has been created
|
||||
/// will apply security attributes to the socket.
|
||||
pub(crate) unsafe fn apply_permissions(&self, path: &str) -> io::Result<()> {
|
||||
let path = CString::new(path.to_owned())?;
|
||||
if let Some(mode) = self.mode {
|
||||
if chmod(path.as_ptr(), mode as _) == -1 {
|
||||
return Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Endpoint implementation for unix systems
|
||||
pub struct Endpoint {
|
||||
path: String,
|
||||
security_attributes: SecurityAttributes,
|
||||
}
|
||||
|
||||
pub struct Incoming {
|
||||
socket: UnixListener,
|
||||
}
|
||||
|
||||
impl Incoming {
|
||||
pub async fn next(&mut self) -> Option<io::Result<Connection>> {
|
||||
match self.socket.accept().await {
|
||||
Ok((stream, _)) => Some(Ok(Connection::wrap(stream))),
|
||||
Err(err) => Some(Err(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Endpoint {
|
||||
/// Stream of incoming connections
|
||||
pub fn incoming(&mut self) -> io::Result<Incoming> {
|
||||
unsafe {
|
||||
// the call to bind in `inner()` creates the file
|
||||
// `apply_permission()` will set the file permissions.
|
||||
self.security_attributes.apply_permissions(&self.path)?;
|
||||
};
|
||||
let socket = self.inner()?;
|
||||
Ok(Incoming { socket })
|
||||
}
|
||||
|
||||
/// Inner platform-dependant state of the endpoint
|
||||
fn inner(&self) -> io::Result<UnixListener> {
|
||||
UnixListener::bind(&self.path)
|
||||
}
|
||||
|
||||
/// Set security attributes for the connection
|
||||
pub fn set_security_attributes(&mut self, security_attributes: SecurityAttributes) {
|
||||
self.security_attributes = security_attributes;
|
||||
}
|
||||
|
||||
/// Make new connection using the provided path and running event pool
|
||||
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Connection> {
|
||||
Ok(Connection::wrap(UnixStream::connect(path.as_ref()).await?))
|
||||
}
|
||||
|
||||
/// Returns the path of the endpoint.
|
||||
pub fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// New IPC endpoint at the given path
|
||||
pub fn new(path: String) -> Self {
|
||||
Endpoint {
|
||||
path,
|
||||
security_attributes: SecurityAttributes::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// IPC connection.
|
||||
pub struct Connection {
|
||||
inner: UnixStream,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
fn wrap(stream: UnixStream) -> Self {
|
||||
Self { inner: stream }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for Connection {
|
||||
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit<u8>]) -> bool {
|
||||
self.inner.prepare_uninitialized_buffer(buf)
|
||||
}
|
||||
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
ctx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
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, io::Error>> {
|
||||
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<(), io::Error>> {
|
||||
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<(), io::Error>> {
|
||||
let this = Pin::into_inner(self);
|
||||
Pin::new(&mut this.inner).poll_shutdown(ctx)
|
||||
}
|
||||
}
|
||||
488
libs/parity-tokio-ipc/src/win.rs
Normal file
488
libs/parity-tokio-ipc/src/win.rs
Normal file
@@ -0,0 +1,488 @@
|
||||
use winapi::shared::winerror::ERROR_SUCCESS;
|
||||
use winapi::um::accctrl::*;
|
||||
use winapi::um::aclapi::*;
|
||||
use winapi::um::minwinbase::{LPTR, PSECURITY_ATTRIBUTES, SECURITY_ATTRIBUTES};
|
||||
use winapi::um::securitybaseapi::*;
|
||||
use winapi::um::winbase::{LocalAlloc, LocalFree};
|
||||
use winapi::um::winnt::*;
|
||||
|
||||
use std::io;
|
||||
use std::marker;
|
||||
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::mem::MaybeUninit;
|
||||
use tokio::io::PollEvented;
|
||||
|
||||
type NamedPipe = PollEvented<mio_named_pipes::NamedPipe>;
|
||||
|
||||
const PIPE_AVAILABILITY_TIMEOUT: u64 = 5000;
|
||||
|
||||
/// Endpoint implementation for windows
|
||||
pub struct Endpoint {
|
||||
path: String,
|
||||
security_attributes: SecurityAttributes,
|
||||
}
|
||||
|
||||
impl Endpoint {
|
||||
/// Stream of incoming connections
|
||||
pub fn incoming(mut self) -> io::Result<Incoming> {
|
||||
let pipe = self.inner()?;
|
||||
Ok(Incoming {
|
||||
path: self.path.clone(),
|
||||
inner: NamedPipeSupport {
|
||||
path: self.path,
|
||||
pipe,
|
||||
security_attributes: self.security_attributes,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Inner platform-dependant state of the endpoint
|
||||
fn inner(&mut self) -> io::Result<NamedPipe> {
|
||||
use miow::pipe::NamedPipeBuilder;
|
||||
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
|
||||
pub fn set_security_attributes(&mut self, security_attributes: SecurityAttributes) {
|
||||
self.security_attributes = security_attributes;
|
||||
}
|
||||
|
||||
/// Returns the path of the endpoint.
|
||||
pub fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Make new connection using the provided path and running event pool.
|
||||
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Connection> {
|
||||
Ok(Connection::wrap(Self::connect_inner(path.as_ref())?))
|
||||
}
|
||||
|
||||
fn connect_inner(path: &Path) -> io::Result<NamedPipe> {
|
||||
use std::fs::OpenOptions;
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
use std::os::windows::io::{FromRawHandle, IntoRawHandle};
|
||||
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
||||
|
||||
// Wait for the pipe to become available or fail after 5 seconds.
|
||||
miow::pipe::NamedPipe::wait(
|
||||
path,
|
||||
Some(std::time::Duration::from_millis(PIPE_AVAILABILITY_TIMEOUT)),
|
||||
)?;
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.custom_flags(FILE_FLAG_OVERLAPPED)
|
||||
.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
|
||||
pub fn new(path: String) -> Self {
|
||||
Endpoint {
|
||||
path,
|
||||
security_attributes: SecurityAttributes::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NamedPipeSupport {
|
||||
path: String,
|
||||
pipe: NamedPipe,
|
||||
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
|
||||
pub struct Incoming {
|
||||
#[allow(dead_code)]
|
||||
path: String,
|
||||
inner: NamedPipeSupport,
|
||||
}
|
||||
|
||||
impl Stream for Incoming {
|
||||
type Item = tokio::io::Result<Connection>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match self.inner.pipe.get_ref().connect() {
|
||||
Ok(()) => {
|
||||
log::trace!("Incoming connection polled successfully");
|
||||
let new_listener = self.inner.replacement_pipe()?;
|
||||
Poll::Ready(
|
||||
Some(Ok(Connection::wrap(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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// IPC connection.
|
||||
pub struct Connection {
|
||||
inner: NamedPipe,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub fn wrap(pipe: NamedPipe) -> Self {
|
||||
Self { inner: pipe }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for Connection {
|
||||
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit<u8>]) -> bool {
|
||||
self.inner.prepare_uninitialized_buffer(buf)
|
||||
}
|
||||
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
ctx: &mut Context<'_>,
|
||||
buf: &mut [u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
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, io::Error>> {
|
||||
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<(), io::Error>> {
|
||||
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<(), io::Error>> {
|
||||
let this = Pin::into_inner(self);
|
||||
Pin::new(&mut this.inner).poll_shutdown(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/// Security attributes.
|
||||
pub struct SecurityAttributes {
|
||||
attributes: Option<InnerAttributes>,
|
||||
}
|
||||
|
||||
impl SecurityAttributes {
|
||||
/// New default security attributes.
|
||||
pub fn empty() -> SecurityAttributes {
|
||||
SecurityAttributes { attributes: None }
|
||||
}
|
||||
|
||||
/// New default security attributes that allow everyone to connect.
|
||||
pub fn allow_everyone_connect(&self) -> io::Result<SecurityAttributes> {
|
||||
let attributes = Some(InnerAttributes::allow_everyone(
|
||||
GENERIC_READ | FILE_WRITE_DATA,
|
||||
)?);
|
||||
Ok(SecurityAttributes { attributes })
|
||||
}
|
||||
|
||||
/// Set a custom permission on the socket
|
||||
pub fn set_mode(self, _mode: u32) -> io::Result<Self> {
|
||||
// for now, does nothing.
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// New default security attributes that allow everyone to create.
|
||||
pub fn allow_everyone_create() -> io::Result<SecurityAttributes> {
|
||||
let attributes = Some(InnerAttributes::allow_everyone(
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
)?);
|
||||
Ok(SecurityAttributes { attributes })
|
||||
}
|
||||
|
||||
/// Return raw handle of security attributes.
|
||||
pub(crate) unsafe fn as_ptr(&mut self) -> PSECURITY_ATTRIBUTES {
|
||||
match self.attributes.as_mut() {
|
||||
Some(attributes) => attributes.as_ptr(),
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for SecurityAttributes {}
|
||||
|
||||
struct Sid {
|
||||
sid_ptr: PSID,
|
||||
}
|
||||
|
||||
impl Sid {
|
||||
fn everyone_sid() -> io::Result<Sid> {
|
||||
let mut sid_ptr = ptr::null_mut();
|
||||
let result = unsafe {
|
||||
AllocateAndInitializeSid(
|
||||
SECURITY_WORLD_SID_AUTHORITY.as_mut_ptr() as *mut _,
|
||||
1,
|
||||
SECURITY_WORLD_RID,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&mut sid_ptr,
|
||||
)
|
||||
};
|
||||
if result == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(Sid { sid_ptr })
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe - the returned pointer is only valid for the lifetime of self.
|
||||
unsafe fn as_ptr(&self) -> PSID {
|
||||
self.sid_ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Sid {
|
||||
fn drop(&mut self) {
|
||||
if !self.sid_ptr.is_null() {
|
||||
unsafe {
|
||||
FreeSid(self.sid_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AceWithSid<'a> {
|
||||
explicit_access: EXPLICIT_ACCESS_W,
|
||||
_marker: marker::PhantomData<&'a Sid>,
|
||||
}
|
||||
|
||||
impl<'a> AceWithSid<'a> {
|
||||
fn new(sid: &'a Sid, trustee_type: u32) -> AceWithSid<'a> {
|
||||
let mut explicit_access = unsafe { mem::zeroed::<EXPLICIT_ACCESS_W>() };
|
||||
explicit_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||||
explicit_access.Trustee.TrusteeType = trustee_type;
|
||||
explicit_access.Trustee.ptstrName = unsafe { sid.as_ptr() as *mut _ };
|
||||
|
||||
AceWithSid {
|
||||
explicit_access,
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_access_mode(&mut self, access_mode: u32) -> &mut Self {
|
||||
self.explicit_access.grfAccessMode = access_mode;
|
||||
self
|
||||
}
|
||||
|
||||
fn set_access_permissions(&mut self, access_permissions: u32) -> &mut Self {
|
||||
self.explicit_access.grfAccessPermissions = access_permissions;
|
||||
self
|
||||
}
|
||||
|
||||
fn allow_inheritance(&mut self, inheritance_flags: u32) -> &mut Self {
|
||||
self.explicit_access.grfInheritance = inheritance_flags;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct Acl {
|
||||
acl_ptr: PACL,
|
||||
}
|
||||
|
||||
impl Acl {
|
||||
fn empty() -> io::Result<Acl> {
|
||||
Self::new(&mut [])
|
||||
}
|
||||
|
||||
fn new(entries: &mut [AceWithSid<'_>]) -> io::Result<Acl> {
|
||||
let mut acl_ptr = ptr::null_mut();
|
||||
let result = unsafe {
|
||||
SetEntriesInAclW(
|
||||
entries.len() as u32,
|
||||
entries.as_mut_ptr() as *mut _,
|
||||
ptr::null_mut(),
|
||||
&mut acl_ptr,
|
||||
)
|
||||
};
|
||||
|
||||
if result != ERROR_SUCCESS {
|
||||
return Err(io::Error::from_raw_os_error(result as i32));
|
||||
}
|
||||
|
||||
Ok(Acl { acl_ptr })
|
||||
}
|
||||
|
||||
unsafe fn as_ptr(&self) -> PACL {
|
||||
self.acl_ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Acl {
|
||||
fn drop(&mut self) {
|
||||
if !self.acl_ptr.is_null() {
|
||||
unsafe { LocalFree(self.acl_ptr as *mut _) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SecurityDescriptor {
|
||||
descriptor_ptr: PSECURITY_DESCRIPTOR,
|
||||
}
|
||||
|
||||
impl SecurityDescriptor {
|
||||
fn new() -> io::Result<Self> {
|
||||
let descriptor_ptr = unsafe { LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH) };
|
||||
if descriptor_ptr.is_null() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Failed to allocate security descriptor",
|
||||
));
|
||||
}
|
||||
|
||||
if unsafe {
|
||||
InitializeSecurityDescriptor(descriptor_ptr, SECURITY_DESCRIPTOR_REVISION) == 0
|
||||
} {
|
||||
return Err(io::Error::last_os_error());
|
||||
};
|
||||
|
||||
Ok(SecurityDescriptor { descriptor_ptr })
|
||||
}
|
||||
|
||||
fn set_dacl(&mut self, acl: &Acl) -> io::Result<()> {
|
||||
if unsafe {
|
||||
SetSecurityDescriptorDacl(self.descriptor_ptr, true as i32, acl.as_ptr(), false as i32)
|
||||
== 0
|
||||
} {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn as_ptr(&self) -> PSECURITY_DESCRIPTOR {
|
||||
self.descriptor_ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SecurityDescriptor {
|
||||
fn drop(&mut self) {
|
||||
if !self.descriptor_ptr.is_null() {
|
||||
unsafe { LocalFree(self.descriptor_ptr) };
|
||||
self.descriptor_ptr = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InnerAttributes {
|
||||
descriptor: SecurityDescriptor,
|
||||
acl: Acl,
|
||||
attrs: SECURITY_ATTRIBUTES,
|
||||
}
|
||||
|
||||
impl InnerAttributes {
|
||||
fn empty() -> io::Result<InnerAttributes> {
|
||||
let descriptor = SecurityDescriptor::new()?;
|
||||
let mut attrs = unsafe { mem::zeroed::<SECURITY_ATTRIBUTES>() };
|
||||
attrs.nLength = mem::size_of::<SECURITY_ATTRIBUTES>() as u32;
|
||||
attrs.lpSecurityDescriptor = unsafe { descriptor.as_ptr() };
|
||||
attrs.bInheritHandle = false as i32;
|
||||
|
||||
let acl = Acl::empty().expect("this should never fail");
|
||||
|
||||
Ok(InnerAttributes {
|
||||
acl,
|
||||
descriptor,
|
||||
attrs,
|
||||
})
|
||||
}
|
||||
|
||||
fn allow_everyone(permissions: u32) -> io::Result<InnerAttributes> {
|
||||
let mut attributes = Self::empty()?;
|
||||
let sid = Sid::everyone_sid()?;
|
||||
|
||||
let mut everyone_ace = AceWithSid::new(&sid, TRUSTEE_IS_WELL_KNOWN_GROUP);
|
||||
everyone_ace
|
||||
.set_access_mode(SET_ACCESS)
|
||||
.set_access_permissions(permissions)
|
||||
.allow_inheritance(false as u32);
|
||||
|
||||
let mut entries = vec![everyone_ace];
|
||||
attributes.acl = Acl::new(&mut entries)?;
|
||||
attributes.descriptor.set_dacl(&attributes.acl)?;
|
||||
|
||||
Ok(attributes)
|
||||
}
|
||||
|
||||
unsafe fn as_ptr(&mut self) -> PSECURITY_ATTRIBUTES {
|
||||
&mut self.attrs as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::SecurityAttributes;
|
||||
|
||||
#[test]
|
||||
fn test_allow_everyone_everything() {
|
||||
SecurityAttributes::allow_everyone_create()
|
||||
.expect("failed to create security attributes that allow everyone to create a pipe");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_allow_eveyone_read_write() {
|
||||
SecurityAttributes::empty()
|
||||
.allow_everyone_connect()
|
||||
.expect("failed to create security attributes that allow everyone to read and write to/from a pipe");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user