1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! nwep address, an ipv6 socket address NW110300.
//!
//! Address is the opaque transport address a server binds and a client dials.
//! web/1 is ipv6 only, so an ipv4 address is carried in the ::ffff:a.b.c.d
//! mapped form. it is a plain value, cheap to copy. construct one from a part
//! (loopback, a std SocketAddr, raw bytes) and read its port back.
use crate::error::{Error, Result};
use core::fmt;
use core::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
use core::str::FromStr;
use nwep_sys as sys;
/// Address is an opaque ipv6 socket address, the bind or dial target of a node.
#[derive(Clone, Copy)]
pub struct Address(sys::nwep_address);
impl Address {
/// builds the ::1 loopback address at port.
pub fn loopback(port: u16) -> Address {
let mut a = sys::nwep_address { opaque: [0; 32] };
// SAFETY: all pointers are valid references for the duration of the call; sizes match the nwep.h contract.
unsafe { sys::nwep_address_loopback(&mut a, port) };
Address(a)
}
/// builds the :: wildcard address (all interfaces) at port.
pub fn wildcard(port: u16) -> Address {
let mut a = sys::nwep_address { opaque: [0; 32] };
// SAFETY: all pointers are valid references for the duration of the call; sizes match the nwep.h contract.
unsafe { sys::nwep_address_wildcard(&mut a, port) };
Address(a)
}
/// builds the ::ffff:a.b.c.d ipv4 mapped address at port NW110300.
pub fn ipv4_mapped(a: u8, b: u8, c: u8, d: u8, port: u16) -> Address {
let mut addr = sys::nwep_address { opaque: [0; 32] };
// SAFETY: all pointers are valid references for the duration of the call; sizes match the nwep.h contract.
unsafe { sys::nwep_address_ipv4_mapped(&mut addr, a, b, c, d, port) };
Address(addr)
}
/// builds an address from 16 raw ipv6 bytes (network order) and a port.
pub fn from_bytes(addr: [u8; 16], port: u16) -> Address {
let mut out = sys::nwep_address { opaque: [0; 32] };
// SAFETY: all pointers are valid references for the duration of the call; sizes match the nwep.h contract.
unsafe { sys::nwep_address_from_bytes(&mut out, addr.as_ptr(), port) };
Address(out)
}
/// returns the host order port of this address.
pub fn port(&self) -> u16 {
// SAFETY: all pointers are valid references for the duration of the call; sizes match the nwep.h contract.
unsafe { sys::nwep_address_get_port(&self.0) }
}
/// borrows the raw c address, for handing to a lower layer (no-cliffs).
// used by the server and client slices to pass a bind or dial target down.
#[allow(dead_code)]
pub(crate) fn as_raw(&self) -> &sys::nwep_address {
&self.0
}
/// wraps a raw c address returned by a lower layer (for example a dht record).
pub(crate) fn from_raw(raw: sys::nwep_address) -> Address {
Address(raw)
}
}
impl From<SocketAddrV6> for Address {
fn from(s: SocketAddrV6) -> Address {
Address::from_bytes(s.ip().octets(), s.port())
}
}
impl From<SocketAddr> for Address {
fn from(s: SocketAddr) -> Address {
match s {
SocketAddr::V6(v6) => v6.into(),
SocketAddr::V4(v4) => {
let o = v4.ip().octets();
Address::ipv4_mapped(o[0], o[1], o[2], o[3], v4.port())
}
}
}
}
impl From<(Ipv6Addr, u16)> for Address {
fn from((ip, port): (Ipv6Addr, u16)) -> Address {
Address::from_bytes(ip.octets(), port)
}
}
impl FromStr for Address {
type Err = Error;
/// parses a socket address like the ::1 loopback or a v4 host, each with a port.
///
/// an ipv4 address becomes its ::ffff:a.b.c.d mapped form NW110300.
///
/// returns the parsed [Address].
/// errors [Error::ConfigInvalid] when s is not a valid socket address.
fn from_str(s: &str) -> Result<Address> {
s.parse::<SocketAddr>()
.map(Address::from)
.map_err(|_| Error::ConfigInvalid)
}
}
impl fmt::Debug for Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// the address bytes are opaque NW110300, so only the port is shown.
f.debug_struct("Address")
.field("port", &self.port())
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn constructors_carry_the_port() {
assert_eq!(Address::loopback(443).port(), 443);
assert_eq!(Address::wildcard(80).port(), 80);
assert_eq!(Address::ipv4_mapped(127, 0, 0, 1, 7000).port(), 7000);
assert_eq!(Address::from_bytes([0; 16], 9).port(), 9);
}
#[test]
fn parses_v6_and_v4_socket_strings() {
assert_eq!("[::1]:443".parse::<Address>().unwrap().port(), 443);
assert_eq!("127.0.0.1:8080".parse::<Address>().unwrap().port(), 8080);
assert!("not an address".parse::<Address>().is_err());
}
}