1use rustix::fd::{AsFd, BorrowedFd};
2use std::io::{IoSlice, Result};
3use std::net::TcpStream;
4#[cfg(unix)]
5use std::os::unix::io::{AsRawFd, IntoRawFd, OwnedFd, RawFd};
6#[cfg(unix)]
7use std::os::unix::net::UnixStream;
8#[cfg(windows)]
9use std::os::windows::io::{
10 AsRawSocket, AsSocket, BorrowedSocket, IntoRawSocket, OwnedSocket, RawSocket,
11};
12
13use crate::utils::RawFdContainer;
14use x11rb_protocol::parse_display::ConnectAddress;
15use x11rb_protocol::xauth::Family;
16
17#[derive(Debug, Clone, Copy)]
19pub enum PollMode {
20 Readable,
22
23 Writable,
25
26 ReadAndWritable,
28}
29
30impl PollMode {
31 pub fn readable(self) -> bool {
33 match self {
34 PollMode::Readable | PollMode::ReadAndWritable => true,
35 PollMode::Writable => false,
36 }
37 }
38
39 pub fn writable(self) -> bool {
41 match self {
42 PollMode::Writable | PollMode::ReadAndWritable => true,
43 PollMode::Readable => false,
44 }
45 }
46}
47
48pub trait Stream {
53 fn poll(&self, mode: PollMode) -> Result<()>;
69
70 fn read(&self, buf: &mut [u8], fd_storage: &mut Vec<RawFdContainer>) -> Result<usize>;
92
93 fn write(&self, buf: &[u8], fds: &mut Vec<RawFdContainer>) -> Result<usize>;
119
120 fn write_vectored(&self, bufs: &[IoSlice<'_>], fds: &mut Vec<RawFdContainer>) -> Result<usize> {
131 for buf in bufs {
132 if !buf.is_empty() {
133 return self.write(buf, fds);
134 }
135 }
136 Ok(0)
137 }
138}
139
140#[derive(Debug)]
144pub struct DefaultStream {
145 inner: DefaultStreamInner,
146}
147
148#[cfg(unix)]
149type DefaultStreamInner = RawFdContainer;
150
151#[cfg(not(unix))]
152type DefaultStreamInner = TcpStream;
153
154type PeerAddr = (Family, Vec<u8>);
158
159impl DefaultStream {
160 pub fn connect(addr: &ConnectAddress<'_>) -> Result<(Self, PeerAddr)> {
162 match addr {
163 ConnectAddress::Hostname(host, port) => {
164 let stream = TcpStream::connect((*host, *port))?;
166 Self::from_tcp_stream(stream)
167 }
168 #[cfg(unix)]
169 ConnectAddress::Socket(path) => {
170 let stream = UnixStream::connect(path)?;
172 Self::from_unix_stream(stream)
173 }
174 #[cfg(not(unix))]
175 ConnectAddress::Socket(_) => {
176 Err(std::io::Error::new(
178 std::io::ErrorKind::Other,
179 "Unix domain sockets are not supported on Windows",
180 ))
181 }
182 _ => Err(std::io::Error::new(
183 std::io::ErrorKind::Other,
184 "The given address family is not implemented",
185 )),
186 }
187 }
188
189 pub fn from_tcp_stream(stream: TcpStream) -> Result<(Self, PeerAddr)> {
195 let peer_addr = peer_addr::tcp(&stream.peer_addr()?);
196 stream.set_nonblocking(true)?;
197 let result = Self {
198 inner: stream.into(),
199 };
200 Ok((result, peer_addr))
201 }
202
203 #[cfg(unix)]
209 pub fn from_unix_stream(stream: UnixStream) -> Result<(Self, PeerAddr)> {
210 stream.set_nonblocking(true)?;
211 let result = Self {
212 inner: stream.into(),
213 };
214 Ok((result, peer_addr::local()))
215 }
216
217 fn as_fd(&self) -> BorrowedFd<'_> {
218 self.inner.as_fd()
219 }
220}
221
222#[cfg(unix)]
223impl AsRawFd for DefaultStream {
224 fn as_raw_fd(&self) -> RawFd {
225 self.inner.as_raw_fd()
226 }
227}
228
229#[cfg(unix)]
230impl AsFd for DefaultStream {
231 fn as_fd(&self) -> BorrowedFd<'_> {
232 self.inner.as_fd()
233 }
234}
235
236#[cfg(unix)]
237impl IntoRawFd for DefaultStream {
238 fn into_raw_fd(self) -> RawFd {
239 self.inner.into_raw_fd()
240 }
241}
242
243#[cfg(unix)]
244impl From<DefaultStream> for OwnedFd {
245 fn from(stream: DefaultStream) -> Self {
246 stream.inner
247 }
248}
249
250#[cfg(windows)]
251impl AsRawSocket for DefaultStream {
252 fn as_raw_socket(&self) -> RawSocket {
253 self.inner.as_raw_socket()
254 }
255}
256
257#[cfg(windows)]
258impl AsSocket for DefaultStream {
259 fn as_socket(&self) -> BorrowedSocket<'_> {
260 self.inner.as_socket()
261 }
262}
263
264#[cfg(windows)]
265impl IntoRawSocket for DefaultStream {
266 fn into_raw_socket(self) -> RawSocket {
267 self.inner.into_raw_socket()
268 }
269}
270
271#[cfg(windows)]
272impl From<DefaultStream> for OwnedSocket {
273 fn from(stream: DefaultStream) -> Self {
274 stream.inner.into()
275 }
276}
277
278#[cfg(unix)]
279fn do_write(
280 stream: &DefaultStream,
281 bufs: &[IoSlice<'_>],
282 fds: &mut Vec<RawFdContainer>,
283) -> Result<usize> {
284 use rustix::io::Errno;
285 use rustix::net::{sendmsg, SendAncillaryBuffer, SendAncillaryMessage, SendFlags};
286 use std::mem::MaybeUninit;
287
288 fn sendmsg_wrapper(
289 fd: BorrowedFd<'_>,
290 iov: &[IoSlice<'_>],
291 cmsgs: &mut SendAncillaryBuffer<'_, '_, '_>,
292 flags: SendFlags,
293 ) -> Result<usize> {
294 loop {
295 match sendmsg(fd, iov, cmsgs, flags) {
296 Ok(n) => return Ok(n),
297 Err(Errno::INTR) => {}
299 Err(e) => return Err(e.into()),
300 }
301 }
302 }
303
304 let fd = stream.as_fd();
305
306 let res = if !fds.is_empty() {
307 let fds = fds.iter().map(|fd| fd.as_fd()).collect::<Vec<_>>();
308 let rights = SendAncillaryMessage::ScmRights(&fds);
309
310 let mut cmsg_space = vec![MaybeUninit::uninit(); rights.size()];
311 let mut cmsg_buffer = SendAncillaryBuffer::new(&mut cmsg_space);
312 assert!(cmsg_buffer.push(rights));
313
314 sendmsg_wrapper(fd, bufs, &mut cmsg_buffer, SendFlags::empty())?
315 } else {
316 sendmsg_wrapper(fd, bufs, &mut Default::default(), SendFlags::empty())?
317 };
318
319 fds.clear();
321
322 Ok(res)
323}
324
325impl Stream for DefaultStream {
326 fn poll(&self, mode: PollMode) -> Result<()> {
327 use rustix::event::{poll, PollFd, PollFlags};
328 use rustix::io::Errno;
329
330 let mut poll_flags = PollFlags::empty();
331 if mode.readable() {
332 poll_flags |= PollFlags::IN;
333 }
334 if mode.writable() {
335 poll_flags |= PollFlags::OUT;
336 }
337 let fd = self.as_fd();
338 let mut poll_fds = [PollFd::from_borrowed_fd(fd, poll_flags)];
339 loop {
340 match poll(&mut poll_fds, None) {
341 Ok(_) => break,
342 Err(Errno::INTR) => {}
343 Err(e) => return Err(e.into()),
344 }
345 }
346 Ok(())
348 }
349
350 fn read(&self, buf: &mut [u8], fd_storage: &mut Vec<RawFdContainer>) -> Result<usize> {
351 #[cfg(unix)]
352 {
353 use rustix::io::Errno;
354 use rustix::net::{recvmsg, RecvAncillaryBuffer, RecvAncillaryMessage};
355 use std::io::IoSliceMut;
356 use std::mem::MaybeUninit;
357
358 let mut cmsg = [MaybeUninit::uninit(); 1024];
362 let mut iov = [IoSliceMut::new(buf)];
363 let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg);
364
365 let fd = self.as_fd();
366 let msg = loop {
367 match recvmsg(fd, &mut iov, &mut cmsg_buffer, recvmsg::flags()) {
368 Ok(msg) => break msg,
369 Err(Errno::INTR) => {}
371 Err(e) => return Err(e.into()),
372 }
373 };
374
375 let fds_received = cmsg_buffer
376 .drain()
377 .filter_map(|cmsg| match cmsg {
378 RecvAncillaryMessage::ScmRights(r) => Some(r),
379 _ => None,
380 })
381 .flatten();
382
383 let mut cloexec_error = Ok(());
384 fd_storage.extend(recvmsg::after_recvmsg(fds_received, &mut cloexec_error));
385 cloexec_error?;
386
387 Ok(msg.bytes)
388 }
389 #[cfg(not(unix))]
390 {
391 use std::io::Read;
392 let _ = fd_storage;
394 loop {
395 match (&mut &self.inner).read(buf) {
397 Ok(n) => return Ok(n),
398 Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {}
400 Err(e) => return Err(e),
401 }
402 }
403 }
404 }
405
406 fn write(&self, buf: &[u8], fds: &mut Vec<RawFdContainer>) -> Result<usize> {
407 #[cfg(unix)]
408 {
409 do_write(self, &[IoSlice::new(buf)], fds)
410 }
411 #[cfg(not(unix))]
412 {
413 use std::io::{Error, ErrorKind, Write};
414 if !fds.is_empty() {
415 return Err(Error::new(ErrorKind::Other, "FD passing is unsupported"));
416 }
417 loop {
418 match (&mut &self.inner).write(buf) {
420 Ok(n) => return Ok(n),
421 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
423 Err(e) => return Err(e),
424 }
425 }
426 }
427 }
428
429 fn write_vectored(&self, bufs: &[IoSlice<'_>], fds: &mut Vec<RawFdContainer>) -> Result<usize> {
430 #[cfg(unix)]
431 {
432 do_write(self, bufs, fds)
433 }
434 #[cfg(not(unix))]
435 {
436 use std::io::{Error, ErrorKind, Write};
437 if !fds.is_empty() {
438 return Err(Error::new(ErrorKind::Other, "FD passing is unsupported"));
439 }
440 loop {
441 match (&mut &self.inner).write_vectored(bufs) {
443 Ok(n) => return Ok(n),
444 Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
446 Err(e) => return Err(e),
447 }
448 }
449 }
450 }
451}
452
453#[cfg(any(
455 target_os = "android",
456 target_os = "dragonfly",
457 target_os = "freebsd",
458 target_os = "linux",
459 target_os = "netbsd",
460 target_os = "openbsd"
461))]
462mod recvmsg {
463 use super::RawFdContainer;
464 use rustix::net::RecvFlags;
465
466 pub(crate) fn flags() -> RecvFlags {
467 RecvFlags::CMSG_CLOEXEC
468 }
469
470 pub(crate) fn after_recvmsg<'a>(
471 fds: impl Iterator<Item = RawFdContainer> + 'a,
472 _cloexec_error: &'a mut Result<(), rustix::io::Errno>,
473 ) -> impl Iterator<Item = RawFdContainer> + 'a {
474 fds
475 }
476}
477
478#[cfg(all(
480 unix,
481 not(any(
482 target_os = "android",
483 target_os = "dragonfly",
484 target_os = "freebsd",
485 target_os = "linux",
486 target_os = "netbsd",
487 target_os = "openbsd"
488 ))
489))]
490mod recvmsg {
491 use super::RawFdContainer;
492 use rustix::io::{fcntl_getfd, fcntl_setfd, FdFlags};
493 use rustix::net::RecvFlags;
494
495 pub(crate) fn flags() -> RecvFlags {
496 RecvFlags::empty()
497 }
498
499 pub(crate) fn after_recvmsg<'a>(
500 fds: impl Iterator<Item = RawFdContainer> + 'a,
501 cloexec_error: &'a mut rustix::io::Result<()>,
502 ) -> impl Iterator<Item = RawFdContainer> + 'a {
503 fds.map(move |fd| {
504 if let Err(e) =
505 fcntl_getfd(&fd).and_then(|flags| fcntl_setfd(&fd, flags | FdFlags::CLOEXEC))
506 {
507 *cloexec_error = Err(e);
508 }
509 fd
510 })
511 }
512}
513
514mod peer_addr {
515 use super::{Family, PeerAddr};
516 use std::net::{Ipv4Addr, SocketAddr};
517
518 pub(super) fn local() -> PeerAddr {
520 let hostname = gethostname::gethostname()
521 .to_str()
522 .map_or_else(Vec::new, |s| s.as_bytes().to_vec());
523 (Family::LOCAL, hostname)
524 }
525
526 pub(super) fn tcp(addr: &SocketAddr) -> PeerAddr {
528 let ip = match addr {
529 SocketAddr::V4(addr) => *addr.ip(),
530 SocketAddr::V6(addr) => {
531 let ip = addr.ip();
532 if ip.is_loopback() {
533 Ipv4Addr::LOCALHOST
536 } else if let Some(ip) = ip.to_ipv4() {
537 ip
539 } else {
540 return (Family::INTERNET6, ip.octets().to_vec());
542 }
543 }
544 };
545
546 if ip.is_loopback() {
548 local()
549 } else {
550 (Family::INTERNET, ip.octets().to_vec())
551 }
552 }
553}