From 609fe435b57e3499b6d92f30a261d5ce7466d611 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Wed, 24 Sep 2014 13:50:33 -0500 Subject: [PATCH] Don't send more than one ACK to the last DATA packet when writing. The write session needs to remain open for a short while so that ACKs can be returned if a duplicate DATA packet is received. However, when the last packet is received the code will always send additional ACKs because there is no next DATA packet to cancel the ScheduledCall the handles ACK retransmission. So, in the special case of the last DATA packet, send an ACK once, but never again. The timeout needs to remain to keep the session active in case the ACK packet gets lost and the remote system re-sends the last DATA packet. --- tftp/session.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tftp/session.py b/tftp/session.py index 37a8631..c9abf98 100644 --- a/tftp/session.py +++ b/tftp/session.py @@ -116,18 +116,26 @@ def blockWriteSuccess(self, ign, datagram): """ bytes = ACKDatagram(datagram.blocknum).to_wire() - self.timeout_watchdog = SequentialCall.run(self.timeout[:-1], - callable=self.sendData, callable_args=[bytes, ], - on_timeout=lambda: self._clock.callLater(self.timeout[-1], self.timedOut), - run_now=True, - _clock=self._clock - ) if len(datagram.data) < self.block_size: + self._clock.callLater(0, self.sendData, bytes) + self.timeout_watchdog = SequentialCall.run(self.timeout[:-1], + callable=lambda: None, + on_timeout=lambda: self._clock.callLater(self.timeout[-1], self.timedOut), + run_now=False, + _clock=self._clock + ) self.completed = True self.writer.finish() # TODO: If self.tsize is not None, compare it with the actual # count of bytes written. Log if there's a mismatch. Should it # also emit an error datagram? + else: + self.timeout_watchdog = SequentialCall.run(self.timeout[:-1], + callable=self.sendData, callable_args=[bytes, ], + on_timeout=lambda: self._clock.callLater(self.timeout[-1], self.timedOut), + run_now=True, + _clock=self._clock + ) def blockWriteFailure(self, failure): """Write failed"""