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}