Skip to content

Commit a4da863

Browse files
authored
feat!: distinguish peer and peer_id on api level (#136)
1 parent ef62dd9 commit a4da863

12 files changed

+275
-129
lines changed

.circleci/config.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@ workflows:
77
- rust/lint-test-build:
88
clippy_arguments: '--all-targets --all-features -- --deny warnings'
99
release: true
10-
version: 1.71.1
11-
10+
version: 1.81.0

src/cid.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
1-
use std::fmt::Debug;
2-
use std::hash::Hash;
3-
use std::net::SocketAddr;
4-
5-
/// A remote peer.
6-
pub trait ConnectionPeer: Clone + Debug + Eq + Hash + PartialEq + Send + Sync {}
7-
8-
impl ConnectionPeer for SocketAddr {}
9-
101
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
112
pub struct ConnectionId<P> {
123
pub send: u16,
134
pub recv: u16,
14-
pub peer: P,
5+
pub peer_id: P,
156
}

src/conn.rs

+23-17
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ use delay_map::HashMapDelay;
88
use futures::StreamExt;
99
use tokio::sync::{mpsc, oneshot, Notify};
1010

11-
use crate::cid::{ConnectionId, ConnectionPeer};
11+
use crate::cid::ConnectionId;
1212
use crate::congestion;
1313
use crate::event::{SocketEvent, StreamEvent};
1414
use crate::packet::{Packet, PacketBuilder, PacketType, SelectiveAck};
15+
use crate::peer::ConnectionPeer;
16+
use crate::peer::Peer;
1517
use crate::recv::ReceiveBuffer;
1618
use crate::send::SendBuffer;
1719
use crate::sent::{SentPackets, SentPacketsError};
@@ -167,9 +169,10 @@ impl From<ConnectionConfig> for congestion::Config {
167169
}
168170
}
169171

