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::{
22 multiaddr::{Multiaddr, Protocol},
23 transport::PortUse,
24};
25
26/// The endpoint roles associated with a peer-to-peer communication channel.
27#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
28pub enum Endpoint {
29 /// The socket comes from a dialer.
30 Dialer,
31 /// The socket comes from a listener.
32 Listener,
33}
34
35impl std::ops::Not for Endpoint {
36 type Output = Endpoint;
37
38 fn not(self) -> Self::Output {
39 match self {
40 Endpoint::Dialer => Endpoint::Listener,
41 Endpoint::Listener => Endpoint::Dialer,
42 }
43 }
44}
45
46impl Endpoint {
47 /// Is this endpoint a dialer?
48 pub fn is_dialer(self) -> bool {
49 matches!(self, Endpoint::Dialer)
50 }
51
52 /// Is this endpoint a listener?
53 pub fn is_listener(self) -> bool {
54 matches!(self, Endpoint::Listener)
55 }
56}
57
58/// The endpoint roles associated with an established peer-to-peer connection.
59#[derive(PartialEq, Eq, Debug, Clone, Hash)]
60pub enum ConnectedPoint {
61 /// We dialed the node.
62 Dialer {
63 /// Multiaddress that was successfully dialed.
64 address: Multiaddr,
65 /// Whether the role of the local node on the connection should be
66 /// overridden. I.e. whether the local node should act as a listener on
67 /// the outgoing connection.
68 ///
69 /// This option is needed for NAT and firewall hole punching.
70 ///
71 /// - [`Endpoint::Dialer`] represents the default non-overriding option.
72 ///
73 /// - [`Endpoint::Listener`] represents the overriding option.
74 /// Realization depends on the transport protocol. E.g. in the case of
75 /// TCP, both endpoints dial each other, resulting in a _simultaneous
76 /// open_ TCP connection. On this new connection both endpoints assume
77 /// to be the dialer of the connection. This is problematic during the
78 /// connection upgrade process where an upgrade assumes one side to be
79 /// the listener. With the help of this option, both peers can
80 /// negotiate the roles (dialer and listener) for the new connection
81 /// ahead of time, through some external channel, e.g. the DCUtR
82 /// protocol, and thus have one peer dial the other and upgrade the
83 /// connection as a dialer and one peer dial the other and upgrade the
84 /// connection _as a listener_ overriding its role.
85 role_override: Endpoint,
86 /// Whether the port for the outgoing connection was reused from a listener
87 /// or a new port was allocated. This is useful for address translation.
88 ///
89 /// The port use is implemented on a best-effort basis. It is not guaranteed
90 /// that [`PortUse::Reuse`] actually reused a port. A good example is the case
91 /// where there is no listener available to reuse a port from.
92 port_use: PortUse,
93 },
94 /// We received the node.
95 Listener {
96 /// Local connection address.
97 local_addr: Multiaddr,
98 /// Address used to send back data to the remote.
99 send_back_addr: Multiaddr,
100 },
101}
102
103impl From<&'_ ConnectedPoint> for Endpoint {
104 fn from(endpoint: &'_ ConnectedPoint) -> Endpoint {
105 endpoint.to_endpoint()
106 }
107}
108
109impl From<ConnectedPoint> for Endpoint {
110 fn from(endpoint: ConnectedPoint) -> Endpoint {
111 endpoint.to_endpoint()
112 }
113}
114
115impl ConnectedPoint {
116 /// Turns the `ConnectedPoint` into the corresponding `Endpoint`.
117 pub fn to_endpoint(&self) -> Endpoint {
118 match self {
119 ConnectedPoint::Dialer { .. } => Endpoint::Dialer,
120 ConnectedPoint::Listener { .. } => Endpoint::Listener,
121 }
122 }
123
124 /// Returns true if we are `Dialer`.
125 pub fn is_dialer(&self) -> bool {
126 match self {
127 ConnectedPoint::Dialer { .. } => true,
128 ConnectedPoint::Listener { .. } => false,
129 }
130 }
131
132 /// Returns true if we are `Listener`.
133 pub fn is_listener(&self) -> bool {
134 match self {
135 ConnectedPoint::Dialer { .. } => false,
136 ConnectedPoint::Listener { .. } => true,
137 }
138 }
139
140 /// Returns true if the connection is relayed.
141 pub fn is_relayed(&self) -> bool {
142 match self {
143 ConnectedPoint::Dialer {
144 address,
145 role_override: _,
146 port_use: _,
147 } => address,
148 ConnectedPoint::Listener { local_addr, .. } => local_addr,
149 }
150 .iter()
151 .any(|p| p == Protocol::P2pCircuit)
152 }
153
154 /// Returns the address of the remote stored in this struct.
155 ///
156 /// For `Dialer`, this returns `address`. For `Listener`, this returns `send_back_addr`.
157 ///
158 /// Note that the remote node might not be listening on this address and hence the address might
159 /// not be usable to establish new connections.
160 pub fn get_remote_address(&self) -> &Multiaddr {
161 match self {
162 ConnectedPoint::Dialer { address, .. } => address,
163 ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr,
164 }
165 }
166
167 /// Modifies the address of the remote stored in this struct.
168 ///
169 /// For `Dialer`, this modifies `address`. For `Listener`, this modifies `send_back_addr`.
170 pub fn set_remote_address(&mut self, new_address: Multiaddr) {
171 match self {
172 ConnectedPoint::Dialer { address, .. } => *address = new_address,
173 ConnectedPoint::Listener { send_back_addr, .. } => *send_back_addr = new_address,
174 }
175 }
176}