// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![feature(async_await, await_macro)]
#![deny(warnings)]

use {
    dhcp::{
        configuration,
        protocol::{Message, SERVER_PORT},
        server::Server,
    },
    failure::{Error, Fail, ResultExt},
    fuchsia_async::{net::UdpSocket, Executor, Interval},
    fuchsia_syslog::{self as fx_syslog, fx_log_info},
    fuchsia_zircon::{self as zx, DurationNum},
    futures::{future::try_join, Future, StreamExt, TryStreamExt},
    getopts::Options,
    std::{
        env,
        net::{IpAddr, Ipv4Addr, SocketAddr},
        sync::Mutex,
    },
    void::Void,
};

/// A buffer size in excess of the maximum allowable DHCP message size.
const BUF_SZ: usize = 1024;
const DEFAULT_CONFIG_PATH: &str = "/pkg/data/config.json";
/// The rate in seconds at which expiration DHCP leases are recycled back into the managed address
/// pool. The current value of 5 is meant to facilitate manual testing.
// TODO(atait): Replace with Duration type after it has been updated to const fn.
const EXPIRATION_INTERVAL_SECS: i64 = 5;

fn main() -> Result<(), Error> {
    fx_syslog::init_with_tags(&["dhcpd"])?;

    let mut exec = Executor::new().context("error creating executor")?;
    let path = get_server_config_file_path()?;
    let config = configuration::load_server_config_from_file(path)?;
    let server_ip = config.server_ip;
    let socket_addr = SocketAddr::new(IpAddr::V4(server_ip), SERVER_PORT);
    let udp_socket = UdpSocket::bind(&socket_addr).context("unable to bind socket")?;
    udp_socket.set_broadcast(true).context("unable to set broadcast")?;
    let server = Mutex::new(Server::from_config(config, || {
        zx::Time::get(zx::ClockId::UTC).into_nanos() / 1_000_000_000
    }));
    let msg_handling_loop = define_msg_handling_loop_future(udp_socket, &server);
    let lease_expiration_handler = define_lease_expiration_handler_future(&server);

    fx_log_info!(tag: "dhcpd", "starting server");
    exec.run_singlethreaded(try_join(msg_handling_loop, lease_expiration_handler))
        .map_err(|e| e.context("failed to start event loop"))?;
    fx_log_info!(tag: "dhcpd", "server shutting down");
    Ok(())
}

fn get_server_config_file_path() -> Result<String, Error> {
    let args: Vec<String> = env::args().collect();
    let program = &args[0];
    let mut opts = Options::new();
    opts.optopt("c", "config", "dhcpd configuration file path", "FILE");
    let matches = match opts.parse(args[1..].iter()) {
        Ok(m) => m,
        Err(e) => {
            opts.short_usage(program);
            return Err(e.context("failed to parse options").into());
        }
    };
    match matches.opt_str("c") {
        Some(p) => Ok(p),
        None => Ok(DEFAULT_CONFIG_PATH.to_string()),
    }
}

async fn define_msg_handling_loop_future<F: Fn() -> i64>(
    sock: UdpSocket,
    server: &Mutex<Server<F>>,
) -> Result<Void, Error> {
    let mut buf = vec![0u8; BUF_SZ];
    loop {
        let (received, mut sender) = await!(sock.recv_from(&mut *buf))
            .map_err(|_e| failure::err_msg("unable to receive buffer"))?;
        fx_log_info!("received message from: {:?}", sender);
        let msg = Message::from_buffer(&buf[0..received])
            .ok_or_else(|| failure::err_msg("unable to parse buffer"))?;
        fx_log_info!("parsed message: {:?}", msg);
        // This call should not block because the server is single-threaded.
        let response = server
            .lock()
            .unwrap()
            .dispatch(msg)
            .ok_or_else(|| failure::err_msg("invalid message"))?;
        fx_log_info!("generated response: {:?}", response);
        let response_buffer = response.serialize();
        // A new DHCP client sending a DHCPDISCOVER message will send
        // it from 0.0.0.0. In order to respond with a DHCPOFFER, the server
        // must broadcast the response. See RFC 2131 Section 4.4.1 for further
        // details.
        if sender.ip() == IpAddr::V4(Ipv4Addr::UNSPECIFIED) {
            sender.set_ip(IpAddr::V4(Ipv4Addr::BROADCAST));
        }
        await!(sock.send_to(&response_buffer, sender)).context("unable to send response")?;
        fx_log_info!("response sent to: {:?}", sender);
    }
}

fn define_lease_expiration_handler_future<'a, F: Fn() -> i64>(
    server: &'a Mutex<Server<F>>,
) -> impl Future<Output = Result<(), Error>> + 'a {
    let expiration_interval = Interval::new(EXPIRATION_INTERVAL_SECS.seconds());
    expiration_interval
        .map(move |()| {
            server.lock().unwrap().release_expired_leases();
        })
        .map(|_| Ok(()))
        .try_collect::<()>()
}
