libp2p_core/
connection.rs

1// Copyright 2020 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use crate::multiaddr::{Multiaddr, Protocol};
22
23/// The endpoint roles associated with a peer-to-peer communication channel.
24#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
25pub enum Endpoint {
26    /// The socket comes from a dialer.
27    Dialer,
28    /// The socket comes from a listener.
29    Listener,
30}
31
32impl std::ops::Not for Endpoint {
33    type Output = Endpoint;
34
35    fn not(self) -> Self::Output {
36        match self {
37            Endpoint::Dialer => Endpoint::Listener,
38            Endpoint::Listener => Endpoint::Dialer,
39        }
40    }
41}
42
43impl Endpoint {
44    /// Is this endpoint a dialer?
45    pub fn is_dialer(self) -> bool {
46        matches!(self, Endpoint::Dialer)
47    }
48
49    /// Is this endpoint a listener?
50    pub fn is_listener(self) -> bool {
51        matches!(self, Endpoint::Listener)
52    }
53}
54
55/// The endpoint roles associated with an established peer-to-peer connection.
56#[derive(PartialEq, Eq, Debug, Clone, Hash)]
57pub enum ConnectedPoint {
58    /// We dialed the node.
59    Dialer {
60        /// Multiaddress that was successfully dialed.
61        address: Multiaddr,
62        /// Whether the role of the local node on the connection should be
63        /// overriden. I.e. whether the local node should act as a listener on
64        /// the outgoing connection.
65        ///
66        /// This option is needed for NAT and firewall hole punching.
67        ///
68        /// - [`Endpoint::Dialer`] represents the default non-overriding option.
69        ///
70        /// - [`Endpoint::Listener`] represents the overriding option.
71        ///   Realization depends on the transport protocol. E.g. in the case of
72        ///   TCP, both endpoints dial each other, resulting in a _simultaneous
73        ///   open_ TCP connection. On this new connection both endpoints assume
74        ///   to be the dialer of the connection. This is problematic during the
75        ///   connection upgrade process where an upgrade assumes one side to be
76        ///   the listener. With the help of this option, both peers can
77        ///   negotiate the roles (dialer and listener) for the new connection
78        ///   ahead of time, through some external channel, e.g. the DCUtR
79        ///   protocol, and thus have one peer dial the other and upgrade the
80        ///   connection as a dialer and one peer dial the other and upgrade the
81        ///   connection _as a listener_ overriding its role.
82        role_override: Endpoint,
83    },
84    /// We received the node.
85    Listener {
86        /// Local connection address.
87        local_addr: Multiaddr,
88        /// Address used to send back data to the remote.
89        send_back_addr: Multiaddr,
90    },
91}
92
93impl From<&'_ ConnectedPoint> for Endpoint {
94    fn from(endpoint: &'_ ConnectedPoint) -> Endpoint {
95        endpoint.to_endpoint()
96    }
97}
98
99impl From<ConnectedPoint> for Endpoint {
100    fn from(endpoint: ConnectedPoint) -> Endpoint {
101        endpoint.to_endpoint()
102    }
103}
104
105impl ConnectedPoint {
106    /// Turns the `ConnectedPoint` into the corresponding `Endpoint`.
107    pub fn to_endpoint(&self) -> Endpoint {
108        match self {
109            ConnectedPoint::Dialer { .. } => Endpoint::Dialer,
110            ConnectedPoint::Listener { .. } => Endpoint::Listener,
111        }
112    }
113
114    /// Returns true if we are `Dialer`.
115    pub fn is_dialer(&self) -> bool {
116        match self {
117            ConnectedPoint::Dialer { .. } => true,
118            ConnectedPoint::Listener { .. } => false,
119        }
120    }
121
122    /// Returns true if we are `Listener`.
123    pub fn is_listener(&self) -> bool {
124        match self {
125            ConnectedPoint::Dialer { .. } => false,
126            ConnectedPoint::Listener { .. } => true,
127        }
128    }
129
130    /// Returns true if the connection is relayed.
131    pub fn is_relayed(&self) -> bool {
132        match self {
133            ConnectedPoint::Dialer {
134                address,
135                role_override: _,
136            } => address,
137            ConnectedPoint::Listener { local_addr, .. } => local_addr,
138        }
139        .iter()
140        .any(|p| p == Protocol::P2pCircuit)
141    }
142
143    /// Returns the address of the remote stored in this struct.
144    ///
145    /// For `Dialer`, this returns `address`. For `Listener`, this returns `send_back_addr`.
146    ///
147    /// Note that the remote node might not be listening on this address and hence the address might
148    /// not be usable to establish new connections.
149    pub fn get_remote_address(&self) -> &Multiaddr {
150        match self {
151            ConnectedPoint::Dialer { address, .. } => address,
152            ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
153        }
154    }
155
156    /// Modifies the address of the remote stored in this struct.
157    ///
158    /// For `Dialer`, this modifies `address`. For `Listener`, this modifies `send_back_addr`.
159    pub fn set_remote_address(&mut self, new_address: Multiaddr) {
160        match self {
161            ConnectedPoint::Dialer { address, .. } => *address = new_address,
162            ConnectedPoint::Listener { send_back_addr, .. } => *send_back_addr = new_address,
163        }
164    }
165}