170-
pub struct Connection<const N: usize, P> {
172+
pub struct Connection<const N: usize, P: ConnectionPeer> {
171173
state: State<N>,
172-
cid: ConnectionId<P>,
174+
cid: ConnectionId<P::Id>,
175+
peer: Peer<P>,
173176
config: ConnectionConfig,
174177
endpoint: Endpoint,
175178
peer_ts_diff: Duration,
@@ -185,7 +188,8 @@ pub struct Connection<const N: usize, P> {
185188

186189
impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
187190
pub fn new(
188-
cid: ConnectionId<P>,
191+
cid: ConnectionId<P::Id>,
192+
peer: Peer<P>,
189193
config: ConnectionConfig,
190194
syn: Option<Packet>,
191195
connected: oneshot::Sender<io::Result<()>>,
@@ -212,6 +216,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
212216
Self {
213217
state: State::Connecting(Some(connected)),
214218
cid,
219+
peer,
215220
config,
216221
endpoint,
217222
peer_ts_diff,
@@ -232,15 +237,15 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
232237
mut writes: mpsc::UnboundedReceiver<Write>,
233238
mut shutdown: oneshot::Receiver<()>,
234239
) -> io::Result<()> {
235-
tracing::debug!("uTP conn starting... {:?}", self.cid.peer);
240+
tracing::debug!("uTP conn starting... {:?}", self.peer);
236241

237242
// If we are the initiating endpoint, then send the SYN. If we are the accepting endpoint,
238243
// then send the SYN-ACK.
239244
match self.endpoint {
240245
Endpoint::Initiator((syn_seq_num, ..)) => {
241246
let syn = self.syn_packet(syn_seq_num);
242247
self.socket_events
243-
.send(SocketEvent::Outgoing((syn.clone(), self.cid.peer.clone())))
248+
.send(SocketEvent::Outgoing((syn.clone(), self.peer.clone())))
244249
.unwrap();
245250
self.unacked
246251
.insert_at(syn_seq_num, syn, self.config.initial_timeout);
@@ -250,7 +255,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
250255
Endpoint::Acceptor((syn, syn_ack)) => {
251256
let state = self.state_packet().unwrap();
252257
self.socket_events
253-
.send(SocketEvent::Outgoing((state, self.cid.peer.clone())))
258+
.send(SocketEvent::Outgoing((state, self.peer.clone())))
254259
.unwrap();
255260

256261
let recv_buf = ReceiveBuffer::new(syn);
@@ -409,7 +414,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
409414
&mut self.unacked,
410415
&mut self.socket_events,
411416
fin,
412-
&self.cid.peer,
417+
&self.peer,
413418
Instant::now(),
414419
);
415420
}
@@ -441,7 +446,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
441446
&mut self.unacked,
442447
&mut self.socket_events,
443448
fin,
444-
&self.cid.peer,
449+
&self.peer,
445450
Instant::now(),
446451
);
447452
}
@@ -542,7 +547,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
542547
&mut self.unacked,
543548
&mut self.socket_events,
544549
packet,
545-
&self.cid.peer,
550+
&self.peer,
546551
now,
547552
);
548553
seq_num = seq_num.wrapping_add(1);
@@ -680,7 +685,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
680685
let packet = self.syn_packet(seq);
681686
let _ = self
682687
.socket_events
683-
.send(SocketEvent::Outgoing((packet, self.cid.peer.clone())));
688+
.send(SocketEvent::Outgoing((packet, self.peer.clone())));
684689
}
685690
}
686691
Endpoint::Acceptor(..) => {}
@@ -728,7 +733,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
728733
&mut self.unacked,
729734
&mut self.socket_events,
730735
packet,
731-
&self.cid.peer,
736+
&self.peer,
732737
now,
733738
);
734739
}
@@ -784,7 +789,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
784789
match packet.packet_type() {
785790
PacketType::Syn | PacketType::Fin | PacketType::Data => {
786791
if let Some(state) = self.state_packet() {
787-
let event = SocketEvent::Outgoing((state, self.cid.peer.clone()));
792+
let event = SocketEvent::Outgoing((state, self.peer.clone()));
788793
if self.socket_events.send(event).is_err() {
789794
tracing::warn!("Cannot transmit state packet: socket closed channel");
790795
return;
@@ -1156,7 +1161,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
11561161
&mut self.unacked,
11571162
&mut self.socket_events,
11581163
packet,
1159-
&self.cid.peer,
1164+
&self.peer,
11601165
now,
11611166
);
11621167
}
@@ -1167,7 +1172,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
11671172
unacked: &mut HashMapDelay<u16, Packet>,
11681173
socket_events: &mut mpsc::UnboundedSender<SocketEvent<P>>,
11691174
packet: Packet,
1170-
dest: &P,
1175+
peer: &Peer<P>,
11711176
now: Instant,
11721177
) {
11731178
let (payload, len) = if packet.payload().is_empty() {
@@ -1189,7 +1194,7 @@ impl<const N: usize, P: ConnectionPeer> Connection<N, P> {
11891194

11901195
sent_packets.on_transmit(packet.seq_num(), packet.packet_type(), payload, len, now);
11911196
unacked.insert_at(packet.seq_num(), packet.clone(), sent_packets.timeout());
1192-
let outbound = SocketEvent::Outgoing((packet, dest.clone()));
1197+
let outbound = SocketEvent::Outgoing((packet, peer.clone()));
11931198
if socket_events.send(outbound).is_err() {
11941199
tracing::warn!("Cannot transmit packet: socket closed channel");
11951200
}
@@ -1214,12 +1219,13 @@ mod test {
12141219
let cid = ConnectionId {
12151220
send: 101,
12161221
recv: 100,
1217-
peer,
1222+
peer_id: peer,
12181223
};
12191224

12201225
Connection {
12211226
state: State::Connecting(Some(connected)),
12221227
cid,
1228+
peer: Peer::new(peer),
12231229
config: ConnectionConfig::default(),
12241230
endpoint,
12251231
peer_ts_diff: Duration::from_millis(100),

src/event.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::cid::ConnectionId;
22
use crate::packet::Packet;
3+
use crate::peer::{ConnectionPeer, Peer};
34

45
#[derive(Clone, Debug)]
56
pub enum StreamEvent {
@@ -8,7 +9,7 @@ pub enum StreamEvent {
89
}
910

1011
#[derive(Clone, Debug)]
11-
pub enum SocketEvent<P> {
12-
Outgoing((Packet, P)),
13-
Shutdown(ConnectionId<P>),
12+
pub enum SocketEvent<P: ConnectionPeer> {
13+
Outgoing((Packet, Peer<P>)),
14+
Shutdown(ConnectionId<P::Id>),
1415
}

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod congestion;
33
pub mod conn;
44
pub mod event;
55
pub mod packet;
6+
pub mod peer;
67
pub mod recv;
78
pub mod send;
89
pub mod sent;

src/peer.rs

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use std::fmt::Debug;
2+
use std::hash::Hash;
3+
use std::net::SocketAddr;
4+
5+
/// A trait that describes remote peer
6+
pub trait ConnectionPeer: Debug + Clone + Send + Sync {
7+
type Id: Debug + Clone + PartialEq + Eq + Hash + Send + Sync;
8+
9+
/// Returns peer's id
10+
fn id(&self) -> Self::Id;
11+
12+
/// Consolidates two peers into one.
13+
///
14+
/// It's possible that we have two instances that represent the same peer (equal `peer_id`),
15+
/// and we need to consolidate them into one. This can happen when [Peer]-s passed with
16+
/// [UtpSocket::accept_with_cid](crate::socket::UtpSocket::accept_with_cid) or
17+
/// [UtpSocket::connect_with_cid](crate::socket::UtpSocket::connect_with_cid), and returned by
18+
/// [AsyncUdpSocket::recv_from](crate::udp::AsyncUdpSocket::recv_from) contain peers (not just
19+
/// `peer_id`).
20+
///
21+
/// The structure implementing this trait can decide on the exact behavior. Some examples:
22+
/// - If structure is simple (i.e. two peers are the same iff all fields are the same), return
23+
/// either (see implementation for `SocketAddr`)
24+
/// - If we can determine which peer is newer (e.g. using timestamp or version field), return
25+
/// newer peer
26+
/// - If structure behaves more like a key-value map whose values don't change over time,
27+
/// merge key-value pairs from both instances into one
28+
///
29+
/// Should panic if ids are not matching.
30+
fn consolidate(a: Self, b: Self) -> Self;
31+
}
32+
33+
impl ConnectionPeer for SocketAddr {
34+
type Id = Self;
35+
36+
fn id(&self) -> Self::Id {
37+
*self
38+
}
39+
40+
fn consolidate(a: Self, b: Self) -> Self {
41+
assert!(a == b, "Consolidating non-equal peers");
42+
a
43+
}
44+
}
45+
46+
/// Structure that stores peer's id, and maybe peer as well.
47+
#[derive(Debug, Clone)]
48+
pub struct Peer<P: ConnectionPeer> {
49+
id: P::Id,
50+
peer: Option<P>,
51+
}
52+
53+
impl<P: ConnectionPeer> Peer<P> {
54+
/// Creates new instance that stores peer
55+
pub fn new(peer: P) -> Self {
56+
Self {
57+
id: peer.id(),
58+
peer: Some(peer),
59+
}
60+
}
61+
62+
/// Creates new instance that only stores peer's id
63+
pub fn new_id(peer_id: P::Id) -> Self {
64+
Self {
65+
id: peer_id,
66+
peer: None,
67+
}
68+
}
69+
70+
/// Returns peer's id
71+
pub fn id(&self) -> &P::Id {
72+
&self.id
73+
}
74+
75+
/// Returns optional reference to peer
76+
pub fn peer(&self) -> Option<&P> {
77+
self.peer.as_ref()
78+
}
79+
80+
/// Consolidates given peer into `Self` whilst consuming it.
81+
///
82+
/// See [ConnectionPeer::consolidate] for details.
83+
///
84+
/// Panics if ids are not matching.
85+
pub fn consolidate(&mut self, other: Self) {
86+
assert!(self.id == other.id, "Consolidating with non-equal peer");
87+
let Some(other_peer) = other.peer else {
88+
return;
89+
};
90+
91+
self.peer = match self.peer.take() {
92+
Some(peer) => Some(P::consolidate(peer, other_peer)),
93+
None => Some(other_peer),
94+
};
95+
}
96+
}

0 commit comments

Comments
 (0)