renet2_netcode/
server.rs

1use std::{io, net::SocketAddr, time::Duration};
2
3use renetcode2::{NetcodeServer, ServerConfig, ServerResult, NETCODE_MAX_PACKET_BYTES, NETCODE_USER_DATA_BYTES};
4use renetcode2::{ServerAuthentication, ServerSocketConfig};
5
6use renet2::{ClientId, Payload, RenetServer};
7
8use super::{NetcodeTransportError, ServerSocket};
9
10/// Config for setting up a [`NetcodeServerTransport`].
11///
12/// Will be converted to a [`ServerConfig`].
13pub struct ServerSetupConfig {
14    pub current_time: Duration,
15    /// Maximum numbers of clients that can be connected at a time
16    pub max_clients: usize,
17    /// Unique identifier for this particular game/application.
18    /// You can use a hash function with the current version of the game to generate this value
19    /// so that older versions cannot connect to newer versions.
20    pub protocol_id: u64,
21    /// Public addresses for each socket associated with this server.
22    pub socket_addresses: Vec<Vec<SocketAddr>>,
23    /// Authentication configuration for the server
24    pub authentication: ServerAuthentication,
25}
26
27/// Convenience wrapper for [`ServerSocket`].
28///
29/// Used in [`NetcodeServerTransport::new_with_sockets`].
30pub struct BoxedSocket(Box<dyn ServerSocket>);
31
32impl BoxedSocket {
33    /// Makes a new boxed socket.
34    pub fn new(socket: impl ServerSocket) -> Self {
35        Self(Box::new(socket))
36    }
37}
38
39#[derive(Debug)]
40#[cfg_attr(feature = "bevy", derive(bevy_ecs::resource::Resource))]
41pub struct NetcodeServerTransport {
42    sockets: Vec<Box<dyn ServerSocket>>,
43    netcode_server: NetcodeServer,
44    buffer: [u8; NETCODE_MAX_PACKET_BYTES],
45}
46
47impl NetcodeServerTransport {
48    /// Makes a new server transport that uses `netcode` for managing connections and data flow.
49    pub fn new(server_config: ServerSetupConfig, socket: impl ServerSocket) -> Result<Self, std::io::Error> {
50        Self::new_with_sockets(server_config, vec![BoxedSocket::new(socket)])
51    }
52
53    /// Makes a new server transport that uses `netcode` for managing connections and data flow.
54    ///
55    /// Multiple [`ServerSockets`](ServerSocket) may be inserted. Each socket must line
56    /// up 1:1 with socket entries in [`ServerSetupConfig::socket_addresses`].
57    pub fn new_with_sockets(mut server_config: ServerSetupConfig, mut boxed: Vec<BoxedSocket>) -> Result<Self, std::io::Error> {
58        if server_config.socket_addresses.is_empty() {
59            panic!("netcode server transport must have at least 1 socket");
60        }
61        if server_config.socket_addresses.len() != boxed.len() {
62            panic!("server config does not match the number of sockets");
63        }
64
65        // Unwrap the boxed sockets so they can be accessed as raw boxes.
66        let mut sockets = Vec::with_capacity(boxed.len());
67        for socket in boxed.drain(..) {
68            sockets.push(socket.0);
69        }
70
71        // Transfer config details, use the actual socket impls to determine whether the sockets need netcode encryption.
72        let mut socket_configs = Vec::with_capacity(sockets.len());
73        let mut socket_addresses = std::mem::take(&mut server_config.socket_addresses);
74        for (addrs, socket) in socket_addresses.drain(..).zip(sockets.iter()) {
75            socket_configs.push(ServerSocketConfig {
76                needs_encryption: !socket.is_encrypted(),
77                public_addresses: addrs,
78            });
79        }
80
81        let server_config = ServerConfig {
82            current_time: server_config.current_time,
83            max_clients: server_config.max_clients,
84            protocol_id: server_config.protocol_id,
85            sockets: socket_configs,
86            authentication: server_config.authentication,
87        };
88
89        Ok(Self {
90            sockets,
91            netcode_server: NetcodeServer::new(server_config),
92            buffer: [0; NETCODE_MAX_PACKET_BYTES],
93        })
94    }
95
96    /// Returns the server's public addresses for the first transport socket.
97    pub fn addresses(&self) -> Vec<SocketAddr> {
98        self.get_addresses(0).unwrap()
99    }
100
101    /// Returns the server's public addresses for a given `socket_id`.
102    pub fn get_addresses(&self, socket_id: usize) -> Option<Vec<SocketAddr>> {
103        if socket_id >= self.sockets.len() {
104            return None;
105        }
106        Some(self.netcode_server.addresses(socket_id))
107    }
108
109    /// Returns the maximum number of clients that can be connected.
110    pub fn max_clients(&self) -> usize {
111        self.netcode_server.max_clients()
112    }
113
114    /// Update the maximum numbers of clients that can be connected.
115    ///
116    /// Changing the `max_clients` to a lower value than the current number of connect clients
117    /// does not disconnect clients. So [`NetcodeServerTransport::connected_clients()`] can
118    /// return a higher value than [`NetcodeServerTransport::max_clients()`].
119    pub fn set_max_clients(&mut self, max_clients: usize) {
120        self.netcode_server.set_max_clients(max_clients);
121    }
122
123    /// Returns current number of clients connected.
124    pub fn connected_clients(&self) -> usize {
125        self.netcode_server.connected_clients()
126    }
127
128    /// Returns the user data for client if connected.
129    pub fn user_data(&self, client_id: ClientId) -> Option<[u8; NETCODE_USER_DATA_BYTES]> {
130        self.netcode_server.user_data(client_id)
131    }
132
133    /// Returns the client socket id and address if connected.
134    pub fn client_addr(&self, client_id: ClientId) -> Option<(usize, SocketAddr)> {
135        self.netcode_server.client_addr(client_id)
136    }
137
138    /// Disconnects all connected clients.
139    ///
140    /// This sends the disconnect packet instantly, use this when closing/exiting games,
141    /// should use [RenetServer::disconnect_all] otherwise.
142    pub fn disconnect_all(&mut self, server: &mut RenetServer) {
143        for client_id in self.netcode_server.clients_id() {
144            let server_result = self.netcode_server.disconnect(client_id);
145            handle_server_result(server_result, &mut self.sockets, server);
146        }
147    }
148
149    /// Returns the duration since the connected client last received a packet.
150    ///
151    /// Useful to detect users that are timing out.
152    pub fn time_since_last_received_packet(&self, client_id: ClientId) -> Option<Duration> {
153        self.netcode_server.time_since_last_received_packet(client_id)
154    }
155
156    /// Advances the transport by the duration, and receive packets from the network.
157    pub fn update(&mut self, duration: Duration, server: &mut RenetServer) -> Result<(), Vec<NetcodeTransportError>> {
158        self.netcode_server.update(duration);
159
160        let mut transport_errors = Vec::default();
161        for socket_id in 0..self.sockets.len() {
162            self.sockets[socket_id].preupdate();
163
164            loop {
165                match self.sockets[socket_id].try_recv(&mut self.buffer) {
166                    Ok((len, addr)) => {
167                        let server_result = self.netcode_server.process_packet(socket_id, addr, &mut self.buffer[..len]);
168                        handle_server_result(server_result, &mut self.sockets, server);
169                    }
170                    Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
171                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => break,
172                    Err(ref e) if e.kind() == io::ErrorKind::ConnectionReset => continue,
173                    Err(e) => {
174                        transport_errors.push(e.into());
175                    }
176                };
177            }
178        }
179
180        for client_id in self.netcode_server.clients_id() {
181            let server_result = self.netcode_server.update_client(client_id);
182            handle_server_result(server_result, &mut self.sockets, server);
183        }
184
185        for disconnection_id in server.disconnections_id() {
186            let server_result = self.netcode_server.disconnect(disconnection_id);
187            handle_server_result(server_result, &mut self.sockets, server);
188        }
189
190        for socket in self.sockets.iter_mut() {
191            socket.postupdate();
192        }
193
194        if !transport_errors.is_empty() {
195            return Err(transport_errors);
196        }
197
198        Ok(())
199    }
200
201    /// Sends packets to connected clients.
202    pub fn send_packets(&mut self, server: &mut RenetServer) {
203        //TODO: it isn't necessary to allocate client ids here, just use one big vec of packets for all clients
204        // - also, the vec can be cached in RenetServer for reuse, and likewise with the internal pieces of packets
205        for client_id in server.clients_id() {
206            let packets = server.get_packets_to_send(client_id).unwrap();
207            for packet in packets {
208                if !send_packet_to_client(&mut self.sockets, &mut self.netcode_server, server, &packet, client_id) {
209                    break;
210                }
211            }
212        }
213    }
214}
215
216/// Sends a packet to a client.
217///
218/// Disconnects the client if its address connection is broken.
219fn send_packet_to_client(
220    sockets: &mut [Box<dyn ServerSocket>],
221    netcode_server: &mut NetcodeServer,
222    reliable_server: &mut RenetServer,
223    packet: &Payload,
224    client_id: ClientId,
225) -> bool {
226    let (send_result, socket_id, addr) = match netcode_server.generate_payload_packet(client_id, packet) {
227        Ok((socket_id, addr, payload)) => (sockets[socket_id].send(addr, payload), socket_id, addr),
228        Err(e) => {
229            log::error!("Failed to encrypt payload packet for client {client_id}: {e}");
230            return false;
231        }
232    };
233
234    match send_result {
235        Ok(()) => true,
236        Err(NetcodeTransportError::IO(ref e)) if e.kind() == io::ErrorKind::ConnectionAborted => {
237            // Manually disconnect the client if the client's address is disconnected.
238            reliable_server.remove_connection(client_id);
239            // Ignore the server result since this client is not connected.
240            let _ = netcode_server.disconnect(client_id);
241
242            false
243        }
244        Err(e) => {
245            log::error!("Failed to send packet to client {client_id} ({socket_id}/{addr}): {e}");
246            false
247        }
248    }
249}
250
251fn handle_server_result(server_result: ServerResult, sockets: &mut [Box<dyn ServerSocket>], reliable_server: &mut RenetServer) {
252    let send_packet = |sockets: &mut [Box<dyn ServerSocket>], packet: &[u8], socket_id: usize, addr: SocketAddr| {
253        if let Err(err) = sockets[socket_id].send(addr, packet) {
254            log::trace!("Failed to send packet to {socket_id}/{addr}: {err}");
255        }
256    };
257
258    match server_result {
259        ServerResult::None => {}
260        ServerResult::Error { addr, socket_id } => {
261            sockets[socket_id].disconnect(addr);
262        }
263        ServerResult::ConnectionDenied { addr, socket_id, payload } => {
264            if let Some(payload) = payload {
265                send_packet(sockets, payload, socket_id, addr);
266            }
267            sockets[socket_id].connection_denied(addr);
268        }
269        ServerResult::ConnectionAccepted {
270            client_id,
271            addr,
272            socket_id,
273            payload,
274        } => {
275            sockets[socket_id].connection_accepted(client_id, addr);
276            send_packet(sockets, payload, socket_id, addr);
277        }
278        ServerResult::PacketToSend { payload, addr, socket_id } => {
279            send_packet(sockets, payload, socket_id, addr);
280        }
281        ServerResult::Payload { client_id, payload } => {
282            if let Err(e) = reliable_server.process_packet_from(payload, client_id) {
283                log::error!("Error while processing payload for {}: {}", client_id, e);
284            }
285        }
286        ServerResult::ClientConnected {
287            client_id,
288            user_data: _,
289            addr,
290            payload,
291            socket_id,
292        } => {
293            reliable_server.add_connection(client_id, sockets[socket_id].is_reliable());
294            send_packet(sockets, payload, socket_id, addr);
295        }
296        ServerResult::ClientDisconnected {
297            client_id,
298            addr,
299            payload,
300            socket_id,
301        } => {
302            reliable_server.remove_connection(client_id);
303            if let Some(payload) = payload {
304                send_packet(sockets, payload, socket_id, addr);
305            }
306            sockets[socket_id].disconnect(addr);
307        }
308    }
309}