1- use crate :: cursor:: { BufferError , ReadCursor } ;
1+ use crate :: cursor:: ReadCursor ;
22use crate :: datagram_stream:: DatagramStream ;
33use crate :: fs:: { FileError , OpenedFile , Root } ;
44use crate :: local_fs:: LocalRoot ;
@@ -9,6 +9,7 @@ use crate::remote_fs::{Config, VirtualRootError};
99use serde_json:: Value ;
1010use std:: collections:: HashMap ;
1111use std:: fmt:: { Debug , Display , Formatter } ;
12+ use std:: io;
1213use std:: net:: { IpAddr , SocketAddr } ;
1314use std:: ops:: DerefMut ;
1415use std:: path:: { Path , PathBuf } ;
@@ -100,13 +101,6 @@ impl Window {
100101 }
101102}
102103
103- fn push_ack ( window : & mut Window , oack : & OptionsAcknowledge ) -> Result < usize , BufferError > {
104- let buffer = window. buffer ( 0 ) ;
105- let read_bytes = oack. serialize ( buffer) ?;
106- buffer. truncate ( read_bytes) ;
107- Ok ( read_bytes)
108- }
109-
110104async fn send_file (
111105 mut opened_file : Box < dyn OpenedFile > ,
112106 datagram_stream : & DatagramStream ,
@@ -524,6 +518,57 @@ async fn send_reliably(
524518 }
525519 Err ( SendError :: Timeout )
526520}
521+
522+ async fn send_oack_reliably (
523+ oack : & OptionsAcknowledge ,
524+ datagram_stream : & DatagramStream ,
525+ ack_timeout : & AckTimeout ,
526+ buffer : & mut [ u8 ] ,
527+ ) -> io:: Result < ( ) > {
528+ let oack_index = 0 ;
529+ let oack_size = match oack. serialize ( buffer) {
530+ Ok ( size) => size,
531+ Err ( buffer_error) => {
532+ let tftp_error = TFTPError :: new ( "OACK build error" , UNDEFINED_ERROR ) ;
533+ fire_error ( tftp_error, datagram_stream, buffer) . await ;
534+ return Err ( io:: Error :: other ( format ! (
535+ "Error building options: {buffer_error}"
536+ ) ) ) ;
537+ }
538+ } ;
539+ for attempt in 1 ..=SEND_ATTEMPTS {
540+ datagram_stream. send ( & buffer[ ..oack_size] ) . await ?;
541+ match read_acknowledge ( datagram_stream, buffer, ack_timeout) . await {
542+ Ok ( ack_num) if ack_num == oack_index => return Ok ( ( ) ) ,
543+ Ok ( ack_num) => {
544+ let tftp_error = TFTPError :: new ( "Unexpected non-zero ACK" , UNDEFINED_ERROR ) ;
545+ fire_error ( tftp_error, datagram_stream, buffer) . await ;
546+ return Err ( io:: Error :: other ( format ! (
547+ "Received unexpected ACK {ack_num} while expecting {oack_index}"
548+ ) ) ) ;
549+ }
550+ Err ( RecvError :: Timeout ) => {
551+ eprintln ! ( "Timeout waiting for ACK {oack_index}, attempt {attempt}" ) ;
552+ continue ;
553+ }
554+ Err ( RecvError :: ClientError ( code, string) ) => {
555+ return Err ( io:: Error :: other ( format ! (
556+ "Early termination while options negotiation [{code}] {string}"
557+ ) ) ) ;
558+ }
559+ Err ( error) => {
560+ return Err ( io:: Error :: other ( format ! ( "ACK read error: {:?}" , error) ) ) ;
561+ }
562+ }
563+ }
564+ let tftp_error = TFTPError :: new ( "Send timeout occurred" , UNDEFINED_ERROR ) ;
565+ fire_error ( tftp_error, datagram_stream, buffer) . await ;
566+ Err ( io:: Error :: new (
567+ io:: ErrorKind :: TimedOut ,
568+ format ! ( "Timeout waiting for ACK {oack_index}" ) ,
569+ ) )
570+ }
571+
527572async fn negotiate_options (
528573 datagram_stream : & DatagramStream ,
529574 opened_file : & mut Box < dyn OpenedFile > ,
@@ -563,25 +608,14 @@ async fn negotiate_options(
563608 Default :: default ( )
564609 }
565610 } ;
566- let mut window = Window :: new ( block_size. get_size ( ) as u16 , window_size. get_size ( ) as u16 ) ;
567- if oack. has_options ( ) {
568- eprintln ! ( "{datagram_stream}: {oack}" ) ;
569- match push_ack ( & mut window, & oack) {
570- Ok ( _) => { }
571- Err ( buffer_error) => {
572- eprintln ! ( "{datagram_stream}: Error building options: {buffer_error}" ) ;
573- let tftp_error = TFTPError :: new ( "OACK build error" , UNDEFINED_ERROR ) ;
574- fire_error ( tftp_error, datagram_stream, buffer) . await ;
575- return None ;
576- }
577- }
578- if let Err ( error) =
579- send_reliably ( & mut window, & ack_timeout, datagram_stream, buffer, 0 , 1 ) . await
580- {
581- eprintln ! ( "{datagram_stream}: Error sending options: {error:?}" ) ;
582- return None ;
583- }
611+ if oack. has_options ( )
612+ && let Err ( oack_negotiation_error) =
613+ send_oack_reliably ( & oack, datagram_stream, & ack_timeout, buffer) . await
614+ {
615+ eprintln ! ( "{datagram_stream}: {oack_negotiation_error}" ) ;
616+ return None ;
584617 } ;
618+ let window = Window :: new ( block_size. get_size ( ) as u16 , window_size. get_size ( ) as u16 ) ;
585619 Some ( ( window, ack_timeout) )
586620}
587621
0 commit comments