enet/
host.rs

1use std;
2use ll;
3use crate::{
4  peer, Address, EnetDrop, Event, Packet, Peer, MAX_PEERS, MAX_CHANNEL_COUNT
5};
6
7////////////////////////////////////////////////////////////////////////////////
8//  structs                                                                   //
9////////////////////////////////////////////////////////////////////////////////
10
11/// An ENet host for communicating with peers.
12///
13/// A `Host` cannot be sent accross threads but will keep Enet alive.
14#[derive(Clone, Debug)]
15pub struct Host {
16  hostdrop : std::rc::Rc <HostDrop>
17}
18
19#[derive(Debug, PartialEq)]
20pub(crate) struct HostDrop {
21  raw      : *mut ll::ENetHost,
22  enetdrop : std::sync::Arc <EnetDrop>
23}
24
25////////////////////////////////////////////////////////////////////////////////
26//  enums                                                                     //
27////////////////////////////////////////////////////////////////////////////////
28
29#[derive(Debug)]
30pub enum Error {
31  /// Error from `service()`
32  ServiceError,
33  /// Error from `check_events()`
34  DispatchError
35}
36
37#[derive(Clone, Debug)]
38pub enum CreateError {
39  /// Maximum peer count is `enet::MAX_PEERS` (4096)
40  TooManyPeers    (u32),
41  /// Maximum channel count is `enet::MAX_CHANNEL_COUNT` (255)
42  TooManyChannels (u32),
43  ReturnedNull
44}
45
46////////////////////////////////////////////////////////////////////////////////
47//  impls                                                                     //
48////////////////////////////////////////////////////////////////////////////////
49
50impl Host {
51  pub(crate) fn new (
52    address            : Option <Address>,
53    peer_count         : u32,
54    channel_limit      : Option <u32>,
55    incoming_bandwidth : Option <u32>,
56    outgoing_bandwidth : Option <u32>,
57    enetdrop           : std::sync::Arc <EnetDrop>
58  ) -> Result <Self, CreateError> {
59    if MAX_PEERS < peer_count {
60      return Err (CreateError::TooManyPeers (peer_count))
61    }
62    let channel_limit = channel_limit.unwrap_or (0);
63    if MAX_CHANNEL_COUNT < channel_limit {
64      return Err (CreateError::TooManyChannels (channel_limit))
65    }
66    let host;
67    match address {
68      Some (a) => unsafe {
69        host = ll::enet_host_create (
70          a.raw(),
71          peer_count    as usize,
72          channel_limit as usize,
73          incoming_bandwidth.unwrap_or (0),
74          outgoing_bandwidth.unwrap_or (0)
75        );
76        if host.is_null() {
77          return Err (CreateError::ReturnedNull)
78        }
79      },
80      None => unsafe {
81        host = ll::enet_host_create (
82          std::ptr::null(),
83          peer_count    as usize,
84          channel_limit as usize,
85          incoming_bandwidth.unwrap_or (0),
86          outgoing_bandwidth.unwrap_or (0)
87        );
88        if host.is_null() {
89          return Err (CreateError::ReturnedNull)
90        }
91      }
92    } // end match address
93    Ok (Host {
94      hostdrop: std::rc::Rc::new (HostDrop {
95        raw: host, enetdrop
96      })
97    })
98  } // end new
99
100  /// # Safety
101  ///
102  /// Unsafe: returns raw pointer.
103  #[inline]
104  pub unsafe fn raw (&self) -> *mut ll::ENetHost {
105    unsafe { self.hostdrop.raw() }
106  }
107
108  /// Number of peers allocated for this host
109  #[inline]
110  pub fn peer_count (&self) -> usize {
111    unsafe { (*self.raw()).peerCount }
112  }
113
114  /// Number of connected peers
115  #[inline]
116  pub fn connected_peers (&self) -> usize {
117    unsafe { (*self.raw()).connectedPeers }
118  }
119
120  /// Maximum number of channels for incoming connections
121  #[inline]
122  pub fn channel_limit (&self) -> usize {
123    unsafe { (*self.raw()).channelLimit }
124  }
125
126  /// Total UDP packets sent.
127  ///
128  /// User must reset to prevent overflow.
129  #[inline]
130  pub fn total_sent_packets (&self) -> u32 {
131    unsafe { (*self.raw()).totalSentPackets }
132  }
133  pub fn reset_total_sent_packets (&mut self) {
134    unsafe {
135      (*self.raw()).totalSentPackets = 0;
136    }
137  }
138
139  /// Total bytes sent.
140  ///
141  /// User must reset to prevent overflow.
142  #[inline]
143  pub fn total_sent_data (&self) -> u32 {
144    unsafe { (*self.raw()).totalSentPackets }
145  }
146  pub fn reset_total_sent_data (&mut self) {
147    unsafe {
148      (*self.raw()).totalSentData = 0;
149    }
150  }
151
152  /// Total UDP packets received.
153  ///
154  /// User must reset to prevent overflow.
155  #[inline]
156  pub fn total_received_packets (&self) -> u32 {
157    unsafe { (*self.raw()).totalReceivedPackets }
158  }
159  pub fn reset_total_received_packets (&mut self) {
160    unsafe {
161      (*self.raw()).totalReceivedPackets = 0;
162    }
163  }
164
165  /// Total bytes received.
166  ///
167  /// User must reset to prevent overflow.
168  #[inline]
169  pub fn total_received_data (&self) -> u32 {
170    unsafe { (*self.raw()).totalReceivedPackets }
171  }
172  pub fn reset_total_received_data (&mut self) {
173    unsafe {
174      (*self.raw()).totalReceivedData = 0;
175    }
176  }
177
178
179  /// Initiate a connection with a remote host.
180  ///
181  /// When connecting to a peer with the `host.connect()` method, a `Peer` representing
182  /// the connection will be created in the `PeerState::Connecting` state:
183  /// ```
184  /// # use enet::Address;
185  /// # let enet = enet::initialize().unwrap();
186  /// # let mut client = enet.client_host_create (1, None, None).unwrap();
187  /// let mut peer = client.connect (&Address::localhost (12345), 2, 0);
188  /// ```
189  /// where the second argument (`2`) is the number of channels to allocate to
190  /// the connection and the third argument (`0`) is an internal `data : u32`
191  /// that can be used by the application.
192  ///
193  /// After receipt of a `Connect` event, the peer is ready to use.
194  ///
195  /// *Note*: after receipt of the `Connect` event on the host that originated
196  /// the connection request, a call to `flush()` or `service()` is required to
197  /// *acknowledge* the connection has succeeded in order to generate the
198  /// corresponding `Connect` event on the server end.
199  ///
200  /// That connection will now be 'in use' until the peer is changed to the
201  /// `PeerState::Disconnected` state.
202  ///
203  /// Note that `Host`s can connect *mutually* (host A connected to host B, and
204  /// host B connected to host A), or *multiply* (host A connected to host B
205  /// more than 1 time), and each connection will have its own `Peer` structure
206  /// in each host A and B.
207  pub fn connect (&mut self, address : &Address, channel_count : u8, data : u32)
208    -> Result <Peer, peer::ConnectError>
209  {
210    unsafe {
211      if self.peer_count() <= self.connected_peers() {
212        return Err (peer::ConnectError::NoPeersAvailable)
213      }
214      let peer = ll::enet_host_connect (
215        self.raw(),
216        address.raw(),
217        channel_count as usize,
218        data
219      );
220      if peer.is_null() {
221        return Err (peer::ConnectError::Failure)
222      }
223      Ok (Peer::from_raw(peer, self.hostdrop.clone()))
224    }
225  }
226
227  /// Waits for events on the host specified and shuttles packets between the
228  /// host and its peers. Sends queued messages and dispatches events.
229  /// Alternatively, `flush()` will send queued messages without dispatching
230  /// events.
231  ///
232  /// `timeout` is the number of milliseconds that ENet should wait for events.
233  pub fn service (&mut self, timeout : u32) -> Result <Option <Event>, Error> {
234    let event = unsafe {
235      let mut mem = std::mem::MaybeUninit::<ll::ENetEvent>::uninit();
236      let event   = mem.as_mut_ptr();
237      if ll::enet_host_service (self.hostdrop.raw, event, timeout) < 0 {
238        return Err (Error::ServiceError)
239      }
240      *event
241    };
242    Ok (Event::from_ll (event, self.hostdrop.clone()))
243  }
244
245  /// Checks for any queued events on the host and dispatches one if available
246  #[inline]
247  pub fn check_events (&mut self) -> Result <Option <Event>, Error> {
248    let event = unsafe {
249      let mut mem = std::mem::MaybeUninit::<ll::ENetEvent>::uninit();
250      let event   = mem.as_mut_ptr();
251      if ll::enet_host_check_events (self.hostdrop.raw, event) < 0 {
252        return Err (Error::DispatchError)
253      }
254      *event
255    };
256    Ok (Event::from_ll (event, self.hostdrop.clone()))
257  }
258
259  /// Send any queued messages without dispatching events. Alternatively,
260  /// `service()` will send queued messages and also dispatch events.
261  #[inline]
262  pub fn flush (&mut self) {
263    unsafe { ll::enet_host_flush (self.hostdrop.raw) }
264  }
265
266  /// Queue a packet to be sent to all peers associated with the host
267  pub fn broadcast (&mut self, channel_id : u8, packet : Packet) {
268    unsafe {
269      let raw = match packet {
270        Packet::Allocate { bytes, flags } => {
271          ll::enet_packet_create (
272            bytes.as_ptr() as *const std::os::raw::c_void,
273            bytes.len(),
274            flags.bits())
275        }
276        #[expect(clippy::unnecessary_cast)]  // NOTE: on windows ll flags are i32
277        Packet::NoAllocate { bytes, flags } => {
278          ll::enet_packet_create (
279            bytes.as_ptr() as *const std::os::raw::c_void,
280            bytes.len(),
281            flags.bits() | ll::_ENetPacketFlag_ENET_PACKET_FLAG_NO_ALLOCATE as u32)
282        }
283      };
284      ll::enet_host_broadcast (self.raw(), channel_id, raw)
285    }
286  }
287
288} // end impl Host
289
290impl HostDrop {
291  #[inline]
292  pub(crate) const unsafe fn raw (&self) -> *mut ll::ENetHost {
293    self.raw
294  }
295}
296impl Drop for HostDrop {
297  #[inline]
298  fn drop (&mut self) {
299    unsafe { ll::enet_host_destroy (self.raw) }
300  }
301}