1use std::error::Error;
2use std::str::FromStr;
3use std::fmt;
4
5use crate::{Convert, TransferOption, OptionType};
6
7#[derive(Debug, PartialEq)]
22pub enum Packet {
23 Rrq {
25 filename: String,
27 mode: String,
29 options: Vec<TransferOption>,
31 },
32 Wrq {
34 filename: String,
36 mode: String,
38 options: Vec<TransferOption>,
40 },
41 Data {
43 block_num: u16,
45 data: Vec<u8>,
47 },
48 Ack(u16),
50 Error {
52 code: ErrorCode,
54 msg: String,
56 },
57 Oack(Vec<TransferOption>),
59}
60
61impl Packet {
62 pub fn deserialize(buf: &[u8]) -> Result<Packet, Box<dyn Error>> {
64 if buf.len() < 2 {
65 return Err("Buffer too short to serialize".into());
66 }
67 let opcode = Opcode::from_u16(Convert::to_u16(&buf[0..=1])?)?;
68
69 match opcode {
70 Opcode::Rrq | Opcode::Wrq => parse_rq(buf, opcode),
71 Opcode::Data => parse_data(buf),
72 Opcode::Ack => parse_ack(buf),
73 Opcode::Oack => parse_oack(buf),
74 Opcode::Error => parse_error(buf),
75 }
76 }
77
78 pub fn serialize(&self) -> Result<Vec<u8>, &'static str> {
80 match self {
81 Packet::Rrq {
82 filename,
83 mode,
84 options,
85 } => Ok(serialize_rrq(filename, mode, options)),
86 Packet::Wrq {
87 filename,
88 mode,
89 options,
90 } => Ok(serialize_wrq(filename, mode, options)),
91 Packet::Data { block_num, data } => Ok(serialize_data(block_num, data)),
92 Packet::Ack(block_num) => Ok(serialize_ack(block_num)),
93 Packet::Error { code, msg } => Ok(serialize_error(code, msg)),
94 Packet::Oack(options) => Ok(serialize_oack(options)),
95 }
96 }
97}
98
99#[repr(u16)]
113#[derive(Debug, PartialEq)]
114pub enum Opcode {
115 Rrq = 0x0001,
117 Wrq = 0x0002,
119 Data = 0x0003,
121 Ack = 0x0004,
123 Error = 0x0005,
125 Oack = 0x0006,
127}
128
129impl Opcode {
130 pub fn from_u16(val: u16) -> Result<Opcode, &'static str> {
132 match val {
133 0x0001 => Ok(Opcode::Rrq),
134 0x0002 => Ok(Opcode::Wrq),
135 0x0003 => Ok(Opcode::Data),
136 0x0004 => Ok(Opcode::Ack),
137 0x0005 => Ok(Opcode::Error),
138 0x0006 => Ok(Opcode::Oack),
139 _ => Err("Invalid opcode"),
140 }
141 }
142
143 pub const fn as_bytes(self) -> [u8; 2] {
145 (self as u16).to_be_bytes()
146 }
147}
148
149#[repr(u16)]
163#[derive(Clone, Copy, PartialEq, Debug)]
164pub enum ErrorCode {
165 NotDefined = 0,
167 FileNotFound = 1,
169 AccessViolation = 2,
171 DiskFull = 3,
173 IllegalOperation = 4,
175 UnknownId = 5,
177 FileExists = 6,
179 NoSuchUser = 7,
181 RefusedOption = 8,
183}
184
185impl ErrorCode {
186 pub fn from_u16(code: u16) -> Result<ErrorCode, &'static str> {
188 match code {
189 0 => Ok(ErrorCode::NotDefined),
190 1 => Ok(ErrorCode::FileNotFound),
191 2 => Ok(ErrorCode::AccessViolation),
192 3 => Ok(ErrorCode::DiskFull),
193 4 => Ok(ErrorCode::IllegalOperation),
194 5 => Ok(ErrorCode::UnknownId),
195 6 => Ok(ErrorCode::FileExists),
196 7 => Ok(ErrorCode::NoSuchUser),
197 8 => Ok(ErrorCode::RefusedOption),
198 _ => Err("Invalid error code"),
199 }
200 }
201
202 pub fn as_bytes(self) -> [u8; 2] {
204 (self as u16).to_be_bytes()
205 }
206}
207
208impl fmt::Display for ErrorCode {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 ErrorCode::NotDefined => write!(f, "Not Defined"),
212 ErrorCode::FileNotFound => write!(f, "File Not Found"),
213 ErrorCode::AccessViolation => write!(f, "Access Violation"),
214 ErrorCode::DiskFull => write!(f, "Disk Full"),
215 ErrorCode::IllegalOperation => write!(f, "Illegal Operation"),
216 ErrorCode::UnknownId => write!(f, "Unknown ID"),
217 ErrorCode::FileExists => write!(f, "File Exists"),
218 ErrorCode::NoSuchUser => write!(f, "No Such User"),
219 ErrorCode::RefusedOption => write!(f, "Refused option"),
220 }
221 }
222}
223
224fn parse_rq(buf: &[u8], opcode: Opcode) -> Result<Packet, Box<dyn Error>> {
225 let mut options = vec![];
226 let filename: String;
227 let mode: String;
228 let mut zero_index: usize;
229
230 (filename, zero_index) = Convert::to_string(buf, 2)?;
231 (mode, zero_index) = Convert::to_string(buf, zero_index + 1)?;
232
233 let mut value: String;
234 let mut option;
235 while zero_index < buf.len() - 1 {
236 (option, zero_index) = Convert::to_string(buf, zero_index + 1)?;
237 (value, zero_index) = Convert::to_string(buf, zero_index + 1)?;
238
239 if let Ok(option) = OptionType::from_str(option.to_lowercase().as_str()) {
240 options.push(TransferOption {
241 option,
242 value: value.parse()?,
243 });
244 }
245 }
246
247 match opcode {
248 Opcode::Rrq => Ok(Packet::Rrq {
249 filename,
250 mode,
251 options,
252 }),
253 Opcode::Wrq => Ok(Packet::Wrq {
254 filename,
255 mode,
256 options,
257 }),
258 _ => Err("Non request opcode".into()),
259 }
260}
261
262fn parse_data(buf: &[u8]) -> Result<Packet, Box<dyn Error>> {
263 Ok(Packet::Data {
264 block_num: Convert::to_u16(&buf[2..])?,
265 data: buf[4..].to_vec(),
266 })
267}
268
269fn parse_ack(buf: &[u8]) -> Result<Packet, Box<dyn Error>> {
270 Ok(Packet::Ack(Convert::to_u16(&buf[2..])?))
271}
272
273fn parse_oack(buf: &[u8]) -> Result<Packet, Box<dyn Error>> {
274 let mut options = vec![];
275 let mut value: String;
276 let mut option;
277 let mut zero_index = 1usize;
278
279 while zero_index < buf.len() - 1 {
280 (option, zero_index) = Convert::to_string(buf, zero_index + 1)?;
281 (value, zero_index) = Convert::to_string(buf, zero_index + 1)?;
282 if let Ok(option) = OptionType::from_str(option.to_lowercase().as_str()) {
283 options.push(TransferOption {
284 option,
285 value: value.parse()?,
286 });
287 }
288 }
289
290 Ok(Packet::Oack(options))
291}
292
293fn parse_error(buf: &[u8]) -> Result<Packet, Box<dyn Error>> {
294 let code = ErrorCode::from_u16(Convert::to_u16(&buf[2..])?)?;
295 if let Ok((msg, _)) = Convert::to_string(buf, 4) {
296 Ok(Packet::Error { code, msg })
297 } else {
298 Ok(Packet::Error {
299 code,
300 msg: "(no message)".to_string(),
301 })
302 }
303}
304
305fn serialize_rrq(filename: &String, mode: &String, options: &Vec<TransferOption>) -> Vec<u8> {
306 let mut buf = [
307 &Opcode::Rrq.as_bytes(),
308 filename.as_bytes(),
309 &[0x00],
310 mode.as_bytes(),
311 &[0x00],
312 ]
313 .concat();
314
315 for option in options {
316 buf = [buf, option.as_bytes()].concat();
317 }
318 buf
319}
320
321fn serialize_wrq(filename: &String, mode: &String, options: &Vec<TransferOption>) -> Vec<u8> {
322 let mut buf = [
323 &Opcode::Wrq.as_bytes(),
324 filename.as_bytes(),
325 &[0x00],
326 mode.as_bytes(),
327 &[0x00],
328 ]
329 .concat();
330
331 for option in options {
332 buf = [buf, option.as_bytes()].concat();
333 }
334 buf
335}
336
337fn serialize_data(block_num: &u16, data: &Vec<u8>) -> Vec<u8> {
338 [
339 &Opcode::Data.as_bytes(),
340 &block_num.to_be_bytes(),
341 data.as_slice(),
342 ]
343 .concat()
344}
345
346fn serialize_ack(block_num: &u16) -> Vec<u8> {
347 [Opcode::Ack.as_bytes(), block_num.to_be_bytes()].concat()
348}
349
350fn serialize_error(code: &ErrorCode, msg: &String) -> Vec<u8> {
351 [
352 &Opcode::Error.as_bytes()[..],
353 &code.as_bytes()[..],
354 msg.as_bytes(),
355 &[0x00],
356 ]
357 .concat()
358}
359
360fn serialize_oack(options: &Vec<TransferOption>) -> Vec<u8> {
361 let mut buf = Opcode::Oack.as_bytes().to_vec();
362
363 for option in options {
364 buf = [buf, option.as_bytes()].concat();
365 }
366
367 buf
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn parses_read_request() {
376 let buf = [
377 &Opcode::Rrq.as_bytes()[..],
378 ("test.png".as_bytes()),
379 &[0x00],
380 ("octet".as_bytes()),
381 &[0x00],
382 ]
383 .concat();
384
385 if let Ok(Packet::Rrq {
386 filename,
387 mode,
388 options,
389 }) = parse_rq(&buf, Opcode::Rrq)
390 {
391 assert_eq!(filename, "test.png");
392 assert_eq!(mode, "octet");
393 assert_eq!(options.len(), 0);
394 } else {
395 panic!("cannot parse read request")
396 }
397 }
398
399 #[test]
400 fn parses_read_request_with_options() {
401 let buf = [
402 &Opcode::Rrq.as_bytes()[..],
403 ("test.png".as_bytes()),
404 &[0x00],
405 ("octet".as_bytes()),
406 &[0x00],
407 (OptionType::TransferSize.as_str().as_bytes()),
408 &[0x00],
409 ("0".as_bytes()),
410 &[0x00],
411 (OptionType::Timeout.as_str().as_bytes()),
412 &[0x00],
413 ("5".as_bytes()),
414 &[0x00],
415 (OptionType::WindowSize.as_str().as_bytes()),
416 &[0x00],
417 ("4".as_bytes()),
418 &[0x00],
419 ]
420 .concat();
421
422 if let Ok(Packet::Rrq {
423 filename,
424 mode,
425 options,
426 }) = parse_rq(&buf, Opcode::Rrq)
427 {
428 assert_eq!(filename, "test.png");
429 assert_eq!(mode, "octet");
430 assert_eq!(options.len(), 3);
431 assert_eq!(
432 options[0],
433 TransferOption {
434 option: OptionType::TransferSize,
435 value: 0
436 }
437 );
438 assert_eq!(
439 options[1],
440 TransferOption {
441 option: OptionType::Timeout,
442 value: 5
443 }
444 );
445 assert_eq!(
446 options[2],
447 TransferOption {
448 option: OptionType::WindowSize,
449 value: 4
450 }
451 );
452 } else {
453 panic!("cannot parse read request with options")
454 }
455 }
456
457 #[test]
458 fn parses_write_request() {
459 let buf = [
460 &Opcode::Wrq.as_bytes()[..],
461 ("test.png".as_bytes()),
462 &[0x00],
463 ("octet".as_bytes()),
464 &[0x00],
465 ]
466 .concat();
467
468 if let Ok(Packet::Wrq {
469 filename,
470 mode,
471 options,
472 }) = parse_rq(&buf, Opcode::Wrq)
473 {
474 assert_eq!(filename, "test.png");
475 assert_eq!(mode, "octet");
476 assert_eq!(options.len(), 0);
477 } else {
478 panic!("cannot parse write request")
479 }
480 }
481
482 #[test]
483 fn parses_write_request_with_options() {
484 let buf = [
485 &Opcode::Wrq.as_bytes()[..],
486 ("test.png".as_bytes()),
487 &[0x00],
488 ("octet".as_bytes()),
489 &[0x00],
490 (OptionType::TransferSize.as_str().as_bytes()),
491 &[0x00],
492 ("12341234".as_bytes()),
493 &[0x00],
494 (OptionType::BlockSize.as_str().as_bytes()),
495 &[0x00],
496 ("1024".as_bytes()),
497 &[0x00],
498 ]
499 .concat();
500
501 if let Ok(Packet::Wrq {
502 filename,
503 mode,
504 options,
505 }) = parse_rq(&buf, Opcode::Wrq)
506 {
507 assert_eq!(filename, "test.png");
508 assert_eq!(mode, "octet");
509 assert_eq!(options.len(), 2);
510 assert_eq!(
511 options[0],
512 TransferOption {
513 option: OptionType::TransferSize,
514 value: 12341234
515 }
516 );
517 assert_eq!(
518 options[1],
519 TransferOption {
520 option: OptionType::BlockSize,
521 value: 1024
522 }
523 );
524 } else {
525 panic!("cannot parse write request with options")
526 }
527 }
528
529 #[test]
530 fn parses_data() {
531 let buf = [
532 &Opcode::Data.as_bytes()[..],
533 &5u16.to_be_bytes(),
534 &[
535 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
536 ],
537 ]
538 .concat();
539
540 if let Ok(Packet::Data { block_num, data }) = parse_data(&buf) {
541 assert_eq!(block_num, 5);
542 assert_eq!(
543 data,
544 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C]
545 );
546 } else {
547 panic!("cannot parse data")
548 }
549 }
550
551 #[test]
552 fn parses_ack() {
553 let buf = [&Opcode::Ack.as_bytes()[..], &12u16.to_be_bytes()].concat();
554
555 if let Ok(Packet::Ack(block_num)) = parse_ack(&buf) {
556 assert_eq!(block_num, 12);
557 } else {
558 panic!("cannot parse ack")
559 }
560 }
561
562 #[test]
563 fn parses_oack() {
564 let buf = [
565 &Opcode::Oack.as_bytes()[..],
566 (OptionType::TransferSize.as_str().as_bytes()),
567 &[0x00],
568 ("0".as_bytes()),
569 &[0x00],
570 (OptionType::Timeout.as_str().as_bytes()),
571 &[0x00],
572 ("5".as_bytes()),
573 &[0x00],
574 (OptionType::WindowSize.as_str().as_bytes()),
575 &[0x00],
576 ("4".as_bytes()),
577 &[0x00],
578 ]
579 .concat();
580
581 if let Ok(Packet::Oack(options)) = parse_oack(&buf) {
582 assert_eq!(options.len(), 3);
583 assert_eq!(
584 options[0],
585 TransferOption {
586 option: OptionType::TransferSize,
587 value: 0
588 }
589 );
590 assert_eq!(
591 options[1],
592 TransferOption {
593 option: OptionType::Timeout,
594 value: 5
595 }
596 );
597 assert_eq!(
598 options[2],
599 TransferOption {
600 option: OptionType::WindowSize,
601 value: 4
602 }
603 );
604 } else {
605 panic!("cannot parse read request with options")
606 }
607 }
608
609 #[test]
610 fn parses_error() {
611 let buf = [
612 &Opcode::Error.as_bytes()[..],
613 &ErrorCode::FileExists.as_bytes(),
614 "file already exists".as_bytes(),
615 &[0x00],
616 ]
617 .concat();
618
619 if let Ok(Packet::Error { code, msg }) = parse_error(&buf) {
620 assert_eq!(code, ErrorCode::FileExists);
621 assert_eq!(msg, "file already exists");
622 } else {
623 panic!("cannot parse error")
624 }
625 }
626
627 #[test]
628 fn parses_error_without_message() {
629 let buf = [
630 &Opcode::Error.as_bytes()[..],
631 &ErrorCode::FileExists.as_bytes(),
632 &[0x00],
633 ]
634 .concat();
635
636 if let Ok(Packet::Error { code, msg }) = parse_error(&buf) {
637 assert_eq!(code, ErrorCode::FileExists);
638 assert_eq!(msg, "");
639 } else {
640 panic!("cannot parse error")
641 }
642 }
643
644 #[test]
645 fn serializes_rrq() {
646 let serialized_data = vec![
647 0x00, 0x01, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00,
648 ];
649
650 assert_eq!(
651 serialize_rrq(&"test".into(), &"octet".into(), &vec![]),
652 serialized_data
653 )
654 }
655
656 #[test]
657 fn serializes_rrq_with_options() {
658 let serialized_data = vec![
659 0x00, 0x01, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00, 0x62,
660 0x6c, 0x6b, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x31, 0x34, 0x36, 0x38, 0x00, 0x77, 0x69,
661 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x31, 0x00, 0x74, 0x69, 0x6d,
662 0x65, 0x6f, 0x75, 0x74, 0x00, 0x35, 0x00,
663 ];
664
665 assert_eq!(
666 serialize_rrq(
667 &"test".into(),
668 &"octet".into(),
669 &vec![
670 TransferOption {
671 option: OptionType::BlockSize,
672 value: 1468,
673 },
674 TransferOption {
675 option: OptionType::WindowSize,
676 value: 1,
677 },
678 TransferOption {
679 option: OptionType::Timeout,
680 value: 5,
681 }
682 ]
683 ),
684 serialized_data
685 )
686 }
687
688 #[test]
689 fn serializes_wrq() {
690 let serialized_data = vec![
691 0x00, 0x02, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00,
692 ];
693
694 assert_eq!(
695 serialize_wrq(&"test".into(), &"octet".into(), &vec![]),
696 serialized_data
697 )
698 }
699
700 #[test]
701 fn serializes_wrq_with_options() {
702 let serialized_data = vec![
703 0x00, 0x02, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x00, 0x62,
704 0x6c, 0x6b, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x31, 0x34, 0x36, 0x38, 0x00, 0x77, 0x69,
705 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x31, 0x00, 0x74, 0x69, 0x6d,
706 0x65, 0x6f, 0x75, 0x74, 0x00, 0x35, 0x00,
707 ];
708
709 assert_eq!(
710 serialize_wrq(
711 &"test".into(),
712 &"octet".into(),
713 &vec![
714 TransferOption {
715 option: OptionType::BlockSize,
716 value: 1468,
717 },
718 TransferOption {
719 option: OptionType::WindowSize,
720 value: 1,
721 },
722 TransferOption {
723 option: OptionType::Timeout,
724 value: 5,
725 }
726 ]
727 ),
728 serialized_data
729 )
730 }
731
732 #[test]
733 fn serializes_data() {
734 let serialized_data = vec![0x00, 0x03, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04];
735
736 assert_eq!(
737 serialize_data(&16, &vec![0x01, 0x02, 0x03, 0x04]),
738 serialized_data
739 );
740 }
741
742 #[test]
743 fn serializes_ack() {
744 let serialized_ack = vec![0x00, 0x04, 0x04, 0xD2];
745
746 assert_eq!(serialize_ack(&1234), serialized_ack);
747 }
748
749 #[test]
750 fn serializes_error() {
751 let serialized_error = vec![
752 0x00, 0x05, 0x00, 0x04, 0x69, 0x6C, 0x6C, 0x65, 0x67, 0x61, 0x6C, 0x20, 0x6F, 0x70,
753 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00,
754 ];
755
756 assert_eq!(
757 serialize_error(
758 &ErrorCode::IllegalOperation,
759 &"illegal operation".to_string()
760 ),
761 serialized_error
762 );
763 }
764
765 #[test]
766 fn serializes_oack() {
767 let serialized_oack = vec![
768 0x00, 0x06, 0x62, 0x6C, 0x6B, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x31, 0x34, 0x33, 0x32,
769 0x00,
770 ];
771
772 assert_eq!(
773 serialize_oack(&vec![TransferOption {
774 option: OptionType::BlockSize,
775 value: 1432
776 }]),
777 serialized_oack
778 );
779 }
780}