raknet-rust 0.2.0

Asynchronous, high-performance RakNet transport library for Rust.
Documentation
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

use bytes::{Buf, BufMut};

use crate::error::{DecodeError, EncodeError};

use super::codec::RaknetCodec;

pub const SYSTEM_ADDRESS_COUNT: usize = 10;

pub const ID_CONNECTED_PING: u8 = 0x00;
pub const ID_CONNECTED_PONG: u8 = 0x03;
pub const ID_CONNECTION_REQUEST: u8 = 0x09;
pub const ID_CONNECTION_REQUEST_ACCEPTED: u8 = 0x10;
pub const ID_NEW_INCOMING_CONNECTION: u8 = 0x13;
pub const ID_DISCONNECTION_NOTIFICATION: u8 = 0x15;
pub const ID_DETECT_LOST_CONNECTION: u8 = 0x04;

#[derive(Debug, Clone)]
pub struct ConnectedPing {
    pub ping_time: i64,
}

#[derive(Debug, Clone)]
pub struct ConnectedPong {
    pub ping_time: i64,
    pub pong_time: i64,
}

#[derive(Debug, Clone)]
pub struct ConnectionRequest {
    pub client_guid: u64,
    pub request_time: i64,
    pub use_encryption: bool,
}

#[derive(Debug, Clone)]
pub struct ConnectionRequestAccepted {
    pub client_addr: SocketAddr,
    pub system_index: u16,
    pub internal_addrs: [SocketAddr; SYSTEM_ADDRESS_COUNT],
    pub request_time: i64,
    pub accepted_time: i64,
}

#[derive(Debug, Clone)]
pub struct NewIncomingConnection {
    pub server_addr: SocketAddr,
    pub internal_addrs: [SocketAddr; SYSTEM_ADDRESS_COUNT],
    pub request_time: i64,
    pub accepted_time: i64,
}

#[derive(Debug, Clone)]
pub struct DisconnectionNotification {
    pub reason: Option<u8>,
}

#[derive(Debug, Clone)]
pub struct DetectLostConnection;

#[derive(Debug, Clone)]
pub enum ConnectedControlPacket {
    ConnectedPing(ConnectedPing),
    ConnectedPong(ConnectedPong),
    ConnectionRequest(ConnectionRequest),
    ConnectionRequestAccepted(ConnectionRequestAccepted),
    NewIncomingConnection(NewIncomingConnection),
    DisconnectionNotification(DisconnectionNotification),
    DetectLostConnection(DetectLostConnection),
}

impl ConnectedControlPacket {
    pub fn id(&self) -> u8 {
        match self {
            Self::ConnectedPing(_) => ID_CONNECTED_PING,
            Self::ConnectedPong(_) => ID_CONNECTED_PONG,
            Self::ConnectionRequest(_) => ID_CONNECTION_REQUEST,
            Self::ConnectionRequestAccepted(_) => ID_CONNECTION_REQUEST_ACCEPTED,
            Self::NewIncomingConnection(_) => ID_NEW_INCOMING_CONNECTION,
            Self::DisconnectionNotification(_) => ID_DISCONNECTION_NOTIFICATION,
            Self::DetectLostConnection(_) => ID_DETECT_LOST_CONNECTION,
        }
    }

    pub fn encode(&self, dst: &mut impl BufMut) -> Result<(), EncodeError> {
        self.id().encode_raknet(dst)?;
        match self {
            Self::ConnectedPing(pkt) => pkt.ping_time.encode_raknet(dst)?,
            Self::ConnectedPong(pkt) => {
                pkt.ping_time.encode_raknet(dst)?;
                pkt.pong_time.encode_raknet(dst)?;
            }
            Self::ConnectionRequest(pkt) => {
                pkt.client_guid.encode_raknet(dst)?;
                pkt.request_time.encode_raknet(dst)?;
                pkt.use_encryption.encode_raknet(dst)?;
            }
            Self::ConnectionRequestAccepted(pkt) => {
                pkt.client_addr.encode_raknet(dst)?;
                pkt.system_index.encode_raknet(dst)?;
                for addr in &pkt.internal_addrs {
                    addr.encode_raknet(dst)?;
                }
                pkt.request_time.encode_raknet(dst)?;
                pkt.accepted_time.encode_raknet(dst)?;
            }
            Self::NewIncomingConnection(pkt) => {
                pkt.server_addr.encode_raknet(dst)?;
                for addr in &pkt.internal_addrs {
                    addr.encode_raknet(dst)?;
                }
                pkt.request_time.encode_raknet(dst)?;
                pkt.accepted_time.encode_raknet(dst)?;
            }
            Self::DisconnectionNotification(pkt) => {
                if let Some(reason) = pkt.reason {
                    reason.encode_raknet(dst)?;
                }
            }
            Self::DetectLostConnection(_) => {}
        }
        Ok(())
    }

    pub fn decode(src: &mut impl Buf) -> Result<Self, DecodeError> {
        let id = u8::decode_raknet(src)?;
        match id {
            ID_CONNECTED_PING => Ok(Self::ConnectedPing(ConnectedPing {
                ping_time: i64::decode_raknet(src)?,
            })),
            ID_CONNECTED_PONG => Ok(Self::ConnectedPong(ConnectedPong {
                ping_time: i64::decode_raknet(src)?,
                pong_time: i64::decode_raknet(src)?,
            })),
            ID_CONNECTION_REQUEST => Ok(Self::ConnectionRequest(ConnectionRequest {
                client_guid: u64::decode_raknet(src)?,
                request_time: i64::decode_raknet(src)?,
                use_encryption: bool::decode_raknet(src)?,
            })),
            ID_CONNECTION_REQUEST_ACCEPTED => {
                let client_addr = SocketAddr::decode_raknet(src)?;
                let system_index = u16::decode_raknet(src)?;
                let mut internal_addrs = [default_socket_addr(); SYSTEM_ADDRESS_COUNT];
                for item in &mut internal_addrs {
                    *item = SocketAddr::decode_raknet(src)?;
                }
                let request_time = i64::decode_raknet(src)?;
                let accepted_time = i64::decode_raknet(src)?;

                Ok(Self::ConnectionRequestAccepted(ConnectionRequestAccepted {
                    client_addr,
                    system_index,
                    internal_addrs,
                    request_time,
                    accepted_time,
                }))
            }
            ID_NEW_INCOMING_CONNECTION => {
                let server_addr = SocketAddr::decode_raknet(src)?;
                let mut internal_addrs = [default_socket_addr(); SYSTEM_ADDRESS_COUNT];
                for item in &mut internal_addrs {
                    *item = SocketAddr::decode_raknet(src)?;
                }
                let request_time = i64::decode_raknet(src)?;
                let accepted_time = i64::decode_raknet(src)?;

                Ok(Self::NewIncomingConnection(NewIncomingConnection {
                    server_addr,
                    internal_addrs,
                    request_time,
                    accepted_time,
                }))
            }
            ID_DISCONNECTION_NOTIFICATION => {
                let reason = if src.has_remaining() {
                    Some(u8::decode_raknet(src)?)
                } else {
                    None
                };
                Ok(Self::DisconnectionNotification(DisconnectionNotification {
                    reason,
                }))
            }
            ID_DETECT_LOST_CONNECTION => Ok(Self::DetectLostConnection(DetectLostConnection)),
            _ => Err(DecodeError::InvalidConnectedPacketId(id)),
        }
    }
}

fn default_socket_addr() -> SocketAddr {
    SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))
}