use std::collections::HashMap;
use std::io::{Read, Write};
use num_traits::cast::FromPrimitive;
use tracing::error;
use crate::protocol::xdr::{self, portmap, Serialize};
mod dump;
mod get_port;
mod null;
mod set_port;
mod unset_port;
use crate::protocol::nfs::portmap::dump::pmapproc_dump;
use crate::protocol::nfs::portmap::set_port::pmapproc_setport;
use crate::protocol::nfs::portmap::unset_port::pmapproc_unsetport;
use crate::protocol::rpc::Context;
use get_port::pmapproc_getport;
use null::pmapproc_null;
#[derive(Default)]
pub struct PortmapTable {
table: HashMap<PortmapKey, u16>,
}
#[derive(Debug, Hash, Eq, PartialEq)]
pub struct PortmapKey {
prog: u32,
vers: u32,
prot: u32,
}
pub fn handle_portmap(
xid: u32,
call: &xdr::rpc::call_body,
input: &mut impl Read,
output: &mut impl Write,
context: &mut Context,
) -> Result<(), anyhow::Error> {
if call.vers != portmap::VERSION {
error!("Invalid Portmap Version number {} != {}", call.vers, portmap::VERSION);
xdr::rpc::prog_mismatch_reply_message(xid, portmap::VERSION).serialize(output)?;
return Ok(());
}
let prog =
portmap::PortmapProgram::from_u32(call.proc).unwrap_or(portmap::PortmapProgram::INVALID);
match prog {
portmap::PortmapProgram::PMAPPROC_NULL => pmapproc_null(xid, output)?,
portmap::PortmapProgram::PMAPPROC_GETPORT => pmapproc_getport(xid, input, output, context)?,
portmap::PortmapProgram::PMAPPROC_SET => pmapproc_setport(xid, input, output, context)?,
portmap::PortmapProgram::PMAPPROC_DUMP => pmapproc_dump(xid, output, context)?,
portmap::PortmapProgram::PMAPPROC_UNSET => pmapproc_unsetport(xid, input, output, context)?,
_ => {
xdr::rpc::proc_unavail_reply_message(xid).serialize(output)?;
}
}
Ok(())
}
fn get_port(context: &Context, entry: &PortmapKey) -> Option<u16> {
let binding = context.portmap_table.read().unwrap();
binding.table.get(entry).copied()
}