netcode/
server.rs

1use std::collections::{HashMap, VecDeque};
2use std::net::{SocketAddr, ToSocketAddrs};
3use std::time::{SystemTime, UNIX_EPOCH};
4
5use crate::{
6    bytes::Bytes,
7    crypto::{self, Key},
8    error::{Error, Result},
9    free_list::FreeList,
10    packet::{
11        ChallengePacket, DeniedPacket, DisconnectPacket, KeepAlivePacket, Packet, PayloadPacket,
12        RequestPacket, ResponsePacket,
13    },
14    replay::ReplayProtection,
15    socket::NetcodeSocket,
16    token::{ChallengeToken, ConnectToken, ConnectTokenBuilder, ConnectTokenPrivate},
17    transceiver::Transceiver,
18    MAC_BYTES, MAX_PACKET_SIZE, MAX_PKT_BUF_SIZE, PACKET_SEND_RATE_SEC,
19};
20
21pub const MAX_CLIENTS: usize = 256;
22const RECV_BUF_SIZE: usize = 4 * 1024 * 1024;
23const SEND_BUF_SIZE: usize = 4 * 1024 * 1024;
24
25#[derive(Clone, Copy)]
26struct TokenEntry {
27    time: f64,
28    mac: [u8; 16],
29    addr: SocketAddr,
30}
31
32struct TokenEntries {
33    inner: Vec<TokenEntry>,
34}
35
36impl TokenEntries {
37    fn new() -> Self {
38        Self { inner: Vec::new() }
39    }
40    fn find_or_insert(&mut self, entry: TokenEntry) -> bool {
41        let (mut oldest, mut matching) = (None, None);
42        let mut oldest_time = f64::INFINITY;
43        // Perform a linear search for the oldest and matching entries at the same time
44        for (idx, saved_entry) in self.inner.iter().enumerate() {
45            if entry.time < oldest_time {
46                oldest_time = saved_entry.time;
47                oldest = Some(idx);
48            }
49            if entry.mac == saved_entry.mac {
50                matching = Some(idx);
51            }
52        }
53        let Some(oldest) = oldest else {
54            // If there is no oldest entry then the list is empty, so just insert the entry
55            self.inner.push(entry);
56            return true;
57        };
58        if let Some(matching) = matching {
59            // Allow reusing tokens only if the address matches
60            self.inner[matching].addr == entry.addr
61        } else {
62            // If there is no matching entry, replace the oldest one
63            self.inner[oldest] = entry;
64            true
65        }
66    }
67}
68
69#[derive(Debug, Clone, Copy)]
70struct Connection {
71    confirmed: bool,
72    connected: bool,
73    client_id: ClientId,
74    addr: SocketAddr,
75    timeout: i32,
76    last_access_time: f64,
77    last_send_time: f64,
78    last_receive_time: f64,
79    send_key: Key,
80    receive_key: Key,
81    sequence: u64,
82}
83
84impl Connection {
85    fn confirm(&mut self) {
86        self.confirmed = true;
87    }
88    fn connect(&mut self) {
89        self.connected = true;
90    }
91    fn is_confirmed(&self) -> bool {
92        self.confirmed
93    }
94    fn is_connected(&self) -> bool {
95        self.connected
96    }
97}
98
99/// The client id from a connect token, must be unique for each client.
100///
101/// Note that this is not the same as the [`ClientIndex`](ClientIndex), which is used by the server to identify clients.
102pub type ClientId = u64;
103
104/// Newtype over `usize` used by the server to identify clients.
105#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
106pub struct ClientIndex(pub(crate) usize);
107
108impl<T> std::ops::Index<ClientIndex> for [T] {
109    type Output = T;
110    fn index(&self, index: ClientIndex) -> &Self::Output {
111        &self[index.0]
112    }
113}
114
115impl<T> std::ops::IndexMut<ClientIndex> for [T] {
116    fn index_mut(&mut self, index: ClientIndex) -> &mut Self::Output {
117        &mut self[index.0]
118    }
119}
120
121impl std::fmt::Display for ClientIndex {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        self.0.fmt(f)
124    }
125}
126
127struct ConnectionCache {
128    // this somewhat mimics the original C implementation,
129    // the main difference being that `Connection` includes the encryption mapping as well.
130    clients: FreeList<Connection, MAX_CLIENTS>,
131
132    // we are not using a free-list here to not allocate memory up-front, since `ReplayProtection` is biggish (~2kb)
133    replay_protection: HashMap<ClientIndex, ReplayProtection>,
134
135    // packet queue for all clients
136    packet_queue: VecDeque<(Vec<u8>, ClientIndex)>,
137
138    // corresponds to the server time
139    time: f64,
140}
141
142impl ConnectionCache {
143    fn new(server_time: f64) -> Self {
144        Self {
145            clients: FreeList::new(),
146            replay_protection: HashMap::with_capacity(MAX_CLIENTS),
147            packet_queue: VecDeque::with_capacity(MAX_CLIENTS * 2),
148            time: server_time,
149        }
150    }
151    fn add(
152        &mut self,
153        client_id: ClientId,
154        addr: SocketAddr,
155        timeout: i32,
156        send_key: Key,
157        receive_key: Key,
158    ) {
159        if let Some((_, ref mut existing)) = self.find_by_addr(&addr) {
160            existing.client_id = client_id;
161            existing.timeout = timeout;
162            existing.send_key = send_key;
163            existing.receive_key = receive_key;
164            existing.last_access_time = self.time;
165            return;
166        }
167        let conn = Connection {
168            confirmed: false,
169            connected: false,
170            client_id,
171            addr,
172            timeout,
173            last_access_time: self.time,
174            last_send_time: f64::NEG_INFINITY,
175            last_receive_time: f64::NEG_INFINITY,
176            send_key,
177            receive_key,
178            sequence: 0,
179        };
180        let client_idx = ClientIndex(self.clients.insert(conn));
181        self.replay_protection
182            .insert(client_idx, ReplayProtection::new());
183    }
184    fn remove(&mut self, client_idx: ClientIndex) {
185        let Some(conn) = self.clients.get_mut(client_idx.0) else {
186            return;
187        };
188        if !conn.is_connected() {
189            return;
190        }
191        self.replay_protection.remove(&client_idx);
192        self.clients.remove(client_idx.0);
193    }
194    fn find_by_addr(&self, addr: &SocketAddr) -> Option<(ClientIndex, Connection)> {
195        self.clients
196            .iter()
197            .find_map(|(idx, conn)| (conn.addr == *addr).then_some((ClientIndex(idx), conn)))
198    }
199    fn find_by_id(&self, client_id: ClientId) -> Option<(ClientIndex, Connection)> {
200        self.clients.iter().find_map(|(idx, conn)| {
201            (conn.client_id == client_id).then_some((ClientIndex(idx), conn))
202        })
203    }
204    fn update(&mut self, time: f64) {
205        self.time = time;
206    }
207}
208type Callback<Ctx> = Box<dyn FnMut(ClientIndex, &mut Ctx) + Send + Sync + 'static>;
209/// Configuration for a server.
210///
211/// * `num_disconnect_packets` - The number of redundant disconnect packets that will be sent to a client when the server is disconnecting it.
212/// * `keep_alive_send_rate` - The rate at which keep-alive packets will be sent to clients.
213/// * `on_connect` - A callback that will be called when a client is connected to the server.
214/// * `on_disconnect` - A callback that will be called when a client is disconnected from the server.
215///
216/// # Example
217/// ```
218/// # let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 40005));
219/// # let protocol_id = 0x123456789ABCDEF0;
220/// # let private_key = [42u8; 32];
221/// use std::sync::{Arc, Mutex};
222/// use netcode::{Server, ServerConfig};
223///
224/// let thread_safe_counter = Arc::new(Mutex::new(0));
225/// let cfg = ServerConfig::with_context(thread_safe_counter).on_connect(|idx, ctx| {
226///     let mut counter = ctx.lock().unwrap();
227///     *counter += 1;
228///     println!("client {} connected, counter: {idx}", counter);
229/// });
230/// let server = Server::with_config(addr, protocol_id, private_key, cfg).unwrap();
231/// ```
232pub struct ServerConfig<Ctx> {
233    num_disconnect_packets: usize,
234    keep_alive_send_rate: f64,
235    context: Ctx,
236    on_connect: Option<Callback<Ctx>>,
237    on_disconnect: Option<Callback<Ctx>>,
238}
239impl Default for ServerConfig<()> {
240    fn default() -> Self {
241        Self {
242            num_disconnect_packets: 10,
243            keep_alive_send_rate: PACKET_SEND_RATE_SEC,
244            context: (),
245            on_connect: None,
246            on_disconnect: None,
247        }
248    }
249}
250
251impl<Ctx> ServerConfig<Ctx> {
252    /// Create a new, default server configuration with no context.
253    pub fn new() -> ServerConfig<()> {
254        ServerConfig::<()>::default()
255    }
256    /// Create a new server configuration with context that will be passed to the callbacks.
257    pub fn with_context(ctx: Ctx) -> Self {
258        Self {
259            num_disconnect_packets: 10,
260            keep_alive_send_rate: PACKET_SEND_RATE_SEC,
261            context: ctx,
262            on_connect: None,
263            on_disconnect: None,
264        }
265    }
266    /// Set the number of redundant disconnect packets that will be sent to a client when the server is disconnecting it. <br>
267    /// The default is 10 packets.
268    pub fn num_disconnect_packets(mut self, num: usize) -> Self {
269        self.num_disconnect_packets = num;
270        self
271    }
272    /// Set the rate (in seconds) at which keep-alive packets will be sent to clients. <br>
273    /// The default is 10 packets per second. (`0.1` seconds)
274    pub fn keep_alive_send_rate(mut self, rate_seconds: f64) -> Self {
275        self.keep_alive_send_rate = rate_seconds;
276        self
277    }
278    /// Provide a callback that will be called when a client is connected to the server. <br>
279    /// The callback will be called with the client index and the context that was provided (provide a `None` context if you don't need one).
280    ///
281    /// See [`ServerConfig`](ServerConfig) for an example.
282    pub fn on_connect<F>(mut self, cb: F) -> Self
283    where
284        F: FnMut(ClientIndex, &mut Ctx) + Send + Sync + 'static,
285    {
286        self.on_connect = Some(Box::new(cb));
287        self
288    }
289    /// Provide a callback that will be called when a client is disconnected from the server. <br>
290    /// The callback will be called with the client index and the context that was provided (provide a `None` context if you don't need one).
291    ///
292    /// See [`ServerConfig`](ServerConfig) for an example.
293    pub fn on_disconnect<F>(mut self, cb: F) -> Self
294    where
295        F: FnMut(ClientIndex, &mut Ctx) + Send + Sync + 'static,
296    {
297        self.on_disconnect = Some(Box::new(cb));
298        self
299    }
300}
301
302/// The `netcode` server.
303///
304/// Responsible for accepting connections from clients and communicating with them using the netcode protocol. <br>
305/// The server should be run in a loop to process incoming packets, send updates to clients, and maintain stable connections.
306///
307/// # Example
308///
309/// ```
310/// # use netcode::Server;
311/// # use std::net::{SocketAddr, Ipv4Addr};
312/// # use std::time::{Instant, Duration};
313/// # use std::thread;
314/// let private_key = netcode::generate_key();
315/// let protocol_id = 0x123456789ABCDEF0;
316/// let addr = "127.0.0.1:41235";
317/// let mut server = Server::new(addr, protocol_id, private_key).unwrap();
318///
319/// let start = Instant::now();
320/// let tick_rate = Duration::from_secs_f64(1.0 / 60.0);
321///
322/// loop {
323///     server.update(start.elapsed().as_secs_f64());
324///     if let Some((received, from)) = server.recv() {
325///         // ...
326///     }
327///     thread::sleep(tick_rate);
328///     # break;
329/// }
330/// ```
331///
332pub struct Server<T: Transceiver, Ctx = ()> {
333    transceiver: T,
334    time: f64,
335    private_key: Key,
336    sequence: u64,
337    token_sequence: u64,
338    challenge_sequence: u64,
339    challenge_key: Key,
340    protocol_id: u64,
341    conn_cache: ConnectionCache,
342    token_entries: TokenEntries,
343    cfg: ServerConfig<Ctx>,
344}
345
346impl Server<NetcodeSocket> {
347    /// Create a new server with a default configuration.
348    ///
349    /// For a custom configuration, use [`Server::with_config`](Server::with_config) instead.
350    pub fn new(bind_addr: impl ToSocketAddrs, protocol_id: u64, private_key: Key) -> Result<Self> {
351        let server: Server<_, ()> = Server {
352            transceiver: NetcodeSocket::new(bind_addr, SEND_BUF_SIZE, RECV_BUF_SIZE)?,
353            time: 0.0,
354            private_key,
355            protocol_id,
356            sequence: 1 << 63,
357            token_sequence: 0,
358            challenge_sequence: 0,
359            challenge_key: crypto::try_generate_key()?,
360            conn_cache: ConnectionCache::new(0.0),
361            token_entries: TokenEntries::new(),
362            cfg: ServerConfig::default(),
363        };
364        log::info!("server started on {}", server.transceiver.addr());
365        Ok(server)
366    }
367}
368
369impl<Ctx> Server<NetcodeSocket, Ctx> {
370    /// Create a new server with a custom configuration. <br>
371    /// Callbacks with context can be registered with the server to be notified when the server changes states. <br>
372    /// See [`ServerConfig`](ServerConfig) for more details.
373    ///
374    /// # Example
375    /// ```
376    /// use netcode::{Server, ServerConfig};
377    /// use std::net::{SocketAddr, Ipv4Addr};
378    ///
379    /// let private_key = netcode::generate_key();
380    /// let protocol_id = 0x123456789ABCDEF0;
381    /// let addr = "127.0.0.1:40002";
382    /// let cfg = ServerConfig::with_context(42).on_connect(|idx, ctx| {
383    ///     assert_eq!(ctx, &42);
384    /// });
385    /// let server = Server::with_config(addr, protocol_id, private_key, cfg).unwrap();
386    /// ```
387    pub fn with_config(
388        bind_addr: impl ToSocketAddrs,
389        protocol_id: u64,
390        private_key: Key,
391        cfg: ServerConfig<Ctx>,
392    ) -> Result<Self> {
393        let server = Server {
394            transceiver: NetcodeSocket::new(bind_addr, SEND_BUF_SIZE, RECV_BUF_SIZE)?,
395            time: 0.0,
396            private_key,
397            protocol_id,
398            sequence: 1 << 63,
399            token_sequence: 0,
400            challenge_sequence: 0,
401            challenge_key: crypto::try_generate_key()?,
402            conn_cache: ConnectionCache::new(0.0),
403            token_entries: TokenEntries::new(),
404            cfg,
405        };
406        log::info!("server started on {}", server.addr());
407        Ok(server)
408    }
409}
410
411impl<T: Transceiver, S> Server<T, S> {
412    const ALLOWED_PACKETS: u8 = 1 << Packet::REQUEST
413        | 1 << Packet::RESPONSE
414        | 1 << Packet::KEEP_ALIVE
415        | 1 << Packet::PAYLOAD
416        | 1 << Packet::DISCONNECT;
417    fn on_connect(&mut self, client_idx: ClientIndex) {
418        if let Some(cb) = self.cfg.on_connect.as_mut() {
419            cb(client_idx, &mut self.cfg.context)
420        }
421    }
422    fn on_disconnect(&mut self, client_idx: ClientIndex) {
423        if let Some(cb) = self.cfg.on_disconnect.as_mut() {
424            cb(client_idx, &mut self.cfg.context)
425        }
426    }
427    fn touch_client(&mut self, client_idx: Option<ClientIndex>) -> Result<()> {
428        let Some(idx) = client_idx else {
429            return Ok(());
430        };
431        let Some(conn) = self.conn_cache.clients.get_mut(idx.0) else {
432            return Ok(());
433        };
434        conn.last_receive_time = self.time;
435        if !conn.is_confirmed() {
436            log::debug!("server confirmed connection with client {idx}");
437            conn.confirm();
438        }
439        Ok(())
440    }
441    fn process_packet(&mut self, addr: SocketAddr, packet: Packet) -> Result<()> {
442        let client_idx = self.conn_cache.find_by_addr(&addr).map(|(idx, _)| idx);
443        log::trace!(
444            "server received {} from {}",
445            packet.to_string(),
446            client_idx
447                .map(|idx| format!("client {idx}"))
448                .unwrap_or_else(|| addr.to_string())
449        );
450        match packet {
451            Packet::Request(packet) => self.process_connection_request(addr, packet),
452            Packet::Response(packet) => self.process_connection_response(addr, packet),
453            Packet::KeepAlive(_) => self.touch_client(client_idx),
454            Packet::Payload(packet) => {
455                self.touch_client(client_idx)?;
456                if let Some(idx) = client_idx {
457                    self.conn_cache
458                        .packet_queue
459                        .push_back((packet.buf.to_vec(), idx));
460                }
461                Ok(())
462            }
463            Packet::Disconnect(_) => {
464                if let Some(idx) = client_idx {
465                    log::debug!("server disconnected client {idx}");
466                    self.on_disconnect(idx);
467                    self.conn_cache.remove(idx);
468                }
469                Ok(())
470            }
471            _ => unreachable!("packet should have been filtered out by `ALLOWED_PACKETS`"),
472        }
473    }
474    fn send_to_addr(&mut self, packet: Packet, addr: SocketAddr, key: Key) -> Result<()> {
475        let mut buf = [0u8; MAX_PKT_BUF_SIZE];
476        let size = packet.write(&mut buf, self.sequence, &key, self.protocol_id)?;
477        self.transceiver
478            .send(&buf[..size], addr)
479            .map_err(|e| e.into())?;
480        self.sequence += 1;
481        Ok(())
482    }
483    fn send_to_client(&mut self, packet: Packet, idx: ClientIndex) -> Result<()> {
484        let mut buf = [0u8; MAX_PKT_BUF_SIZE];
485        let conn = &mut self.conn_cache.clients[idx.0];
486        let size = packet.write(&mut buf, conn.sequence, &conn.send_key, self.protocol_id)?;
487        self.transceiver
488            .send(&buf[..size], conn.addr)
489            .map_err(|e| e.into())?;
490        conn.last_access_time = self.time;
491        conn.last_send_time = self.time;
492        conn.sequence += 1;
493        Ok(())
494    }
495    fn process_connection_request(
496        &mut self,
497        from_addr: SocketAddr,
498        mut packet: RequestPacket,
499    ) -> Result<()> {
500        let mut reader = std::io::Cursor::new(&mut packet.token_data[..]);
501        let Ok(token) = ConnectTokenPrivate::read_from(&mut reader) else {
502            log::debug!("server ignored connection request. failed to read connect token");
503            return Ok(());
504        };
505        if !token
506            .server_addresses
507            .iter()
508            .any(|(_, addr)| addr == self.transceiver.addr())
509        {
510            log::debug!(
511                "server ignored connection request. server address not in connect token whitelist"
512            );
513            return Ok(());
514        };
515        if self
516            .conn_cache
517            .find_by_addr(&from_addr)
518            .is_some_and(|(_, conn)| conn.is_connected())
519        {
520            log::debug!("server ignored connection request. a client with this address is already connected");
521            return Ok(());
522        };
523        if self
524            .conn_cache
525            .find_by_id(token.client_id)
526            .is_some_and(|(_, conn)| conn.is_connected())
527        {
528            log::debug!(
529                "server ignored connection request. a client with this id is already connected"
530            );
531            return Ok(());
532        };
533        let entry = TokenEntry {
534            time: self.time,
535            addr: from_addr,
536            mac: packet.token_data
537                [ConnectTokenPrivate::SIZE - MAC_BYTES..ConnectTokenPrivate::SIZE]
538                .try_into()
539                .expect("valid MAC size"),
540        };
541        if !self.token_entries.find_or_insert(entry) {
542            log::debug!("server ignored connection request. connect token has already been used");
543            return Ok(());
544        };
545        if self.num_connected_clients() >= MAX_CLIENTS {
546            log::debug!("server denied connection request. server is full");
547            self.send_to_addr(
548                DeniedPacket::create(),
549                from_addr,
550                token.server_to_client_key,
551            )?;
552            return Ok(());
553        };
554        self.conn_cache.add(
555            token.client_id,
556            from_addr,
557            token.timeout_seconds,
558            token.server_to_client_key,
559            token.client_to_server_key,
560        );
561        let Ok(challenge_token_encrypted) = ChallengeToken {
562            client_id: token.client_id,
563            user_data: token.user_data,
564        }
565        .encrypt(self.challenge_sequence, &self.challenge_key) else {
566            log::debug!("server ignored connection request. failed to encrypt challenge token");
567            return Ok(());
568        };
569        self.send_to_addr(
570            ChallengePacket::create(self.challenge_sequence, challenge_token_encrypted),
571            from_addr,
572            token.server_to_client_key,
573        )?;
574        log::debug!("server sent connection challenge packet");
575        self.challenge_sequence += 1;
576        Ok(())
577    }
578    fn process_connection_response(
579        &mut self,
580        from_addr: SocketAddr,
581        mut packet: ResponsePacket,
582    ) -> Result<()> {
583        let Ok(challenge_token) =
584            ChallengeToken::decrypt(&mut packet.token, packet.sequence, &self.challenge_key)
585        else {
586            log::debug!("server ignored connection response. failed to decrypt challenge token");
587            return Ok(());
588        };
589        let Some((idx, conn)) = self.conn_cache.find_by_id(challenge_token.client_id) else {
590            log::debug!("server ignored connection response. no packet send key");
591            return Ok(());
592        };
593        if conn.is_connected() {
594            log::debug!(
595                "server ignored connection request. a client with this id is already connected"
596            );
597            return Ok(());
598        };
599        if self.num_connected_clients() >= MAX_CLIENTS {
600            log::debug!("server denied connection response. server is full");
601            self.send_to_addr(
602                DeniedPacket::create(),
603                from_addr,
604                self.conn_cache.clients[idx.0].send_key,
605            )?;
606            return Ok(());
607        };
608        let client = &mut self.conn_cache.clients[idx.0];
609        client.connect();
610        client.last_send_time = self.time;
611        client.last_receive_time = self.time;
612        log::debug!(
613            "server accepted client {} with id {}",
614            idx,
615            challenge_token.client_id
616        );
617        self.send_to_client(
618            KeepAlivePacket::create(idx.0 as i32, MAX_CLIENTS as i32),
619            idx,
620        )?;
621        self.on_connect(idx);
622        Ok(())
623    }
624    fn check_for_timeouts(&mut self) {
625        for idx in 0..MAX_CLIENTS {
626            let Some(client) = self.conn_cache.clients.get_mut(idx) else {
627                continue;
628            };
629            let idx = ClientIndex(idx);
630            if !client.is_connected() {
631                continue;
632            }
633            if client.timeout.is_positive()
634                && client.last_receive_time + (client.timeout as f64) < self.time
635            {
636                log::debug!("server timed out client {idx}");
637                self.on_disconnect(idx);
638                self.conn_cache.remove(idx);
639            }
640        }
641    }
642    fn send_packets(&mut self) -> Result<()> {
643        for idx in 0..MAX_CLIENTS {
644            let Some(client) = self.conn_cache.clients.get_mut(idx) else {
645                continue;
646            };
647            if !client.is_connected() {
648                continue;
649            }
650            if client.last_send_time + self.cfg.keep_alive_send_rate >= self.time {
651                continue;
652            }
653
654            self.send_to_client(
655                KeepAlivePacket::create(idx as i32, MAX_CLIENTS as i32),
656                ClientIndex(idx),
657            )?;
658            log::trace!("server sent connection keep-alive packet to client {idx}");
659        }
660        Ok(())
661    }
662    fn recv_packet(&mut self, buf: &mut [u8], now: u64, addr: SocketAddr) -> Result<()> {
663        if buf.len() <= 1 {
664            // Too small to be a packet
665            return Ok(());
666        }
667        let (key, replay_protection) = match self.conn_cache.find_by_addr(&addr) {
668            // Regardless of whether an entry in the connection cache exists for the client or not,
669            // if the packet is a connection request we need to use the server's private key to decrypt it.
670            _ if buf[0] == Packet::REQUEST => (self.private_key, None),
671            Some((client_idx, _)) => (
672                // If the packet is not a connection request, use the receive key to decrypt it.
673                self.conn_cache.clients[client_idx.0].receive_key,
674                self.conn_cache.replay_protection.get_mut(&client_idx),
675            ),
676            None => {
677                // Not a connection request packet, and not a known client, so ignore
678                log::debug!(
679                    "server ignored non-connection-request packet from unknown address {addr}"
680                );
681                return Ok(());
682            }
683        };
684        let packet = match Packet::read(
685            buf,
686            self.protocol_id,
687            now,
688            key,
689            replay_protection,
690            Self::ALLOWED_PACKETS,
691        ) {
692            Ok(packet) => packet,
693            Err(Error::Crypto(_)) => {
694                log::debug!("server ignored packet because it failed to decrypt");
695                return Ok(());
696            }
697            Err(e) => {
698                log::error!("server ignored packet: {e}");
699                return Ok(());
700            }
701        };
702        self.process_packet(addr, packet)
703    }
704    fn recv_packets(&mut self) -> Result<()> {
705        let mut buf = [0u8; MAX_PACKET_SIZE];
706        let now = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
707        while let Some((size, addr)) = self.transceiver.recv(&mut buf).map_err(|e| e.into())? {
708            self.recv_packet(&mut buf[..size], now, addr)?;
709        }
710        Ok(())
711    }
712    /// Creates a new server instance with the given configuration and transceiver.
713    ///
714    /// This is useful if you want to use a custom transceiver implementation,
715    /// in any other case you should use [`Server::new`](Server::new) or [`Server::with_config`](Server::with_config).
716    ///
717    /// # Examples
718    ///
719    /// ```
720    /// use netcode::{Server, ServerConfig, Transceiver};
721    ///
722    /// struct MyTransceiver {
723    ///    // ...
724    /// };
725    ///
726    /// impl Transceiver for MyTransceiver {
727    ///    // ...
728    ///    # type IntoError = std::io::Error;
729    ///    # fn addr(&self) -> std::net::SocketAddr { unimplemented!() }
730    ///    # fn send(&self, buf: &[u8], addr: std::net::SocketAddr) -> std::io::Result<usize> { unimplemented!() }
731    ///    # fn recv(&self, buf: &mut [u8]) -> std::io::Result<Option<(usize, std::net::SocketAddr)>> { unimplemented!() }
732    /// }
733    ///
734    /// let protocol_id = 0x1122334455667788;
735    /// let private_key = netcode::generate_key();
736    /// let cfg = ServerConfig::default();
737    /// let trx = MyTransceiver { /* .. */ };
738    ///
739    /// let server = Server::with_config_and_transceiver(protocol_id, private_key, cfg, trx).unwrap();
740    /// ```
741    pub fn with_config_and_transceiver(
742        protocol_id: u64,
743        private_key: Key,
744        cfg: ServerConfig<S>,
745        trx: T,
746    ) -> Result<Self> {
747        let server = Server {
748            transceiver: trx,
749            time: 0.0,
750            private_key,
751            protocol_id,
752            sequence: 1 << 63,
753            token_sequence: 0,
754            challenge_sequence: 0,
755            challenge_key: crypto::try_generate_key()?,
756            conn_cache: ConnectionCache::new(0.0),
757            token_entries: TokenEntries::new(),
758            cfg,
759        };
760        log::info!("server started on {}", server.addr());
761        Ok(server)
762    }
763    /// Updates the server.
764    ///
765    /// * Updates the server's elapsed time.
766    /// * Receives and processes packets from clients, any received payload packets will be queued.
767    /// * Sends keep-alive packets to connected clients.
768    /// * Checks for timed out clients and disconnects them.
769    ///
770    /// This method should be called regularly, probably at a fixed rate (e.g., 60Hz).
771    ///
772    /// # Panics
773    /// Panics if the server can't send or receive packets.
774    /// For a non-panicking version, use [`try_update`](Server::try_update).
775    pub fn update(&mut self, time: f64) {
776        self.try_update(time)
777            .expect("send/recv error while updating server")
778    }
779    /// The fallible version of [`update`](Server::update).
780    ///
781    /// Returns an error if the server can't send or receive packets.
782    pub fn try_update(&mut self, time: f64) -> Result<()> {
783        self.time = time;
784        self.conn_cache.update(self.time);
785        self.recv_packets()?;
786        self.send_packets()?;
787        self.check_for_timeouts();
788        Ok(())
789    }
790    /// Receives a packet from a client, if one is available in the queue.
791    ///
792    /// The packet will be returned as a `Vec<u8>` along with the client index of the sender.
793    ///
794    /// If no packet is available, `None` will be returned.
795    ///
796    /// # Example
797    /// ```
798    /// # use netcode::{Server, ServerConfig};
799    /// # use std::net::{SocketAddr, Ipv4Addr};
800    /// # use std::time::Instant;
801    /// # let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 40003));
802    /// # let protocol_id = 0x123456789ABCDEF0;
803    /// # let private_key = [42u8; 32];
804    /// # let mut server = Server::new(addr, protocol_id, private_key).unwrap();
805    /// let start = Instant::now();
806    /// loop {
807    ///    let now = start.elapsed().as_secs_f64();
808    ///    server.update(now);
809    ///    let mut packet_buf = [0u8; netcode::MAX_PACKET_SIZE];
810    ///    while let Some((packet, from)) = server.recv() {
811    ///        // ...
812    ///    }
813    ///    # break;
814    /// }
815    pub fn recv(&mut self) -> Option<(Vec<u8>, ClientIndex)> {
816        self.conn_cache.packet_queue.pop_front()
817    }
818    /// Sends a packet to a client.
819    ///
820    /// The provided buffer must be smaller than [`MAX_PACKET_SIZE`](crate::MAX_PACKET_SIZE).
821    pub fn send(&mut self, buf: &[u8], client_idx: ClientIndex) -> Result<()> {
822        if buf.len() > MAX_PACKET_SIZE {
823            return Err(Error::SizeMismatch(MAX_PACKET_SIZE, buf.len()));
824        }
825        let Some(conn) = self.conn_cache.clients.get_mut(client_idx.0) else {
826            return Err(Error::ClientNotFound);
827        };
828        if !conn.is_connected() {
829            // since there is no way to obtain a client index of clients that are not connected,
830            // there is no straight-forward way for a user to send a packet to a non-connected client.
831            // still, in case a user somehow manages to obtain such index, we'll return an error.
832            return Err(Error::ClientNotConnected);
833        }
834        if !conn.is_confirmed() {
835            // send a keep-alive packet to the client to confirm the connection
836            self.send_to_client(
837                KeepAlivePacket::create(client_idx.0 as i32, MAX_CLIENTS as i32),
838                client_idx,
839            )?;
840        }
841        let packet = PayloadPacket::create(buf);
842        self.send_to_client(packet, client_idx)
843    }
844    /// Sends a packet to all connected clients.
845    ///
846    /// The provided buffer must be smaller than [`MAX_PACKET_SIZE`](crate::MAX_PACKET_SIZE).
847    pub fn send_all(&mut self, buf: &[u8]) -> Result<()> {
848        for idx in 0..MAX_CLIENTS {
849            match self.send(buf, ClientIndex(idx)) {
850                Ok(_) | Err(Error::ClientNotConnected) | Err(Error::ClientNotFound) => continue,
851                Err(e) => return Err(e),
852            }
853        }
854        Ok(())
855    }
856    /// Creates a connect token builder for a given client ID.
857    /// The builder can be used to configure the token with additional data before generating the final token.
858    /// The `generate` method must be called on the builder to generate the final token.
859    ///
860    /// # Example
861    ///
862    /// ```
863    /// # use netcode::{Server, ServerConfig};
864    /// # use std::net::{SocketAddr, Ipv4Addr};
865    ///  
866    /// let private_key = netcode::generate_key();
867    /// let protocol_id = 0x123456789ABCDEF0;
868    /// let bind_addr = "0.0.0.0:0";
869    /// let mut server = Server::new(bind_addr, protocol_id, private_key).unwrap();
870    ///
871    /// let client_id = 123u64;
872    /// let token = server.token(client_id)
873    ///     .expire_seconds(60)  // defaults to 30 seconds, negative for no expiry
874    ///     .timeout_seconds(-1) // defaults to 15 seconds, negative for no timeout
875    ///     .generate()
876    ///     .unwrap();
877    /// ```
878    ///
879    /// See [`ConnectTokenBuilder`](ConnectTokenBuilder) for more options.
880    pub fn token(&mut self, client_id: ClientId) -> ConnectTokenBuilder<SocketAddr> {
881        let token_builder = ConnectToken::build(
882            self.transceiver.addr(),
883            self.protocol_id,
884            client_id,
885            self.private_key,
886        );
887        self.token_sequence += 1;
888        token_builder
889    }
890    /// Disconnects a client.
891    ///
892    /// The server will send a number of redundant disconnect packets to the client, and then remove its connection info.
893    pub fn disconnect(&mut self, client_idx: ClientIndex) -> Result<()> {
894        let Some(conn) = self.conn_cache.clients.get_mut(client_idx.0) else {
895            return Ok(());
896        };
897        if !conn.is_connected() {
898            return Ok(());
899        }
900        log::debug!("server disconnecting client {client_idx}");
901        for _ in 0..self.cfg.num_disconnect_packets {
902            self.send_to_client(DisconnectPacket::create(), client_idx)?;
903        }
904        self.on_disconnect(client_idx);
905        self.conn_cache.remove(client_idx);
906        Ok(())
907    }
908    /// Disconnects all clients.
909    pub fn disconnect_all(&mut self) -> Result<()> {
910        log::debug!("server disconnecting all clients");
911        for idx in 0..MAX_CLIENTS {
912            let Some(conn) = self.conn_cache.clients.get_mut(idx) else {
913                continue;
914            };
915            if conn.is_connected() {
916                self.disconnect(ClientIndex(idx))?;
917            }
918        }
919        Ok(())
920    }
921    /// Gets the local `SocketAddr` this server is bound to.
922    pub fn addr(&self) -> SocketAddr {
923        self.transceiver.addr()
924    }
925    /// Gets the number of connected clients.
926    pub fn num_connected_clients(&self) -> usize {
927        self.conn_cache
928            .clients
929            .iter()
930            .filter(|(_, c)| c.is_connected())
931            .count()
932    }
933    /// Gets the [`ClientId`](ClientId) of a client.
934    pub fn client_id(&self, client_idx: ClientIndex) -> Option<ClientId> {
935        self.conn_cache
936            .clients
937            .get(client_idx.0)
938            .map(|c| c.client_id)
939    }
940    /// Gets the address of a client.
941    pub fn client_addr(&self, client_idx: ClientIndex) -> Option<SocketAddr> {
942        self.conn_cache.clients.get(client_idx.0).map(|c| c.addr)
943    }
944}
945
946#[cfg(test)]
947pub mod tests {
948    use super::*;
949    use crate::simulator::NetworkSimulator;
950    impl Server<NetworkSimulator> {
951        pub(crate) fn with_simulator(
952            sim: NetworkSimulator,
953            private_key: Option<Key>,
954        ) -> Result<Self> {
955            let private_key = private_key.unwrap_or(crypto::generate_key());
956            let cfg = ServerConfig::default();
957            let server = Server::with_config_and_transceiver(0, private_key, cfg, sim)?;
958            Ok(server)
959        }
960        pub(crate) fn iter_clients(&self) -> impl Iterator<Item = ClientIndex> + '_ {
961            self.conn_cache
962                .clients
963                .iter()
964                .filter(|(_, c)| c.is_connected())
965                .map(|(idx, _)| ClientIndex(idx))
966        }
967    }
968}