os_socketaddr/
lib.rs

1//! This crate provides a type that can act as a platform-native socket address
2//! (i.e. [libc::sockaddr])
3//!
4//! # Motivation
5//!
6//! The std crate provides [SocketAddr] for managing socket addresses. However there is no easy way
7//! to convert `SocketAddr` from/into a `libc::sockaddr` because `SocketAddr` has a different
8//! internal layout.
9
10//!
11//! This crate provides [OsSocketAddr] which holds a `libc::sockaddr` (containing an IPv4 or IPv6
12//! address) and the conversion functions:
13//!
14//!   - from/into `SocketAddr`
15//!   - from `(*const sockaddr, socklen_t)`
16//!   - into `(*mut sockaddr, *mut socklen_t)`
17//!
18//! # Example
19//!
20//! ```
21//! # mod foo {
22//! extern crate libc;
23//! extern crate os_socketaddr;
24//!
25//! use std::net::{SocketAddr,UdpSocket};
26//! use self::libc::{c_int, c_void, size_t, ssize_t, sockaddr};
27//! #[cfg(target_family = "unix")]
28//! use libc::socklen_t;
29//! #[cfg(target_family = "windows")]
30//! use winapi::um::ws2tcpip::socklen_t;
31//!
32//! use self::os_socketaddr::OsSocketAddr;
33//!
34//! ////////// unix examples //////////
35//!
36//! //
37//! // calling C functions from Rust
38//! //
39//!
40//! #[cfg(target_family = "unix")]
41//! fn sendto(socket: c_int, payload: &[u8], dst: SocketAddr) -> ssize_t
42//! {
43//!     let addr : OsSocketAddr = dst.into();
44//!     unsafe {
45//!         libc::sendto(socket, payload.as_ptr() as *const c_void, payload.len() as size_t, 0,
46//!                      addr.as_ptr(), addr.len())
47//!     }
48//! }
49//!
50//! #[cfg(target_family = "unix")]
51//! fn recvfrom(socket: c_int, payload: &mut[u8]) -> (ssize_t, Option<SocketAddr>)
52//! {
53//!     let mut addr = OsSocketAddr::new();
54//!     let mut addrlen = addr.capacity();
55//!     let nb = unsafe {
56//!         libc::recvfrom(socket, payload.as_mut_ptr() as *mut c_void, payload.len(), 0,
57//!                        addr.as_mut_ptr(), &mut addrlen as *mut _)
58//!     };
59//!     (nb, addr.into())
60//! }
61//!
62//! //
63//! // calling Rust functions from C
64//! //
65//!
66//! #[cfg(target_family = "unix")]
67//! #[no_mangle]
68//! pub unsafe extern "C" fn send_to(
69//!         sock: *const UdpSocket, buf: *const u8, buflen: size_t,
70//!         addr: *const sockaddr, addrlen: socklen_t) -> ssize_t
71//! {
72//! 
73//!     let Some(dst) = OsSocketAddr::copy_from_raw(addr, addrlen).into_addr() else {
74//!         // not an IPv4/IPv6 address
75//!         return -1;
76//!     };
77//!     let slice = std::slice::from_raw_parts(buf, buflen);
78//!     match (*sock).send_to(&slice, dst) {
79//!         Ok(nb) => nb as ssize_t,
80//!         Err(_) => -1,
81//!     }
82//! }
83//!
84//! #[cfg(target_family = "unix")]
85//! #[no_mangle]
86//! pub unsafe extern "C" fn recv_from(
87//!         sock: *const UdpSocket, buf: *mut u8, buflen: size_t,
88//!         addr: *mut sockaddr, addrlen: *mut socklen_t) -> ssize_t
89//! {
90//!     let slice = std::slice::from_raw_parts_mut(buf, buflen);
91//!     match (*sock).recv_from(slice) {
92//!         Ok((nb, src)) => {
93//!             OsSocketAddr::from(src).copy_to_raw(addr, addrlen);
94//!             nb as ssize_t
95//!         },
96//!         Err(_) => -1,
97//!     }
98//! }
99//!
100//! ////////// windows examples //////////
101//!
102//! //
103//! // calling C functions from Rust
104//! //
105//!
106//! #[cfg(target_family = "windows")]
107//! fn sendto(socket: winapi::um::winsock2::SOCKET,
108//!           payload: &mut winapi::shared::ws2def::WSABUF,
109//!           dst: SocketAddr) -> ssize_t
110//! {
111//!     let addr : OsSocketAddr = dst.into();
112//!     let mut nb : u32 = 0;
113//!     match unsafe {
114//!         winapi::um::winsock2::WSASendTo(socket, payload, 1u32, &mut nb, 0u32,
115//!                                         addr.as_ptr(), addr.len() as i32,
116//!                                         std::ptr::null_mut::<winapi::um::minwinbase::OVERLAPPED>(), None)
117//!     } {
118//!         0 => nb as ssize_t,
119//!         _ => -1,
120//!     }
121//! }
122//!
123//! #[cfg(target_family = "windows")]
124//! fn recvfrom(socket: winapi::um::winsock2::SOCKET,
125//!             payload: &mut winapi::shared::ws2def::WSABUF) -> (ssize_t, Option<SocketAddr>)
126//! {
127//!     let mut addr = OsSocketAddr::new();
128//!     let mut addrlen = addr.capacity();
129//!     let mut nb : u32 = 0;
130//!     let mut flags : u32 = 0;
131//!     match unsafe {
132//!         winapi::um::winsock2::WSARecvFrom(socket, payload, 1u32, &mut nb, &mut flags,
133//!                                           addr.as_mut_ptr(), &mut addrlen as *mut _,
134//!                                           std::ptr::null_mut::<winapi::um::minwinbase::OVERLAPPED>(), None)
135//!     } {
136//!         0 => (nb as ssize_t, addr.into()),
137//!         _ => (-1, None),
138//!     }
139//! }
140//! # }
141//! ```
142//!
143
144extern crate libc;
145
146use std::convert::TryInto;
147use std::net::{Ipv4Addr,Ipv6Addr,SocketAddr,SocketAddrV4,SocketAddrV6};
148use std::str::FromStr;
149
150#[cfg(not(target_os = "windows"))]
151use libc::{sockaddr, sockaddr_in, sockaddr_in6, AF_INET, AF_INET6};
152
153#[cfg(target_os = "windows")]
154use winapi::shared::{
155    ws2def::{AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in},
156    ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6,
157};
158
159/// A type for handling platform-native socket addresses (`struct sockaddr`)
160///
161/// This type has a buffer big enough to hold a [libc::sockaddr_in] or [libc::sockaddr_in6]
162/// struct. Its content can be arbitrary written using [.as_mut()](Self::as_mut) or
163/// [.as_mut_ptr()](Self::as_mut_ptr).
164///
165/// It also provides the conversion functions:
166///
167///   - from/into `SocketAddr`
168///   - from `(*const sockaddr, socklen_t)`
169///   - into `(*mut sockaddr, *mut socklen_t)`
170///
171/// See [crate] level documentation.
172///
173#[derive(Copy, Clone)]
174#[repr(C)]
175pub union OsSocketAddr {
176    sa4: sockaddr_in,
177    sa6: sockaddr_in6,
178}
179
180
181/// Portable re-export of `socklen_t`
182///
183/// Uses `winapi::um::ws2tcpip::socklen_t` on windows and `libc::socklen_t` on other systems.
184#[cfg(not(target_os = "windows"))]
185pub use libc::socklen_t;
186///
187/// Portable re-export of `socklen_t`
188///
189/// Uses `winapi::um::ws2tcpip::socklen_t` on windows and `libc::socklen_t` on other systems.
190#[cfg(target_os = "windows")]
191pub use winapi::um::ws2tcpip::socklen_t;
192
193
194#[allow(dead_code)]
195impl OsSocketAddr {
196    /// Create a new empty socket address (all bytes initialised to 0)
197    pub fn new() -> Self {
198        OsSocketAddr {
199            sa6: unsafe { std::mem::zeroed() },
200        }
201    }
202
203    /// Create a new socket address from a raw byte slice
204    ///
205    /// The location pointed by `ptr` is assumed to hold a `struct sockaddr` whose length in bytes
206    /// is given by `len`.
207    ///
208    /// Its content is copied into a new [OsSocketAddr] object. If `len` is greater than the size
209    /// of [sockaddr_in6] then the resulting address is truncated. If less, then the extra bytes
210    /// are zeroed.
211    ///
212    /// If `ptr` is NULL, then the resulting address is zeroed.
213    ///
214    /// See also [OsSocketAddr::copy_to_raw]
215    pub unsafe fn copy_from_raw(ptr: *const sockaddr, len: socklen_t) -> Self {
216        let mut addr = OsSocketAddr::new();
217        if !ptr.is_null() {
218            let src = std::slice::from_raw_parts(ptr as *const u8, len as usize);
219            let dst = addr.as_mut();
220            let nb = src.len().min(dst.len());
221            dst[..nb].copy_from_slice(&src[..nb]);
222        }
223        addr
224    }
225
226    /// Create a new socket address from a raw slice
227    #[deprecated(since="0.2.4", note="use copy_from_raw()")]
228    pub unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self {
229        Self::copy_from_raw(ptr as *const sockaddr, len as socklen_t)
230    }
231
232
233    /// Copy the socket address into a raw byte slice
234    ///
235    /// The value pointed by `len` must be initialised with the length in bytes of the buffer
236    /// pointed by `ptr`. On return it contains the actual size of the returned address.
237    ///
238    /// If the provided buffer is too small, then the returned address is truncated (and `len` will
239    /// have a greater value than before the call).
240    ///
241    /// If `ptr` is NULL then the function does nothing.
242    ///
243    /// If the value of .sa_family does not resolve to AF_INET or AF_INET6 then the function
244    /// sets `*len` to 0 and returns an error.
245    /// 
246    /// See also [OsSocketAddr::copy_from_raw]
247    pub unsafe fn copy_to_raw(&self, ptr: *mut sockaddr, len: *mut socklen_t) -> Result<(), BadFamilyError>
248    {
249        if !ptr.is_null() {
250            let src = self.as_ref();
251            let dst = std::slice::from_raw_parts_mut(ptr as *mut u8, *len as usize);
252            if src.len() == 0 {
253                *len = 0;
254                return Err(BadFamilyError(self.sa4.sin_family as i32))
255            }
256            let nb = src.len().min(dst.len());
257            dst[..nb].copy_from_slice(&src[..nb]);
258            *len = src.len() as socklen_t
259        }
260        Ok(())
261    }
262
263    /// Create a new socket address from a [SocketAddr] object
264    pub fn from(addr: SocketAddr) -> Self {
265        addr.into()
266    }
267
268    /// Attempt to convert the internal buffer into a [SocketAddr] object
269    ///
270    /// The internal buffer is assumed to be a [sockaddr].
271    ///
272    /// If the value of `.sa_family` resolves to `AF_INET` or `AF_INET6` then the buffer is
273    /// converted into `SocketAddr`, otherwise the function returns None.
274    ///
275    pub fn into_addr(self) -> Option<SocketAddr> {
276        self.into()
277    }
278
279    /// Return the length of the address
280    ///
281    /// The result depends on the value of `.sa_family` in the internal buffer:
282    /// * `AF_INET`  -> the size of [sockaddr_in]
283    /// * `AF_INET6` -> the size of [sockaddr_in6]
284    /// * *other* -> 0
285    pub fn len(&self) -> socklen_t {
286        (match unsafe { self.sa6.sin6_family } as i32 {
287            AF_INET => std::mem::size_of::<sockaddr_in>(),
288            AF_INET6 => std::mem::size_of::<sockaddr_in6>(),
289            _ => 0,
290        }) as socklen_t
291    }
292
293    /// Return the size of the internal buffer
294    pub fn capacity(&self) -> socklen_t {
295        std::mem::size_of::<sockaddr_in6>() as socklen_t
296    }
297
298    /// Get a pointer to the internal buffer
299    pub fn as_ptr(&self) -> *const sockaddr {
300        unsafe { &self.sa6 as *const _ as *const _ }
301    }
302
303    /// Get a mutable pointer to the internal buffer
304    pub fn as_mut_ptr(&mut self) -> *mut sockaddr {
305        unsafe { &mut self.sa6 as *mut _ as *mut _ }
306    }
307}
308
309impl AsRef<[u8]> for OsSocketAddr {
310    /// Get the internal buffer as a byte slice
311    ///
312    /// Note: the actual length of slice depends on the value of `.sa_family`
313    /// (see [.len()](Self::len))
314    ///
315    fn as_ref(&self) -> &[u8] {
316        unsafe {
317            std::slice::from_raw_parts(&self.sa6 as *const _ as *const u8, self.len() as usize)
318        }
319    }
320}
321
322impl AsMut<[u8]> for OsSocketAddr {
323    /// Get the internal buffer as a mutable slice
324    fn as_mut(&mut self) -> &mut [u8] {
325        unsafe {
326            std::slice::from_raw_parts_mut(
327                &mut self.sa6 as *mut _ as *mut u8,
328                self.capacity() as usize,
329            )
330        }
331    }
332}
333
334impl Into<Option<SocketAddr>> for OsSocketAddr {
335    /// Attempt to convert the internal buffer into a [SocketAddr] object
336    ///
337    /// The internal buffer is assumed to be a [sockaddr].
338    ///
339    /// If the value of `.sa_family` resolves to `AF_INET` or `AF_INET6` then the buffer is
340    /// converted into `SocketAddr`, otherwise the function returns None.
341    ///
342    fn into(self) -> Option<SocketAddr> {
343        self.try_into().ok()
344    }
345}
346
347impl TryInto<SocketAddr> for OsSocketAddr {
348    type Error = BadFamilyError;
349
350    /// Attempt to convert the internal buffer into a [SocketAddr] object
351    ///
352    /// The internal buffer is assumed to be a [sockaddr].
353    ///
354    /// If the value of `.sa_family` resolves to `AF_INET` or `AF_INET6` then the buffer is
355    /// converted into `SocketAddr`, otherwise the function returns an error.
356    ///
357    fn try_into(self) -> Result<SocketAddr, BadFamilyError> {
358        unsafe {
359            match self.sa6.sin6_family as i32 {
360                AF_INET => {
361                    #[cfg(not(target_os = "windows"))]
362                    let ip = self.sa4.sin_addr.s_addr;
363                    #[cfg(target_os = "windows")]
364                    let ip = *self.sa4.sin_addr.S_un.S_addr();
365
366                    Ok(SocketAddr::V4(SocketAddrV4::new(
367                            Ipv4Addr::from(u32::from_be(ip)),
368                            u16::from_be(self.sa4.sin_port),
369                        )))
370                },
371                AF_INET6 => {
372                    #[cfg(not(target_os = "windows"))]
373                    let (ip, scope_id) = (self.sa6.sin6_addr.s6_addr, self.sa6.sin6_scope_id);
374                    #[cfg(target_os = "windows")]
375                    let (ip, scope_id) = (*self.sa6.sin6_addr.u.Byte(), *self.sa6.u.sin6_scope_id());
376
377                    Ok(SocketAddr::V6(SocketAddrV6::new(
378                            Ipv6Addr::from(u128::from_be_bytes(ip)),
379                            u16::from_be(self.sa6.sin6_port),
380                            self.sa6.sin6_flowinfo,
381                            scope_id)))
382                },
383                f => Err(BadFamilyError(f)),
384            }
385        }
386    }
387}
388
389/// Error type returned by [OsSocketAddr::try_into()]
390#[derive(Debug,Eq,PartialEq)]
391pub struct BadFamilyError(i32);
392impl std::error::Error for BadFamilyError {}
393impl std::fmt::Display for BadFamilyError {
394   fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
395   {
396       "not an ip address (family=".fmt(f)?;
397       self.0.fmt(f)?;
398       ')'.fmt(f)
399   }
400}
401
402impl From<SocketAddr> for OsSocketAddr {
403    fn from(addr: SocketAddr) -> Self {
404        let mut result : Self = unsafe { std::mem::zeroed() };
405        match addr {
406            SocketAddr::V4(addr) => {
407                let sa4 = unsafe { &mut result.sa4 };
408
409                #[cfg(any(
410                        target_os = "dragonfly",
411                        target_os = "freebsd",
412                        target_os = "haiku",
413                        target_os = "hermit",
414                        target_os = "ios",
415                        target_os = "macos",
416                        target_os = "netbsd",
417                        target_os = "openbsd",
418                        target_os = "vxworks",
419                        target_os = "watchos",
420                        ))]
421                {
422                    sa4.sin_len = std::mem::size_of::<sockaddr_in>() as u8;
423                }
424
425                sa4.sin_family = AF_INET.try_into().unwrap();
426                sa4.sin_port = u16::to_be(addr.port());
427
428                let raw_ip = u32::to_be((*addr.ip()).into());
429                #[cfg(not(target_os = "windows"))]
430                {
431                    sa4.sin_addr.s_addr = raw_ip;
432                }
433                #[cfg(target_os = "windows")]
434                unsafe {
435                    *sa4.sin_addr.S_un.S_addr_mut() = raw_ip;
436                }
437            },
438            SocketAddr::V6(addr) => {
439                let sa6 = unsafe { &mut result.sa6 };
440
441                #[cfg(any(
442                        target_os = "dragonfly",
443                        target_os = "freebsd",
444                        target_os = "haiku",
445                        target_os = "hermit",
446                        target_os = "ios",
447                        target_os = "macos",
448                        target_os = "netbsd",
449                        target_os = "openbsd",
450                        target_os = "vxworks",
451                        target_os = "watchos",
452                        ))]
453                {
454                    sa6.sin6_len = std::mem::size_of::<sockaddr_in6>() as u8;
455                }
456
457                sa6.sin6_family = AF_INET6.try_into().unwrap();
458                sa6.sin6_port = u16::to_be(addr.port());
459                sa6.sin6_flowinfo = addr.flowinfo();
460
461                let raw_ip = u128::to_be_bytes((*addr.ip()).into());
462                #[cfg(not(target_os = "windows"))]
463                {
464                    sa6.sin6_addr.s6_addr = raw_ip;
465                    sa6.sin6_scope_id = addr.scope_id();
466                }
467                #[cfg(target_os = "windows")]
468                unsafe {
469                    *sa6.sin6_addr.u.Byte_mut() = raw_ip;
470                    *sa6.u.sin6_scope_id_mut() = addr.scope_id();
471                }
472            }
473        }
474        result
475    }
476}
477
478impl From<Option<SocketAddr>> for OsSocketAddr {
479    fn from(addr: Option<SocketAddr>) -> Self {
480        match addr {
481            None => Self::new(),
482            Some(addr) => addr.into(),
483        }
484    }
485}
486
487impl FromStr for OsSocketAddr {
488    type Err = std::net::AddrParseError;
489    fn from_str(val: &str) -> Result<Self,Self::Err> {
490        let addr : SocketAddr = val.parse()?;
491        Ok(addr.into())
492    }
493}
494
495impl std::fmt::Debug for OsSocketAddr {
496    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
497        self.into_addr().fmt(fmt)
498    }
499}
500
501#[cfg(test)]
502mod tests {
503    use super::*;
504    use std::net::SocketAddrV6;
505
506    #[cfg(not(target_os = "windows"))]
507    use libc::{in6_addr, in_addr};
508
509    #[cfg(target_os = "windows")]
510    use winapi::shared::{in6addr::in6_addr, inaddr::in_addr};
511
512    fn check_as_mut(osa: &mut OsSocketAddr) {
513        let ptr = osa as *mut _ as usize;
514        let buf = osa.as_mut();
515        assert_eq!(buf.as_mut_ptr(), ptr as *mut _);
516        assert_eq!(buf.len(), std::mem::size_of::<sockaddr_in6>());
517    }
518
519    #[test]
520    fn ptr_and_capacity() {
521        let mut osa = OsSocketAddr::new();
522        assert_eq!(osa.as_ptr(), &osa as *const _ as *const _);
523        assert_eq!(osa.as_mut_ptr(), &mut osa as *mut _ as *mut _);
524        assert_eq!(osa.capacity() as usize, std::mem::size_of::<sockaddr_in6>());
525    }
526
527    #[test]
528    fn as_slice() {
529        let mut osa = OsSocketAddr::new();
530        {
531            let sl = osa.as_ref();
532            assert_eq!(sl.as_ptr(), &osa as *const _ as *const _);
533            assert_eq!(sl.len(), 0);
534        }
535        {
536            let ptr = &mut osa as *mut _ as *mut _;
537            let sl = osa.as_mut();
538            assert_eq!(sl.as_mut_ptr(), ptr);
539            assert_eq!(sl.len(), std::mem::size_of::<sockaddr_in6>());
540        }
541    }
542
543    #[test]
544    fn convert_from_and_to_raw() {
545        let osa4 : OsSocketAddr = "12.34.56.78:12345".parse().unwrap();
546        let osa6 : OsSocketAddr = "[0123:4567:89ab:cdef:fedc:ba98:7654:3210]:12345"
547            .parse().unwrap();
548        const LEN4 : usize = std::mem::size_of::<sockaddr_in>();
549        const LEN6 : usize = std::mem::size_of::<sockaddr_in6>();
550
551        fn with_buf<F>(len: usize, f: F)
552            where F: Fn(&mut [u8], *mut sockaddr, *mut socklen_t)
553        {
554            let mut buf = Vec::new();
555            buf.resize(len, 0xff);
556            let sa = buf.as_mut_ptr() as *mut sockaddr;
557            let mut sa_len = len as socklen_t;
558            f(&mut buf, sa , &mut sa_len as *mut socklen_t);
559        }
560        // ipv4
561        with_buf(128, |buf, sa, sa_len| unsafe {
562            osa4.copy_to_raw(sa, sa_len).unwrap();
563
564            assert_eq!(*sa_len as usize, LEN4);
565            assert_eq!(&buf[..LEN4], osa4.as_ref());
566            assert!(buf[LEN4..].iter().all(|v| *v==0xff));
567
568            let mut osa4_bis = OsSocketAddr::copy_from_raw(sa, *sa_len);
569            assert_eq!(osa4.into_addr(), osa4_bis.into_addr());
570            assert_eq!(&osa4_bis.as_ref()[..LEN4], &buf[..LEN4]);
571            assert!(osa4_bis.as_mut()[LEN4..].iter().all(|v| *v==0x0));
572
573            let mut osa4_ter = OsSocketAddr::copy_from_raw(sa, 128);
574            assert_eq!(osa4.into_addr(), osa4_ter.into_addr());
575            assert_eq!(&osa4_ter.as_ref()[..LEN4], &buf[..LEN4]);
576            assert!(osa4_ter.as_mut()[LEN4..].iter().all(|v| *v==0xff));
577        });
578        // ipv6
579        with_buf(128, |buf, sa, sa_len| unsafe {
580            osa6.copy_to_raw(sa, sa_len).unwrap();
581
582            assert_eq!(*sa_len as usize, LEN6);
583            assert_eq!(&buf[..LEN6], osa6.as_ref());
584            assert!(buf[LEN6..].iter().all(|v| *v==0xff));
585
586            let mut osa6_bis = OsSocketAddr::copy_from_raw(sa, *sa_len);
587            assert_eq!(osa6.into_addr(), osa6_bis.into_addr());
588            assert_eq!(osa6_bis.as_ref(), &buf[..LEN6]);
589            assert_eq!(osa6_bis.as_mut(), &buf[..LEN6]);
590        });
591        // copy to smaller buffer (must truncate)
592        with_buf(128, |buf, sa, sa_len| unsafe {
593            let limit = 6;
594
595            *sa_len = limit as socklen_t;
596            osa4.copy_to_raw(sa, sa_len).unwrap();
597            assert_eq!(*sa_len as usize, LEN4);
598            assert_eq!(&buf[..limit], &osa4.as_ref()[..limit]);
599            assert!(buf[limit..].iter().all(|v| *v==0xff));
600
601            buf.fill(0xff);
602            *sa_len = limit as socklen_t;
603            osa6.copy_to_raw(sa, sa_len).unwrap();
604            assert_eq!(*sa_len as usize, LEN6);
605            assert_eq!(&buf[..limit], &osa6.as_ref()[..limit]);
606            assert!(buf[limit..].iter().all(|v| *v==0xff));
607        });
608        // copy unknown sin_addr
609        with_buf(128, |_, sa, sa_len| unsafe {
610            assert_eq!(OsSocketAddr::new().copy_to_raw(sa, sa_len), Err(BadFamilyError(0)));
611            assert_eq!(*sa_len, 0);
612        });
613        // null pointers
614        unsafe { osa4.copy_to_raw(std::ptr::null_mut(), std::ptr::null_mut()).unwrap(); }
615
616        let mut null = unsafe { OsSocketAddr::copy_from_raw(std::ptr::null(), 456) };
617        assert_eq!(null.as_mut(), OsSocketAddr::new().as_mut());
618    }
619
620    #[test]
621    fn os_socketaddr_ipv4() {
622        let addr: SocketAddr = "12.34.56.78:4242".parse().unwrap();
623        unsafe {
624            #[cfg(any(
625                    target_os = "android",
626                    target_os = "emscripten",
627                    target_os = "fuchsia",
628                    target_os = "illumos",
629                    target_os = "l4re",
630                    target_os = "linux",
631                    target_os = "redox",
632                    target_os = "solaris",
633
634                    target_os = "windows",
635                    ))]
636            let sa = sockaddr_in {
637                sin_family: AF_INET as u16,
638                sin_addr: *(&[12u8, 34, 56, 78] as *const _ as *const in_addr),
639                sin_port: 4242u16.to_be(),
640                sin_zero: std::mem::zeroed(),
641            };
642            #[cfg(any(
643                    target_os = "dragonfly",
644                    target_os = "freebsd",
645                    target_os = "haiku",
646                    target_os = "hermit",
647                    target_os = "ios",
648                    target_os = "macos",
649                    target_os = "netbsd",
650                    target_os = "openbsd",
651                    target_os = "vxworks",
652                    target_os = "watchos",
653                    ))]
654            let sa = sockaddr_in {
655                sin_len: std::mem::size_of::<sockaddr_in>() as u8,
656                sin_family: AF_INET as u8,
657                sin_addr: *(&[12u8, 34, 56, 78] as *const _ as *const in_addr),
658                sin_port: 4242u16.to_be(),
659                sin_zero: std::mem::zeroed(),
660            };
661            let mut osa = OsSocketAddr::copy_from_raw(
662                &sa as *const _ as *const sockaddr,
663                std::mem::size_of_val(&sa) as socklen_t,
664            );
665            assert_eq!(osa.len() as usize, std::mem::size_of::<sockaddr_in>());
666            assert_eq!(osa.capacity() as usize, std::mem::size_of::<sockaddr_in6>());
667            assert_eq!(osa.into_addr(), Some(addr));
668            assert_eq!(osa.try_into(), Ok(addr));
669            assert_eq!(OsSocketAddr::from(addr).into_addr(), Some(addr));
670            {
671                let buf = osa.as_ref();
672                assert_eq!(buf.as_ptr(), &osa as *const _ as *const _);
673                assert_eq!(buf.len(), std::mem::size_of_val(&sa));
674            }
675            check_as_mut(&mut osa);
676        }
677    }
678
679    #[test]
680    fn os_socketaddr_ipv6() {
681        let ip = [
682            7u8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
683        ];
684        let addr = SocketAddr::V6(SocketAddrV6::new(ip.into(), 4242, 0x11223344, 0x55667788));
685        unsafe {
686            #[cfg(any(
687                    target_os = "android",
688                    target_os = "emscripten",
689                    target_os = "fuchsia",
690                    target_os = "illumos",
691                    target_os = "l4re",
692                    target_os = "linux",
693                    target_os = "redox",
694                    target_os = "solaris",
695                    ))]
696            let sa = sockaddr_in6 {
697                sin6_family: AF_INET6 as u16,
698                sin6_addr: *(&ip as *const _ as *const in6_addr),
699                sin6_port: 4242u16.to_be(),
700                sin6_flowinfo: 0x11223344,
701                sin6_scope_id: 0x55667788,
702            };
703            #[cfg(any(
704                    target_os = "dragonfly",
705                    target_os = "freebsd",
706                    target_os = "haiku",
707                    target_os = "hermit",
708                    target_os = "ios",
709                    target_os = "macos",
710                    target_os = "netbsd",
711                    target_os = "openbsd",
712                    target_os = "vxworks",
713                    target_os = "watchos",
714                    ))]
715            let sa = sockaddr_in6 {
716                sin6_len: std::mem::size_of::<sockaddr_in6>() as u8,
717                sin6_family: AF_INET6 as u8,
718                sin6_addr: *(&ip as *const _ as *const in6_addr),
719                sin6_port: 4242u16.to_be(),
720                sin6_flowinfo: 0x11223344,
721                sin6_scope_id: 0x55667788,
722            };
723            #[cfg(target_os = "windows")]
724            let mut sa = sockaddr_in6 {
725                sin6_family: AF_INET6 as u16,
726                sin6_addr: *(&ip as *const _ as *const in6_addr),
727                sin6_port: 4242u16.to_be(),
728                sin6_flowinfo: 0x11223344,
729                u: std::mem::zeroed(),
730            };
731            #[cfg(target_os = "windows")]
732            let sa = {
733                let scope_id = sa.u.sin6_scope_id_mut();
734                *scope_id = 0x55667788;
735                sa
736            };
737
738            let mut osa = OsSocketAddr::copy_from_raw(
739                &sa as *const _ as *const sockaddr,
740                std::mem::size_of_val(&sa) as socklen_t,
741            );
742            assert_eq!(osa.len() as usize, std::mem::size_of::<sockaddr_in6>());
743            assert_eq!(osa.capacity() as usize, std::mem::size_of::<sockaddr_in6>());
744            assert_eq!(osa.into_addr(), Some(addr));
745            assert_eq!(osa.try_into(), Ok(addr));
746            assert_eq!(OsSocketAddr::from(addr).into_addr(), Some(addr));
747            {
748                let buf = osa.as_ref();
749                assert_eq!(buf.as_ptr(), &osa as *const _ as *const _);
750                assert_eq!(buf.len(), std::mem::size_of_val(&sa));
751            }
752            check_as_mut(&mut osa);
753        }
754    }
755
756    #[test]
757    fn os_socketaddr_other() {
758        fn check(mut osa: OsSocketAddr) {
759            assert_eq!(osa.into_addr(), None);
760
761            let r : Result<SocketAddr, _> = osa.try_into();
762            assert!(r.is_err());
763            {
764                let buf = osa.as_ref();
765                assert_eq!(buf.len(), 0);
766                assert_eq!(osa.len(), 0);
767                assert_eq!(osa.capacity() as usize, std::mem::size_of::<sockaddr_in6>());
768            }
769            check_as_mut(&mut osa);
770        }
771
772        check(OsSocketAddr::new());
773        check(None.into());
774        unsafe {
775            check(OsSocketAddr::copy_from_raw(
776                [0xde, 0xad, 0xbe, 0xef].as_ptr() as *const sockaddr,
777                4,
778            ));
779        }
780
781        let r : Result<SocketAddr, BadFamilyError> = OsSocketAddr::new().try_into();
782        assert!(r.is_err());
783        let e = r.unwrap_err();
784        assert_eq!(e, BadFamilyError(0));
785        assert_eq!(e.to_string(), "not an ip address (family=0)");
786    }
787}