Skip to main content

compio_driver/sys/
unix_op.rs

1use std::{
2    ffi::CString,
3    io,
4    marker::PhantomPinned,
5    net::Shutdown,
6    os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd},
7    pin::Pin,
8};
9
10use compio_buf::{IntoInner, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
11#[cfg(not(gnulinux))]
12use libc::openat;
13#[cfg(gnulinux)]
14use libc::openat64 as openat;
15#[cfg(not(any(
16    all(target_os = "linux", not(target_env = "musl")),
17    target_os = "android",
18    target_os = "l4re",
19    target_os = "hurd"
20)))]
21use libc::{ftruncate as ftruncate64, off_t as off64_t};
22#[cfg(any(
23    all(target_os = "linux", not(target_env = "musl")),
24    target_os = "android",
25    target_os = "l4re",
26    target_os = "hurd"
27))]
28use libc::{ftruncate64, off64_t};
29use pin_project_lite::pin_project;
30use socket2::{SockAddr, SockAddrStorage, Socket as Socket2, socklen_t};
31
32use crate::{op::*, sys::aio::*, sys_slice::*, syscall};
33
34/// A special file descriptor that always refers to the current working
35/// directory. It represents [`AT_FDCWD`](libc::AT_FDCWD) in libc.
36pub struct CurrentDir;
37
38impl AsRawFd for CurrentDir {
39    fn as_raw_fd(&self) -> RawFd {
40        libc::AT_FDCWD
41    }
42}
43
44impl AsFd for CurrentDir {
45    fn as_fd(&self) -> BorrowedFd<'_> {
46        unsafe { BorrowedFd::borrow_raw(libc::AT_FDCWD) }
47    }
48}
49
50pin_project! {
51    /// Open or create a file with flags and mode.
52    pub struct OpenFile<S: AsFd> {
53        pub(crate) dirfd: S,
54        pub(crate) path: CString,
55        pub(crate) flags: i32,
56        pub(crate) mode: libc::mode_t,
57        pub(crate) opened_fd: Option<OwnedFd>,
58    }
59}
60
61impl<S: AsFd> OpenFile<S> {
62    /// Create [`OpenFile`].
63    pub fn new(dirfd: S, path: CString, flags: i32, mode: libc::mode_t) -> Self {
64        Self {
65            dirfd,
66            path,
67            flags,
68            mode,
69            opened_fd: None,
70        }
71    }
72
73    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
74        Ok(syscall!(openat(
75            self.dirfd.as_fd().as_raw_fd(),
76            self.path.as_ptr(),
77            self.flags | libc::O_CLOEXEC,
78            self.mode as libc::c_int
79        ))? as _)
80    }
81}
82
83impl<S: AsFd> IntoInner for OpenFile<S> {
84    type Inner = OwnedFd;
85
86    fn into_inner(self) -> Self::Inner {
87        self.opened_fd.expect("file not opened")
88    }
89}
90
91impl CloseFile {
92    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
93        Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
94    }
95}
96
97#[derive(Debug)]
98///  Truncates or extends the underlying file, updating the size of this file to
99/// become `size`.
100pub struct TruncateFile<S: AsFd> {
101    pub(crate) fd: S,
102    pub(crate) size: u64,
103}
104
105impl<S: AsFd> TruncateFile<S> {
106    /// Create [`TruncateFile`].
107    pub fn new(fd: S, size: u64) -> Self {
108        Self { fd, size }
109    }
110
111    pub(crate) fn call(&self) -> io::Result<usize> {
112        let size: off64_t = self
113            .size
114            .try_into()
115            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
116        crate::syscall!(ftruncate64(self.fd.as_fd().as_raw_fd(), size)).map(|v| v as _)
117    }
118}
119
120#[cfg(not(gnulinux))]
121pub use libc::stat as Stat;
122#[cfg(gnulinux)]
123pub use libc::stat64 as Stat;
124#[cfg(gnulinux)]
125pub(crate) use libc::statx as Statx;
126
127#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
128#[repr(C)]
129pub(crate) struct StatxTimestamp {
130    pub tv_sec: i64,
131    pub tv_nsec: u32,
132    pub __statx_timestamp_pad1: [i32; 1],
133}
134
135#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
136#[repr(C)]
137pub(crate) struct Statx {
138    pub stx_mask: u32,
139    pub stx_blksize: u32,
140    pub stx_attributes: u64,
141    pub stx_nlink: u32,
142    pub stx_uid: u32,
143    pub stx_gid: u32,
144    pub stx_mode: u16,
145    __statx_pad1: [u16; 1],
146    pub stx_ino: u64,
147    pub stx_size: u64,
148    pub stx_blocks: u64,
149    pub stx_attributes_mask: u64,
150    pub stx_atime: StatxTimestamp,
151    pub stx_btime: StatxTimestamp,
152    pub stx_ctime: StatxTimestamp,
153    pub stx_mtime: StatxTimestamp,
154    pub stx_rdev_major: u32,
155    pub stx_rdev_minor: u32,
156    pub stx_dev_major: u32,
157    pub stx_dev_minor: u32,
158    pub stx_mnt_id: u64,
159    pub stx_dio_mem_align: u32,
160    pub stx_dio_offset_align: u32,
161    __statx_pad3: [u64; 12],
162}
163
164#[cfg(target_os = "linux")]
165pub(crate) const fn statx_mask() -> u32 {
166    // Set mask to ensure all known fields are filled
167    // libc::STATX_ALL | libc::STATX_MNT_ID | libc::STATX_DIOALIGN
168    0x3FFF
169}
170
171#[cfg(target_os = "linux")]
172pub(crate) const fn statx_to_stat(statx: Statx) -> Stat {
173    let mut stat: Stat = unsafe { std::mem::zeroed() };
174    stat.st_dev = libc::makedev(statx.stx_dev_major, statx.stx_dev_minor) as _;
175    stat.st_ino = statx.stx_ino as _;
176    stat.st_nlink = statx.stx_nlink as _;
177    stat.st_mode = statx.stx_mode as _;
178    stat.st_uid = statx.stx_uid as _;
179    stat.st_gid = statx.stx_gid as _;
180    stat.st_rdev = libc::makedev(statx.stx_rdev_major, statx.stx_rdev_minor) as _;
181    stat.st_size = statx.stx_size as _;
182    stat.st_blksize = statx.stx_blksize as _;
183    stat.st_blocks = statx.stx_blocks as _;
184    stat.st_atime = statx.stx_atime.tv_sec as _;
185    stat.st_atime_nsec = statx.stx_atime.tv_nsec as _;
186    stat.st_mtime = statx.stx_mtime.tv_sec as _;
187    stat.st_mtime_nsec = statx.stx_mtime.tv_nsec as _;
188    stat.st_ctime = statx.stx_btime.tv_sec as _;
189    stat.st_ctime_nsec = statx.stx_btime.tv_nsec as _;
190    stat
191}
192
193#[cfg(all(target_os = "linux", not(target_env = "gnu")))]
194pub(crate) const fn stat_to_statx(stat: Stat) -> Statx {
195    let mut statx: Statx = unsafe { std::mem::zeroed() };
196    statx.stx_dev_major = libc::major(stat.st_dev as _) as _;
197    statx.stx_dev_minor = libc::minor(stat.st_dev as _) as _;
198    statx.stx_ino = stat.st_ino as _;
199    statx.stx_nlink = stat.st_nlink as _;
200    statx.stx_mode = stat.st_mode as _;
201    statx.stx_uid = stat.st_uid as _;
202    statx.stx_gid = stat.st_gid as _;
203    statx.stx_rdev_major = libc::major(stat.st_rdev as _) as _;
204    statx.stx_rdev_minor = libc::minor(stat.st_rdev as _) as _;
205    statx.stx_size = stat.st_size as _;
206    statx.stx_blksize = stat.st_blksize as _;
207    statx.stx_blocks = stat.st_blocks as _;
208    statx.stx_atime.tv_sec = stat.st_atime as _;
209    statx.stx_atime.tv_nsec = stat.st_atime_nsec as _;
210    statx.stx_mtime.tv_sec = stat.st_mtime as _;
211    statx.stx_mtime.tv_nsec = stat.st_mtime_nsec as _;
212    statx.stx_btime.tv_sec = stat.st_ctime as _;
213    statx.stx_btime.tv_nsec = stat.st_ctime_nsec as _;
214    statx
215}
216
217pin_project! {
218    /// Read a file at specified position into vectored buffer.
219    pub struct ReadVectoredAt<T: IoVectoredBufMut, S> {
220        pub(crate) fd: S,
221        pub(crate) offset: u64,
222        #[pin]
223        pub(crate) buffer: T,
224        pub(crate) slices: Vec<SysSlice>,
225        pub(crate) aiocb: aiocb,
226        _p: PhantomPinned,
227    }
228}
229
230impl<T: IoVectoredBufMut, S> ReadVectoredAt<T, S> {
231    /// Create [`ReadVectoredAt`].
232    pub fn new(fd: S, offset: u64, buffer: T) -> Self {
233        Self {
234            fd,
235            offset,
236            buffer,
237            slices: vec![],
238            aiocb: new_aiocb(),
239            _p: PhantomPinned,
240        }
241    }
242}
243
244impl<T: IoVectoredBufMut, S> IntoInner for ReadVectoredAt<T, S> {
245    type Inner = T;
246
247    fn into_inner(self) -> Self::Inner {
248        self.buffer
249    }
250}
251
252pin_project! {
253    /// Write a file at specified position from vectored buffer.
254    pub struct WriteVectoredAt<T: IoVectoredBuf, S> {
255        pub(crate) fd: S,
256        pub(crate) offset: u64,
257        #[pin]
258        pub(crate) buffer: T,
259        pub(crate) slices: Vec<SysSlice>,
260        pub(crate) aiocb: aiocb,
261        _p: PhantomPinned,
262    }
263}
264impl<T: IoVectoredBuf, S> WriteVectoredAt<T, S> {
265    /// Create [`WriteVectoredAt`]
266    pub fn new(fd: S, offset: u64, buffer: T) -> Self {
267        Self {
268            fd,
269            offset,
270            buffer,
271            slices: vec![],
272            aiocb: new_aiocb(),
273            _p: PhantomPinned,
274        }
275    }
276}
277
278impl<T: IoVectoredBuf, S> IntoInner for WriteVectoredAt<T, S> {
279    type Inner = T;
280
281    fn into_inner(self) -> Self::Inner {
282        self.buffer
283    }
284}
285
286pin_project! {
287    /// Receive a file into vectored buffer.
288    pub struct ReadVectored<T: IoVectoredBufMut, S> {
289        pub(crate) fd: S,
290        #[pin]
291        pub(crate) buffer: T,
292        pub(crate) slices: Vec<SysSlice>,
293        _p: PhantomPinned,
294    }
295}
296
297impl<T: IoVectoredBufMut, S> ReadVectored<T, S> {
298    /// Create [`ReadVectored`].
299    pub fn new(fd: S, buffer: T) -> Self {
300        Self {
301            fd,
302            buffer,
303            slices: vec![],
304            _p: PhantomPinned,
305        }
306    }
307}
308
309impl<T: IoVectoredBufMut, S> IntoInner for ReadVectored<T, S> {
310    type Inner = T;
311
312    fn into_inner(self) -> Self::Inner {
313        self.buffer
314    }
315}
316
317pin_project! {
318    /// Send to a file from vectored buffer.
319    pub struct WriteVectored<T: IoVectoredBuf, S> {
320        pub(crate) fd: S,
321        #[pin]
322        pub(crate) buffer: T,
323        pub(crate) slices: Vec<SysSlice>,
324        _p: PhantomPinned,
325    }
326}
327
328impl<T: IoVectoredBuf, S> WriteVectored<T, S> {
329    /// Create [`WriteVectored`].
330    pub fn new(fd: S, buffer: T) -> Self {
331        Self {
332            fd,
333            buffer,
334            slices: vec![],
335            _p: PhantomPinned,
336        }
337    }
338}
339
340impl<T: IoVectoredBuf, S> IntoInner for WriteVectored<T, S> {
341    type Inner = T;
342
343    fn into_inner(self) -> Self::Inner {
344        self.buffer
345    }
346}
347
348/// Remove file or directory.
349pub struct Unlink<S: AsFd> {
350    pub(crate) dirfd: S,
351    pub(crate) path: CString,
352    pub(crate) dir: bool,
353}
354
355impl<S: AsFd> Unlink<S> {
356    /// Create [`Unlink`].
357    pub fn new(dirfd: S, path: CString, dir: bool) -> Self {
358        Self { dirfd, path, dir }
359    }
360
361    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
362        Ok(syscall!(libc::unlinkat(
363            self.dirfd.as_fd().as_raw_fd(),
364            self.path.as_ptr(),
365            if self.dir { libc::AT_REMOVEDIR } else { 0 }
366        ))? as _)
367    }
368}
369
370/// Create a directory.
371pub struct CreateDir<S: AsFd> {
372    pub(crate) dirfd: S,
373    pub(crate) path: CString,
374    pub(crate) mode: libc::mode_t,
375}
376
377impl<S: AsFd> CreateDir<S> {
378    /// Create [`CreateDir`].
379    pub fn new(dirfd: S, path: CString, mode: libc::mode_t) -> Self {
380        Self { dirfd, path, mode }
381    }
382
383    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
384        Ok(syscall!(libc::mkdirat(
385            self.dirfd.as_fd().as_raw_fd(),
386            self.path.as_ptr(),
387            self.mode
388        ))? as _)
389    }
390}
391
392/// Rename a file or directory.
393pub struct Rename<S1: AsFd, S2: AsFd> {
394    pub(crate) old_dirfd: S1,
395    pub(crate) old_path: CString,
396    pub(crate) new_dirfd: S2,
397    pub(crate) new_path: CString,
398}
399
400impl<S1: AsFd, S2: AsFd> Rename<S1, S2> {
401    /// Create [`Rename`].
402    pub fn new(old_dirfd: S1, old_path: CString, new_dirfd: S2, new_path: CString) -> Self {
403        Self {
404            old_dirfd,
405            old_path,
406            new_dirfd,
407            new_path,
408        }
409    }
410
411    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
412        Ok(syscall!(libc::renameat(
413            self.old_dirfd.as_fd().as_raw_fd(),
414            self.old_path.as_ptr(),
415            self.new_dirfd.as_fd().as_raw_fd(),
416            self.new_path.as_ptr()
417        ))? as _)
418    }
419}
420
421/// Create a symlink.
422pub struct Symlink<S: AsFd> {
423    pub(crate) source: CString,
424    pub(crate) dirfd: S,
425    pub(crate) target: CString,
426}
427
428impl<S: AsFd> Symlink<S> {
429    /// Create [`Symlink`]. `target` is a symlink to `source`.
430    pub fn new(source: CString, dirfd: S, target: CString) -> Self {
431        Self {
432            source,
433            dirfd,
434            target,
435        }
436    }
437
438    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
439        Ok(syscall!(libc::symlinkat(
440            self.source.as_ptr(),
441            self.dirfd.as_fd().as_raw_fd(),
442            self.target.as_ptr()
443        ))? as _)
444    }
445}
446
447/// Create a hard link.
448pub struct HardLink<S1: AsFd, S2: AsFd> {
449    pub(crate) source_dirfd: S1,
450    pub(crate) source: CString,
451    pub(crate) target_dirfd: S2,
452    pub(crate) target: CString,
453}
454
455impl<S1: AsFd, S2: AsFd> HardLink<S1, S2> {
456    /// Create [`HardLink`]. `target` is a hard link to `source`.
457    pub fn new(source_dirfd: S1, source: CString, target_dirfd: S2, target: CString) -> Self {
458        Self {
459            source_dirfd,
460            source,
461            target_dirfd,
462            target,
463        }
464    }
465
466    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
467        Ok(syscall!(libc::linkat(
468            self.source_dirfd.as_fd().as_raw_fd(),
469            self.source.as_ptr(),
470            self.target_dirfd.as_fd().as_raw_fd(),
471            self.target.as_ptr(),
472            0
473        ))? as _)
474    }
475}
476
477pin_project! {
478    /// Create a socket.
479    pub struct CreateSocket {
480        pub(crate) domain: i32,
481        pub(crate) socket_type: i32,
482        pub(crate) protocol: i32,
483        pub(crate) opened_fd: Option<Socket2>,
484    }
485}
486
487impl CreateSocket {
488    /// Create [`CreateSocket`].
489    pub fn new(domain: i32, socket_type: i32, protocol: i32) -> Self {
490        Self {
491            domain,
492            socket_type,
493            protocol,
494            opened_fd: None,
495        }
496    }
497}
498
499impl IntoInner for CreateSocket {
500    type Inner = Socket2;
501
502    fn into_inner(self) -> Self::Inner {
503        self.opened_fd.expect("socket not created")
504    }
505}
506
507impl<S: AsFd> ShutdownSocket<S> {
508    pub(crate) fn how(&self) -> i32 {
509        match self.how {
510            Shutdown::Write => libc::SHUT_WR,
511            Shutdown::Read => libc::SHUT_RD,
512            Shutdown::Both => libc::SHUT_RDWR,
513        }
514    }
515
516    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
517        Ok(syscall!(libc::shutdown(self.fd.as_fd().as_raw_fd(), self.how()))? as _)
518    }
519}
520
521impl CloseSocket {
522    pub(crate) fn call(self: Pin<&mut Self>) -> io::Result<usize> {
523        Ok(syscall!(libc::close(self.fd.as_fd().as_raw_fd()))? as _)
524    }
525}
526
527pin_project! {
528    /// Accept a connection.
529    pub struct Accept<S> {
530        pub(crate) fd: S,
531        pub(crate) buffer: SockAddrStorage,
532        pub(crate) addr_len: socklen_t,
533        pub(crate) accepted_fd: Option<Socket2>,
534        _p: PhantomPinned,
535    }
536}
537
538impl<S> Accept<S> {
539    /// Create [`Accept`].
540    pub fn new(fd: S) -> Self {
541        let buffer = SockAddrStorage::zeroed();
542        let addr_len = buffer.size_of();
543        Self {
544            fd,
545            buffer,
546            addr_len,
547            accepted_fd: None,
548            _p: PhantomPinned,
549        }
550    }
551}
552
553impl<S> IntoInner for Accept<S> {
554    type Inner = (Socket2, SockAddr);
555
556    fn into_inner(mut self) -> Self::Inner {
557        let socket = self.accepted_fd.take().expect("socket not accepted");
558        (socket, unsafe { SockAddr::new(self.buffer, self.addr_len) })
559    }
560}
561
562pin_project! {
563    /// Receive data from remote.
564    ///
565    /// It is only used for socket operations. If you want to read from a pipe, use
566    /// [`Read`].
567    pub struct Recv<T: IoBufMut, S> {
568        pub(crate) fd: S,
569        #[pin]
570        pub(crate) buffer: T,
571        pub(crate) flags: i32,
572        _p: PhantomPinned,
573    }
574}
575
576impl<T: IoBufMut, S> Recv<T, S> {
577    /// Create [`Recv`].
578    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
579        Self {
580            fd,
581            buffer,
582            flags,
583            _p: PhantomPinned,
584        }
585    }
586}
587
588impl<T: IoBufMut, S> IntoInner for Recv<T, S> {
589    type Inner = T;
590
591    fn into_inner(self) -> Self::Inner {
592        self.buffer
593    }
594}
595
596pin_project! {
597    /// Send data to remote.
598    ///
599    /// It is only used for socket operations. If you want to write to a pipe, use
600    /// [`Write`].
601    pub struct Send<T: IoBuf, S> {
602        pub(crate) fd: S,
603        #[pin]
604        pub(crate) buffer: T,
605        pub(crate) flags: i32,
606        _p: PhantomPinned,
607    }
608}
609
610impl<T: IoBuf, S> Send<T, S> {
611    /// Create [`Send`].
612    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
613        Self {
614            fd,
615            buffer,
616            flags,
617            _p: PhantomPinned,
618        }
619    }
620}
621
622impl<T: IoBuf, S> IntoInner for Send<T, S> {
623    type Inner = T;
624
625    fn into_inner(self) -> Self::Inner {
626        self.buffer
627    }
628}
629
630pin_project! {
631    /// Receive data from remote into vectored buffer.
632    pub struct RecvVectored<T: IoVectoredBufMut, S> {
633        pub(crate) msg: libc::msghdr,
634        pub(crate) fd: S,
635        #[pin]
636        pub(crate) buffer: T,
637        pub(crate) slices: Vec<SysSlice>,
638        pub(crate) flags: i32,
639        _p: PhantomPinned,
640    }
641}
642
643impl<T: IoVectoredBufMut, S> RecvVectored<T, S> {
644    /// Create [`RecvVectored`].
645    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
646        Self {
647            msg: unsafe { std::mem::zeroed() },
648            fd,
649            buffer,
650            slices: vec![],
651            flags,
652            _p: PhantomPinned,
653        }
654    }
655
656    pub(crate) fn set_msg(self: Pin<&mut Self>) {
657        let this = self.project();
658
659        *this.slices = this.buffer.sys_slices_mut();
660        this.msg.msg_iov = this.slices.as_mut_ptr() as _;
661        this.msg.msg_iovlen = this.slices.len() as _;
662    }
663}
664
665impl<T: IoVectoredBufMut, S> IntoInner for RecvVectored<T, S> {
666    type Inner = T;
667
668    fn into_inner(self) -> Self::Inner {
669        self.buffer
670    }
671}
672
673pin_project! {
674    /// Send data to remote from vectored buffer.
675    pub struct SendVectored<T: IoVectoredBuf, S> {
676        pub(crate) msg: libc::msghdr,
677        pub(crate) fd: S,
678        #[pin]
679        pub(crate) buffer: T,
680        pub(crate) slices: Vec<SysSlice>,
681        pub(crate) flags: i32,
682        _p: PhantomPinned,
683    }
684}
685
686impl<T: IoVectoredBuf, S> SendVectored<T, S> {
687    /// Create [`SendVectored`].
688    pub fn new(fd: S, buffer: T, flags: i32) -> Self {
689        Self {
690            msg: unsafe { std::mem::zeroed() },
691            fd,
692            buffer,
693            slices: vec![],
694            flags,
695            _p: PhantomPinned,
696        }
697    }
698
699    pub(crate) fn set_msg(self: Pin<&mut Self>) {
700        let this = self.project();
701
702        *this.slices = this.buffer.as_ref().sys_slices();
703        this.msg.msg_iov = this.slices.as_mut_ptr() as _;
704        this.msg.msg_iovlen = this.slices.len() as _;
705    }
706}
707
708impl<T: IoVectoredBuf, S> IntoInner for SendVectored<T, S> {
709    type Inner = T;
710
711    fn into_inner(self) -> Self::Inner {
712        self.buffer
713    }
714}
715
716pin_project! {
717    /// Receive data and source address with ancillary data into vectored buffer.
718    pub struct RecvMsg<T: IoVectoredBufMut, C: IoBufMut, S> {
719        pub(crate) msg: libc::msghdr,
720        pub(crate) addr: SockAddrStorage,
721        pub(crate) fd: S,
722        #[pin]
723        pub(crate) buffer: T,
724        pub(crate) control: C,
725        pub(crate) slices: Vec<SysSlice>,
726        pub(crate) flags: i32,
727        _p: PhantomPinned,
728    }
729}
730
731impl<T: IoVectoredBufMut, C: IoBufMut, S> RecvMsg<T, C, S> {
732    /// Create [`RecvMsg`].
733    ///
734    /// # Panics
735    ///
736    /// This function will panic if the control message buffer is misaligned.
737    pub fn new(fd: S, buffer: T, control: C, flags: i32) -> Self {
738        assert!(
739            control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
740            "misaligned control message buffer"
741        );
742        Self {
743            msg: unsafe { std::mem::zeroed() },
744            addr: SockAddrStorage::zeroed(),
745            fd,
746            buffer,
747            control,
748            slices: vec![],
749            flags,
750            _p: PhantomPinned,
751        }
752    }
753
754    pub(crate) fn set_msg(self: Pin<&mut Self>) {
755        let this = self.project();
756        *this.slices = this.buffer.sys_slices_mut();
757
758        this.msg.msg_name = this.addr as *mut _ as _;
759        this.msg.msg_namelen = this.addr.size_of() as _;
760        this.msg.msg_iov = this.slices.as_mut_ptr() as _;
761        this.msg.msg_iovlen = this.slices.len() as _;
762        this.msg.msg_control = this.control.buf_mut_ptr() as _;
763        this.msg.msg_controllen = this.control.buf_capacity() as _;
764    }
765}
766
767impl<T: IoVectoredBufMut, C: IoBufMut, S> IntoInner for RecvMsg<T, C, S> {
768    type Inner = ((T, C), SockAddrStorage, socklen_t, usize);
769
770    fn into_inner(self) -> Self::Inner {
771        (
772            (self.buffer, self.control),
773            self.addr,
774            self.msg.msg_namelen,
775            self.msg.msg_controllen as _,
776        )
777    }
778}
779
780pin_project! {
781    /// Send data to specified address accompanied by ancillary data from vectored
782    /// buffer.
783    pub struct SendMsg<T: IoVectoredBuf, C: IoBuf, S> {
784        pub(crate) msg: libc::msghdr,
785        pub(crate) fd: S,
786        #[pin]
787        pub(crate) buffer: T,
788        #[pin]
789        pub(crate) control: C,
790        pub(crate) addr: Option<SockAddr>,
791        pub(crate) slices: Vec<SysSlice>,
792        pub(crate) flags: i32,
793        _p: PhantomPinned,
794    }
795}
796
797impl<T: IoVectoredBuf, C: IoBuf, S> SendMsg<T, C, S> {
798    /// Create [`SendMsg`].
799    ///
800    /// # Panics
801    ///
802    /// This function will panic if the control message buffer is misaligned.
803    pub fn new(fd: S, buffer: T, control: C, addr: Option<SockAddr>, flags: i32) -> Self {
804        assert!(
805            control.buf_ptr().cast::<libc::cmsghdr>().is_aligned(),
806            "misaligned control message buffer"
807        );
808        Self {
809            msg: unsafe { std::mem::zeroed() },
810            fd,
811            buffer,
812            control,
813            addr,
814            slices: vec![],
815            flags,
816            _p: PhantomPinned,
817        }
818    }
819
820    pub(crate) fn set_msg(self: Pin<&mut Self>) {
821        let this = self.project();
822        *this.slices = this.buffer.as_ref().sys_slices();
823        match this.addr.as_ref() {
824            Some(addr) => {
825                this.msg.msg_name = addr.as_ptr() as _;
826                this.msg.msg_namelen = addr.len();
827            }
828            None => {
829                this.msg.msg_name = std::ptr::null_mut();
830                this.msg.msg_namelen = 0;
831            }
832        }
833        this.msg.msg_iov = this.slices.as_ptr() as _;
834        this.msg.msg_iovlen = this.slices.len() as _;
835        this.msg.msg_control = this.control.buf_ptr() as _;
836        this.msg.msg_controllen = this.control.buf_len() as _;
837    }
838}
839
840impl<T: IoVectoredBuf, C: IoBuf, S> IntoInner for SendMsg<T, C, S> {
841    type Inner = (T, C);
842
843    fn into_inner(self) -> Self::Inner {
844        (self.buffer, self.control)
845    }
846}
847
848/// The interest to poll a file descriptor.
849#[derive(Debug, Clone, Copy, PartialEq, Eq)]
850pub enum Interest {
851    /// Represents a read operation.
852    Readable,
853    /// Represents a write operation.
854    Writable,
855}
856
857/// Poll a file descriptor for specified [`Interest`].
858pub struct PollOnce<S> {
859    pub(crate) fd: S,
860    pub(crate) interest: Interest,
861}
862
863impl<S> PollOnce<S> {
864    /// Create [`PollOnce`].
865    pub fn new(fd: S, interest: Interest) -> Self {
866        Self { fd, interest }
867    }
868}
869
870/// Splice data between two file descriptors.
871#[cfg(linux_all)]
872pub struct Splice<S1, S2> {
873    pub(crate) fd_in: S1,
874    pub(crate) offset_in: i64,
875    pub(crate) fd_out: S2,
876    pub(crate) offset_out: i64,
877    pub(crate) len: usize,
878    pub(crate) flags: u32,
879}
880
881#[cfg(linux_all)]
882impl<S1, S2> Splice<S1, S2> {
883    /// Create [`Splice`].
884    ///
885    /// `offset_in` and `offset_out` specify the offset to read from and write
886    /// to. Use `-1` for pipe ends or to use/update the current file
887    /// position.
888    pub fn new(
889        fd_in: S1,
890        offset_in: i64,
891        fd_out: S2,
892        offset_out: i64,
893        len: usize,
894        flags: u32,
895    ) -> Self {
896        Self {
897            fd_in,
898            offset_in,
899            fd_out,
900            offset_out,
901            len,
902            flags,
903        }
904    }
905}