ockam_core/routing/
address.rs

1use crate::compat::rand::{distributions::Standard, prelude::Distribution, random, Rng};
2use crate::compat::{
3    string::{String, ToString},
4    vec::Vec,
5};
6use crate::{
7    serialize, AddressParseError, AddressParseErrorKind, Encodable, Encoded, Result, TransportType,
8    LOCAL,
9};
10use core::fmt::{self, Debug, Display};
11use core::ops::Deref;
12use core::str::from_utf8;
13use minicbor::{CborLen, Decode, Encode};
14use serde::{Deserialize, Serialize};
15
16/// A generic address type.
17///
18/// The address type is parsed by routers to determine the next local
19/// hop in the router chain to resolve a route to a remote connection.
20///
21/// ## Parsing addresses
22///
23/// While addresses are concrete types, creating them from strings is
24/// possible for ergonomic reasons.
25///
26/// When parsing an address from a string, the first `#` symbol is
27/// used to separate the transport type from the rest of the address.
28/// If no `#` symbol is found, the address is assumed to be of `transport =
29/// 0`, the Local Worker transport type.
30///
31/// For example:
32/// * `"0#alice"` represents a local worker with the address: `alice`.
33/// * `"1#carol"` represents a remote worker with the address `carol`, reachable over TCP transport.
34///
35#[derive(
36    Serialize, Deserialize, Encode, Decode, CborLen, Clone, Hash, Ord, PartialOrd, Eq, PartialEq,
37)]
38#[rustfmt::skip]
39pub struct Address {
40    #[n(0)] tt: TransportType,
41    // It's binary but in most cases we assume it to be a UTF-8 string
42    #[cbor(with = "minicbor::bytes")]
43    #[n(1)] inner: Vec<u8>,
44}
45
46impl AsRef<Address> for Address {
47    fn as_ref(&self) -> &Address {
48        self
49    }
50}
51
52impl Encodable for Address {
53    fn encode(self) -> Result<Encoded> {
54        serialize(self)
55    }
56}
57
58impl Address {
59    /// Creates a new address from separate transport type and data parts.
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// # use ockam_core::{Address, TransportType};
65    /// # pub const TCP: TransportType = TransportType::new(1);
66    /// // create a new remote worker address from a transport type and data
67    /// let tcp_worker: Address = Address::new_with_string(TCP, "carol");
68    /// ```
69    pub fn new_with_string(tt: TransportType, data: impl Into<String>) -> Self {
70        Self {
71            tt,
72            inner: data.into().as_bytes().to_vec(),
73        }
74    }
75
76    /// Constructor
77    pub fn new(tt: TransportType, inner: Vec<u8>) -> Self {
78        Self { tt, inner }
79    }
80
81    /// Parses an address from a string.
82    ///
83    /// # Panics
84    ///
85    /// This function will panic if passed an invalid address string.
86    ///
87    /// # Examples
88    ///
89    /// ```
90    /// # use ockam_core::Address;
91    /// // parse a local worker address
92    /// let local_worker: Address = Address::from_string("alice");
93    ///
94    /// // parse a remote worker address reachable over tcp transport
95    /// let tcp_worker: Address = Address::from_string("1#carol");
96    /// ```
97    pub fn from_string<S: Into<String>>(s: S) -> Self {
98        // FIXME: This should not panic...
99        s.into()
100            .parse::<Address>()
101            .unwrap_or_else(|e| panic!("Invalid address string {e}"))
102    }
103
104    /// Get the string value of this address without the address type
105    #[doc(hidden)]
106    pub fn without_type(&self) -> &str {
107        from_utf8(&self.inner).unwrap_or("<unprintable>")
108    }
109
110    /// Generate a random address with the given transport type.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// # use ockam_core::{Address, LOCAL};
116    /// // generate a random local address
117    /// let local_worker: Address = Address::random(LOCAL);
118    /// ```
119    pub fn random(tt: TransportType) -> Self {
120        Self { tt, ..random() }
121    }
122
123    /// Generate a random address with transport type [`LOCAL`].
124    pub fn random_local() -> Self {
125        Self {
126            tt: LOCAL,
127            ..random()
128        }
129    }
130
131    // TODO: Replace with macro to take less space when "debugger" feature is disabled?
132    /// Generate a random address with a debug tag and transport type [`LOCAL`].
133    pub fn random_tagged(_tag: &str) -> Self {
134        #[cfg(feature = "debugger")]
135        {
136            use core::sync::atomic::{AtomicU32, Ordering};
137            static COUNTER: AtomicU32 = AtomicU32::new(0);
138            let address = format!("{}_{}", _tag, COUNTER.fetch_add(1, Ordering::Relaxed),).into();
139            let address = Self {
140                tt: LOCAL,
141                ..address
142            };
143            tracing::trace!("random_tagged => {}", address);
144            address
145        }
146
147        #[cfg(not(feature = "debugger"))]
148        Self::random_local()
149    }
150
151    /// Get transport type of this address.
152    pub fn transport_type(&self) -> TransportType {
153        self.tt
154    }
155
156    /// Get address portion of this address
157    pub fn address(&self) -> &str {
158        from_utf8(self.inner.as_slice()).unwrap_or("Invalid UTF-8")
159    }
160
161    /// Check if address is local
162    pub fn is_local(&self) -> bool {
163        self.tt == LOCAL
164    }
165
166    /// Take inner Vec
167    pub fn inner(self) -> Vec<u8> {
168        self.inner
169    }
170}
171
172impl core::str::FromStr for Address {
173    type Err = AddressParseError;
174    /// Parse an address from a string.
175    ///
176    /// See type documentation for more detail.
177    fn from_str(s: &str) -> Result<Address, Self::Err> {
178        let buf: String = s.into();
179        let mut vec: Vec<_> = buf.split('#').collect();
180
181        // If after the split we only have one element, there was no
182        // `#` separator, so the type needs to be implicitly `= 0`
183        if vec.len() == 1 {
184            Ok(Address {
185                tt: LOCAL,
186                inner: vec.remove(0).as_bytes().to_vec(),
187            })
188        }
189        // If after the split we have 2 elements, we extract the type
190        // value from the string, and use the rest as the address
191        else if vec.len() == 2 {
192            match str::parse(vec.remove(0)) {
193                Ok(tt) => Ok(Address {
194                    tt: TransportType::new(tt),
195                    inner: vec.remove(0).as_bytes().to_vec(),
196                }),
197                Err(e) => Err(AddressParseError::new(AddressParseErrorKind::InvalidType(
198                    e,
199                ))),
200            }
201        } else {
202            Err(AddressParseError::new(AddressParseErrorKind::MultipleSep))
203        }
204    }
205}
206
207impl Display for Address {
208    fn fmt<'a>(&'a self, f: &mut fmt::Formatter) -> fmt::Result {
209        let inner: &'a str = from_utf8(self.inner.as_slice()).unwrap_or("Invalid UTF-8");
210        write!(f, "{}#{}", self.tt, inner)
211    }
212}
213
214impl Debug for Address {
215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216        <Self as Display>::fmt(self, f)
217    }
218}
219
220impl Deref for Address {
221    type Target = Vec<u8>;
222    fn deref(&self) -> &Self::Target {
223        &self.inner
224    }
225}
226
227impl From<String> for Address {
228    fn from(s: String) -> Self {
229        Self::from_string(s)
230    }
231}
232
233impl From<&String> for Address {
234    fn from(s: &String) -> Self {
235        Self::from_string(s.as_str())
236    }
237}
238
239impl<'a> From<&'a str> for Address {
240    fn from(s: &'a str) -> Self {
241        Self::from_string(s)
242    }
243}
244
245impl From<Vec<u8>> for Address {
246    fn from(data: Vec<u8>) -> Self {
247        Self {
248            tt: LOCAL,
249            inner: data,
250        }
251    }
252}
253
254impl From<(TransportType, Vec<u8>)> for Address {
255    fn from((tt, data): (TransportType, Vec<u8>)) -> Self {
256        Self { tt, inner: data }
257    }
258}
259
260impl<'a> From<(TransportType, &'a str)> for Address {
261    fn from((tt, data): (TransportType, &'a str)) -> Self {
262        Self {
263            tt,
264            inner: data.as_bytes().to_vec(),
265        }
266    }
267}
268
269impl<'a> From<(TransportType, &'a String)> for Address {
270    fn from((tt, inner): (TransportType, &'a String)) -> Self {
271        Self::from((tt, inner.as_str()))
272    }
273}
274
275impl From<(TransportType, String)> for Address {
276    fn from((transport, data): (TransportType, String)) -> Self {
277        Self::from((transport, data.as_str()))
278    }
279}
280
281impl<'a> From<&'a [u8]> for Address {
282    fn from(data: &'a [u8]) -> Self {
283        Self {
284            tt: LOCAL,
285            inner: data.to_vec(),
286        }
287    }
288}
289
290impl<'a> From<&'a [&u8]> for Address {
291    fn from(data: &'a [&u8]) -> Self {
292        Self {
293            tt: LOCAL,
294            inner: data.iter().map(|x| **x).collect(),
295        }
296    }
297}
298
299impl From<Address> for String {
300    fn from(address: Address) -> Self {
301        address.to_string()
302    }
303}
304
305impl Distribution<Address> for Standard {
306    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Address {
307        let address: [u8; 16] = rng.gen();
308        hex::encode(address).as_bytes().into()
309    }
310}
311
312impl Address {
313    pub(crate) fn manual_encode(&self, buffer: &mut Vec<u8>) {
314        buffer.push(self.tt.into());
315        crate::bare::write_slice(buffer, &self.inner);
316    }
317
318    pub(crate) fn encoded_size(&self) -> usize {
319        1 + crate::bare::size_of_slice(&self.inner)
320    }
321    pub(crate) fn manually_decode(slice: &[u8], index: &mut usize) -> Option<Address> {
322        if slice.len() - *index < 2 {
323            return None;
324        }
325        let tt = slice[*index];
326        *index += 1;
327
328        let inner = crate::bare::read_slice(slice, index)?;
329        Some(Address {
330            tt: TransportType::new(tt),
331            inner: inner.to_vec(),
332        })
333    }
334}
335
336#[cfg(test)]
337mod test {
338    use super::*;
339    use crate::Encodable;
340
341    #[test]
342    fn encode_and_manually_decode_address() {
343        let super_long_string = "a".repeat(250);
344        let address = Address::from_string("42#".to_string() + &super_long_string);
345        assert_eq!(address.address(), super_long_string.as_str());
346
347        let encoded = address.clone().encode().unwrap();
348        let decoded = Address::manually_decode(&encoded, &mut 0).unwrap();
349        assert_eq!(address, decoded);
350    }
351
352    #[test]
353    fn parse_addr_simple() {
354        let addr = Address::from_string("local_friend");
355        assert_eq!(
356            addr,
357            Address {
358                tt: LOCAL,
359                inner: "local_friend".as_bytes().to_vec(),
360            }
361        );
362    }
363
364    #[test]
365    fn parse_addr_with_type() {
366        let addr = Address::from_string("1#remote_friend");
367        assert_eq!(
368            addr,
369            Address {
370                tt: TransportType::new(1),
371                inner: "remote_friend".as_bytes().to_vec(),
372            }
373        );
374    }
375
376    #[test]
377    #[should_panic(expected = "Failed to parse address type:")]
378    fn parse_addr_invalid() {
379        Address::from_string("#,my_friend");
380    }
381
382    #[test]
383    #[should_panic(expected = "Invalid address string:")]
384    fn parse_addr_invalid_multiple_separators() {
385        let _ = Address::from_string("1#invalid#");
386    }
387}