Skip to main content

net_io/
handoff.rs

1//! Listener hand-off between processes, and the owned listener handle that
2//! inheritance, hand-off, and `Server::release_listeners` produce.
3//!
4//! `send_listeners` and `recv_listeners` are Unix (feature `local`); Windows
5//! follows in `0.5.0`. `ListenerHandle` and the error type exist in every build.
6//!
7//! Manifest, version 1 (big-endian integers):
8//!
9//! ```text
10//!  "NIOH" | version 1 | count | total length (u16, all bytes including the CRC)
11//!  per listener: kind (1 TCP, 2 Unix) | name length (at most 64) | name
12//!                | address length (u16) | address (TCP: family 4 or 6, IP, port;
13//!                  Unix: the path bytes)
14//!  CRC32C of everything before it (u32)
15//! ```
16
17// The manifest is read and written only by the Unix hand-off functions.
18#![cfg_attr(not(all(unix, feature = "local")), allow(dead_code))]
19
20use std::fmt;
21use std::io;
22#[cfg(unix)]
23use std::sync::Arc;
24
25#[cfg(unix)]
26use crate::info::UnixPath;
27use crate::info::{Endpoint, Transport};
28use crate::sys::{self, KindError, SockKind};
29
30/// Why a listener hand-off failed. Nothing is adopted on any error.
31///
32/// ```
33/// assert_eq!(net_io::HandoffError::BadChecksum.to_string(), "the hand-off manifest checksum does not match");
34/// ```
35#[non_exhaustive]
36#[derive(Debug)]
37pub enum HandoffError {
38    /// The sender is not the expected process or user.
39    PeerMismatch,
40    /// The control message was truncated.
41    Truncated,
42    /// The descriptor count does not match the manifest.
43    CountMismatch,
44    /// The manifest does not start with the expected magic.
45    BadMagic,
46    /// The manifest version is unknown.
47    BadVersion,
48    /// The manifest checksum does not match.
49    BadChecksum,
50    /// More listeners than one hand-off carries.
51    TooMany {
52        /// The maximum.
53        max: u8,
54    },
55    /// A received socket failed verification.
56    VerifyFailed {
57        /// Its position in the manifest.
58        index: u8,
59        /// Which check failed.
60        why: &'static str,
61    },
62    /// The hand-off did not finish in time.
63    Timeout,
64    /// An OS call failed.
65    Os(io::Error),
66}
67
68impl fmt::Display for HandoffError {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        match self {
71            HandoffError::PeerMismatch => {
72                f.write_str("the hand-off sender is not the expected process or user")
73            }
74            HandoffError::Truncated => f.write_str("the hand-off message was truncated"),
75            HandoffError::CountMismatch => {
76                f.write_str("the descriptor count does not match the manifest")
77            }
78            HandoffError::BadMagic => f.write_str("not a hand-off manifest"),
79            HandoffError::BadVersion => f.write_str("unknown hand-off manifest version"),
80            HandoffError::BadChecksum => {
81                f.write_str("the hand-off manifest checksum does not match")
82            }
83            HandoffError::TooMany { max } => write!(f, "more than {max} listeners in one hand-off"),
84            HandoffError::VerifyFailed { index, why } => {
85                write!(f, "received listener {index} failed: {why}")
86            }
87            HandoffError::Timeout => f.write_str("the hand-off did not finish in time"),
88            HandoffError::Os(e) => write!(f, "{e}"),
89        }
90    }
91}
92
93impl std::error::Error for HandoffError {
94    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
95        match self {
96            HandoffError::Os(e) => Some(e),
97            _ => None,
98        }
99    }
100}
101
102/// An owned listening socket with what is known about it: its kind, an
103/// optional name (up to 64 bytes), and its local endpoint. Dropping it closes
104/// the socket. Made by [`crate::systemd`], hand-off, and
105/// `Server::release_listeners`; used by `ListenerSpec::adopt`.
106pub struct ListenerHandle {
107    kind: Transport,
108    name: Option<String>,
109    local: Endpoint,
110    sock: sys::OwnedSock,
111}
112
113impl ListenerHandle {
114    /// Verifies `sock` (a listening stream socket of a family net-io serves) and
115    /// records its endpoint.
116    pub(crate) fn verified(
117        sock: sys::OwnedSock,
118        name: Option<String>,
119    ) -> Result<ListenerHandle, KindError> {
120        let kind = sys::listener_kind(sys::AsSock::sock(&sock))?;
121        let (kind, local) = endpoint_of(kind)?;
122        Ok(ListenerHandle {
123            kind,
124            name,
125            local,
126            sock,
127        })
128    }
129
130    pub(crate) fn new(
131        kind: Transport,
132        name: Option<String>,
133        local: Endpoint,
134        sock: sys::OwnedSock,
135    ) -> ListenerHandle {
136        ListenerHandle {
137            kind,
138            name,
139            local,
140            sock,
141        }
142    }
143
144    pub(crate) fn into_sock(self) -> sys::OwnedSock {
145        self.sock
146    }
147
148    /// TCP or Unix.
149    #[must_use]
150    pub fn kind(&self) -> Transport {
151        self.kind
152    }
153
154    /// The name it was given (systemd's `LISTEN_FDNAMES`, a listener's name).
155    #[must_use]
156    pub fn name(&self) -> Option<&str> {
157        self.name.as_deref()
158    }
159
160    /// The address it is bound to.
161    #[must_use]
162    pub fn local(&self) -> &Endpoint {
163        &self.local
164    }
165}
166
167/// The transport and endpoint of a verified socket.
168fn endpoint_of(kind: SockKind) -> Result<(Transport, Endpoint), KindError> {
169    match kind {
170        SockKind::Tcp(a) => Ok((Transport::Tcp, Endpoint::Ip(a))),
171        #[cfg(unix)]
172        SockKind::Unix(path) => {
173            if !cfg!(feature = "local") {
174                return Err(KindError::WrongKind);
175            }
176            let local = UnixPath::new(&path)
177                .filter(|_| !path.is_empty())
178                .map_or(Endpoint::Unnamed, |p| Endpoint::Unix(Arc::new(p)));
179            Ok((Transport::Unix, local))
180        }
181    }
182}
183
184impl fmt::Debug for ListenerHandle {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        f.debug_struct("ListenerHandle")
187            .field("kind", &self.kind)
188            .field("name", &self.name)
189            .field("local", &self.local)
190            .finish()
191    }
192}
193
194#[cfg(unix)]
195impl std::os::fd::AsFd for ListenerHandle {
196    fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
197        self.sock.as_fd()
198    }
199}
200
201#[cfg(windows)]
202impl std::os::windows::io::AsSocket for ListenerHandle {
203    fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
204        self.sock.as_socket()
205    }
206}
207
208/// Whom `recv_listeners` accepts listeners from. `uid: None` means this
209/// process's own effective user id; `pid: None` accepts any process of that user.
210///
211/// ```
212/// let only_parent = net_io::HandoffPeer { uid: None, pid: Some(1234) };
213/// # let _ = only_parent;
214/// ```
215#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
216pub struct HandoffPeer {
217    /// The sender's user id (`None`: ours).
218    pub uid: Option<u32>,
219    /// The sender's process id (`None`: any).
220    pub pid: Option<u32>,
221}
222
223const MAGIC: [u8; 4] = *b"NIOH";
224const VERSION: u8 = 1;
225const HEADER: usize = 8;
226/// The most listeners one hand-off carries (one `SCM_RIGHTS` message).
227const MAX_LISTENERS: usize = 64;
228/// The longest name carried; longer names are cut at a character boundary.
229const MAX_NAME: usize = 64;
230
231/// One listener as the manifest describes it.
232#[derive(Clone, Debug, PartialEq, Eq)]
233struct Record {
234    kind: SockKind,
235    name: Option<String>,
236}
237
238/// Encodes the manifest for `records`.
239fn encode(records: &[Record]) -> Vec<u8> {
240    let mut out = Vec::with_capacity(HEADER + records.len() * 96 + 4);
241    out.extend_from_slice(&MAGIC);
242    out.push(VERSION);
243    out.push(records.len() as u8);
244    out.extend_from_slice(&[0, 0]); // total length, filled in below
245    for r in records {
246        let mut name = r.name.as_deref().unwrap_or("");
247        if name.len() > MAX_NAME {
248            let mut cut = MAX_NAME;
249            while !name.is_char_boundary(cut) {
250                cut -= 1;
251            }
252            name = &name[..cut];
253        }
254        let mut addr = Vec::with_capacity(32);
255        let kind = match &r.kind {
256            SockKind::Tcp(a) => {
257                match a.ip() {
258                    std::net::IpAddr::V4(ip) => {
259                        addr.push(4);
260                        addr.extend_from_slice(&ip.octets());
261                    }
262                    std::net::IpAddr::V6(ip) => {
263                        addr.push(6);
264                        addr.extend_from_slice(&ip.octets());
265                    }
266                }
267                addr.extend_from_slice(&a.port().to_be_bytes());
268                1u8
269            }
270            #[cfg(unix)]
271            SockKind::Unix(path) => {
272                addr.extend_from_slice(path);
273                2u8
274            }
275        };
276        out.push(kind);
277        out.push(name.len() as u8);
278        out.extend_from_slice(name.as_bytes());
279        out.extend_from_slice(&(addr.len() as u16).to_be_bytes());
280        out.extend_from_slice(&addr);
281    }
282    let total = (out.len() + 4) as u16;
283    out[6..8].copy_from_slice(&total.to_be_bytes());
284    let mut crc = crate::crc32c::Crc32c::new();
285    crc.update(&out);
286    out.extend_from_slice(&crc.finish().to_be_bytes());
287    out
288}
289
290/// Checks the header: magic, version, count, total length.
291fn parse_header(h: &[u8; HEADER]) -> Result<(usize, usize), HandoffError> {
292    if h[..4] != MAGIC {
293        return Err(HandoffError::BadMagic);
294    }
295    if h[4] != VERSION {
296        return Err(HandoffError::BadVersion);
297    }
298    let count = usize::from(h[5]);
299    if count > MAX_LISTENERS {
300        return Err(HandoffError::TooMany {
301            max: MAX_LISTENERS as u8,
302        });
303    }
304    let total = usize::from(u16::from_be_bytes([h[6], h[7]]));
305    if total < HEADER + 4 {
306        return Err(HandoffError::Truncated);
307    }
308    Ok((count, total))
309}
310
311/// Parses a whole manifest (header included).
312fn decode(bytes: &[u8]) -> Result<Vec<Record>, HandoffError> {
313    let header: &[u8; HEADER] = bytes
314        .get(..HEADER)
315        .and_then(|h| h.try_into().ok())
316        .ok_or(HandoffError::Truncated)?;
317    let (count, total) = parse_header(header)?;
318    if bytes.len() != total {
319        return Err(HandoffError::Truncated);
320    }
321    let (body, sum) = bytes.split_at(total - 4);
322    let mut crc = crate::crc32c::Crc32c::new();
323    crc.update(body);
324    if crc.finish().to_be_bytes() != sum {
325        return Err(HandoffError::BadChecksum);
326    }
327    let mut at = HEADER;
328    let mut take = |n: usize| -> Result<&[u8], HandoffError> {
329        let s = body.get(at..at + n).ok_or(HandoffError::Truncated)?;
330        at += n;
331        Ok(s)
332    };
333    let mut records = Vec::with_capacity(count);
334    for i in 0..count {
335        let bad = |why| HandoffError::VerifyFailed {
336            index: i as u8,
337            why,
338        };
339        let kind = take(1)?[0];
340        let name_len = usize::from(take(1)?[0]);
341        if name_len > MAX_NAME {
342            return Err(bad("name longer than 64 bytes"));
343        }
344        let name = std::str::from_utf8(take(name_len)?)
345            .map_err(|_| bad("name is not UTF-8"))?
346            .to_owned();
347        let addr_len = take(2)?;
348        let addr_len = usize::from(u16::from_be_bytes([addr_len[0], addr_len[1]]));
349        let addr = take(addr_len)?;
350        let kind = match (kind, addr) {
351            (1, [4, a, b, c, d, p0, p1]) => SockKind::Tcp(std::net::SocketAddr::from((
352                [*a, *b, *c, *d],
353                u16::from_be_bytes([*p0, *p1]),
354            ))),
355            (1, [6, rest @ ..]) if rest.len() == 18 => {
356                let mut ip = [0u8; 16];
357                ip.copy_from_slice(&rest[..16]);
358                SockKind::Tcp(std::net::SocketAddr::from((
359                    ip,
360                    u16::from_be_bytes([rest[16], rest[17]]),
361                )))
362            }
363            #[cfg(unix)]
364            (2, path) => SockKind::Unix(path.to_vec()),
365            _ => return Err(bad("unknown kind or malformed address")),
366        };
367        records.push(Record {
368            kind,
369            name: (!name.is_empty()).then_some(name),
370        });
371    }
372    if at != body.len() {
373        return Err(HandoffError::Truncated);
374    }
375    Ok(records)
376}
377
378/// The fuzz target's entry: decoding never panics, and an accepted manifest
379/// encodes back to the same bytes.
380#[cfg(fuzzing)]
381pub(crate) fn fuzz_manifest(data: &[u8]) {
382    if let Ok(records) = decode(data) {
383        assert_eq!(encode(&records), data);
384    }
385}
386
387/// Sends `listeners` over `channel` in one message: the manifest and every
388/// socket (`SCM_RIGHTS`). The listeners stay open here; the receiver gets its
389/// own copies. At most 64.
390///
391/// # Errors
392///
393/// `TooMany`, `Timeout`, `Os`.
394#[cfg(all(unix, feature = "local"))]
395pub fn send_listeners(
396    channel: &mut crate::local::UnixConnection,
397    listeners: &[&ListenerHandle],
398) -> Result<(), HandoffError> {
399    use std::os::fd::AsFd;
400    if listeners.len() > MAX_LISTENERS {
401        return Err(HandoffError::TooMany {
402            max: MAX_LISTENERS as u8,
403        });
404    }
405    let mut records = Vec::with_capacity(listeners.len());
406    for (i, l) in listeners.iter().enumerate() {
407        let kind = sys::listener_kind(l.as_fd()).map_err(|e| HandoffError::VerifyFailed {
408            index: i as u8,
409            why: why(&e),
410        })?;
411        records.push(Record {
412            kind,
413            name: l.name.clone(),
414        });
415    }
416    let manifest = encode(&records);
417    let fds: Vec<_> = listeners.iter().map(|l| l.as_fd()).collect();
418    channel
419        .send_descriptors(&manifest, &fds)
420        .map_err(handoff_error)
421}
422
423/// Receives listeners from `channel`. The sender's credentials must match
424/// `expect` (by default: the same user); the message must be complete, intact
425/// (magic, version, CRC32C), carry exactly as many sockets as it lists, and
426/// every socket must be a listener bound to the address the manifest names.
427/// All or nothing: on any error every received socket is closed.
428///
429/// # Errors
430///
431/// `PeerMismatch`, `Timeout` (nothing arrived by `deadline`), `Truncated` (the
432/// sender closed mid-message or the control data was cut), `BadMagic`,
433/// `BadVersion`, `BadChecksum`, `CountMismatch`, `TooMany`, `VerifyFailed`, `Os`.
434#[cfg(all(unix, feature = "local"))]
435pub fn recv_listeners(
436    channel: &mut crate::local::UnixConnection,
437    expect: &HandoffPeer,
438    deadline: std::time::Instant,
439) -> Result<Vec<ListenerHandle>, HandoffError> {
440    use crate::local::Descriptors;
441    let creds = channel
442        .peer_credentials()
443        .map_err(|_| HandoffError::PeerMismatch)?;
444    let uid = expect.uid.unwrap_or_else(sys::effective_uid);
445    if creds.uid != Some(uid) || expect.pid.is_some_and(|p| creds.pid != Some(p)) {
446        return Err(HandoffError::PeerMismatch);
447    }
448    channel.set_phase(crate::session::Phase::Receiving);
449    channel.set_exchange_deadline(Some(deadline));
450    let result = receive(channel);
451    channel.set_exchange_deadline(None);
452    let (records, mut fds): (Vec<Record>, Descriptors) = result?;
453    if fds.len() != records.len() {
454        return Err(HandoffError::CountMismatch);
455    }
456    let mut handles = Vec::with_capacity(records.len());
457    for (i, (record, fd)) in records.into_iter().zip(fds.take()).enumerate() {
458        let index = i as u8;
459        let got = sys::listener_kind(std::os::fd::AsFd::as_fd(&fd)).map_err(|e| {
460            HandoffError::VerifyFailed {
461                index,
462                why: why(&e),
463            }
464        })?;
465        if got != record.kind {
466            return Err(HandoffError::VerifyFailed {
467                index,
468                why: "bound to another address than the manifest says",
469            });
470        }
471        let (kind, local) = endpoint_of(got).map_err(|e| HandoffError::VerifyFailed {
472            index,
473            why: why(&e),
474        })?;
475        handles.push(ListenerHandle::new(kind, record.name, local, fd));
476    }
477    Ok(handles)
478}
479
480/// Reads the manifest and its descriptors.
481#[cfg(all(unix, feature = "local"))]
482fn receive(
483    channel: &mut crate::local::UnixConnection,
484) -> Result<(Vec<Record>, crate::local::Descriptors), HandoffError> {
485    use crate::local::Descriptors;
486    let mut fds = Descriptors::new();
487    let mut header = [0u8; HEADER];
488    let mut got = 0;
489    while got < HEADER {
490        // The descriptors travel with the first byte; a later read must bring none.
491        let mut extra = Descriptors::new();
492        let into = if got == 0 { &mut fds } else { &mut extra };
493        let n = channel
494            .recv_descriptors(&mut header[got..], into)
495            .map_err(handoff_error)?;
496        if n == 0 {
497            return Err(HandoffError::Truncated);
498        }
499        if !extra.is_empty() {
500            return Err(HandoffError::CountMismatch);
501        }
502        got += n;
503    }
504    let (_, total) = parse_header(&header)?;
505    let mut manifest = vec![0u8; total];
506    manifest[..HEADER].copy_from_slice(&header);
507    let mut at = HEADER;
508    while at < total {
509        let mut extra = Descriptors::new();
510        let n = channel
511            .recv_descriptors(&mut manifest[at..], &mut extra)
512            .map_err(handoff_error)?;
513        if n == 0 {
514            return Err(HandoffError::Truncated);
515        }
516        if !extra.is_empty() {
517            return Err(HandoffError::CountMismatch);
518        }
519        at += n;
520    }
521    let records = decode(&manifest)?;
522    Ok((records, fds))
523}
524
525#[cfg(all(unix, feature = "local"))]
526fn handoff_error(e: crate::error::NetError) -> HandoffError {
527    use crate::error::NetError;
528    match e {
529        NetError::TimedOut { .. } => HandoffError::Timeout,
530        NetError::Handoff(h) => h,
531        NetError::Closed => HandoffError::Truncated,
532        other => HandoffError::Os(io::Error::from(other)),
533    }
534}
535
536fn why(e: &KindError) -> &'static str {
537    match e {
538        KindError::NotASocket => "not a socket",
539        KindError::NotListening => "not listening",
540        KindError::WrongKind => "not a TCP or Unix stream listener",
541        KindError::Os(_) => "could not be inspected",
542    }
543}
544
545#[cfg(test)]
546mod tests {
547    use super::*;
548
549    fn records() -> Vec<Record> {
550        #[cfg_attr(not(unix), allow(unused_mut))]
551        let mut v = vec![
552            Record {
553                kind: SockKind::Tcp("127.0.0.1:8080".parse().unwrap()),
554                name: Some("web".into()),
555            },
556            Record {
557                kind: SockKind::Tcp("[2001:db8::1]:443".parse().unwrap()),
558                name: None,
559            },
560        ];
561        #[cfg(unix)]
562        v.push(Record {
563            kind: SockKind::Unix(b"/run/app/api.sock".to_vec()),
564            name: Some("api".into()),
565        });
566        v
567    }
568
569    #[test]
570    fn test_manifest_round_trips() {
571        let r = records();
572        assert_eq!(decode(&encode(&r)).unwrap(), r);
573        assert_eq!(decode(&encode(&[])).unwrap(), Vec::new());
574    }
575
576    #[test]
577    fn test_manifest_rejects_damage() {
578        let good = encode(&records());
579        let mut m = good.clone();
580        m[0] = b'X';
581        assert!(matches!(decode(&m), Err(HandoffError::BadMagic)));
582        let mut m = good.clone();
583        m[4] = 2;
584        assert!(matches!(decode(&m), Err(HandoffError::BadVersion)));
585        let mut m = good.clone();
586        let mid = m.len() / 2;
587        m[mid] ^= 1;
588        assert!(matches!(decode(&m), Err(HandoffError::BadChecksum)));
589        assert!(matches!(
590            decode(&good[..good.len() - 1]),
591            Err(HandoffError::Truncated)
592        ));
593        let mut m = good.clone();
594        m[5] = 65;
595        assert!(matches!(decode(&m), Err(HandoffError::TooMany { max: 64 })));
596        assert!(matches!(decode(&good[..3]), Err(HandoffError::Truncated)));
597    }
598
599    #[test]
600    fn test_long_names_are_cut_at_a_character_boundary() {
601        let r = [Record {
602            kind: SockKind::Tcp("127.0.0.1:1".parse().unwrap()),
603            name: Some("é".repeat(40)),
604        }];
605        let back = decode(&encode(&r)).unwrap();
606        let name = back[0].name.clone().unwrap();
607        assert_eq!(name.len(), 64);
608        assert!(name.chars().all(|c| c == 'é'));
609    }
610
611    /// A connected channel pair in a fresh directory: (sender, receiver).
612    #[cfg(all(unix, feature = "local"))]
613    fn channel(
614        tag: &str,
615    ) -> (
616        crate::local::UnixConnection,
617        crate::local::UnixConnection,
618        std::path::PathBuf,
619    ) {
620        let dir = std::env::temp_dir().join(format!("nio-ho-{}-{tag}", std::process::id()));
621        let _ = std::fs::remove_dir_all(&dir);
622        std::fs::create_dir(&dir).unwrap();
623        let l = crate::local::UnixListener::bind(dir.join("c.sock")).unwrap();
624        let tx = crate::local::UnixConnection::connect(dir.join("c.sock")).unwrap();
625        let (rx, _) = l.accept().unwrap();
626        (tx, rx, dir)
627    }
628
629    #[cfg(all(unix, feature = "local"))]
630    #[test]
631    fn test_count_mismatch_truncation_timeout_and_peer() {
632        use std::os::fd::AsFd;
633        use std::time::{Duration, Instant};
634        let soon = || Instant::now() + Duration::from_secs(5);
635        let l = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
636        let r = Record {
637            kind: SockKind::Tcp(l.local_addr().unwrap()),
638            name: None,
639        };
640        // Edge case 83: the manifest lists two, one socket came.
641        let (mut tx, mut rx, d1) = channel("count");
642        tx.send_descriptors(&encode(&[r.clone(), r.clone()]), &[l.as_fd()])
643            .unwrap();
644        assert!(matches!(
645            recv_listeners(&mut rx, &HandoffPeer::default(), soon()),
646            Err(HandoffError::CountMismatch)
647        ));
648        // Edge case 103: the sender dies mid-message: nothing adopted.
649        let (mut tx, mut rx, d2) = channel("dies");
650        let m = encode(std::slice::from_ref(&r));
651        tx.send_descriptors(&m[..m.len() / 2], &[l.as_fd()])
652            .unwrap();
653        drop(tx);
654        assert!(matches!(
655            recv_listeners(&mut rx, &HandoffPeer::default(), soon()),
656            Err(HandoffError::Truncated)
657        ));
658        // Edge case 102: nothing arrives in time.
659        let (_tx, mut rx, d3) = channel("timeout");
660        let started = Instant::now();
661        assert!(matches!(
662            recv_listeners(
663                &mut rx,
664                &HandoffPeer::default(),
665                Instant::now() + Duration::from_millis(200)
666            ),
667            Err(HandoffError::Timeout)
668        ));
669        assert!(started.elapsed() < Duration::from_secs(3));
670        // The wrong sender.
671        let (_tx, mut rx, d4) = channel("peer");
672        let other = HandoffPeer {
673            uid: Some(sys::effective_uid().wrapping_add(1)),
674            pid: None,
675        };
676        assert!(matches!(
677            recv_listeners(&mut rx, &other, soon()),
678            Err(HandoffError::PeerMismatch)
679        ));
680        let wrong_pid = HandoffPeer {
681            uid: None,
682            pid: Some(1),
683        };
684        assert!(matches!(
685            recv_listeners(&mut rx, &wrong_pid, soon()),
686            Err(HandoffError::PeerMismatch)
687        ));
688        for d in [d1, d2, d3, d4] {
689            let _ = std::fs::remove_dir_all(d);
690        }
691    }
692
693    /// A socket bound elsewhere than the manifest says is refused.
694    #[cfg(all(unix, feature = "local"))]
695    #[test]
696    fn test_address_must_match_the_manifest() {
697        use std::os::fd::AsFd;
698        use std::time::{Duration, Instant};
699        let a = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
700        let b = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
701        let (mut tx, mut rx, dir) = channel("addr");
702        let lie = Record {
703            kind: SockKind::Tcp(b.local_addr().unwrap()),
704            name: None,
705        };
706        tx.send_descriptors(&encode(&[lie]), &[a.as_fd()]).unwrap();
707        assert!(matches!(
708            recv_listeners(
709                &mut rx,
710                &HandoffPeer::default(),
711                Instant::now() + Duration::from_secs(5)
712            ),
713            Err(HandoffError::VerifyFailed { index: 0, .. })
714        ));
715        let _ = std::fs::remove_dir_all(dir);
716    }
717
718    #[test]
719    fn test_handle_verifies_its_socket() {
720        let l = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
721        let addr = l.local_addr().unwrap();
722        let h = ListenerHandle::verified(sys::OwnedSock::from(l), Some("x".into())).unwrap();
723        assert_eq!(h.kind(), Transport::Tcp);
724        assert_eq!(h.local().socket_addr(), Some(addr));
725        assert_eq!(h.name(), Some("x"));
726        let u = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
727        assert!(matches!(
728            ListenerHandle::verified(sys::OwnedSock::from(u), None),
729            Err(KindError::WrongKind)
730        ));
731    }
732}