krimedc 0.2.0

A KDC based on libkrimes
use crate::config::{CoreAction, TaskName};
use libkrimes::cldap::{CldapConfig, CldapConfigBuilder};
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::net::UdpSocket;
use tokio::sync::broadcast;
use tokio_stream::StreamExt;
use tokio_util::codec::BytesCodec;
use tokio_util::udp::UdpFramed;
use tracing::{error, info};

async fn cldap_udp_acceptor(
    sock: UdpSocket,
    cfg: &'static CldapConfig,
    mut rx: broadcast::Receiver<CoreAction>,
) {
    info!("Started task {}", TaskName::CldapUdp);

    let sock = Arc::new(sock);
    let mut codec = UdpFramed::new(sock.clone(), BytesCodec::new());

    loop {
        tokio::select! {
        Ok(action) = rx.recv() => {
            match action {
                CoreAction::Shutdown => break,
            }
        }
        frame = codec.next() => {
                if let Some(frame) = frame {
                    match frame {
                        Ok((msg, addr)) => {
                            tokio::spawn(libkrimes::cldap::process(cfg, sock.clone(), addr, msg));
                        },
                        Err(e) => {
                            error!("LDAP codec error, no LDAP message: {:?}", e)
                        }
                    }
                }
            }
        }
    }

    info!("Stopped task {}", TaskName::CldapUdp);
}

pub(crate) async fn create_cldap_server(
    cfg: &CldapConfigBuilder,
    rx: broadcast::Receiver<CoreAction>,
) -> Result<tokio::task::JoinHandle<()>, ()> {
    let cfg = cfg.build().expect("TODO");
    let cfg = Box::new(cfg);
    let cfg: &'static CldapConfig = Box::leak(cfg);

    if cfg.address().starts_with(":::") {
        let port = cfg.address().replacen(":::", "", 1);
        error!(
            "Address '{}' looks like an attempt to wildcard bind with IPv6 on port {} - please try using '[::]:{}'",
            cfg.address(),
            port,
            port
        );
    }

    let address = cfg.address().parse::<SocketAddr>().map_err(|e| {
        error!("Could not parse address {} -> {:?}", cfg.address(), e);
    })?;

    let sock = UdpSocket::bind(address).await.map_err(|e| {
        error!("Could not bind to address {} -> {:?}", cfg.address(), e);
    })?;

    let handle = tokio::spawn(cldap_udp_acceptor(sock, cfg, rx));

    Ok(handle)
}