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)
182 }
183}
184
185impl<P> AcceptedStatus<P>
186where
187 P: AsRef<[u8]>,
188{
189 pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
192 match self {
193 Self::Success(p) => {
194 buf.write_u32::<BigEndian>(REPLY_SUCCESS)?;
195 buf.write_all(p.as_ref())
196 }
197 Self::ProgramUnavailable => buf.write_u32::<BigEndian>(REPLY_PROG_UNAVAIL),
198 Self::ProgramMismatch { low: l, high: h } => {
199 buf.write_u32::<BigEndian>(REPLY_PROG_MISMATCH)?;
200 buf.write_u32::<BigEndian>(*l)?;
201 buf.write_u32::<BigEndian>(*h)
202 }
203 Self::ProcedureUnavailable => buf.write_u32::<BigEndian>(REPLY_PROC_UNAVAIL),
204 Self::GarbageArgs => buf.write_u32::<BigEndian>(REPLY_GARBAGE_ARGS),
205 Self::SystemError => buf.write_u32::<BigEndian>(REPLY_SYSTEM_ERR),
206 }
207 }
208
209 pub fn serialised_len(&self) -> u32 {
211 let mut len = 0;
212
213 len += 4;
215
216 len += match self {
218 Self::Success(p) => p.as_ref().len() as u32,
219 Self::ProgramUnavailable => 0,
220 Self::ProgramMismatch { low: _l, high: _h } => 8,
221 Self::ProcedureUnavailable => 0,
222 Self::GarbageArgs => 0,
223 Self::SystemError => 0,
224 };
225
226 len
227 }
228}
229
230impl<'a> TryFrom<&'a [u8]> for AcceptedStatus<&'a [u8]> {
231 type Error = Error;
232
233 fn try_from(v: &'a [u8]) -> Result<Self, Self::Error> {
234 let mut c = Cursor::new(v);
235 AcceptedStatus::from_cursor(&mut c)
236 }
237}
238
239#[cfg(feature = "bytes")]
240impl TryFrom<crate::Bytes> for AcceptedStatus<crate::Bytes> {
241 type Error = Error;
242
243 fn try_from(mut v: crate::Bytes) -> Result<Self, Self::Error> {
244 use crate::bytes_ext::BytesReaderExt;
245
246 let reply = match v.try_u32()? {
247 REPLY_SUCCESS => Self::Success(v),
248 REPLY_PROG_UNAVAIL => Self::ProgramUnavailable,
249 REPLY_PROG_MISMATCH => Self::ProgramMismatch {
250 low: v.try_u32()?,
251 high: v.try_u32()?,
252 },
253 REPLY_PROC_UNAVAIL => Self::ProcedureUnavailable,
254 REPLY_GARBAGE_ARGS => Self::GarbageArgs,
255 REPLY_SYSTEM_ERR => Self::SystemError,
256 v => return Err(Error::InvalidReplyStatus(v)),
257 };
258
259 Ok(reply)
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[test]
270 fn test_differing_payload_type() {
271 let auth = AuthFlavor::AuthNone(Some(vec![42]));
272 let payload = [42, 42, 42, 42];
273
274 let _reply: AcceptedReply<Vec<u8>, [u8; 4]> =
275 AcceptedReply::new(auth, AcceptedStatus::Success(payload));
276 }
277}