1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! The TLS/TCP [LoginServer].

use crate::gameplay_socket::PeerIdentifier;
use crate::secure_rand;
use anyhow::Context;
use rustls::{Certificate, PrivateKey, ServerConfig, ServerConnection};
use std::io::Write;
use std::net::{Shutdown, TcpListener, TcpStream};
use std::sync::mpsc::{self, Receiver, SyncSender};
use std::sync::Arc;
use std::thread;

// Used in docs.
#[allow(unused_imports)]
use crate::gameplay_socket::GameplaySocket;
#[allow(unused_imports)]
use common::protocol::MessageOrderer;

/// Wrapper for a TcpListener that accepts new clients and gives them the needed
/// bits of information to talk to [GameplaySocket].
pub struct LoginServer {
    peer_id_receiver: Receiver<(PeerIdentifier, [u8; 32])>,
}

impl LoginServer {
    /// Creates the TCP listener, and spawns a thread that will spawn another
    /// new thread for each incoming connection, one for each client.
    ///
    /// Each client that succesfully finishes the TLS handshake gets a
    /// [PeerIdentifier] and an encryption key to pass to [MessageOrderer::new].
    pub fn new() -> anyhow::Result<LoginServer> {
        let addr = "0.0.0.0:7812";
        let listener = TcpListener::bind(addr)
            .context("Could not bind the TCP listener! Is the server already running?")?;
        let cert_chain = vec![Certificate(
            include_bytes!("../../certs/server.crt").to_vec(),
        )];
        let cert_key = PrivateKey(include_bytes!("../../certs/server.key").to_vec());
        let server_config = Arc::new(
            ServerConfig::builder()
                .with_safe_defaults()
                .with_no_client_auth()
                .with_single_cert(cert_chain, cert_key)
                .context("Could not create rustls ServerConfig!")?,
        );
        log::info!("Login server init done, listening for TCP connections on {addr}.");

        let (sender, peer_id_receiver) = mpsc::sync_channel(0);
        thread::spawn(move || {
            for stream in listener.incoming() {
                match stream {
                    Ok(stream) => {
                        let server_config = server_config.clone();
                        let sender = sender.clone();
                        thread::spawn(move || {
                            if let Err(err) = handle_login_conn(stream, server_config, sender) {
                                log::debug!("Error during login: {err:?}")
                            }
                        });
                    }
                    Err(err) => log::debug!("Failed to accept TCP connection: {err}"),
                }
            }
        });
        Ok(LoginServer { peer_id_receiver })
    }

    /// Returns any new peer-identifier-and-encryption-key-pairs that have been
    /// generated for new clients. Should be called until None is returned, like
    /// an iterator.
    pub fn try_recv_new_peers(&mut self) -> Option<(PeerIdentifier, [u8; 32])> {
        self.peer_id_receiver.try_recv().ok()
    }
}

/// Sends the [PeerIdentifier] and a randomly generated encryption key over the
/// [TcpStream], encrypted with TLS.
fn handle_login_conn(
    mut stream: TcpStream,
    server_config: Arc<ServerConfig>,
    peer_id_sender: SyncSender<(PeerIdentifier, [u8; 32])>,
) -> anyhow::Result<()> {
    let mut connection = ServerConnection::new(server_config)
        .context("Failed to create new rustls ServerConnection for this tcp stream")?;
    connection
        .complete_io(&mut stream)
        .context("Failed to establish TLS connection.")?;
    let mut stream = rustls::Stream::new(&mut connection, &mut stream);

    // NOTE: For an actual user system or similar, we'd need an actual messaging
    // protocol here. But the only point currently for this is to send the
    // client a unique id. So just send it and close the stream.
    let mut peer_identifier_bytes = [0u8; 16];
    let mut encryption_key = [0u8; 32];
    secure_rand::gen_bytes(&mut peer_identifier_bytes);
    secure_rand::gen_bytes(&mut encryption_key);
    let peer_id = u128::from_be_bytes(peer_identifier_bytes);
    peer_id_sender
        .send((PeerIdentifier(peer_id), encryption_key))
        .context("Could not send peer identifier from new connection")?;
    log::info!("New peer: {peer_id:032x}");
    stream
        .write_all(&peer_identifier_bytes)
        .context("Failed to write the peer identifier to the tcp stream")?;
    stream
        .write_all(&encryption_key)
        .context("Failed to write the peer identifier to the tcp stream")?;
    stream
        .sock
        .shutdown(Shutdown::Both)
        .context("Failed to shutdown tcp connection")?;
    Ok(())
}