Skip to content

Commit b448b18

Browse files
committed
Make PeerID generational
Side effects: The members of the PeerEvent now need to be private to make sure the Peer is correctly cleaned up.
1 parent e765e0f commit b448b18

File tree

5 files changed

+194
-91
lines changed

5 files changed

+194
-91
lines changed

examples/client.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ fn main() -> anyhow::Result<()> {
3434

3535
println!("[client] event: {:#?}", e);
3636

37-
match e.kind {
38-
EventKind::Connect => break e.peer_id,
37+
match e.kind() {
38+
EventKind::Connect => break e.peer_id(),
3939
EventKind::Disconnect { data } => {
4040
println!(
4141
"connection NOT successful, peer: {:?}, reason: {}",
42-
e.peer_id, data
42+
e.peer_id(),
43+
data
4344
);
4445
std::process::exit(0);
4546
}

examples/server.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ fn main() -> anyhow::Result<()> {
2222

2323
loop {
2424
// Wait 500 ms for any events.
25-
if let Some(Event { kind, .. }) = host
25+
if let Some(event) = host
2626
.service(Duration::from_secs(1))
2727
.context("service failed")?
2828
{
29-
match kind {
30-
EventKind::Connect => println!("new connection!"),
31-
EventKind::Disconnect { .. } => println!("disconnect!"),
32-
EventKind::Receive { channel_id, packet } => println!(
29+
match event.kind() {
30+
&EventKind::Connect => println!("new connection!"),
31+
&EventKind::Disconnect { .. } => println!("disconnect!"),
32+
&EventKind::Receive {
33+
ref channel_id,
34+
ref packet,
35+
} => println!(
3336
"got packet on channel {}, content: '{}'",
3437
channel_id,
3538
std::str::from_utf8(packet.data()).unwrap()

src/event.rs

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ use enet_sys::{
44
_ENetEventType_ENET_EVENT_TYPE_NONE, _ENetEventType_ENET_EVENT_TYPE_RECEIVE,
55
};
66

7-
use crate::{Host, Packet, PeerID};
7+
use crate::{Host, Packet, Peer, PeerID};
88

99
/// This struct represents an event that can occur when servicing an `Host`.
1010
#[derive(Debug)]
11-
pub struct Event {
12-
/// The peer that this event happened on.
13-
pub peer_id: PeerID,
14-
/// The type of this event.
15-
pub kind: EventKind,
11+
pub struct Event<'a, T> {
12+
peer: &'a mut Peer<T>,
13+
peer_id: PeerID,
14+
kind: EventKind,
1615
}
1716

1817
/// The type of an event.
@@ -22,7 +21,7 @@ pub enum EventKind {
2221
Connect,
2322
/// Peer has disconnected.
2423
//
25-
/// The data of the peer will be dropped on the next call to Host::service or when the structure is dropped.
24+
/// The data of the peer will be dropped when the received `Event` is dropped.
2625
Disconnect {
2726
/// The data associated with this event. Usually a reason for disconnection.
2827
data: u32,
@@ -36,12 +35,13 @@ pub enum EventKind {
3635
},
3736
}
3837

39-
impl Event {
40-
pub(crate) fn from_sys_event<T>(event_sys: ENetEvent, host: &Host<T>) -> Option<Event> {
38+
impl<'a, T> Event<'a, T> {
39+
pub(crate) fn from_sys_event(event_sys: ENetEvent, host: &'a Host<T>) -> Option<Event<'a, T>> {
4140
if event_sys.type_ == _ENetEventType_ENET_EVENT_TYPE_NONE {
4241
return None;
4342
}
4443

44+
let peer = unsafe { Peer::new_mut(&mut *event_sys.peer) };
4545
let peer_id = unsafe { host.peer_id(event_sys.peer) };
4646
let kind = match event_sys.type_ {
4747
_ENetEventType_ENET_EVENT_TYPE_CONNECT => EventKind::Connect,
@@ -55,6 +55,61 @@ impl Event {
5555
_ => panic!("unrecognized event type: {}", event_sys.type_),
5656
};
5757

58-
Some(Event { peer_id, kind })
58+
Some(Event {
59+
peer,
60+
peer_id,
61+
kind,
62+
})
63+
}
64+
65+
/// The peer that this event happened on.
66+
pub fn peer(&'_ self) -> &'_ Peer<T> {
67+
&*self.peer
68+
}
69+
70+
/// The peer that this event happened on.
71+
pub fn peer_mut(&'_ mut self) -> &'_ mut Peer<T> {
72+
self.peer
73+
}
74+
75+
/// The `PeerID` of the peer that this event happened on.
76+
pub fn peer_id(&self) -> PeerID {
77+
self.peer_id
78+
}
79+
80+
/// The type of this event.
81+
pub fn kind(&self) -> &EventKind {
82+
&self.kind
83+
}
84+
85+
/// Take the EventKind out of this event.
86+
/// If this peer is a Disconnect event, it will clean up the Peer.
87+
/// See the `Drop` implementation
88+
pub fn take_kind(mut self) -> EventKind {
89+
// Unfortunately we can't simply take the `kind` out of the Event, as otherwise the `Drop`
90+
// implementation would no longer work.
91+
// We can however, swap the actual EventKind with an empty EventKind (in this case
92+
// Connect).
93+
// As the `Drop` implementation will then do nothing, we need to call cleanup_after_disconnect before we do the swap.
94+
self.cleanup_after_disconnect();
95+
96+
let mut kind = EventKind::Connect;
97+
std::mem::swap(&mut kind, &mut self.kind);
98+
kind
99+
}
100+
101+
fn cleanup_after_disconnect(&mut self) {
102+
match self.kind {
103+
EventKind::Disconnect { .. } => self.peer.cleanup_after_disconnect(),
104+
EventKind::Connect | EventKind::Receive { .. } => {}
105+
}
106+
}
107+
}
108+
109+
/// Dropping an `Event` with `EventKind::Disconnect` will clean up the Peer, by dropping
110+
/// the data associated with the `Peer`, as well as invalidating the `PeerID`.
111+
impl<'a, T> Drop for Event<'a, T> {
112+
fn drop(&mut self) {
113+
self.cleanup_after_disconnect();
59114
}
60115
}

src/host.rs

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use enet_sys::{
66
ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT,
77
};
88

9-
use crate::{Address, EnetKeepAlive, Error, Event, EventKind, Peer, PeerID};
9+
use crate::{Address, EnetKeepAlive, Error, Event, Peer, PeerID};
1010

1111
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1212
/// Represents a bandwidth limit or unlimited.
@@ -60,7 +60,6 @@ impl BandwidthLimit {
6060
/// transmission.
6161
pub struct Host<T> {
6262
inner: *mut ENetHost,
63-
disconnect_drop: Option<PeerID>,
6463
_keep_alive: Arc<EnetKeepAlive>,
6564
_peer_data: PhantomData<*const T>,
6665
}
@@ -71,7 +70,6 @@ impl<T> Host<T> {
7170

7271
Host {
7372
inner,
74-
disconnect_drop: None,
7573
_keep_alive,
7674
_peer_data: PhantomData,
7775
}
@@ -134,33 +132,41 @@ impl<T> Host<T> {
134132
unsafe { (*self.inner).peerCount }
135133
}
136134

137-
/// Returns a mutable reference to a peer at the index, None if the index is invalid.
135+
/// Returns a mutable reference to a peer at the given PeerID, None if the index is invalid.
138136
pub fn peer_mut(&mut self, idx: PeerID) -> Option<&mut Peer<T>> {
139-
if idx.0 >= self.peer_count() {
137+
if !(0..self.peer_count() as isize).contains(&idx.index) {
140138
return None;
141139
}
142140

143-
Some(Peer::new_mut(unsafe {
144-
&mut *((*self.inner).peers.offset(idx.0 as isize))
145-
}))
141+
let peer = Peer::new_mut(unsafe { &mut *((*self.inner).peers.offset(idx.index)) });
142+
if peer.generation() != idx.generation {
143+
return None;
144+
}
145+
146+
Some(peer)
146147
}
147148

148-
/// Returns a reference to a peer at the index, None if the index is invalid.
149+
/// Returns a reference to a peer at the given PeerID, None if the index is invalid.
149150
pub fn peer(&self, idx: PeerID) -> Option<&Peer<T>> {
150-
if idx.0 >= self.peer_count() {
151+
if !(0..self.peer_count() as isize).contains(&idx.index) {
151152
return None;
152153
}
153154

154-
Some(Peer::new(unsafe {
155-
&*((*self.inner).peers.offset(idx.0 as isize))
156-
}))
155+
let peer = Peer::new(unsafe { &*((*self.inner).peers.offset(idx.index)) });
156+
if peer.generation() != idx.generation {
157+
return None;
158+
}
159+
160+
Some(peer)
157161
}
158162

159163
pub(crate) unsafe fn peer_id(&self, peer: *mut ENetPeer) -> PeerID {
160-
PeerID(
161-
(peer as enet_sys::size_t - (*self.inner).peers as enet_sys::size_t)
162-
/ std::mem::size_of::<ENetPeer>() as enet_sys::size_t,
163-
)
164+
let index = peer.offset_from((*self.inner).peers);
165+
let peer = Peer::<T>::new_mut(&mut *peer);
166+
PeerID {
167+
index,
168+
generation: peer.generation(),
169+
}
164170
}
165171

166172
/// Returns an iterator over all peers connected to this `Host`.
@@ -187,39 +193,16 @@ impl<T> Host<T> {
187193
peers.iter().map(|peer| Peer::new(&*peer))
188194
}
189195

190-
fn drop_disconnected(&mut self) {
191-
// Seemingly, the lifetime of an ENetPeer ends when the Disconnect event is received.
192-
// However, this is *not really clear* in the ENet docs!
193-
// It looks like the Peer *might* live longer, but not shorter, so it should be safe
194-
// to destroy the associated data (if any) here.
195-
if let Some(idx) = self.disconnect_drop.take() {
196-
self.peer_mut(idx)
197-
.expect("Invalid PeerID in disconnect_drop in enet::Host")
198-
.set_data(None);
199-
}
200-
}
201-
202-
fn process_event(&mut self, sys_event: ENetEvent) -> Option<Event> {
203-
self.drop_disconnected();
204-
205-
let event = Event::from_sys_event(sys_event, self);
206-
if let Some(Event {
207-
peer_id,
208-
kind: EventKind::Disconnect { .. },
209-
}) = event
210-
{
211-
self.disconnect_drop = Some(peer_id);
212-
}
213-
214-
event
196+
fn process_event(&'_ mut self, sys_event: ENetEvent) -> Option<Event<'_, T>> {
197+
Event::from_sys_event(sys_event, self)
215198
}
216199

217200
/// Maintains this host and delivers an event if available.
218201
///
219202
/// This should be called regularly for ENet to work properly with good performance.
220203
///
221204
/// The function won't block if `timeout` is less than 1ms.
222-
pub fn service(&mut self, timeout: Duration) -> Result<Option<Event>, Error> {
205+
pub fn service(&'_ mut self, timeout: Duration) -> Result<Option<Event<'_, T>>, Error> {
223206
// ENetEvent is Copy (aka has no Drop impl), so we don't have to make sure we `mem::forget` it later on
224207
let mut sys_event = MaybeUninit::uninit();
225208

@@ -244,7 +227,7 @@ impl<T> Host<T> {
244227

245228
/// Checks for any queued events on this `Host` and dispatches one if
246229
/// available
247-
pub fn check_events(&mut self) -> Result<Option<Event>, Error> {
230+
pub fn check_events(&'_ mut self) -> Result<Option<Event<'_, T>>, Error> {
248231
// ENetEvent is Copy (aka has no Drop impl), so we don't have to make sure we
249232
// `mem::forget` it later on
250233
let mut sys_event = MaybeUninit::uninit();
@@ -298,7 +281,7 @@ impl<T> Drop for Host<T> {
298281
/// Call the corresponding ENet cleanup-function(s).
299282
fn drop(&mut self) {
300283
for peer in self.peers_mut() {
301-
peer.set_data(None);
284+
peer.drop_raw_data();
302285
}
303286

304287
unsafe {

0 commit comments

Comments
 (0)