onc_rpc/reply/
accepted_reply.rs1use std::{
2 convert::TryFrom,
3 io::{Cursor, Write},
4};
5
6use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
7
8use crate::{auth::AuthFlavor, Error};
9
10const REPLY_SUCCESS: u32 = 0;
11const REPLY_PROG_UNAVAIL: u32 = 1;
12const REPLY_PROG_MISMATCH: u32 = 2;
13const REPLY_PROC_UNAVAIL: u32 = 3;
14const REPLY_GARBAGE_ARGS: u32 = 4;
15const REPLY_SYSTEM_ERR: u32 = 5;
16
17#[derive(Debug, PartialEq)]
20pub struct AcceptedReply<T, P>
21where
22 T: AsRef<[u8]>,
23 P: AsRef<[u8]>,
24{
25 auth_verifier: AuthFlavor<T>,
26 status: AcceptedStatus<P>,
27}
28
29impl<'a> AcceptedReply<&'a [u8], &'a [u8]> {
30 pub(crate) fn from_cursor(r: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
36 Ok(AcceptedReply {
37 auth_verifier: AuthFlavor::from_cursor(r)?,
38 status: AcceptedStatus::from_cursor(r)?,
39 })
40 }
41}
42
43impl<T, P> AcceptedReply<T, P>
44where
45 T: AsRef<[u8]>,
46 P: AsRef<[u8]>,
47{
48 pub fn new(auth_verifier: AuthFlavor<T>, status: AcceptedStatus<P>) -> Self {
50 Self {
51 auth_verifier,
52 status,
53 }
54 }
55
56 pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
59 self.auth_verifier.serialise_into(&mut buf)?;
60 self.status.serialise_into(&mut buf)
61 }
62
63 pub fn serialised_len(&self) -> u32 {
65 self.auth_verifier.serialised_len() + self.status.serialised_len()
66 }
67
68 pub fn auth_verifier(&self) -> &AuthFlavor<T> {
70 &self.auth_verifier
71 }
72
73 pub fn status(&self) -> &AcceptedStatus<P> {
75 &self.status
76 }
77}
78
79impl<'a> TryFrom<&'a [u8]> for AcceptedReply<&'a [u8], &'a [u8]> {
80 type Error = Error;
81
82 fn try_from(v: &'a [u8]) -> Result<Self, Self::Error> {
83 let mut c = Cursor::new(v);
84 AcceptedReply::from_cursor(&mut c)
85 }
86}
87
88#[cfg(feature = "bytes")]
89impl TryFrom<crate::Bytes> for AcceptedReply<crate::Bytes, crate::Bytes> {
90 type Error = Error;
91
92 fn try_from(mut v: crate::Bytes) -> Result<Self, Self::Error> {
93 use crate::Buf;
94
95 let auth_verifier = AuthFlavor::try_from(v.clone())?;
98 v.advance(auth_verifier.serialised_len() as usize);
99
100 Ok(Self {
101 auth_verifier,
102 status: AcceptedStatus::try_from(v)?,
103 })
104 }
105}
106
107#[derive(Debug, PartialEq, Clone)]
109pub enum AcceptedStatus<P>
110where
111 P: AsRef<[u8]>,
112{
113 Success(P),
116
117 ProgramUnavailable,
121
122 ProgramMismatch {
127 low: u32,
129
130 high: u32,
132 },
133
134 ProcedureUnavailable,
139
140 GarbageArgs,
145
146 SystemError,
150}
151
152impl<'a> AcceptedStatus<&'a [u8]> {
153 pub(crate) fn from_cursor(r: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
159 let reply = match r.read_u32::<BigEndian>()? {
161 REPLY_SUCCESS => AcceptedStatus::new_success(r),
162 REPLY_PROG_UNAVAIL => AcceptedStatus::ProgramUnavailable,
163 REPLY_PROG_MISMATCH => AcceptedStatus::ProgramMismatch {
164 low: r.read_u32::<BigEndian>()?,
165 high: r.read_u32::<BigEndian>()?,
166 },
167 REPLY_PROC_UNAVAIL => AcceptedStatus::ProcedureUnavailable,
168 REPLY_GARBAGE_ARGS => AcceptedStatus::GarbageArgs,
169 REPLY_SYSTEM_ERR => AcceptedStatus::SystemError,
170 v => return Err(Error::InvalidReplyStatus(v)),
171 };
172
173 Ok(reply)
174 }
175
176 fn new_success(r: &mut Cursor<&'a [u8]>) -> Self {
177 let data = *r.get_ref();
178 let start = r.position() as usize;
179 let payload = &data[start..];
180
181 AcceptedStatus::Success(payload)
186 }
187}
188
189impl<P> AcceptedStatus<P>
190where
191 P: AsRef<[u8]>,
192{
193 pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
196 match self {
197 Self::Success(p) => {
198 buf.write_u32::<BigEndian>(REPLY_SUCCESS)?;
199 buf.write_all(p.as_ref())
200 }
201 Self::ProgramUnavailable => buf.write_u32::<BigEndian>(REPLY_PROG_UNAVAIL),
202 Self::ProgramMismatch { low: l, high: h } => {
203 buf.write_u32::<BigEndian>(REPLY_PROG_MISMATCH)?;
204 buf.write_u32::<BigEndian>(*l)?;
205 buf.write_u32::<BigEndian>(*h)
206 }
207 Self::ProcedureUnavailable => buf.write_u32::<BigEndian>(REPLY_PROC_UNAVAIL),
208 Self::GarbageArgs => buf.write_u32::<BigEndian>(REPLY_GARBAGE_ARGS),
209 Self::SystemError => buf.write_u32::<BigEndian>(REPLY_SYSTEM_ERR),
210 }
211 }
212
213 pub fn serialised_len(&self) -> u32 {
215 let mut len = 0;
216
217 len += 4;
219
220 len += match self {
222 Self::Success(p) => p.as_ref().len() as u32,
223 Self::ProgramUnavailable => 0,
224 Self::ProgramMismatch { low: _l, high: _h } => 8,
225 Self::ProcedureUnavailable => 0,
226 Self::GarbageArgs => 0,
227 Self::SystemError => 0,
228 };
229
230 len
231 }
232}
233
234impl<'a> TryFrom<&'a [u8]> for AcceptedStatus<&'a [u8]> {
235 type Error = Error;
236
237 fn try_from(v: &'a [u8]) -> Result<Self, Self::Error> {
238 let mut c = Cursor::new(v);
239 AcceptedStatus::from_cursor(&mut c)
240 }
241}
242
243#[cfg(feature = "bytes")]
244impl TryFrom<crate::Bytes> for AcceptedStatus<crate::Bytes> {
245 type Error = Error;
246
247 fn try_from(mut v: crate::Bytes) -> Result<Self, Self::Error> {
248 use crate::bytes_ext::BytesReaderExt;
249
250 let reply = match v.try_u32()? {
251 REPLY_SUCCESS => Self::Success(v),
252 REPLY_PROG_UNAVAIL => Self::ProgramUnavailable,
253 REPLY_PROG_MISMATCH => Self::ProgramMismatch {
254 low: v.try_u32()?,
255 high: v.try_u32()?,
256 },
257 REPLY_PROC_UNAVAIL => Self::ProcedureUnavailable,
258 REPLY_GARBAGE_ARGS => Self::GarbageArgs,
259 REPLY_SYSTEM_ERR => Self::SystemError,
260 v => return Err(Error::InvalidReplyStatus(v)),
261 };
262
263 Ok(reply)
264 }
265}
266
267#[cfg(test)]
268mod tests {
269
270 use super::*;
271
272 #[test]
275 fn test_differing_payload_type() {
276 let binding = vec![42];
277 let auth = AuthFlavor::AuthNone(Some(binding.as_slice()));
278 let payload = [42, 42, 42, 42];
279
280 let _reply: AcceptedReply<&[u8], [u8; 4]> =
281 AcceptedReply::new(auth, AcceptedStatus::Success(payload));
282 }
283}