netcode 0.3.1

Wrapper for netcode.io library
use common::*;
use error::*;
use replay::ReplayProtection;
use packet::{self, Packet, KeepAlivePacket};
use socket::SocketProvider;

use std::net::SocketAddr;

pub const TIMEOUT_SECONDS: u32 = 5;
pub const KEEPALIVE_RETRY: f64 = 1.0 / 1.0;

#[derive(Clone, Debug)]
pub struct KeepAliveState {
    pub last_sent: f64,
    pub last_response: f64
}

impl KeepAliveState {
    pub fn new() -> KeepAliveState {
        KeepAliveState {
            last_sent: 0.0,
            last_response: 0.0
        }
    }

    pub fn update_sent(&mut self, time: f64) {
        self.last_sent = time;
    }

    pub fn update_response(&mut self, response: f64) {
        self.last_response = response;
    }

    pub fn has_expired(&self, time: f64) -> bool {
        self.last_response + (TIMEOUT_SECONDS as f64) < time
    }

    pub fn should_send_keepalive(&self, time: f64) -> bool {
        self.last_sent + KEEPALIVE_RETRY < time
    }
}

#[derive(Clone)]
pub struct Channel {
    keep_alive: KeepAliveState,
    send_key: [u8; NETCODE_KEY_BYTES],
    recv_key: [u8; NETCODE_KEY_BYTES],
    replay_protection: ReplayProtection,
    next_sequence: u64,
    addr: SocketAddr,
    protocol_id: u64,
    client_idx: usize,
    max_clients: usize
}

pub enum UpdateResult {
    Noop,
    SentKeepAlive,
    Expired
}

impl Channel {
    pub fn new(send_key: &[u8; NETCODE_KEY_BYTES],
               recv_key: &[u8; NETCODE_KEY_BYTES],
               addr: &SocketAddr,
               protocol_id: u64,
               client_idx: usize,
               max_clients: usize) -> Channel {
        Channel {
            keep_alive: KeepAliveState::new(),
            send_key: send_key.clone(),
            recv_key: recv_key.clone(),
            replay_protection: ReplayProtection::new(),
            next_sequence: 0,
            addr: addr.clone(),
            protocol_id: protocol_id,
            client_idx: client_idx,
            max_clients: max_clients
        }
    }

    pub fn send<I,S>(&mut self, elapsed: f64, packet: &Packet, payload: Option<&[u8]>, socket: &mut I) -> Result<usize, SendError> where I: SocketProvider<I,S> {
        let mut scratch = [0; NETCODE_MAX_PACKET_SIZE];
        let len = packet::encode(&mut scratch, self.protocol_id, packet, Some((self.next_sequence, &self.send_key)), payload)?;

        socket.send_to(&scratch[..len], &self.addr)?;

        self.next_sequence += 1;
        self.keep_alive.update_sent(elapsed);

        Ok(len)
    }

    pub fn recv(&mut self, elapsed: f64, packet: &[u8], out_payload: &mut [u8; NETCODE_MAX_PAYLOAD_SIZE]) -> Result<Packet, RecvError> {
        let (seq, packet) = packet::decode(packet, self.protocol_id, Some(&self.recv_key), out_payload)?;

        if self.replay_protection.packet_already_received(seq) {
            return Err(RecvError::DuplicateSequence)
        }

        self.keep_alive.update_response(elapsed);

        Ok(packet)
    }

    pub fn send_keep_alive<I,S>(&mut self, elapsed: f64, socket: &mut I) -> Result<usize, SendError> where I: SocketProvider<I,S> {
        let keep_alive = KeepAlivePacket {
            client_idx: self.client_idx as i32,
            max_clients: self.max_clients as i32
        };

        self.send(elapsed, &Packet::KeepAlive(keep_alive), None, socket)
    }

    pub fn update<I,S>(&mut self, elapsed: f64, socket: &mut I, send_keep_alive: bool) -> Result<UpdateResult, SendError> where I: SocketProvider<I,S> {
        if self.keep_alive.should_send_keepalive(elapsed) {
            if send_keep_alive {
                trace!("Sending keep alive");
                self.send_keep_alive(elapsed, socket)?;
            }

            return Ok(UpdateResult::SentKeepAlive)
        }

        if self.keep_alive.has_expired(elapsed) {
            return Ok(UpdateResult::Expired)
        }

        Ok(UpdateResult::Noop)
    }

    pub fn get_addr(&self) -> &SocketAddr {
        &self.addr
    }
}