Skip to content

Commit 2e24e0e

Browse files
author
germaniuss
committed
♻️ zb: Use async versions of UnixStream when possible
When connecting to a UnixSocket a blocking/threaded API is being used. This commit changes this to use tokio::net::UnixStream and Async<std::os::unix::net::UnixStream> when possible preventing the use of extra threads. The windows version continues using the blocking/threaded API. The connect_addr API is dropped since neither tokio nor async-io supports it. Instead, we use the connect functions in both environments, since they allow for abstract names when the path is prepended with '\0'. Move the connection code to unix.rs for better future maintainability.
1 parent 987bc6f commit 2e24e0e

2 files changed

Lines changed: 72 additions & 60 deletions

File tree

zbus/src/address/transport/mod.rs

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,10 @@ use async_io::Async;
1212
use std::collections::HashMap;
1313
#[cfg(not(feature = "tokio"))]
1414
use std::net::TcpStream;
15-
#[cfg(unix)]
16-
use std::os::unix::net::{SocketAddr, UnixStream};
1715
#[cfg(feature = "tokio")]
1816
use tokio::net::TcpStream;
1917
#[cfg(feature = "tokio-vsock")]
2018
use tokio_vsock::VsockStream;
21-
#[cfg(windows)]
22-
use uds_windows::UnixStream;
2319
#[cfg(all(feature = "vsock", not(feature = "tokio")))]
2420
use vsock::VsockStream;
2521
#[cfg(unix)]
@@ -33,7 +29,7 @@ use std::{
3329
};
3430

