1use crate::ValidStr;
24use packet::{
25 BufferView, FragmentedBytesMut, InnerPacketBuilder, PacketBuilder, PacketConstraints,
26 ParsablePacket, ParseMetadata, SerializeTarget,
27};
28use std::io::Write as _;
29use std::num::NonZeroU16;
30use std::str::FromStr;
31use thiserror::Error;
32use witness::NonEmptyValidStr;
33use zerocopy::byteorder::network_endian::U16;
34use zerocopy::{
35 FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
36};
37
38pub const OUTGOING_PORT: NonZeroU16 = NonZeroU16::new(33340).unwrap();
40
41pub const INCOMING_PORT: NonZeroU16 = NonZeroU16::new(33341).unwrap();
43
44pub const DEFAULT_BLOCK_SIZE_OPTION: u16 = 512;
48
49pub const DEFAULT_WINDOW_SIZE_OPTION: u16 = 512;
53
54pub const DEFAULT_TIMEOUT_SECS_OPTION: u16 = 1;
56
57mod witness {
58 use crate::ValidStr;
59
60 #[derive(Debug)]
62 pub(super) struct NonEmptyValidStr<B: zerocopy::SplitByteSlice>(ValidStr<B>);
63
64 impl<B: zerocopy::SplitByteSlice> NonEmptyValidStr<B> {
65 pub(super) fn new(str: ValidStr<B>) -> Option<Self> {
67 if str.as_str().is_empty() {
68 None
69 } else {
70 Some(Self(str))
71 }
72 }
73 }
74
75 impl<B: zerocopy::SplitByteSlice> std::ops::Deref for NonEmptyValidStr<B> {
76 type Target = ValidStr<B>;
77 fn deref(&self) -> &Self::Target {
78 let Self(b) = self;
79 b
80 }
81 }
82}
83
84#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88pub enum TftpError {
89 Undefined,
90 FileNotFound,
91 AccessViolation,
92 DiskFull,
93 IllegalOperation,
94 UnknownTransferId,
95 FileAlreadyExists,
96 NoSuchUser,
97 BadOptions,
101 Busy,
107 Unknown(u16),
108}
109
110impl Into<u16> for TftpError {
111 fn into(self) -> u16 {
112 match self {
113 TftpError::Undefined => 0,
114 TftpError::FileNotFound => 1,
115 TftpError::AccessViolation => 2,
116 TftpError::DiskFull => 3,
117 TftpError::IllegalOperation => 4,
118 TftpError::UnknownTransferId => 5,
119 TftpError::FileAlreadyExists => 6,
120 TftpError::NoSuchUser => 7,
121 TftpError::BadOptions => 8,
122 TftpError::Busy => 0x143,
123 TftpError::Unknown(v) => v,
124 }
125 }
126}
127
128#[derive(Debug, Eq, PartialEq, Clone)]
130pub enum StringField {
131 OptionName,
132 OptionValue,
133 Filename,
134 TransferMode,
135}
136
137#[derive(Debug, Eq, PartialEq, Clone, Error)]
139pub enum ParseError {
140 #[error("invalid message length")]
141 InvalidLength,
142 #[error("invalid empty string for {0:?}")]
143 EmptyStringValue(StringField),
144 #[error("failed to parse string: {0}")]
145 BadString(crate::ValidStrError),
146 #[error("bad option `{name} = {value}`")]
147 BadOption { name: String, value: String },
148 #[error("bad value for option `{name}`: {error}")]
149 BadOptionValue { name: String, error: std::num::ParseIntError },
150 #[error("unrecognized transfer mode `{0}`")]
151 UnrecognizedTransferMode(String),
152 #[error("invalid opcode: {0}")]
153 InvalidOpcode(u16),
154 #[error("too many options, dropped {0:?}")]
155 TooManyOptions(Forceable<TftpOption>),
156}
157
158impl From<u16> for TftpError {
159 fn from(value: u16) -> Self {
160 match value {
161 0 => TftpError::Undefined,
162 1 => TftpError::FileNotFound,
163 2 => TftpError::AccessViolation,
164 3 => TftpError::DiskFull,
165 4 => TftpError::IllegalOperation,
166 5 => TftpError::UnknownTransferId,
167 6 => TftpError::FileAlreadyExists,
168 7 => TftpError::NoSuchUser,
169 8 => TftpError::BadOptions,
170 0x143 => TftpError::Busy,
171 unknown => TftpError::Unknown(unknown),
172 }
173 }
174}
175
176#[derive(Debug, Copy, Clone, Eq, PartialEq)]
180pub enum Opcode {
181 ReadRequest,
182 WriteRequest,
183 Data,
184 Ack,
185 Error,
186 OptionAck,
190}
191
192impl Into<u16> for Opcode {
193 fn into(self) -> u16 {
194 match self {
195 Opcode::ReadRequest => 1,
196 Opcode::WriteRequest => 2,
197 Opcode::Data => 3,
198 Opcode::Ack => 4,
199 Opcode::Error => 5,
200 Opcode::OptionAck => 6,
201 }
202 }
203}
204
205impl TryFrom<u16> for Opcode {
206 type Error = ParseError;
207
208 fn try_from(value: u16) -> Result<Self, ParseError> {
209 match value {
210 1 => Ok(Opcode::ReadRequest),
211 2 => Ok(Opcode::WriteRequest),
212 3 => Ok(Opcode::Data),
213 4 => Ok(Opcode::Ack),
214 5 => Ok(Opcode::Error),
215 6 => Ok(Opcode::OptionAck),
216 opcode => Err(ParseError::InvalidOpcode(opcode)),
217 }
218 }
219}
220
221#[derive(Debug, Clone, Eq, PartialEq)]
224pub struct Forceable<T> {
225 pub value: T,
226 pub forced: bool,
227}
228
229#[derive(Debug, Default)]
231pub struct OptionCollection(arrayvec::ArrayVec<Forceable<TftpOption>, MAX_OPTIONS>);
232
233impl OptionCollection {
234 pub fn iter(&self) -> impl Iterator<Item = &Forceable<TftpOption>> {
236 let Self(this) = self;
237 this.iter()
238 }
239
240 pub fn try_push(&mut self, option: Forceable<TftpOption>) -> Result<(), Forceable<TftpOption>> {
245 let Self(this) = self;
246 this.try_push(option).map_err(|e| e.element())
247 }
248
249 pub fn serialized_len(&self) -> usize {
251 self.iter().map(|o| o.serialized_len()).sum()
252 }
253
254 fn parse<B: SplitByteSlice, BV: BufferView<B>>(buffer: &mut BV) -> Result<Self, ParseError> {
255 let Self(mut vec) = Self::default();
259 while !buffer.is_empty() {
260 let name = NonEmptyValidStr::new(
261 ValidStr::new_null_terminated_from_buffer(buffer).map_err(ParseError::BadString)?,
262 )
263 .ok_or(ParseError::EmptyStringValue(StringField::OptionName))?;
264 let value = NonEmptyValidStr::new(
265 ValidStr::new_null_terminated_from_buffer(buffer).map_err(ParseError::BadString)?,
266 )
267 .ok_or(ParseError::EmptyStringValue(StringField::OptionValue))?;
268
269 let option = TftpOption::parse(name.as_ref(), value.as_ref())?;
270 let () = vec.try_push(option).map_err(|e| ParseError::TooManyOptions(e.element()))?;
271 }
272 Ok(Self(vec))
273 }
274
275 fn serialize<B: SplitByteSliceMut, BV: BufferView<B>>(&self, buffer: &mut BV) {
276 self.iter().for_each(|v| v.serialize(buffer))
277 }
278
279 pub fn collect(&self) -> AllOptions {
281 self.iter().cloned().collect()
282 }
283}
284
285impl std::iter::FromIterator<Forceable<TftpOption>> for OptionCollection {
286 fn from_iter<T: IntoIterator<Item = Forceable<TftpOption>>>(iter: T) -> Self {
287 Self(iter.into_iter().collect())
288 }
289}
290
291#[derive(Default, Eq, PartialEq, Debug)]
293pub struct AllOptions {
294 pub transfer_size: Option<Forceable<u64>>,
295 pub window_size: Option<Forceable<u16>>,
296 pub timeout: Option<Forceable<u8>>,
297 pub block_size: Option<Forceable<u16>>,
298}
299
300impl std::iter::FromIterator<Forceable<TftpOption>> for AllOptions {
305 fn from_iter<T: IntoIterator<Item = Forceable<TftpOption>>>(iter: T) -> Self {
306 iter.into_iter().fold(Self::default(), |mut all_options, Forceable { value, forced }| {
307 match value {
308 TftpOption::TransferSize(value) => {
309 all_options.transfer_size = Some(Forceable { value, forced })
310 }
311 TftpOption::BlockSize(value) => {
312 all_options.block_size = Some(Forceable { value, forced })
313 }
314 TftpOption::Timeout(value) => {
315 all_options.timeout = Some(Forceable { value, forced })
316 }
317 TftpOption::WindowSize(value) => {
318 all_options.window_size = Some(Forceable { value, forced })
319 }
320 }
321 all_options
322 })
323 }
324}
325
326#[derive(Debug)]
328pub struct RequestBody<B: SplitByteSlice> {
329 filename: NonEmptyValidStr<B>,
330 mode: TftpMode,
331 options: OptionCollection,
332}
333
334impl<B> RequestBody<B>
335where
336 B: SplitByteSlice,
337{
338 fn parse<BV: BufferView<B>>(buffer: &mut BV) -> Result<Self, ParseError> {
339 let filename = ValidStr::new_null_terminated_from_buffer(buffer)
340 .map_err(ParseError::BadString)
341 .and_then(|s| {
342 NonEmptyValidStr::new(s).ok_or(ParseError::EmptyStringValue(StringField::Filename))
343 })?;
344
345 let mode = TftpMode::try_from(
346 ValidStr::new_null_terminated_from_buffer(buffer)
347 .map_err(ParseError::BadString)
348 .and_then(|s| {
349 NonEmptyValidStr::new(s)
350 .ok_or(ParseError::EmptyStringValue(StringField::TransferMode))
351 })?
352 .as_ref(),
353 )?;
354 let options = OptionCollection::parse(buffer)?;
355 Ok(Self { filename, mode, options })
356 }
357
358 pub fn filename(&self) -> &str {
359 self.filename.as_ref()
360 }
361
362 pub fn mode(&self) -> TftpMode {
363 self.mode
364 }
365
366 pub fn options(&self) -> &OptionCollection {
367 &self.options
368 }
369}
370
371#[derive(Debug)]
373pub struct DataBody<B: SplitByteSlice> {
374 block: Ref<B, U16>,
375 payload: B,
376}
377
378impl<B> DataBody<B>
379where
380 B: SplitByteSlice,
381{
382 fn parse<BV: BufferView<B>>(buffer: &mut BV) -> Result<Self, ParseError> {
383 let block = buffer.take_obj_front::<U16>().ok_or(ParseError::InvalidLength)?;
384 let payload = buffer.take_rest_front();
385 Ok(Self { block, payload })
386 }
387
388 pub fn block(&self) -> u16 {
389 self.block.get()
390 }
391
392 pub fn payload(&self) -> &B {
393 &self.payload
394 }
395}
396
397#[derive(Debug)]
399pub struct AckBody<B: SplitByteSlice> {
400 block: Ref<B, U16>,
401}
402
403impl<B> AckBody<B>
404where
405 B: SplitByteSlice,
406{
407 fn parse<BV: BufferView<B>>(buffer: &mut BV) -> Result<Self, ParseError> {
408 let block = buffer.take_obj_front::<U16>().ok_or(ParseError::InvalidLength)?;
409 Ok(Self { block })
410 }
411
412 pub fn block(&self) -> u16 {
413 self.block.get()
414 }
415}
416
417#[derive(Debug)]
419pub struct ErrorBody<B: SplitByteSlice> {
420 error: TftpError,
421 msg: ValidStr<B>,
422}
423
424impl<B> ErrorBody<B>
425where
426 B: SplitByteSlice,
427{
428 fn parse<BV: BufferView<B>>(buffer: &mut BV) -> Result<Self, ParseError> {
429 let error =
430 TftpError::from(buffer.take_obj_front::<U16>().ok_or(ParseError::InvalidLength)?.get());
431 let msg =
432 ValidStr::new_null_terminated_from_buffer(buffer).map_err(ParseError::BadString)?;
433 Ok(Self { error, msg })
434 }
435
436 pub fn error(&self) -> TftpError {
437 self.error
438 }
439
440 pub fn message(&self) -> &str {
441 self.msg.as_ref()
442 }
443}
444
445#[derive(Debug)]
447pub struct OptionAckBody {
448 options: OptionCollection,
449}
450
451impl OptionAckBody {
452 fn parse<B: SplitByteSlice, BV: BufferView<B>>(buffer: &mut BV) -> Result<Self, ParseError> {
453 let options = OptionCollection::parse(buffer)?;
454 Ok(Self { options })
455 }
456
457 pub fn options(&self) -> &OptionCollection {
458 &self.options
459 }
460}
461
462#[derive(Debug)]
466pub enum TftpPacket<B: SplitByteSlice> {
467 ReadRequest(RequestBody<B>),
468 WriteRequest(RequestBody<B>),
469 Data(DataBody<B>),
470 Ack(AckBody<B>),
471 Error(ErrorBody<B>),
472 OptionAck(OptionAckBody),
473}
474
475impl<B: SplitByteSlice> TftpPacket<B> {
476 pub fn opcode(&self) -> Opcode {
478 match self {
479 TftpPacket::ReadRequest(_) => Opcode::ReadRequest,
480 TftpPacket::WriteRequest(_) => Opcode::WriteRequest,
481 TftpPacket::Data(_) => Opcode::Data,
482 TftpPacket::Ack(_) => Opcode::Ack,
483 TftpPacket::Error(_) => Opcode::Error,
484 TftpPacket::OptionAck(_) => Opcode::OptionAck,
485 }
486 }
487
488 pub fn into_read_request(self) -> Result<RequestBody<B>, Self> {
489 match self {
490 Self::ReadRequest(r) => Ok(r),
491 o => Err(o),
492 }
493 }
494
495 pub fn into_write_request(self) -> Result<RequestBody<B>, Self> {
496 match self {
497 Self::WriteRequest(r) => Ok(r),
498 o => Err(o),
499 }
500 }
501
502 pub fn into_data(self) -> Result<DataBody<B>, Self> {
503 match self {
504 Self::Data(r) => Ok(r),
505 o => Err(o),
506 }
507 }
508
509 pub fn into_ack(self) -> Result<AckBody<B>, Self> {
510 match self {
511 Self::Ack(r) => Ok(r),
512 o => Err(o),
513 }
514 }
515
516 pub fn into_error(self) -> Result<ErrorBody<B>, Self> {
517 match self {
518 Self::Error(r) => Ok(r),
519 o => Err(o),
520 }
521 }
522
523 pub fn into_oack(self) -> Result<OptionAckBody, Self> {
524 match self {
525 Self::OptionAck(r) => Ok(r),
526 o => Err(o),
527 }
528 }
529}
530
531impl<B> ParsablePacket<B, ()> for TftpPacket<B>
532where
533 B: SplitByteSlice,
534{
535 type Error = ParseError;
536
537 fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, ParseError> {
538 let opcode: Opcode =
539 buffer.take_obj_front::<MessageHead>().ok_or(ParseError::InvalidLength)?.opcode()?;
540 Ok(match opcode {
541 Opcode::ReadRequest => TftpPacket::ReadRequest(RequestBody::parse(&mut buffer)?),
542 Opcode::WriteRequest => TftpPacket::WriteRequest(RequestBody::parse(&mut buffer)?),
543 Opcode::Data => TftpPacket::Data(DataBody::parse(&mut buffer)?),
544 Opcode::Ack => TftpPacket::Ack(AckBody::parse(&mut buffer)?),
545 Opcode::Error => TftpPacket::Error(ErrorBody::parse(&mut buffer)?),
546 Opcode::OptionAck => TftpPacket::OptionAck(OptionAckBody::parse(&mut buffer)?),
547 })
548 }
549
550 fn parse_metadata(&self) -> ParseMetadata {
551 unimplemented!()
553 }
554}
555
556const OPT_NETASCII: unicase::Ascii<&'static str> = unicase::Ascii::new("NETASCII");
557const OPT_OCTET: unicase::Ascii<&'static str> = unicase::Ascii::new("OCTET");
558const OPT_MAIL: unicase::Ascii<&'static str> = unicase::Ascii::new("MAIL");
559
560#[derive(Debug, Copy, Clone, Eq, PartialEq)]
564pub enum TftpMode {
565 NETASCII,
566 OCTET,
567 MAIL,
568}
569
570impl TftpMode {
571 pub fn as_str(&self) -> &'static str {
572 match self {
573 TftpMode::NETASCII => OPT_NETASCII,
574 TftpMode::OCTET => OPT_OCTET,
575 TftpMode::MAIL => OPT_MAIL,
576 }
577 .into_inner()
578 }
579}
580
581impl Into<&'static str> for TftpMode {
582 fn into(self) -> &'static str {
583 self.as_str()
584 }
585}
586
587impl<'a> TryFrom<&'a str> for TftpMode {
588 type Error = ParseError;
589
590 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
591 let value = unicase::Ascii::new(value);
592 if value == OPT_NETASCII {
594 Ok(TftpMode::NETASCII)
595 } else if value == OPT_OCTET {
596 Ok(TftpMode::OCTET)
597 } else if value == OPT_MAIL {
598 Ok(TftpMode::MAIL)
599 } else {
600 Err(ParseError::UnrecognizedTransferMode(value.to_string()))
601 }
602 }
603}
604
605pub const MAX_OPTIONS: usize = 4;
607
608const OPT_TRANSFER_SIZE: unicase::Ascii<&'static str> = unicase::Ascii::new("TSIZE");
609const OPT_BLOCK_SIZE: unicase::Ascii<&'static str> = unicase::Ascii::new("BLKSIZE");
610const OPT_TIMEOUT: unicase::Ascii<&'static str> = unicase::Ascii::new("TIMEOUT");
611const OPT_WINDOWSIZE: unicase::Ascii<&'static str> = unicase::Ascii::new("WINDOWSIZE");
612
613#[derive(Debug, Eq, PartialEq, Clone)]
619pub enum TftpOption {
620 TransferSize(u64),
625 BlockSize(u16),
632 Timeout(u8),
638 WindowSize(u16),
645}
646
647impl TftpOption {
648 pub fn parse(option: &str, value: &str) -> Result<Forceable<Self>, ParseError> {
649 let (option, forced) = match option.chars().last() {
650 Some('!') => (&option[..option.len() - 1], true),
651 Some(_) | None => (option, false),
652 };
653 let option = unicase::Ascii::new(option);
654 let value = if option == OPT_TRANSFER_SIZE {
655 u64::from_str(value).map(|v| TftpOption::TransferSize(v))
656 } else if option == OPT_BLOCK_SIZE {
657 u16::from_str(value).map(|v| TftpOption::BlockSize(v))
658 } else if option == OPT_TIMEOUT {
659 u8::from_str(value).map(|v| TftpOption::Timeout(v))
660 } else if option == OPT_WINDOWSIZE {
661 u16::from_str(value).map(|v| TftpOption::WindowSize(v))
662 } else {
663 return Err(ParseError::BadOption {
664 name: option.to_string(),
665 value: value.to_string(),
666 });
667 }
668 .map_err(|error| ParseError::BadOptionValue { name: option.to_string(), error })?;
669
670 Ok(Forceable { value, forced })
671 }
672
673 fn get_option_and_value(&self) -> (unicase::Ascii<&'static str>, u64) {
674 match self {
675 TftpOption::TransferSize(v) => (OPT_TRANSFER_SIZE, *v),
676 TftpOption::BlockSize(v) => (OPT_BLOCK_SIZE, (*v).into()),
677 TftpOption::Timeout(v) => (OPT_TIMEOUT, (*v).into()),
678 TftpOption::WindowSize(v) => (OPT_WINDOWSIZE, (*v).into()),
679 }
680 }
681
682 pub const fn not_forced(self) -> Forceable<TftpOption> {
683 Forceable { value: self, forced: false }
684 }
685
686 pub const fn forced(self) -> Forceable<TftpOption> {
687 Forceable { value: self, forced: true }
688 }
689}
690
691impl Forceable<TftpOption> {
692 pub fn serialized_len(&self) -> usize {
697 let Forceable { value, forced } = self;
698 let (option, value) = value.get_option_and_value();
699 let forced = if *forced { 1 } else { 0 };
700
701 #[derive(Default)]
702 struct FormattedLen(usize);
703
704 impl std::io::Write for FormattedLen {
705 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
706 let Self(counter) = self;
707 *counter += buf.len();
708 Ok(buf.len())
709 }
710
711 fn flush(&mut self) -> std::io::Result<()> {
712 Ok(())
713 }
714 }
715
716 let mut value_len = FormattedLen::default();
717 let () =
718 std::write!(&mut value_len, "{}", value).expect("failed to serialize value to string");
719 let FormattedLen(value_len) = value_len;
720 forced + option.len() + value_len + 2
722 }
723
724 pub fn serialize<B: SplitByteSliceMut, BV: BufferView<B>>(&self, bv: &mut BV) {
726 let Forceable { value, forced } = self;
727 let (option, value) = value.get_option_and_value();
728 write_option_and_value(bv, option.as_ref(), *forced, value);
729 }
730}
731
732fn write_str<B, BV>(buff: &mut BV, v: &str)
733where
734 B: SplitByteSliceMut,
735 BV: BufferView<B>,
736{
737 write_str_forced(buff, v, false)
738}
739
740fn write_str_forced<B, BV>(buff: &mut BV, v: &str, forced: bool)
741where
742 B: SplitByteSliceMut,
743 BV: BufferView<B>,
744{
745 let extra = if forced { 2 } else { 1 };
746 let mut d = buff.take_front(v.len() + extra).unwrap();
747 let (data, end) = d.split_at_mut(v.len());
748 data.copy_from_slice(v.as_bytes());
749 if forced {
750 end[0] = '!' as u8;
751 end[1] = 0;
752 } else {
753 end[0] = 0;
754 }
755}
756
757fn write_option_and_value<B, BV, V>(buff: &mut BV, option: &str, forced: bool, value: V)
758where
759 B: SplitByteSliceMut,
760 BV: BufferView<B>,
761 V: std::fmt::Display,
762{
763 write_str_forced(buff, option, forced);
764
765 struct BVIoWriter<'a, B, BV>(&'a mut BV, std::marker::PhantomData<B>);
766
767 impl<'a, B, BV> std::io::Write for BVIoWriter<'a, B, BV>
768 where
769 BV: BufferView<B>,
770 B: SplitByteSliceMut,
771 {
772 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
773 let Self(bv, std::marker::PhantomData) = self;
774 let mut b = bv
775 .take_front(buf.len())
776 .ok_or_else(|| std::io::Error::from(std::io::ErrorKind::OutOfMemory))?;
777 b.as_mut().copy_from_slice(buf);
778 Ok(b.len())
779 }
780
781 fn flush(&mut self) -> std::io::Result<()> {
782 Ok(())
783 }
784 }
785
786 std::write!(&mut BVIoWriter(buff, std::marker::PhantomData), "{}\0", value)
787 .unwrap_or_else(|e| panic!("failed to serialize {}: {:?}", value, e));
788}
789
790#[repr(C)]
791#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
792struct MessageHead {
793 opcode: U16,
794}
795
796impl MessageHead {
797 fn opcode(&self) -> Result<Opcode, ParseError> {
798 Opcode::try_from(self.opcode.get() & 0xff)
801 }
802
803 fn set_opcode(&mut self, opcode: Opcode) {
804 self.opcode.set(opcode.into());
805 }
806}
807
808#[derive(Debug, Copy, Clone)]
810pub enum TransferDirection {
811 Read,
812 Write,
813}
814
815#[derive(Debug)]
816pub struct TransferRequestBuilder<'a> {
818 direction: TransferDirection,
819 filename: &'a str,
820 mode: TftpMode,
821 options: OptionCollection,
822}
823
824impl<'a> TransferRequestBuilder<'a> {
825 pub fn new(direction: TransferDirection, filename: &'a str, mode: TftpMode) -> Self {
827 Self { direction, filename, mode, options: OptionCollection::default() }
828 }
829
830 pub fn new_with_options(
832 direction: TransferDirection,
833 filename: &'a str,
834 mode: TftpMode,
835 options: impl IntoIterator<Item = Forceable<TftpOption>>,
836 ) -> Self {
837 Self { direction, filename, mode, options: options.into_iter().collect() }
838 }
839
840 pub fn options_mut(&mut self) -> &mut OptionCollection {
841 &mut self.options
842 }
843}
844
845impl<'a> InnerPacketBuilder for TransferRequestBuilder<'a> {
846 fn bytes_len(&self) -> usize {
847 std::mem::size_of::<MessageHead>()
848 + self.filename.as_bytes().len()
849 + 1
850 + self.mode.as_str().as_bytes().len()
851 + 1
852 + self.options.serialized_len()
853 }
854
855 fn serialize(&self, mut buffer: &mut [u8]) {
856 let mut bv = crate::as_buffer_view_mut(&mut buffer);
857 bv.take_obj_front::<MessageHead>().unwrap().set_opcode(match self.direction {
858 TransferDirection::Read => Opcode::ReadRequest,
859 TransferDirection::Write => Opcode::WriteRequest,
860 });
861 write_str(&mut bv, self.filename.as_ref());
862 write_str(&mut bv, self.mode.as_str());
863 self.options.serialize(&mut bv);
864 }
865}
866
867#[derive(Debug)]
869pub struct DataPacketBuilder {
870 block: u16,
871}
872
873impl DataPacketBuilder {
874 pub fn new(block: u16) -> Self {
876 Self { block }
877 }
878}
879
880impl PacketBuilder for DataPacketBuilder {
881 fn constraints(&self) -> PacketConstraints {
882 PacketConstraints::new(
883 std::mem::size_of::<MessageHead>() + std::mem::size_of::<U16>(),
884 0,
885 0,
886 std::u16::MAX.into(),
887 )
888 }
889
890 fn serialize(&self, target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {
891 let mut bv = crate::as_buffer_view_mut(&mut target.header);
892 bv.take_obj_front::<MessageHead>().unwrap().set_opcode(Opcode::Data);
893 bv.take_obj_front::<U16>().unwrap().set(self.block);
894 }
895}
896
897#[derive(Debug)]
899pub struct AckPacketBuilder {
900 block: u16,
901}
902
903impl AckPacketBuilder {
904 pub fn new(block: u16) -> Self {
906 Self { block }
907 }
908}
909
910impl InnerPacketBuilder for AckPacketBuilder {
911 fn bytes_len(&self) -> usize {
912 std::mem::size_of::<MessageHead>() + std::mem::size_of::<U16>()
913 }
914
915 fn serialize(&self, mut buffer: &mut [u8]) {
916 let mut bv = crate::as_buffer_view_mut(&mut buffer);
917 bv.take_obj_front::<MessageHead>().unwrap().set_opcode(Opcode::Ack);
918 bv.take_obj_front::<U16>().unwrap().set(self.block);
919 }
920}
921
922#[derive(Debug)]
924pub struct ErrorPacketBuilder<'a> {
925 error: TftpError,
926 msg: &'a str,
927}
928
929impl<'a> ErrorPacketBuilder<'a> {
930 pub fn new(error: TftpError, msg: &'a str) -> Self {
932 Self { error, msg }
933 }
934}
935
936impl<'a> InnerPacketBuilder for ErrorPacketBuilder<'a> {
937 fn bytes_len(&self) -> usize {
938 std::mem::size_of::<MessageHead>()
939 + std::mem::size_of::<U16>()
940 + self.msg.as_bytes().len()
941 + 1
942 }
943
944 fn serialize(&self, mut buffer: &mut [u8]) {
945 let mut bv = crate::as_buffer_view_mut(&mut buffer);
946 bv.take_obj_front::<MessageHead>().unwrap().set_opcode(Opcode::Error);
947 bv.take_obj_front::<U16>().unwrap().set(self.error.into());
948 write_str(&mut bv, self.msg);
949 }
950}
951
952#[derive(Debug, Default)]
954pub struct OptionAckPacketBuilder {
955 options: OptionCollection,
956}
957
958impl OptionAckPacketBuilder {
959 pub fn new_with(options: impl IntoIterator<Item = Forceable<TftpOption>>) -> Self {
961 Self { options: options.into_iter().collect() }
962 }
963
964 pub fn options_mut(&mut self) -> &mut OptionCollection {
965 &mut self.options
966 }
967}
968
969impl InnerPacketBuilder for OptionAckPacketBuilder {
970 fn bytes_len(&self) -> usize {
971 std::mem::size_of::<MessageHead>() + self.options.serialized_len()
972 }
973
974 fn serialize(&self, mut buffer: &mut [u8]) {
975 let mut bv = crate::as_buffer_view_mut(&mut buffer);
976 bv.take_obj_front::<MessageHead>().unwrap().set_opcode(Opcode::OptionAck);
977 self.options.serialize(&mut bv);
978 }
979}
980
981#[cfg(test)]
982mod tests {
983 use super::*;
984 use packet::{ParseBuffer as _, Serializer as _};
985
986 const FILENAME: &'static str = "filename";
987
988 #[test]
989 fn test_read_request() {
990 let mut req =
991 TransferRequestBuilder::new(TransferDirection::Read, FILENAME, TftpMode::OCTET)
992 .into_serializer()
993 .serialize_vec_outer()
994 .unwrap_or_else(|_| panic!("failed to serialize"));
995 let body = match req.parse::<TftpPacket<_>>().expect("failed to parse") {
996 TftpPacket::ReadRequest(b) => b,
997 p => panic!("unexpected packet {:?}", p),
998 };
999 assert_eq!(body.filename(), FILENAME);
1000 assert_eq!(body.mode(), TftpMode::OCTET);
1001 assert!(body.options().iter().next().is_none());
1002 }
1003
1004 #[test]
1005 fn test_write_request() {
1006 let mut req =
1007 TransferRequestBuilder::new(TransferDirection::Write, FILENAME, TftpMode::OCTET)
1008 .into_serializer()
1009 .serialize_vec_outer()
1010 .unwrap_or_else(|_| panic!("failed to serialize"));
1011 let body = match req.parse::<TftpPacket<_>>().expect("failed to parse") {
1012 TftpPacket::WriteRequest(b) => b,
1013 p => panic!("unexpected packet {:?}", p),
1014 };
1015 assert_eq!(body.filename(), FILENAME);
1016 assert_eq!(body.mode(), TftpMode::OCTET);
1017 assert!(body.options().iter().next().is_none());
1018 }
1019
1020 #[test]
1021 fn test_data() {
1022 let data: Vec<_> = std::iter::successors(Some(0u8), |v| Some(*v + 1)).take(128).collect();
1023 let mut ser = (&data[..])
1024 .into_serializer()
1025 .encapsulate(DataPacketBuilder::new(123))
1026 .serialize_vec_outer()
1027 .unwrap_or_else(|_| panic!("failed to serialize"));
1028 let body = match ser.parse::<TftpPacket<_>>().expect("failed to parse") {
1029 TftpPacket::Data(b) => b,
1030 p => panic!("unexpected packet {:?}", p),
1031 };
1032 assert_eq!(body.block(), 123);
1033 assert_eq!(body.payload().as_ref(), &data[..]);
1034 }
1035
1036 #[test]
1037 fn test_error() {
1038 const ERR_STR: &str = "ERROR";
1039 let mut err = ErrorPacketBuilder::new(TftpError::FileNotFound, ERR_STR)
1040 .into_serializer()
1041 .serialize_vec_outer()
1042 .unwrap_or_else(|_| panic!("failed to serialize"));
1043 let body = match err.parse::<TftpPacket<_>>().expect("failed to parse") {
1044 TftpPacket::Error(b) => b,
1045 p => panic!("unexpected packet {:?}", p),
1046 };
1047 assert_eq!(body.error(), TftpError::FileNotFound);
1048 assert_eq!(body.message(), ERR_STR);
1049 }
1050
1051 #[test]
1052 fn test_option_ack() {
1053 let builder = OptionAckPacketBuilder::new_with([
1054 TftpOption::WindowSize(10).not_forced(),
1055 TftpOption::BlockSize(35).not_forced(),
1056 TftpOption::Timeout(1).forced(),
1057 TftpOption::TransferSize(400).forced(),
1058 ]);
1059 let mut oack = builder
1060 .into_serializer()
1061 .serialize_vec_outer()
1062 .unwrap_or_else(|_| panic!("failed to serialize"));
1063 let body = match oack.parse::<TftpPacket<_>>().expect("failed to parse") {
1064 TftpPacket::OptionAck(b) => b,
1065 p => panic!("unexpected packet {:?}", p),
1066 };
1067 let AllOptions { window_size, block_size, timeout, transfer_size } =
1068 body.options().collect();
1069 assert_eq!(window_size, Some(Forceable { value: 10, forced: false }));
1070 assert_eq!(block_size, Some(Forceable { value: 35, forced: false }));
1071 assert_eq!(timeout, Some(Forceable { value: 1, forced: true }));
1072 assert_eq!(transfer_size, Some(Forceable { value: 400, forced: true }));
1073 }
1074
1075 #[test]
1076 fn test_ack() {
1077 let mut ack = AckPacketBuilder::new(123)
1078 .into_serializer()
1079 .serialize_vec_outer()
1080 .unwrap_or_else(|_| panic!("failed to serialize"));
1081 let body = match ack.parse::<TftpPacket<_>>().expect("failed to parse") {
1082 TftpPacket::Ack(b) => b,
1083 p => panic!("unexpected packet {:?}", p),
1084 };
1085 assert_eq!(body.block(), 123);
1086 }
1087
1088 #[test]
1089 fn test_transfer_request_options() {
1090 let builder = TransferRequestBuilder::new_with_options(
1091 TransferDirection::Read,
1092 FILENAME,
1093 TftpMode::OCTET,
1094 [
1095 TftpOption::WindowSize(10).not_forced(),
1096 TftpOption::BlockSize(35).not_forced(),
1097 TftpOption::Timeout(1).forced(),
1098 TftpOption::TransferSize(400).forced(),
1099 ],
1100 );
1101 let mut req = builder
1102 .into_serializer()
1103 .serialize_vec_outer()
1104 .unwrap_or_else(|_| panic!("failed to serialize"));
1105 let body = match req.parse::<TftpPacket<_>>().expect("failed to parse") {
1106 TftpPacket::ReadRequest(b) => b,
1107 p => panic!("unexpected packet {:?}", p),
1108 };
1109 let AllOptions { window_size, block_size, timeout, transfer_size } =
1110 body.options().collect();
1111 assert_eq!(window_size, Some(Forceable { value: 10, forced: false }));
1112 assert_eq!(block_size, Some(Forceable { value: 35, forced: false }));
1113 assert_eq!(timeout, Some(Forceable { value: 1, forced: true }));
1114 assert_eq!(transfer_size, Some(Forceable { value: 400, forced: true }));
1115 }
1116}