Skip to main content

smolsocket/
lib.rs

1#[cfg_attr(test, macro_use)]
2extern crate log;
3
4use core::fmt;
5
6use byteorder::{BigEndian, ByteOrder};
7#[cfg(feature = "proto-ipv4")]
8use smoltcp::wire::Ipv4Address;
9#[cfg(feature = "proto-ipv6")]
10use smoltcp::wire::Ipv6Address;
11#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
12use smoltcp::wire::{IpAddress, IpEndpoint};
13
14#[cfg(feature = "proto-ipv4")]
15pub use crate::ipv4::{ipv4_addr, ipv4_addr_from_bytes, SocketAddrV4};
16#[cfg(feature = "proto-ipv6")]
17pub use crate::ipv6::{ipv6_addr, ipv6_addr_from_bytes, SocketAddrV6};
18#[cfg(feature = "std")]
19pub use crate::std::*;
20
21type Result<T> = core::result::Result<T, Error>;
22
23pub const LEN_V4: usize = 6;
24pub const LEN_V6: usize = 18;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum Error {
28    AddrParseError,
29    UnspecifiedIp,
30}
31
32impl ::std::error::Error for Error {}
33
34impl fmt::Display for Error {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        match self {
37            Error::AddrParseError => write!(f, "invalid IP address bytes"),
38            Error::UnspecifiedIp => write!(f, "UnspecifiedIp"),
39        }
40    }
41}
42
43/// merge two u8s into u16
44pub fn port_from_bytes(high: u8, low: u8) -> u16 {
45    u16::from(high) << 8 | u16::from(low)
46}
47
48pub fn port_to_bytes(port: u16) -> [u8; 2] {
49    let mut buf = [0; 2];
50    BigEndian::write_u16(&mut buf, port);
51    buf
52}
53
54#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
55#[derive(Copy, Clone, Eq, Hash, PartialEq)]
56pub enum SocketAddr {
57    /// An IPv4 socket address.
58    #[cfg(feature = "proto-ipv4")]
59    V4(SocketAddrV4),
60    /// An IPv6 socket address.
61    #[cfg(feature = "proto-ipv6")]
62    V6(SocketAddrV6),
63}
64
65#[allow(clippy::len_without_is_empty)]
66#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
67impl SocketAddr {
68    pub fn new(ip: IpAddress, port: u16) -> Result<Self> {
69        match ip {
70            #[cfg(feature = "proto-ipv4")]
71            IpAddress::Ipv4(ip) => Ok(SocketAddr::new_v4(ip, port)),
72            #[cfg(feature = "proto-ipv6")]
73            IpAddress::Ipv6(ip) => Ok(SocketAddr::V6(SocketAddrV6::new(ip, port))),
74            IpAddress::Unspecified => Err(Error::UnspecifiedIp),
75            _ => unreachable!(),
76        }
77    }
78
79    #[cfg(feature = "proto-ipv4")]
80    pub fn new_v4(ip: Ipv4Address, port: u16) -> Self {
81        SocketAddr::V4(SocketAddrV4::new(ip, port))
82    }
83
84    #[cfg(feature = "proto-ipv4")]
85    pub fn v4_from_bytes(bytes: &[u8]) -> Result<Self> {
86        if bytes.len() == LEN_V4 {
87            let ip_addr = ipv4_addr_from_bytes(&bytes[0..LEN_V4 - 2])?;
88            let port_bytes = &bytes[LEN_V4 - 2..LEN_V4];
89            let port = port_from_bytes(port_bytes[0], port_bytes[1]);
90            Ok(SocketAddr::new_v4(ip_addr, port))
91        } else {
92            Err(Error::AddrParseError)
93        }
94    }
95
96    #[cfg(feature = "proto-ipv4")]
97    pub fn new_ip4_port(a0: u8, a1: u8, a2: u8, a3: u8, port: u16) -> Self {
98        SocketAddr::V4(SocketAddrV4::new_ip4_port(a0, a1, a2, a3, port))
99    }
100
101    #[cfg(feature = "proto-ipv6")]
102    pub fn new_v6(ip: Ipv6Address, port: u16) -> Self {
103        SocketAddr::V6(SocketAddrV6::new(ip, port))
104    }
105
106    #[cfg(feature = "proto-ipv6")]
107    pub fn v6_from_bytes(bytes: &[u8]) -> Result<Self> {
108        if bytes.len() == LEN_V6 {
109            let ip_addr = ipv6_addr_from_bytes(&bytes[0..LEN_V6 - 2])?;
110            let port_bytes = &bytes[LEN_V6 - 2..LEN_V6];
111            let port = port_from_bytes(port_bytes[0], port_bytes[1]);
112            Ok(SocketAddr::new_v6(ip_addr, port))
113        } else {
114            Err(Error::AddrParseError)
115        }
116    }
117
118    #[cfg(feature = "proto-ipv6")]
119    #[allow(clippy::too_many_arguments)]
120    pub fn new_ip6_port(
121        a0: u16,
122        a1: u16,
123        a2: u16,
124        a3: u16,
125        a4: u16,
126        a5: u16,
127        a6: u16,
128        a7: u16,
129        port: u16,
130    ) -> Self {
131        SocketAddr::V6(SocketAddrV6::new_ip6_port(
132            a0, a1, a2, a3, a4, a5, a6, a7, port,
133        ))
134    }
135
136    pub fn len(&self) -> usize {
137        match self {
138            #[cfg(feature = "proto-ipv4")]
139            SocketAddr::V4(addr) => addr.len(),
140            #[cfg(feature = "proto-ipv6")]
141            SocketAddr::V6(addr) => addr.len(),
142        }
143    }
144
145    pub fn ip(&self) -> IpAddress {
146        match self {
147            #[cfg(feature = "proto-ipv4")]
148            SocketAddr::V4(addr) => IpAddress::Ipv4(addr.addr),
149            #[cfg(feature = "proto-ipv6")]
150            SocketAddr::V6(addr) => IpAddress::Ipv6(addr.addr),
151        }
152    }
153
154    pub fn ip_octets(&self) -> Vec<u8> {
155        match self {
156            #[cfg(feature = "proto-ipv4")]
157            SocketAddr::V4(addr) => addr.addr.0.to_vec(),
158            #[cfg(feature = "proto-ipv6")]
159            SocketAddr::V6(addr) => addr.addr.0.to_vec(),
160        }
161    }
162
163    pub fn port(&self) -> u16 {
164        match self {
165            #[cfg(feature = "proto-ipv4")]
166            SocketAddr::V4(addr) => addr.port,
167            #[cfg(feature = "proto-ipv6")]
168            SocketAddr::V6(addr) => addr.port,
169        }
170    }
171
172    pub fn to_vec(&self) -> Vec<u8> {
173        match self {
174            #[cfg(feature = "proto-ipv4")]
175            SocketAddr::V4(addr) => addr.to_vec(),
176            #[cfg(feature = "proto-ipv6")]
177            SocketAddr::V6(addr) => addr.to_vec(),
178        }
179    }
180}
181
182#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
183impl From<SocketAddr> for IpEndpoint {
184    fn from(val: SocketAddr) -> Self {
185        match val {
186            #[cfg(feature = "proto-ipv4")]
187            SocketAddr::V4(val) => IpEndpoint::new(IpAddress::Ipv4(val.addr), val.port),
188            #[cfg(feature = "proto-ipv6")]
189            SocketAddr::V6(val) => IpEndpoint::new(IpAddress::Ipv6(val.addr), val.port),
190        }
191    }
192}
193
194#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
195impl fmt::Display for SocketAddr {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        match *self {
198            #[cfg(feature = "proto-ipv4")]
199            SocketAddr::V4(ref a) => a.fmt(f),
200            #[cfg(feature = "proto-ipv6")]
201            SocketAddr::V6(ref a) => a.fmt(f),
202        }
203    }
204}
205
206#[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
207impl fmt::Debug for SocketAddr {
208    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
209        fmt::Display::fmt(self, fmt)
210    }
211}
212
213#[cfg(feature = "proto-ipv4")]
214mod ipv4 {
215    use core::fmt;
216
217    use smoltcp::wire::Ipv4Address;
218
219    use super::{port_to_bytes, Error, Result, LEN_V4};
220
221    pub fn ipv4_addr_from_bytes(bytes: &[u8]) -> Result<Ipv4Address> {
222        if bytes.len() == 4 {
223            Ok(Ipv4Address::from_bytes(bytes))
224        } else {
225            Err(Error::AddrParseError)
226        }
227    }
228
229    pub fn ipv4_addr(a0: u8, a1: u8, a2: u8, a3: u8) -> Ipv4Address {
230        ipv4_addr_from_bytes(&[a0, a1, a2, a3]).expect("should be valid")
231    }
232
233    #[derive(Copy, Clone, Eq, Hash, PartialEq)]
234    pub struct SocketAddrV4 {
235        pub addr: Ipv4Address,
236        pub port: u16,
237    }
238
239    #[allow(clippy::len_without_is_empty)]
240    #[allow(clippy::trivially_copy_pass_by_ref)]
241    impl SocketAddrV4 {
242        pub fn new(addr: Ipv4Address, port: u16) -> Self {
243            SocketAddrV4 { addr, port }
244        }
245
246        pub fn new_ip4_port(a0: u8, a1: u8, a2: u8, a3: u8, port: u16) -> Self {
247            SocketAddrV4 {
248                addr: Ipv4Address::new(a0, a1, a2, a3),
249                port,
250            }
251        }
252
253        pub fn len(&self) -> usize {
254            LEN_V4
255        }
256
257        pub fn to_vec(&self) -> Vec<u8> {
258            let mut result = Vec::with_capacity(self.len());
259            result.extend_from_slice(&self.addr.0);
260            result.extend_from_slice(&port_to_bytes(self.port));
261            result
262        }
263    }
264
265    impl fmt::Display for SocketAddrV4 {
266        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267            write!(f, "{}:{}", self.addr, self.port)
268        }
269    }
270
271    impl fmt::Debug for SocketAddrV4 {
272        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
273            fmt::Display::fmt(self, fmt)
274        }
275    }
276}
277
278#[cfg(feature = "proto-ipv6")]
279mod ipv6 {
280    use core::fmt;
281
282    use byteorder::{BigEndian, ByteOrder};
283    use smoltcp::wire::Ipv6Address;
284
285    use super::{port_to_bytes, Error, Result, LEN_V6};
286
287    #[cfg(feature = "proto-ipv6")]
288    pub fn ipv6_addr_from_bytes(bytes: &[u8]) -> Result<Ipv6Address> {
289        if bytes.len() == 16 {
290            Ok(Ipv6Address::from_bytes(bytes))
291        } else {
292            Err(Error::AddrParseError)
293        }
294    }
295
296    #[allow(clippy::too_many_arguments)]
297    pub fn ipv6_addr(
298        a0: u16,
299        a1: u16,
300        a2: u16,
301        a3: u16,
302        a4: u16,
303        a5: u16,
304        a6: u16,
305        a7: u16,
306    ) -> Ipv6Address {
307        let ip_address: [u16; 8] = [a0, a1, a2, a3, a4, a5, a6, a7];
308        let mut ip_address_bytes = [0u8; 16];
309        {
310            let p = &mut ip_address_bytes[..];
311            for (idx, quartet) in ip_address.iter().enumerate() {
312                let idx = idx * 2;
313                BigEndian::write_u16(&mut p[idx..idx + 2], *quartet);
314            }
315        }
316        ipv6_addr_from_bytes(&ip_address_bytes).expect("should be valid")
317    }
318
319    #[derive(Copy, Clone, Eq, Hash, PartialEq)]
320    pub struct SocketAddrV6 {
321        pub addr: Ipv6Address,
322        pub port: u16,
323    }
324
325    #[allow(clippy::len_without_is_empty)]
326    #[allow(clippy::trivially_copy_pass_by_ref)]
327    impl SocketAddrV6 {
328        pub fn new(addr: Ipv6Address, port: u16) -> Self {
329            SocketAddrV6 { addr, port }
330        }
331
332        #[allow(clippy::too_many_arguments)]
333        pub fn new_ip6_port(
334            a0: u16,
335            a1: u16,
336            a2: u16,
337            a3: u16,
338            a4: u16,
339            a5: u16,
340            a6: u16,
341            a7: u16,
342            port: u16,
343        ) -> Self {
344            SocketAddrV6 {
345                addr: Ipv6Address::new(a0, a1, a2, a3, a4, a5, a6, a7),
346                port,
347            }
348        }
349
350        pub fn len(&self) -> usize {
351            LEN_V6
352        }
353
354        pub fn to_vec(&self) -> Vec<u8> {
355            let mut result = Vec::with_capacity(self.len());
356            result.extend_from_slice(&self.addr.0);
357            result.extend_from_slice(&port_to_bytes(self.port));
358            result
359        }
360    }
361
362    impl fmt::Display for SocketAddrV6 {
363        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364            write!(f, "[{}]:{}", self.addr, self.port)
365        }
366    }
367
368    impl fmt::Debug for SocketAddrV6 {
369        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
370            fmt::Display::fmt(self, fmt)
371        }
372    }
373}
374
375#[cfg(feature = "std")]
376mod std {
377    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
378    use ::std::net::{IpAddr, SocketAddr as StdSocketAddr};
379    #[cfg(feature = "proto-ipv4")]
380    use ::std::net::{Ipv4Addr, SocketAddrV4 as StdSocketAddrV4};
381    #[cfg(feature = "proto-ipv6")]
382    use ::std::net::{Ipv6Addr, SocketAddrV6 as StdSocketAddrV6};
383
384    #[cfg(feature = "proto-ipv4")]
385    use smoltcp::wire::Ipv4Address;
386    #[cfg(feature = "proto-ipv6")]
387    use smoltcp::wire::Ipv6Address;
388    #[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
389    use smoltcp::wire::{IpAddress, IpEndpoint};
390
391    #[cfg(any(feature = "proto-ipv4", feature = "proto-ipv6"))]
392    use super::SocketAddr;
393    #[cfg(feature = "proto-ipv4")]
394    use super::SocketAddrV4;
395    #[cfg(feature = "proto-ipv6")]
396    use super::SocketAddrV6;
397    use super::{Error, Result};
398
399    #[cfg(feature = "proto-ipv4")]
400    pub trait IntoStdIpv4Addr: Sized {
401        fn into_std(self) -> Ipv4Addr;
402    }
403
404    #[cfg(feature = "proto-ipv4")]
405    impl IntoStdIpv4Addr for Ipv4Address {
406        fn into_std(self) -> Ipv4Addr {
407            self.0.into()
408        }
409    }
410
411    #[cfg(feature = "proto-ipv6")]
412    pub trait IntoStdIpv6Addr: Sized {
413        fn into_std(self) -> Ipv6Addr;
414    }
415
416    #[cfg(feature = "proto-ipv6")]
417    impl IntoStdIpv6Addr for Ipv6Address {
418        fn into_std(self) -> Ipv6Addr {
419            self.0.into()
420        }
421    }
422
423    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
424    pub trait IntoStdIpAddr: Sized {
425        fn into_std(self) -> Result<IpAddr>;
426    }
427
428    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
429    impl IntoStdIpAddr for IpAddress {
430        fn into_std(self) -> Result<IpAddr> {
431            match self {
432                IpAddress::Ipv4(ip) => Ok(ip.0.into()),
433                IpAddress::Ipv6(ip) => Ok(ip.0.into()),
434                IpAddress::Unspecified => Err(Error::UnspecifiedIp),
435                _ => unreachable!(),
436            }
437        }
438    }
439
440    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
441    pub trait IntoStdSocketAddr: Sized {
442        fn into_std(self) -> Result<StdSocketAddr>;
443    }
444
445    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
446    impl IntoStdSocketAddr for IpEndpoint {
447        fn into_std(self) -> Result<StdSocketAddr> {
448            let addr: IpAddr = self.addr.into_std()?;
449            Ok(StdSocketAddr::new(addr, self.port))
450        }
451    }
452
453    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
454    impl From<SocketAddr> for StdSocketAddr {
455        fn from(val: SocketAddr) -> Self {
456            match val {
457                SocketAddr::V4(val) => {
458                    StdSocketAddr::V4(StdSocketAddrV4::new(val.addr.0.into(), val.port))
459                }
460                SocketAddr::V6(val) => {
461                    StdSocketAddr::V6(StdSocketAddrV6::new(val.addr.0.into(), val.port, 0, 0))
462                }
463            }
464        }
465    }
466
467    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
468    impl From<&SocketAddr> for StdSocketAddr {
469        fn from(val: &SocketAddr) -> Self {
470            match val {
471                SocketAddr::V4(val) => {
472                    StdSocketAddr::V4(StdSocketAddrV4::new(val.addr.0.into(), val.port))
473                }
474                SocketAddr::V6(val) => {
475                    StdSocketAddr::V6(StdSocketAddrV6::new(val.addr.0.into(), val.port, 0, 0))
476                }
477            }
478        }
479    }
480
481    #[cfg(all(feature = "proto-ipv4", feature = "proto-ipv6"))]
482    impl From<StdSocketAddr> for SocketAddr {
483        fn from(val: StdSocketAddr) -> Self {
484            match val {
485                StdSocketAddr::V4(val) => SocketAddr::V4(SocketAddrV4 {
486                    addr: Ipv4Address::from(*val.ip()),
487                    port: val.port(),
488                }),
489                StdSocketAddr::V6(val) => SocketAddr::V6(SocketAddrV6 {
490                    addr: Ipv6Address::from(*val.ip()),
491                    port: val.port(),
492                }),
493            }
494        }
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    use ::std::env;
501    #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
502    use ::std::net::IpAddr;
503    #[cfg(all(feature = "std", feature = "proto-ipv4"))]
504    use ::std::net::Ipv4Addr;
505    #[cfg(all(feature = "std", feature = "proto-ipv6"))]
506    use ::std::net::Ipv6Addr;
507    #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
508    use ::std::net::SocketAddr as StdSocketAddr;
509
510    use super::*;
511
512    #[cfg(feature = "proto-ipv4")]
513    #[test]
514    fn ipv4_socket_addr() {
515        if env::var("RUST_LOG").is_err() {
516            env::set_var("RUST_LOG", "debug");
517        }
518        let _ = pretty_env_logger::try_init_timed();
519
520        let ip_address_bytes = [127, 0, 0, 1];
521        let ip_address: Ipv4Address = ipv4_addr(127, 0, 0, 1);
522        info!("ip4 ip_address: {}", ip_address);
523        info!("ip4 ip_address debug: {:?}", ip_address);
524        assert_eq!(ip_address.as_bytes(), &ip_address_bytes);
525
526        let socket_addr = SocketAddrV4::new_ip4_port(127, 0, 0, 1, 8080);
527        info!("ip4 socket_addr: {}", socket_addr);
528        info!("ip4 socket_addr debug: {:?}", socket_addr);
529        assert_eq!(socket_addr.len(), LEN_V4);
530        assert_eq!(socket_addr.addr.as_bytes(), &ip_address_bytes);
531        assert_eq!(
532            socket_addr.addr.as_bytes(),
533            &socket_addr.to_vec().as_slice()[0..4]
534        );
535        assert_eq!(socket_addr.port, 8080);
536    }
537
538    #[cfg(feature = "proto-ipv6")]
539    #[test]
540    fn ipv6_socket_addr() {
541        if env::var("RUST_LOG").is_err() {
542            env::set_var("RUST_LOG", "debug");
543        }
544        let _ = pretty_env_logger::try_init_timed();
545
546        let ip_address_bytes: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
547        info!("ip6 ip_address_bytes: {:x?}", ip_address_bytes);
548
549        let ip_address: Ipv6Address = ipv6_addr(0, 0, 0, 0, 0, 0, 0, 1);
550        info!("ip6 ip_address: {}", ip_address);
551        info!("ip6 ip_address debug: {:?}", ip_address);
552        assert_eq!(ip_address.as_bytes(), &ip_address_bytes);
553
554        let socket_addr = SocketAddrV6::new_ip6_port(0, 0, 0, 0, 0, 0, 0, 1, 8080);
555        info!("ip6 socket_addr: {}", socket_addr);
556        info!("ip6 socket_addr debug: {:?}", socket_addr);
557        assert_eq!(socket_addr.len(), LEN_V6);
558        assert_eq!(socket_addr.addr.as_bytes(), &ip_address_bytes);
559        assert_eq!(
560            socket_addr.addr.as_bytes(),
561            &socket_addr.to_vec().as_slice()[0..16]
562        );
563        assert_eq!(socket_addr.port, 8080);
564    }
565
566    #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
567    #[test]
568    fn ipv4_to_std() {
569        if env::var("RUST_LOG").is_err() {
570            env::set_var("RUST_LOG", "debug");
571        }
572        let _ = pretty_env_logger::try_init_timed();
573
574        let ip_address_bytes = [127, 0, 0, 1];
575        let ip_address: Ipv4Address = ipv4_addr(127, 0, 0, 1);
576        let std_ip_address: Ipv4Addr = ip_address.into_std();
577        assert_eq!(std_ip_address.octets().as_ref(), ip_address_bytes);
578        let std_ip_address: Result<IpAddr> = IpAddress::Ipv4(ip_address).into_std();
579        assert_eq!(std_ip_address, Ok(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
580
581        let socket_addr_v4 = SocketAddrV4::new(ip_address, 80);
582        assert_eq!(socket_addr_v4.len(), LEN_V4);
583        let socket_addr = SocketAddr::V4(socket_addr_v4);
584        assert_eq!(
585            Ok(socket_addr),
586            SocketAddr::new(IpAddress::Ipv4(ip_address), 80)
587        );
588        assert_eq!(
589            Err(Error::UnspecifiedIp),
590            SocketAddr::new(IpAddress::Unspecified, 80)
591        );
592        assert_eq!(socket_addr, SocketAddr::new_v4(ip_address, 80));
593        assert_eq!(socket_addr, SocketAddr::new_ip4_port(127, 0, 0, 1, 80));
594        assert_eq!(socket_addr.len(), LEN_V4);
595        assert_eq!(socket_addr.ip().as_bytes(), ip_address_bytes);
596        assert_eq!(socket_addr.ip_octets(), ip_address_bytes);
597        let socket_addr_vec = socket_addr.to_vec();
598        assert_eq!(socket_addr_vec[0..4], ip_address_bytes);
599        assert_eq!(port_from_bytes(socket_addr_vec[4], socket_addr_vec[5]), 80);
600        info!("ip4 socket_addr: {}", socket_addr);
601        info!("ip4 socket_addr debug: {:?}", socket_addr);
602
603        let std_socket_addr: StdSocketAddr = socket_addr.into();
604        assert!(std_socket_addr.ip().is_loopback());
605        assert_eq!(std_socket_addr.ip().to_string(), "127.0.0.1".to_string());
606        assert_eq!(std_socket_addr.port(), socket_addr_v4.port);
607        assert_eq!(std_socket_addr.port(), socket_addr.port());
608    }
609
610    #[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
611    #[test]
612    fn ipv6_to_std() {
613        if env::var("RUST_LOG").is_err() {
614            env::set_var("RUST_LOG", "debug");
615        }
616        let _ = pretty_env_logger::try_init_timed();
617
618        let ip_address_bytes: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
619        let ip_address: Ipv6Address = ipv6_addr(0, 0, 0, 0, 0, 0, 0, 1);
620        let std_ip_address: Ipv6Addr = ip_address.into_std();
621        assert_eq!(std_ip_address.octets().as_ref(), ip_address_bytes);
622        let std_ip_address: Result<IpAddr> = IpAddress::Ipv6(ip_address).into_std();
623        assert_eq!(
624            std_ip_address,
625            Ok(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)))
626        );
627
628        let socket_addr_v6 = SocketAddrV6::new(ip_address, 80);
629        assert_eq!(socket_addr_v6.len(), LEN_V6);
630        let socket_addr = SocketAddr::V6(socket_addr_v6);
631        assert_eq!(
632            Ok(socket_addr),
633            SocketAddr::new(IpAddress::Ipv6(ip_address), 80)
634        );
635        assert_eq!(
636            Err(Error::UnspecifiedIp),
637            SocketAddr::new(IpAddress::Unspecified, 80)
638        );
639        assert_eq!(socket_addr, SocketAddr::new_v6(ip_address, 80));
640        assert_eq!(
641            socket_addr,
642            SocketAddr::new_ip6_port(0, 0, 0, 0, 0, 0, 0, 1, 80)
643        );
644        assert_eq!(socket_addr.len(), LEN_V6);
645        assert_eq!(socket_addr.ip().as_bytes(), ip_address_bytes);
646        assert_eq!(socket_addr.ip_octets(), ip_address_bytes);
647        let socket_addr_vec = socket_addr.to_vec();
648        assert_eq!(socket_addr_vec[0..16], ip_address_bytes);
649        assert_eq!(
650            port_from_bytes(socket_addr_vec[16], socket_addr_vec[17]),
651            80
652        );
653        info!("ip6 socket_addr: {}", socket_addr);
654        info!("ip6 socket_addr debug: {:?}", socket_addr);
655
656        let std_socket_addr: StdSocketAddr = socket_addr.into();
657        assert!(std_socket_addr.ip().is_loopback());
658        assert_eq!(std_socket_addr.ip().to_string(), "::1".to_string());
659        assert_eq!(std_socket_addr.port(), socket_addr_v6.port);
660        assert_eq!(std_socket_addr.port(), socket_addr.port());
661    }
662}