Skip to main content

netcode/
server.rs

1//! The netcode server.
2
3use std::collections::VecDeque;
4use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
5
6use log::{debug, error, info};
7
8use crate::packet::{AllowedPackets, Packet};
9use crate::replay::ReplayProtection;
10use crate::token::{
11    self, CHALLENGE_TOKEN_BYTES, CONNECT_TOKEN_PRIVATE_BYTES, ChallengeToken, PrivateConnectToken,
12};
13use crate::{
14    Error, KEY_BYTES, Key, MAC_BYTES, MAX_CLIENTS, MAX_PACKET_BYTES, MAX_PAYLOAD_BYTES,
15    NUM_DISCONNECT_PACKETS, PACKET_QUEUE_SIZE, PACKET_SEND_RATE, USER_DATA_BYTES, UserData, crypto,
16    socket,
17};
18
19/// Why a client was disconnected from the server.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum DisconnectReason {
22    /// No packets were received from the client within the timeout period.
23    TimedOut,
24    /// The client sent a disconnect packet.
25    ClientDisconnect,
26    /// The server disconnected the client.
27    ServerDisconnect,
28}
29
30/// A connection event on the server, drained with [`Server::next_event`].
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum ServerEvent {
33    /// A client connected.
34    ClientConnected {
35        /// The slot the client was assigned.
36        client_index: usize,
37    },
38    /// A client disconnected.
39    ClientDisconnected {
40        /// The slot the client occupied. It is free again by the time this event is
41        /// observed.
42        client_index: usize,
43        /// Why the client was disconnected.
44        reason: DisconnectReason,
45    },
46}
47
48// ----------------------------------------------------------------
49
50const MAX_ENCRYPTION_MAPPINGS: usize = MAX_CLIENTS * 4;
51
52/// Maps packet source addresses to the encryption keys from their connect token.
53/// An entry is added when a connection request is accepted and expires after
54/// `timeout` seconds without packets, or at `expire_time` if the client never
55/// finishes connecting.
56struct EncryptionEntry {
57    address: Option<SocketAddr>,
58    timeout_seconds: i32,
59    expire_time: f64,
60    last_access_time: f64,
61    client_index: Option<usize>,
62    send_key: Key,
63    receive_key: Key,
64}
65
66impl EncryptionEntry {
67    fn new() -> Self {
68        Self {
69            address: None,
70            timeout_seconds: 0,
71            expire_time: -1.0,
72            last_access_time: -1000.0,
73            client_index: None,
74            send_key: [0; KEY_BYTES],
75            receive_key: [0; KEY_BYTES],
76        }
77    }
78
79    fn expired(&self, time: f64) -> bool {
80        (self.timeout_seconds > 0 && self.last_access_time + (self.timeout_seconds as f64) < time)
81            || (self.expire_time >= 0.0 && self.expire_time < time)
82    }
83}
84
85struct EncryptionManager {
86    entries: Vec<EncryptionEntry>,
87    /// One past the highest slot ever used, so lookups scan only the live prefix.
88    num_entries: usize,
89}
90
91impl EncryptionManager {
92    fn new() -> Self {
93        Self {
94            entries: (0..MAX_ENCRYPTION_MAPPINGS).map(|_| EncryptionEntry::new()).collect(),
95            num_entries: 0,
96        }
97    }
98
99    fn reset(&mut self) {
100        debug!("reset encryption manager");
101        *self = Self::new();
102    }
103
104    #[allow(clippy::too_many_arguments)]
105    fn add_encryption_mapping(
106        &mut self,
107        address: SocketAddr,
108        send_key: &Key,
109        receive_key: &Key,
110        time: f64,
111        expire_time: f64,
112        timeout_seconds: i32,
113    ) -> bool {
114        for index in 0..self.num_entries {
115            let entry = &mut self.entries[index];
116            if entry.address == Some(address) && !entry.expired(time) {
117                entry.timeout_seconds = timeout_seconds;
118                entry.expire_time = expire_time;
119                entry.last_access_time = time;
120                entry.send_key = *send_key;
121                entry.receive_key = *receive_key;
122                return true;
123            }
124        }
125
126        for index in 0..MAX_ENCRYPTION_MAPPINGS {
127            let entry = &mut self.entries[index];
128            if entry.address.is_none() || (entry.expired(time) && entry.client_index.is_none()) {
129                *entry = EncryptionEntry {
130                    address: Some(address),
131                    timeout_seconds,
132                    expire_time,
133                    last_access_time: time,
134                    client_index: None,
135                    send_key: *send_key,
136                    receive_key: *receive_key,
137                };
138                if index + 1 > self.num_entries {
139                    self.num_entries = index + 1;
140                }
141                return true;
142            }
143        }
144
145        false
146    }
147
148    fn remove_encryption_mapping(&mut self, address: SocketAddr, time: f64) -> bool {
149        for index in 0..self.num_entries {
150            if self.entries[index].address != Some(address) {
151                continue;
152            }
153
154            self.entries[index] = EncryptionEntry::new();
155
156            // shrink the live prefix past any expired unowned entries at the end
157            if index + 1 == self.num_entries {
158                let mut last = index;
159                while last > 0 {
160                    let entry = &self.entries[last - 1];
161                    if !entry.expired(time) || entry.client_index.is_some() {
162                        break;
163                    }
164                    self.entries[last - 1].address = None;
165                    last -= 1;
166                }
167                self.num_entries = last;
168            }
169
170            return true;
171        }
172
173        false
174    }
175
176    fn find_encryption_mapping(&mut self, address: SocketAddr, time: f64) -> Option<usize> {
177        for index in 0..self.num_entries {
178            let entry = &mut self.entries[index];
179            if entry.address == Some(address) && !entry.expired(time) {
180                entry.last_access_time = time;
181                return Some(index);
182            }
183        }
184        None
185    }
186
187    fn touch(&mut self, index: usize, address: SocketAddr, time: f64) -> bool {
188        if self.entries[index].address != Some(address) {
189            return false;
190        }
191        self.entries[index].last_access_time = time;
192        true
193    }
194
195    fn set_expire_time(&mut self, index: usize, expire_time: f64) {
196        self.entries[index].expire_time = expire_time;
197    }
198
199    fn set_client_index(&mut self, index: usize, client_index: Option<usize>) {
200        self.entries[index].client_index = client_index;
201    }
202
203    fn send_key(&self, index: usize) -> Key {
204        self.entries[index].send_key
205    }
206
207    fn receive_key(&self, index: usize) -> Key {
208        self.entries[index].receive_key
209    }
210
211    fn timeout(&self, index: usize) -> i32 {
212        self.entries[index].timeout_seconds
213    }
214}
215
216// ----------------------------------------------------------------
217
218const MAX_CONNECT_TOKEN_ENTRIES: usize = MAX_CLIENTS * 8;
219
220/// A history of connect tokens already used, keyed by token HMAC, so a token stolen
221/// off the wire cannot be replayed from a different address.
222struct ConnectTokenEntry {
223    time: f64,
224    mac: [u8; MAC_BYTES],
225    address: Option<SocketAddr>,
226}
227
228fn reset_connect_token_entries(entries: &mut Vec<ConnectTokenEntry>) {
229    entries.clear();
230    entries.extend((0..MAX_CONNECT_TOKEN_ENTRIES).map(|_| ConnectTokenEntry {
231        time: -1000.0,
232        mac: [0; MAC_BYTES],
233        address: None,
234    }));
235}
236
237/// Returns whether the connect token may be used from this address: true for a token
238/// never seen before (recording it) or one seen only from the same address.
239fn find_or_add_connect_token_entry(
240    entries: &mut [ConnectTokenEntry],
241    address: SocketAddr,
242    mac: &[u8; MAC_BYTES],
243    time: f64,
244) -> bool {
245    // find the matching entry for the token mac and the oldest token entry.
246    // constant time worst case. This is intentional!
247    let mut matching_index = None;
248    let mut oldest_index = 0;
249    let mut oldest_time = f64::MAX;
250
251    for (index, entry) in entries.iter().enumerate() {
252        if &entry.mac == mac {
253            matching_index = Some(index);
254        }
255        if entry.time < oldest_time {
256            oldest_time = entry.time;
257            oldest_index = index;
258        }
259    }
260
261    match matching_index {
262        // this is a new connect token: replace the oldest entry
263        None => {
264            entries[oldest_index] = ConnectTokenEntry { time, mac: *mac, address: Some(address) };
265            true
266        }
267        // allow connect tokens we have already seen from the same address
268        Some(index) => entries[index].address == Some(address),
269    }
270}
271
272// ----------------------------------------------------------------
273
274struct ClientSlot {
275    connected: bool,
276    confirmed: bool,
277    client_id: u64,
278    timeout_seconds: i32,
279    encryption_index: Option<usize>,
280    address: Option<SocketAddr>,
281    sequence: u64,
282    last_packet_send_time: f64,
283    last_packet_receive_time: f64,
284    user_data: UserData,
285    replay_protection: ReplayProtection,
286    packet_queue: VecDeque<(Vec<u8>, u64)>,
287}
288
289impl ClientSlot {
290    fn new() -> Self {
291        Self {
292            connected: false,
293            confirmed: false,
294            client_id: 0,
295            timeout_seconds: 0,
296            encryption_index: None,
297            address: None,
298            sequence: 0,
299            last_packet_send_time: 0.0,
300            last_packet_receive_time: 0.0,
301            user_data: [0; USER_DATA_BYTES],
302            replay_protection: ReplayProtection::new(),
303            packet_queue: VecDeque::new(),
304        }
305    }
306}
307
308/// A netcode dedicated server.
309///
310/// Create it with the public address clients connect to, [`start`](Server::start) it
311/// with a number of client slots, then drive it by calling [`update`](Server::update)
312/// once per frame with the current time. All methods must be called from one thread;
313/// the server performs no internal synchronization.
314pub struct Server {
315    protocol_id: u64,
316    private_key: Key,
317    socket: UdpSocket,
318    public_address: SocketAddr,
319    time: f64,
320    running: bool,
321    max_clients: usize,
322    num_connected_clients: usize,
323    global_sequence: u64,
324    challenge_sequence: u64,
325    challenge_key: Key,
326    clients: Vec<ClientSlot>,
327    connect_token_entries: Vec<ConnectTokenEntry>,
328    encryption_manager: EncryptionManager,
329    events: VecDeque<ServerEvent>,
330}
331
332impl Server {
333    /// Creates a server that clients reach at `public_address`. The server binds a
334    /// socket on that port on all interfaces of the same address family.
335    ///
336    /// `protocol_id` is a 64-bit value unique to this game or application, and
337    /// `private_key` is shared between the web backend and the dedicated servers.
338    ///
339    /// A public address with port 0 binds an ephemeral port and advertises it as the
340    /// public port, which is convenient for tests running on localhost.
341    pub fn new(
342        public_address: SocketAddr,
343        protocol_id: u64,
344        private_key: &Key,
345        time: f64,
346    ) -> Result<Self, Error> {
347        let bind_address: SocketAddr = match public_address {
348            SocketAddr::V4(_) => (Ipv4Addr::UNSPECIFIED, public_address.port()).into(),
349            SocketAddr::V6(_) => (Ipv6Addr::UNSPECIFIED, public_address.port()).into(),
350        };
351        let socket = socket::create_socket(bind_address)?;
352
353        let mut public_address = public_address;
354        if public_address.port() == 0 {
355            public_address.set_port(socket.local_addr()?.port());
356        }
357
358        info!("server listening on {public_address}");
359
360        let mut connect_token_entries = Vec::new();
361        reset_connect_token_entries(&mut connect_token_entries);
362
363        Ok(Self {
364            protocol_id,
365            private_key: *private_key,
366            socket,
367            public_address,
368            time,
369            running: false,
370            max_clients: 0,
371            num_connected_clients: 0,
372            global_sequence: 1 << 63,
373            challenge_sequence: 0,
374            challenge_key: [0; KEY_BYTES],
375            clients: Vec::new(),
376            connect_token_entries,
377            encryption_manager: EncryptionManager::new(),
378            events: VecDeque::new(),
379        })
380    }
381
382    /// Starts the server with `max_clients` client slots, in `[1, MAX_CLIENTS]`.
383    /// If the server is already running it is stopped first, disconnecting everyone.
384    pub fn start(&mut self, max_clients: usize) -> Result<(), Error> {
385        if max_clients == 0 || max_clients > MAX_CLIENTS {
386            return Err(Error::InvalidMaxClients(max_clients));
387        }
388
389        if self.running {
390            self.stop();
391        }
392
393        info!("server started with {max_clients} client slots");
394
395        self.running = true;
396        self.max_clients = max_clients;
397        self.num_connected_clients = 0;
398        self.challenge_sequence = 0;
399        self.challenge_key = crypto::generate_key();
400        // global packets (challenge, denied) encrypt with the same per-token
401        // server-to-client keys as per-client packets, whose sequences start at zero,
402        // so the global sequence takes the top half of the space to keep AEAD nonces
403        // disjoint under a shared key
404        self.global_sequence = 1 << 63;
405        self.clients = (0..max_clients).map(|_| ClientSlot::new()).collect();
406
407        Ok(())
408    }
409
410    /// Stops the server, disconnecting all clients.
411    pub fn stop(&mut self) {
412        if !self.running {
413            return;
414        }
415
416        self.disconnect_all_clients();
417
418        self.running = false;
419        self.max_clients = 0;
420        self.num_connected_clients = 0;
421        self.global_sequence = 1 << 63;
422        self.challenge_sequence = 0;
423        self.challenge_key = [0; KEY_BYTES];
424        self.clients.clear();
425
426        reset_connect_token_entries(&mut self.connect_token_entries);
427        self.encryption_manager.reset();
428
429        info!("server stopped");
430    }
431
432    /// Advances the server to the current time: receives and processes packets, sends
433    /// keep-alives, and times out unresponsive clients.
434    pub fn update(&mut self, time: f64) {
435        self.time = time;
436        self.receive_packets();
437        self.send_packets();
438        self.check_for_timeouts();
439    }
440
441    /// Pops the next connect or disconnect event.
442    pub fn next_event(&mut self) -> Option<ServerEvent> {
443        self.events.pop_front()
444    }
445
446    /// Sends a payload packet to the client in the given slot. Does nothing unless
447    /// that client is connected.
448    pub fn send_packet(&mut self, client_index: usize, payload: &[u8]) -> Result<(), Error> {
449        if payload.is_empty() || payload.len() > MAX_PAYLOAD_BYTES {
450            return Err(Error::InvalidPayloadSize(payload.len()));
451        }
452
453        if !self.running
454            || client_index >= self.max_clients
455            || !self.clients[client_index].connected
456        {
457            return Ok(());
458        }
459
460        // until the client is confirmed, prefix each payload with a keep-alive so it
461        // learns its client index and max clients as early as possible
462        if !self.clients[client_index].confirmed {
463            let keep_alive = Packet::KeepAlive {
464                client_index: client_index as u32,
465                max_clients: self.max_clients as u32,
466            };
467            self.send_client_packet(&keep_alive, client_index);
468        }
469
470        self.send_client_packet(&Packet::Payload(payload.to_vec()), client_index);
471
472        Ok(())
473    }
474
475    /// Pops the next payload packet received from the client in the given slot, along
476    /// with its sequence number.
477    pub fn receive_packet(&mut self, client_index: usize) -> Option<(Vec<u8>, u64)> {
478        if !self.running || client_index >= self.max_clients {
479            return None;
480        }
481        self.clients[client_index].packet_queue.pop_front()
482    }
483
484    /// Disconnects the client in the given slot, sending redundant disconnect packets
485    /// so it finds out quickly.
486    pub fn disconnect_client(&mut self, client_index: usize) {
487        if !self.running
488            || client_index >= self.max_clients
489            || !self.clients[client_index].connected
490        {
491            return;
492        }
493        self.disconnect_client_internal(client_index, true, DisconnectReason::ServerDisconnect);
494    }
495
496    /// Disconnects all connected clients.
497    pub fn disconnect_all_clients(&mut self) {
498        if !self.running {
499            return;
500        }
501        for client_index in 0..self.max_clients {
502            if self.clients[client_index].connected {
503                self.disconnect_client_internal(
504                    client_index,
505                    true,
506                    DisconnectReason::ServerDisconnect,
507                );
508            }
509        }
510    }
511
512    /// Whether the server is running.
513    pub fn running(&self) -> bool {
514        self.running
515    }
516
517    /// The number of client slots, or 0 when the server is not running.
518    pub fn max_clients(&self) -> usize {
519        self.max_clients
520    }
521
522    /// The number of connected clients.
523    pub fn num_connected_clients(&self) -> usize {
524        self.num_connected_clients
525    }
526
527    /// Whether a client is connected in the given slot.
528    pub fn client_connected(&self, client_index: usize) -> bool {
529        self.running && client_index < self.max_clients && self.clients[client_index].connected
530    }
531
532    /// The client id of the client in the given slot, or 0 if none is connected.
533    pub fn client_id(&self, client_index: usize) -> u64 {
534        if !self.client_connected(client_index) {
535            return 0;
536        }
537        self.clients[client_index].client_id
538    }
539
540    /// The address of the client in the given slot.
541    pub fn client_address(&self, client_index: usize) -> Option<SocketAddr> {
542        if !self.client_connected(client_index) {
543            return None;
544        }
545        self.clients[client_index].address
546    }
547
548    /// The user data carried in the connect token of the client in the given slot.
549    pub fn client_user_data(&self, client_index: usize) -> Option<&UserData> {
550        if !self.client_connected(client_index) {
551            return None;
552        }
553        Some(&self.clients[client_index].user_data)
554    }
555
556    /// The sequence number of the next packet the server will send to the client in
557    /// the given slot.
558    pub fn next_packet_sequence(&self, client_index: usize) -> u64 {
559        if !self.client_connected(client_index) {
560            return 0;
561        }
562        self.clients[client_index].sequence
563    }
564
565    /// The port the server socket is bound to.
566    pub fn port(&self) -> u16 {
567        self.public_address.port()
568    }
569
570    /// The public address clients connect to.
571    pub fn address(&self) -> SocketAddr {
572        self.public_address
573    }
574
575    // ----------------------------------------------------------------
576
577    fn find_client_index_by_address(&self, address: SocketAddr) -> Option<usize> {
578        self.clients[..self.max_clients]
579            .iter()
580            .position(|client| client.connected && client.address == Some(address))
581    }
582
583    fn find_client_index_by_id(&self, client_id: u64) -> Option<usize> {
584        self.clients[..self.max_clients]
585            .iter()
586            .position(|client| client.connected && client.client_id == client_id)
587    }
588
589    fn find_free_client_index(&self) -> Option<usize> {
590        self.clients[..self.max_clients].iter().position(|client| !client.connected)
591    }
592
593    fn receive_packets(&mut self) {
594        let current_timestamp = token::unix_timestamp();
595        let mut packet_data = [0u8; MAX_PACKET_BYTES];
596        while let Some((packet_bytes, from)) =
597            socket::receive_packet(&self.socket, &mut packet_data)
598        {
599            self.read_and_process_packet(from, &mut packet_data[..packet_bytes], current_timestamp);
600        }
601    }
602
603    fn read_and_process_packet(
604        &mut self,
605        from: SocketAddr,
606        packet_data: &mut [u8],
607        current_timestamp: u64,
608    ) {
609        if !self.running || packet_data.len() <= 1 {
610            return;
611        }
612
613        let client_index = self.find_client_index_by_address(from);
614        let encryption_index = match client_index {
615            Some(client_index) => self.clients[client_index].encryption_index,
616            None => self.encryption_manager.find_encryption_mapping(from, self.time),
617        };
618
619        let read_packet_key = encryption_index
620            .map(|encryption_index| self.encryption_manager.receive_key(encryption_index));
621
622        if read_packet_key.is_none() && packet_data[0] != 0 {
623            debug!(
624                "server could not process packet because no encryption mapping exists for {from}"
625            );
626            return;
627        }
628
629        let protocol_id = self.protocol_id;
630        let private_key = self.private_key;
631        let replay_protection =
632            client_index.map(|client_index| &mut self.clients[client_index].replay_protection);
633
634        let Some((packet, sequence)) = crate::packet::read_packet(
635            packet_data,
636            read_packet_key.as_ref(),
637            protocol_id,
638            current_timestamp,
639            Some(&private_key),
640            AllowedPackets::SERVER,
641            replay_protection,
642        ) else {
643            return;
644        };
645
646        self.process_packet(from, packet, sequence, encryption_index, client_index);
647    }
648
649    fn process_packet(
650        &mut self,
651        from: SocketAddr,
652        packet: Packet,
653        sequence: u64,
654        encryption_index: Option<usize>,
655        client_index: Option<usize>,
656    ) {
657        match packet {
658            Packet::Request { private_data, .. } => {
659                debug!("server received connection request from {from}");
660                self.process_connection_request(from, &private_data);
661            }
662
663            Packet::Response { challenge_token_sequence, challenge_token_data } => {
664                debug!("server received connection response from {from}");
665                self.process_connection_response(
666                    from,
667                    challenge_token_sequence,
668                    challenge_token_data,
669                    encryption_index,
670                );
671            }
672
673            Packet::KeepAlive { .. } => {
674                if let Some(client_index) = client_index {
675                    debug!(
676                        "server received connection keep alive packet from client {client_index}"
677                    );
678                    self.touch_client(client_index);
679                }
680            }
681
682            Packet::Payload(payload) => {
683                if let Some(client_index) = client_index {
684                    debug!("server received connection payload packet from client {client_index}");
685                    self.touch_client(client_index);
686                    let queue = &mut self.clients[client_index].packet_queue;
687                    if queue.len() < PACKET_QUEUE_SIZE {
688                        queue.push_back((payload, sequence));
689                    }
690                }
691            }
692
693            Packet::Disconnect => {
694                if let Some(client_index) = client_index {
695                    debug!("server received disconnect packet from client {client_index}");
696                    self.disconnect_client_internal(
697                        client_index,
698                        false,
699                        DisconnectReason::ClientDisconnect,
700                    );
701                }
702            }
703
704            Packet::Denied | Packet::Challenge { .. } => unreachable!(),
705        }
706    }
707
708    /// Marks the client as heard from, confirming it on first contact.
709    fn touch_client(&mut self, client_index: usize) {
710        let client = &mut self.clients[client_index];
711        client.last_packet_receive_time = self.time;
712        if !client.confirmed {
713            debug!("server confirmed connection with client {client_index}");
714            client.confirmed = true;
715        }
716    }
717
718    /// Processes a connection request packet. The private connect token data has
719    /// already been decrypted; its trailing 16 bytes still hold the original HMAC,
720    /// which keys the used-token history.
721    fn process_connection_request(
722        &mut self,
723        from: SocketAddr,
724        private_data: &[u8; CONNECT_TOKEN_PRIVATE_BYTES],
725    ) {
726        let Ok(private_token) = PrivateConnectToken::read(&private_data[..]) else {
727            debug!("server ignored connection request. failed to read connect token");
728            return;
729        };
730
731        if !private_token.server_addresses.contains(&self.public_address) {
732            debug!(
733                "server ignored connection request. server address not in connect token whitelist"
734            );
735            return;
736        }
737
738        if self.find_client_index_by_address(from).is_some() {
739            debug!(
740                "server ignored connection request. a client with this address is already connected"
741            );
742            return;
743        }
744
745        if self.find_client_index_by_id(private_token.client_id).is_some() {
746            debug!("server ignored connection request. a client with this id is already connected");
747            return;
748        }
749
750        let mac: [u8; MAC_BYTES] =
751            private_data[CONNECT_TOKEN_PRIVATE_BYTES - MAC_BYTES..].try_into().unwrap();
752        if !find_or_add_connect_token_entry(&mut self.connect_token_entries, from, &mac, self.time)
753        {
754            debug!("server ignored connection request. connect token has already been used");
755            return;
756        }
757
758        if self.num_connected_clients == self.max_clients {
759            debug!("server denied connection request. server is full");
760            self.send_global_packet(&Packet::Denied, from, &private_token.server_to_client_key);
761            return;
762        }
763
764        let expire_time = if private_token.timeout_seconds >= 0 {
765            self.time + private_token.timeout_seconds as f64
766        } else {
767            -1.0
768        };
769
770        if !self.encryption_manager.add_encryption_mapping(
771            from,
772            &private_token.server_to_client_key,
773            &private_token.client_to_server_key,
774            self.time,
775            expire_time,
776            private_token.timeout_seconds,
777        ) {
778            debug!("server ignored connection request. failed to add encryption mapping");
779            return;
780        }
781
782        let challenge_token = ChallengeToken {
783            client_id: private_token.client_id,
784            user_data: private_token.user_data,
785        };
786        let mut challenge_token_data = [0u8; CHALLENGE_TOKEN_BYTES];
787        challenge_token.write(&mut challenge_token_data);
788        if token::encrypt_challenge_token(
789            &mut challenge_token_data,
790            self.challenge_sequence,
791            &self.challenge_key,
792        )
793        .is_err()
794        {
795            debug!("server ignored connection request. failed to encrypt challenge token");
796            return;
797        }
798
799        let challenge_packet = Packet::Challenge {
800            challenge_token_sequence: self.challenge_sequence,
801            challenge_token_data,
802        };
803        self.challenge_sequence += 1;
804
805        debug!("server sent connection challenge packet");
806        self.send_global_packet(&challenge_packet, from, &private_token.server_to_client_key);
807    }
808
809    fn process_connection_response(
810        &mut self,
811        from: SocketAddr,
812        challenge_token_sequence: u64,
813        mut challenge_token_data: [u8; CHALLENGE_TOKEN_BYTES],
814        encryption_index: Option<usize>,
815    ) {
816        if token::decrypt_challenge_token(
817            &mut challenge_token_data,
818            challenge_token_sequence,
819            &self.challenge_key,
820        )
821        .is_err()
822        {
823            debug!("server ignored connection response. failed to decrypt challenge token");
824            return;
825        }
826
827        let challenge_token = ChallengeToken::read(&challenge_token_data);
828
829        let Some(encryption_index) = encryption_index else {
830            debug!("server ignored connection response. no packet send key");
831            return;
832        };
833
834        if self.find_client_index_by_address(from).is_some() {
835            debug!(
836                "server ignored connection response. a client with this address is already connected"
837            );
838            return;
839        }
840
841        if self.find_client_index_by_id(challenge_token.client_id).is_some() {
842            debug!(
843                "server ignored connection response. a client with this id is already connected"
844            );
845            return;
846        }
847
848        if self.num_connected_clients == self.max_clients {
849            debug!("server denied connection response. server is full");
850            let send_key = self.encryption_manager.send_key(encryption_index);
851            self.send_global_packet(&Packet::Denied, from, &send_key);
852            return;
853        }
854
855        let client_index = self.find_free_client_index().expect("server is not full");
856        let timeout_seconds = self.encryption_manager.timeout(encryption_index);
857        self.connect_client(
858            client_index,
859            from,
860            challenge_token.client_id,
861            encryption_index,
862            timeout_seconds,
863            &challenge_token.user_data,
864        );
865    }
866
867    #[allow(clippy::too_many_arguments)]
868    fn connect_client(
869        &mut self,
870        client_index: usize,
871        address: SocketAddr,
872        client_id: u64,
873        encryption_index: usize,
874        timeout_seconds: i32,
875        user_data: &UserData,
876    ) {
877        self.num_connected_clients += 1;
878        debug_assert!(self.num_connected_clients <= self.max_clients);
879
880        // the encryption mapping now belongs to a connected client: it no longer
881        // expires on its own, only when the client disconnects
882        self.encryption_manager.set_expire_time(encryption_index, -1.0);
883        self.encryption_manager.set_client_index(encryption_index, Some(client_index));
884
885        let client = &mut self.clients[client_index];
886        debug_assert!(!client.connected);
887        client.connected = true;
888        client.confirmed = false;
889        client.client_id = client_id;
890        client.timeout_seconds = timeout_seconds;
891        client.encryption_index = Some(encryption_index);
892        client.address = Some(address);
893        client.sequence = 0;
894        client.last_packet_send_time = self.time;
895        client.last_packet_receive_time = self.time;
896        client.user_data = *user_data;
897
898        info!("server accepted client {address} {client_id:016x} in slot {client_index}");
899
900        let packet = Packet::KeepAlive {
901            client_index: client_index as u32,
902            max_clients: self.max_clients as u32,
903        };
904        self.send_client_packet(&packet, client_index);
905
906        self.events.push_back(ServerEvent::ClientConnected { client_index });
907    }
908
909    fn disconnect_client_internal(
910        &mut self,
911        client_index: usize,
912        send_disconnect_packets: bool,
913        reason: DisconnectReason,
914    ) {
915        debug_assert!(self.running);
916        debug_assert!(self.clients[client_index].connected);
917
918        info!("server disconnected client {client_index}");
919
920        self.events.push_back(ServerEvent::ClientDisconnected { client_index, reason });
921
922        if send_disconnect_packets {
923            debug!("server sent disconnect packets to client {client_index}");
924            for _ in 0..NUM_DISCONNECT_PACKETS {
925                self.send_client_packet(&Packet::Disconnect, client_index);
926            }
927        }
928
929        self.clients[client_index].replay_protection.reset();
930
931        if let Some(encryption_index) = self.clients[client_index].encryption_index {
932            self.encryption_manager.set_client_index(encryption_index, None);
933        }
934        if let Some(address) = self.clients[client_index].address {
935            self.encryption_manager.remove_encryption_mapping(address, self.time);
936        }
937
938        self.clients[client_index] = ClientSlot::new();
939        self.num_connected_clients -= 1;
940    }
941
942    /// Sends a packet outside the context of a connected client (challenge and denied
943    /// packets), using the server's global sequence number.
944    fn send_global_packet(&mut self, packet: &Packet, to: SocketAddr, packet_key: &Key) {
945        let mut packet_data = [0u8; MAX_PACKET_BYTES];
946        let Ok(packet_bytes) = crate::packet::write_packet(
947            packet,
948            &mut packet_data,
949            self.global_sequence,
950            packet_key,
951            self.protocol_id,
952        ) else {
953            return;
954        };
955        let _ = self.socket.send_to(&packet_data[..packet_bytes], to);
956        self.global_sequence += 1;
957    }
958
959    fn send_client_packet(&mut self, packet: &Packet, client_index: usize) {
960        let client = &self.clients[client_index];
961        debug_assert!(client.connected);
962        let (Some(encryption_index), Some(address)) = (client.encryption_index, client.address)
963        else {
964            return;
965        };
966
967        if !self.encryption_manager.touch(encryption_index, address, self.time) {
968            error!("encryption mapping is out of date for client {client_index}");
969            return;
970        }
971
972        let packet_key = self.encryption_manager.send_key(encryption_index);
973
974        let mut packet_data = [0u8; MAX_PACKET_BYTES];
975        let Ok(packet_bytes) = crate::packet::write_packet(
976            packet,
977            &mut packet_data,
978            self.clients[client_index].sequence,
979            &packet_key,
980            self.protocol_id,
981        ) else {
982            return;
983        };
984        let _ = self.socket.send_to(&packet_data[..packet_bytes], address);
985
986        let client = &mut self.clients[client_index];
987        client.sequence += 1;
988        client.last_packet_send_time = self.time;
989    }
990
991    fn send_packets(&mut self) {
992        if !self.running {
993            return;
994        }
995
996        for client_index in 0..self.max_clients {
997            let client = &self.clients[client_index];
998            if client.connected
999                && client.last_packet_send_time + 1.0 / PACKET_SEND_RATE <= self.time
1000            {
1001                debug!("server sent connection keep alive packet to client {client_index}");
1002                let packet = Packet::KeepAlive {
1003                    client_index: client_index as u32,
1004                    max_clients: self.max_clients as u32,
1005                };
1006                self.send_client_packet(&packet, client_index);
1007            }
1008        }
1009    }
1010
1011    fn check_for_timeouts(&mut self) {
1012        if !self.running {
1013            return;
1014        }
1015
1016        for client_index in 0..self.max_clients {
1017            let client = &self.clients[client_index];
1018            if client.connected
1019                && client.timeout_seconds > 0
1020                && client.last_packet_receive_time + client.timeout_seconds as f64 <= self.time
1021            {
1022                info!("server timed out client {client_index}");
1023                self.disconnect_client_internal(client_index, false, DisconnectReason::TimedOut);
1024            }
1025        }
1026    }
1027}
1028
1029impl Drop for Server {
1030    fn drop(&mut self) {
1031        self.stop();
1032    }
1033}
1034
1035#[cfg(test)]
1036mod tests {
1037    use super::*;
1038
1039    fn test_address(port: u16) -> SocketAddr {
1040        format!("127.0.0.1:{port}").parse().unwrap()
1041    }
1042
1043    #[test]
1044    fn encryption_manager_add_find_remove() {
1045        let mut manager = EncryptionManager::new();
1046        let time = 100.0;
1047
1048        let send_key = crypto::generate_key();
1049        let receive_key = crypto::generate_key();
1050
1051        for port in 0..5u16 {
1052            assert!(manager.add_encryption_mapping(
1053                test_address(40000 + port),
1054                &send_key,
1055                &receive_key,
1056                time,
1057                time + 5.0,
1058                5,
1059            ));
1060        }
1061
1062        for port in 0..5u16 {
1063            let index = manager.find_encryption_mapping(test_address(40000 + port), time).unwrap();
1064            assert_eq!(manager.send_key(index), send_key);
1065            assert_eq!(manager.receive_key(index), receive_key);
1066        }
1067        assert!(manager.find_encryption_mapping(test_address(50000), time).is_none());
1068
1069        assert!(manager.remove_encryption_mapping(test_address(40002), time));
1070        assert!(manager.find_encryption_mapping(test_address(40002), time).is_none());
1071        assert!(!manager.remove_encryption_mapping(test_address(40002), time));
1072
1073        // entries expire after their timeout with no access
1074        assert!(manager.find_encryption_mapping(test_address(40000), time + 10.0).is_none());
1075    }
1076
1077    #[test]
1078    fn encryption_manager_expire_time() {
1079        let mut manager = EncryptionManager::new();
1080        let send_key = crypto::generate_key();
1081        let receive_key = crypto::generate_key();
1082
1083        // an entry that expires at time 105 unless a client connects
1084        assert!(manager.add_encryption_mapping(
1085            test_address(40000),
1086            &send_key,
1087            &receive_key,
1088            100.0,
1089            105.0,
1090            -1,
1091        ));
1092        assert!(manager.find_encryption_mapping(test_address(40000), 104.0).is_some());
1093        assert!(manager.find_encryption_mapping(test_address(40000), 106.0).is_none());
1094    }
1095
1096    #[test]
1097    fn connect_token_entries_reject_reuse_from_different_address() {
1098        let mut entries = Vec::new();
1099        reset_connect_token_entries(&mut entries);
1100
1101        let mac = [0x42u8; MAC_BYTES];
1102
1103        // first use records the token
1104        assert!(find_or_add_connect_token_entry(&mut entries, test_address(40000), &mac, 0.0));
1105        // same token from the same address is fine
1106        assert!(find_or_add_connect_token_entry(&mut entries, test_address(40000), &mac, 1.0));
1107        // same token from a different address is rejected
1108        assert!(!find_or_add_connect_token_entry(&mut entries, test_address(40001), &mac, 2.0));
1109    }
1110}