3531
mod unix;
36-
pub use unix::{Unix, UnixSocket};
32+
pub use unix::{Unix, UnixSocket, UnixStream};
3733
mod tcp;
3834
pub use tcp::{Tcp, TcpTransportFamily};
3935
#[cfg(windows)]
@@ -55,8 +51,6 @@ pub use ibus::Ibus;
5551
#[path = "vsock.rs"]
5652
// Gotta rename to avoid name conflict with the `vsock` crate.
5753
mod vsock_transport;
58-
#[cfg(target_os = "linux")]
59-
use std::os::linux::net::SocketAddrExt;
6054
#[cfg(any(
6155
all(feature = "vsock", not(feature = "tokio")),
6256
feature = "tokio-vsock"
@@ -102,59 +96,7 @@ impl Transport {
10296
#[cfg_attr(any(unix, windows), async_recursion::async_recursion)]
10397
pub(super) async fn connect(self) -> Result<Stream> {
10498
match self {
105-
Transport::Unix(unix) => {
106-
// This is a `path` in case of Windows until uds_windows provides the needed API:
107-
// https://github.com/haraldh/rust_uds_windows/issues/14
108-
let addr = match unix.take_path() {
109-
#[cfg(unix)]
110-
UnixSocket::File(path) => SocketAddr::from_pathname(path)?,
111-
#[cfg(windows)]
112-
UnixSocket::File(path) => path,
113-
#[cfg(target_os = "linux")]
114-
UnixSocket::Abstract(name) => {
115-
SocketAddr::from_abstract_name(name.as_encoded_bytes())?
116-
}
117-
UnixSocket::Dir(_) | UnixSocket::TmpDir(_) => {
118-
// you can't connect to a unix:dir
119-
return Err(Error::Unsupported);
120-
}
121-
};
122-
let stream = crate::Task::spawn_blocking(
123-
move || -> Result<_> {
124-
#[cfg(unix)]
125-
let stream = UnixStream::connect_addr(&addr)?;
126-
#[cfg(windows)]
127-
let stream = UnixStream::connect(addr)?;
128-
stream.set_nonblocking(true)?;
129-
130-
Ok(stream)
131-
},
132-
"unix stream connection",
133-
)
134-
.await??;
135-
#[cfg(not(feature = "tokio"))]
136-
{
137-
Async::new(stream)
138-
.map(Stream::Unix)
139-
.map_err(|e| Error::InputOutput(e.into()))
140-
}
141-
142-
#[cfg(feature = "tokio")]
143-
{
144-
#[cfg(unix)]
145-
{
146-
tokio::net::UnixStream::from_std(stream)
147-
.map(Stream::Unix)
148-
.map_err(|e| Error::InputOutput(e.into()))
149-
}
150-
151-
#[cfg(not(unix))]
152-
{
153-
let _ = stream;
154-
Err(Error::Unsupported)
155-
}
156-
}
157-
}
99+
Transport::Unix(unix) => unix.connect().await.map(Stream::Unix),
158100
#[cfg(unix)]
159101
Transport::Unixexec(unixexec) => unixexec.connect().await.map(Stream::Unixexec),
160102
#[cfg(all(feature = "vsock", not(feature = "tokio")))]

zbus/src/address/transport/unix.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::{Error, Result};
2+
13
#[cfg(target_os = "linux")]
24
use std::ffi::OsString;
35
use std::{
@@ -9,6 +11,16 @@ use std::{
911
#[cfg(unix)]
1012
use super::encode_percents;
1113

14+
#[cfg(not(feature = "tokio"))]
15+
use async_io::Async;
16+
17+
#[cfg(unix)]
18+
pub use std::os::unix::net::UnixStream;
19+
#[cfg(feature = "tokio")]
20+
pub use tokio::net::UnixStream;
21+
#[cfg(windows)]
22+
pub use uds_windows::UnixStream;
23+
1224
/// A Unix domain socket transport in a D-Bus address.
1325
#[derive(Clone, Debug, PartialEq, Eq)]
1426
pub struct Unix {
@@ -31,6 +43,25 @@ impl Unix {
3143
self.path
3244
}
3345

46+
fn take_addr(self) -> Result<PathBuf> {
47+
match self.take_path() {
48+
// This is a `path` because neither uds_windows, tokio, nor async_io provide
49+
// SocketAddrExt api
50+
UnixSocket::File(path) => Ok(path),
51+
#[cfg(target_os = "linux")]
52+
UnixSocket::Abstract(name) => {
53+
use std::{ffi::OsString, os::unix::ffi::OsStringExt};
54+
let mut v = name.into_vec();
55+
v.insert(0, 0);
56+
Ok(PathBuf::from(OsString::from_vec(v)))
57+
}
58+
UnixSocket::Dir(_) | UnixSocket::TmpDir(_) => {
59+
// you can't connect to a unix:dir
60+
Err(Error::Unsupported)
61+
}
62+
}
63+
}
64+
3465
pub(super) fn from_options(opts: std::collections::HashMap<&str, &str>) -> crate::Result<Self> {
3566
let path = opts.get("path");
3667
let abs = opts.get("abstract");
@@ -55,6 +86,45 @@ impl Unix {
5586

5687
Ok(Self::new(path))
5788
}
89+
90+
#[cfg(not(feature = "tokio"))]
91+
pub(super) async fn connect(self) -> Result<Async<UnixStream>> {
92+
let addr = self.take_addr()?;
93+
94+
#[cfg(unix)]
95+
let stream = Async::<UnixStream>::connect(addr).await;
96+
97+
#[cfg(windows)]
98+
{
99+
let stream = crate::Task::spawn_blocking(
100+
move || -> Result<_> {
101+
let stream = UnixStream::connect(addr)?;
102+
stream.set_nonblocking(true)?;
103+
104+
Ok(stream)
105+
},
106+
"unix stream connection",
107+
)
108+
.await??;
109+
let stream = Async::new(stream);
110+
}
111+
112+
stream.map_err(|e| Error::InputOutput(e.into()))
113+
}
114+
115+
#[cfg(feature = "tokio")]
116+
pub(super) async fn connect(self) -> Result<UnixStream> {
117+
#[cfg(unix)]
118+
{
119+
let addr = self.take_addr()?;
120+
UnixStream::connect(addr)
121+
.await
122+
.map_err(|e| Error::InputOutput(e.into()))
123+
}
124+
125+
#[cfg(windows)]
126+
Err(Error::Unsupported)
127+
}
58128
}
59129

60130
impl Display for Unix {

0 commit comments

Comments
 (0)