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 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 self.inner.push(entry);
56 return true;
57 };
58 if let Some(matching) = matching {
59 self.inner[matching].addr == entry.addr
61 } else {
62 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
99pub type ClientId = u64;
103
104#[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 clients: FreeList<Connection, MAX_CLIENTS>,
131
132 replay_protection: HashMap<ClientIndex, ReplayProtection>,
134
135 packet_queue: VecDeque<(Vec<u8>, ClientIndex)>,
137
138 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>;
209pub 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 pub fn new() -> ServerConfig<()> {
254 ServerConfig::<()>::default()
255 }
256 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 pub fn num_disconnect_packets(mut self, num: usize) -> Self {
269 self.num_disconnect_packets = num;
270 self
271 }
272 pub fn keep_alive_send_rate(mut self, rate_seconds: f64) -> Self {
275 self.keep_alive_send_rate = rate_seconds;
276 self
277 }
278 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 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
302pub 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 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 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 return Ok(());
666 }
667 let (key, replay_protection) = match self.conn_cache.find_by_addr(&addr) {
668 _ if buf[0] == Packet::REQUEST => (self.private_key, None),
671 Some((client_idx, _)) => (
672 self.conn_cache.clients[client_idx.0].receive_key,
674 self.conn_cache.replay_protection.get_mut(&client_idx),
675 ),
676 None => {
677 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 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 pub fn update(&mut self, time: f64) {
776 self.try_update(time)
777 .expect("send/recv error while updating server")
778 }
779 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 pub fn recv(&mut self) -> Option<(Vec<u8>, ClientIndex)> {
816 self.conn_cache.packet_queue.pop_front()
817 }
818 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 return Err(Error::ClientNotConnected);
833 }
834 if !conn.is_confirmed() {
835 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 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 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 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 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 pub fn addr(&self) -> SocketAddr {
923 self.transceiver.addr()
924 }
925 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 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 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}