///|
/// Resolve an IPv4 TCP service through portmapper v2. Port zero is unavailable.
pub async fn service_port(
host : String,
program : UInt,
version : UInt,
options? : Options = Options::default(),
) -> Int {
let rpc = Rpc::connect(host, 111, options~)
defer rpc.close()
let w = @xdr.Writer::new()
w.write_uint(program)
w.write_uint(version)
w.write_uint(6U)
w.write_uint(0U)
let r = rpc.call(100000U, 2U, 3U, w.bytes())
let port = r.read_uint()
r.finish()
if port == 0U || port > 65535U {
raise RpcFailure("service is unavailable over TCP")
}
port.reinterpret_as_int()
}
///|
pub struct Client {
priv rpc : Rpc
priv options : Options
priv root : Handle
priv mut read_size : Int
priv mut write_size : Int
}
///|
/// Explicit ports avoid portmapper when desired. No system mount is performed.
pub async fn connect_export(
host : String,
export_path : String,
mount_port? : Int = 0,
nfs_port? : Int = 0,
options? : Options = Options::default(),
) -> Client {
options.validate()
let path = @utf8.encode(export_path)
if path.length() == 0 ||
path.length() > 1024 ||
export_path.contains("\u{0000}") {
raise InvalidArgument("invalid export path")
}
let mp = if mount_port == 0 {
service_port(host, 100005U, 3U, options~)
} else {
mount_port
}
let np = if nfs_port == 0 {
service_port(host, 100003U, 3U, options~)
} else {
nfs_port
}
let mount = Rpc::connect(host, mp, options~)
defer mount.close()
let w = @xdr.Writer::new()
w.write_opaque(path.to_array(), bound=1024U)
let r = mount.call(100005U, 3U, 1U, w.bytes())
require_success(r)
let root = get_handle(r)
let count = r.read_length(64U)
let mut auth_sys = false
for _ in 0.. Unit {
self.rpc.close()
}
///|
pub fn Client::root_handle(self : Client) -> Handle {
{ bytes: Bytes::from_array(self.root.bytes.to_array()), }
}
///|
pub async fn unmount_export(
host : String,
export_path : String,
mount_port? : Int = 0,
options? : Options = Options::default(),
) -> Unit {
let mp = if mount_port == 0 {
service_port(host, 100005U, 3U, options~)
} else {
mount_port
}
let rpc = Rpc::connect(host, mp, options~)
defer rpc.close()
let w = @xdr.Writer::new()
if export_path.contains("\u{0000}") {
raise InvalidArgument("invalid export path")
}
w.write_opaque(@utf8.encode(export_path).to_array(), bound=1024U)
let r = rpc.call(100005U, 3U, 3U, w.bytes())
r.finish()
}
///|
async fn Client::invoke(
self : Client,
procedure : UInt,
w : @xdr.Writer,
modifying? : Bool = false,
) -> @xdr.Reader {
let r = self.rpc.call(100003U, 3U, procedure, w.bytes(), modifying~)
if modifying {
self.decode_mutation(r, require_success)
} else {
require_success(r)
}
r
}
///|
fn[T] Client::decode_mutation(
self : Client,
reader : @xdr.Reader,
decode : (@xdr.Reader) -> T raise,
) -> T raise {
decode(reader) catch {
Status(_) as error => raise error
error => {
self.close()
raise OutcomeUnknown("mutation reply could not be decoded: \{error}")
}
}
}