use std::os::raw::c_char;
use std::time::{SystemTime, UNIX_EPOCH};
use nfsv41_sys::*;
use crate::compound::{Compound, CompoundRes};
use crate::error::{RpcError, RpcResult};
use crate::rpc::RpcClient;
pub struct OpenOwner {
pub name: Vec<u8>,
pub seqid: u32,
pub verifier: verifier4,
}
pub struct Session {
pub rpc: RpcClient,
pub clientid: clientid4,
pub sessionid: sessionid4,
slot_seqid: u32,
pub open_owner: OpenOwner,
}
impl Session {
pub fn connect(host: &str) -> RpcResult<Session> {
let rpc = RpcClient::connect(host)?;
let mut s = Session {
rpc,
clientid: 0,
sessionid: [0; 16],
slot_seqid: 1,
open_owner: OpenOwner {
name: b"vnfs-open-owner".to_vec(),
seqid: 0,
verifier: make_verifier(),
},
};
s.exchange_id()?;
s.create_session()?;
s.reclaim_complete()?;
Ok(s)
}
fn exchange_id(&mut self) -> RpcResult<()> {
let verifier = make_verifier();
let owner_id = format!(
"vnfs-client-{}-{:x}",
std::process::id(),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos()
);
let owner_id = owner_id.as_bytes();
let mut c = Compound::new();
c.tag(b"exchange_id");
c.exchange_id(EXCHANGE_ID4args {
eia_clientowner: client_owner4 {
co_verifier: verifier,
co_ownerid: client_owner4__bindgen_ty_1 {
co_ownerid_len: owner_id.len() as u32,
co_ownerid_val: owner_id.as_ptr() as *mut c_char,
},
},
eia_flags: 0,
eia_state_protect: state_protect4_a {
spa_how: state_protect_how4_SP4_NONE,
state_protect4_a_u: state_protect4_a__bindgen_ty_1 {
spa_mach_ops: unsafe { std::mem::zeroed() },
},
},
eia_client_impl_id: EXCHANGE_ID4args__bindgen_ty_1 {
eia_client_impl_id_len: 0,
eia_client_impl_id_val: std::ptr::null_mut(),
},
});
let res = c.call(&self.rpc)?;
let st = res.op_status(0);
if st != nfsstat4_NFS4_OK {
return Err(RpcError::op(0, st));
}
self.clientid = res.exchange_id(0).eir_clientid;
Ok(())
}
fn create_session(&mut self) -> RpcResult<()> {
let fore = channel_attrs4 {
ca_headerpadsize: 0,
ca_maxrequestsize: 4 * 1024 * 1024,
ca_maxresponsesize: 4 * 1024 * 1024,
ca_maxresponsesize_cached: 4 * 1024 * 1024,
ca_maxoperations: 256,
ca_maxrequests: 256,
ca_rdma_ird: channel_attrs4__bindgen_ty_1 {
ca_rdma_ird_len: 0,
ca_rdma_ird_val: std::ptr::null_mut(),
},
};
let back = channel_attrs4 {
ca_headerpadsize: 0,
ca_maxrequestsize: 4 * 1024 * 1024,
ca_maxresponsesize: 4 * 1024 * 1024,
ca_maxresponsesize_cached: 4 * 1024 * 1024,
ca_maxoperations: 2,
ca_maxrequests: 2,
ca_rdma_ird: channel_attrs4__bindgen_ty_1 {
ca_rdma_ird_len: 0,
ca_rdma_ird_val: std::ptr::null_mut(),
},
};
let mut c = Compound::new();
c.tag(b"create_session");
c.create_session(CREATE_SESSION4args {
csa_clientid: self.clientid,
csa_sequence: 1,
csa_flags: 0,
csa_fore_chan_attrs: fore,
csa_back_chan_attrs: back,
csa_cb_program: 0,
csa_sec_parms: CREATE_SESSION4args__bindgen_ty_1 {
csa_sec_parms_len: 0,
csa_sec_parms_val: std::ptr::null_mut(),
},
});
let res = c.call(&self.rpc)?;
let st = res.op_status(0);
if st != nfsstat4_NFS4_OK {
return Err(RpcError::op(0, st));
}
self.sessionid = res.create_session(0).csr_sessionid;
Ok(())
}
fn reclaim_complete(&mut self) -> RpcResult<()> {
let mut c = Compound::new();
c.tag(b"reclaim_complete");
c.reclaim_complete();
let res = self.compound(&mut c)?;
let st = res.op_status(1);
if st != nfsstat4_NFS4_OK {
return Err(RpcError::op(1, st));
}
Ok(())
}
pub fn compound(&mut self, c: &mut Compound) -> RpcResult<CompoundRes> {
let mut seq: nfs_argop4 = unsafe { std::mem::zeroed() };
seq.argop = nfs_opnum4_NFS4_OP_SEQUENCE;
seq.nfs_argop4_u.opsequence = SEQUENCE4args {
sa_sessionid: self.sessionid,
sa_sequenceid: self.slot_seqid,
sa_slotid: 0,
sa_highest_slotid: 0,
sa_cachethis: 0,
};
c.prepend_sequence(seq);
let res = c.call(&self.rpc)?;
if res.op_status(0) == nfsstat4_NFS4_OK {
self.slot_seqid += 1;
}
Ok(res)
}
pub fn expect_all_ok(&self, res: &CompoundRes) -> RpcResult<()> {
if res.status() != nfsstat4_NFS4_OK {
return Err(RpcError::op(0, res.status()));
}
for i in 0..res.nops() {
let st = res.op_status(i);
if st != nfsstat4_NFS4_OK {
return Err(RpcError::op(i, st));
}
}
Ok(())
}
fn destroy(&mut self) {
if self.clientid == 0 {
return;
}
let mut c = Compound::new();
c.tag(b"destroy_session");
c.destroy_session(&self.sessionid);
if let Ok(res) = c.call(&self.rpc) {
let _ = res;
}
let mut c = Compound::new();
c.tag(b"destroy_clientid");
c.destroy_clientid(self.clientid);
if let Ok(res) = c.call(&self.rpc) {
let _ = res;
}
}
}
impl Drop for Session {
fn drop(&mut self) {
self.destroy();
}
}
pub fn make_verifier() -> verifier4 {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos() as u64;
let mut v: verifier4 = [0; 8];
for (i, b) in v.iter_mut().enumerate() {
*b = ((now >> (8 * i)) & 0xff) as u8;
}
v
}