def setUp(self): self.clock = Clock() self.temp_dir = FilePath(tempfile.mkdtemp()).asBytesMode() self.target = self.temp_dir.child(b'foo') self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2) self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port)) self.ws = WriteSession(self.writer, _clock=self.clock) self.ws.timeout = (4, 4, 4) self.ws.transport = self.transport self.ws.startProtocol()
class LocalOriginWriteSession(TFTPBootstrap): """Bootstraps a L{WriteSession}, that was initiated locally, - we've requested a read from a remote server """ def __init__(self, remote, writer, options=None, _clock=None): TFTPBootstrap.__init__(self, remote, writer, options, _clock) self.session = WriteSession(writer, self._clock) def startProtocol(self): """Connect the transport and start the L{timeout_watchdog}""" self.transport.connect(*self.remote) if self.timeout_watchdog is not None: self.timeout_watchdog.start() def tftp_OACK(self, datagram): """Handle the OACK datagram @param datagram: OACK datagram @type datagram: L{OACKDatagram} """ if not self.session.started: self.resultant_options = self.processOptions(datagram.options) if self.timeout_watchdog.active(): self.timeout_watchdog.cancel() return self.transport.write(ACKDatagram(0).to_wire()) else: log.msg("Duplicate OACK received, send back ACK and ignore") self.transport.write(ACKDatagram(0).to_wire()) def _datagramReceived(self, datagram): if datagram.opcode == OP_OACK: return self.tftp_OACK(datagram) elif datagram.opcode == OP_DATA and datagram.blocknum == 1: if self.timeout_watchdog is not None and self.timeout_watchdog.active( ): self.timeout_watchdog.cancel() if not self.session.started: self.applyOptions(self.session, self.resultant_options) self.session.transport = self.transport self.session.startProtocol() return self.session.datagramReceived(datagram) elif self.session.started: return self.session.datagramReceived(datagram)
class LocalOriginWriteSession(TFTPBootstrap): """Bootstraps a L{WriteSession}, that was initiated locally, - we've requested a read from a remote server """ def __init__(self, remote, writer, options=None, _clock=None): TFTPBootstrap.__init__(self, remote, writer, options, _clock) self.session = WriteSession(writer, self._clock) def startProtocol(self): """Connect the transport and start the L{timeout_watchdog}""" self.transport.connect(*self.remote) if self.timeout_watchdog is not None: self.timeout_watchdog.start() def tftp_OACK(self, datagram): """Handle the OACK datagram @param datagram: OACK datagram @type datagram: L{OACKDatagram} """ if not self.session.started: self.resultant_options = self.processOptions(datagram.options) if self.timeout_watchdog.active(): self.timeout_watchdog.cancel() return self.transport.write(ACKDatagram(0).to_wire()) else: log.msg("Duplicate OACK received, send back ACK and ignore") self.transport.write(ACKDatagram(0).to_wire()) def _datagramReceived(self, datagram): if datagram.opcode == OP_OACK: return self.tftp_OACK(datagram) elif datagram.opcode == OP_DATA and datagram.blocknum == 1: if self.timeout_watchdog is not None and self.timeout_watchdog.active(): self.timeout_watchdog.cancel() if not self.session.started: self.applyOptions(self.session, self.resultant_options) self.session.transport = self.transport self.session.startProtocol() return self.session.datagramReceived(datagram) elif self.session.started: return self.session.datagramReceived(datagram)
class RemoteOriginWriteSession(TFTPBootstrap): """Bootstraps a L{WriteSession}, that was originated remotely, - we've received a WRQ from a client. """ timeout = (1, 3, 7) def __init__(self, remote, writer, options=None, _clock=None): TFTPBootstrap.__init__(self, remote, writer, options, _clock) self.session = WriteSession(writer, self._clock) def startProtocol(self): """Connect the transport, respond with an initial ACK or OACK (depending on if we were initialized with options or not). """ self.transport.connect(*self.remote) if self.options: self.resultant_options = self.processOptions(self.options) bytes = OACKDatagram(self.resultant_options).to_wire() else: bytes = ACKDatagram(0).to_wire() self.timeout_watchdog = SequentialCall.run( self.timeout[:-1], callable=self.transport.write, callable_args=[ bytes, ], on_timeout=lambda: self._clock.callLater(self.timeout[-1], self. timedOut), run_now=True, _clock=self._clock) def _datagramReceived(self, datagram): if datagram.opcode == OP_DATA and datagram.blocknum == 1: if self.timeout_watchdog.active(): self.timeout_watchdog.cancel() if not self.session.started: self.applyOptions(self.session, self.resultant_options) self.session.transport = self.transport self.session.startProtocol() return self.session.datagramReceived(datagram) elif self.session.started: return self.session.datagramReceived(datagram)
def setUp(self): self.clock = Clock() self.tmp_dir_path = tempfile.mkdtemp() self.target = FilePath(self.tmp_dir_path).child('foo') self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2) self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port)) self.ws = WriteSession(self.writer, _clock=self.clock) self.ws.timeout = (4, 4, 4) self.ws.transport = self.transport self.ws.startProtocol()
class RemoteOriginWriteSession(TFTPBootstrap): """Bootstraps a L{WriteSession}, that was originated remotely, - we've received a WRQ from a client. """ timeout = (1, 3, 7) def __init__(self, remote, writer, options=None, _clock=None): TFTPBootstrap.__init__(self, remote, writer, options, _clock) self.session = WriteSession(writer, self._clock) def startProtocol(self): """Connect the transport, respond with an initial ACK or OACK (depending on if we were initialized with options or not). """ self.transport.connect(*self.remote) if self.options: self.resultant_options = self.processOptions(self.options) bytes = OACKDatagram(self.resultant_options).to_wire() else: bytes = ACKDatagram(0).to_wire() self.timeout_watchdog = SequentialCall.run( self.timeout[:-1], callable=self.transport.write, callable_args=[bytes], on_timeout=lambda: self._clock.callLater(self.timeout[-1], self.timedOut), run_now=True, _clock=self._clock, ) def _datagramReceived(self, datagram): if datagram.opcode == OP_DATA and datagram.blocknum == 1: if self.timeout_watchdog.active(): self.timeout_watchdog.cancel() if not self.session.started: self.applyOptions(self.session, self.resultant_options) self.session.transport = self.transport self.session.startProtocol() return self.session.datagramReceived(datagram) elif self.session.started: return self.session.datagramReceived(datagram)
class WriteSessions(unittest.TestCase): port = 65466 def setUp(self): self.clock = Clock() self.temp_dir = FilePath(tempfile.mkdtemp()).asBytesMode() self.target = self.temp_dir.child(b'foo') self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2) self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port)) self.ws = WriteSession(self.writer, _clock=self.clock) self.ws.timeout = (4, 4, 4) self.ws.transport = self.transport self.ws.startProtocol() def test_ERROR(self): err_dgram = ERRORDatagram.from_code(ERR_NOT_DEFINED, b'no reason') self.ws.datagramReceived(err_dgram) self.clock.advance(0.1) self.assertFalse(self.transport.value()) self.assertTrue(self.transport.disconnecting) @inlineCallbacks def test_DATA_stale_blocknum(self): self.ws.block_size = 6 self.ws.blocknum = 2 data_datagram = DATADatagram(1, b'foobar') yield self.ws.datagramReceived(data_datagram) self.writer.finish() self.assertFalse(self.target.open('r').read()) self.assertFalse(self.transport.disconnecting) ack_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.assertEqual(ack_dgram.blocknum, 1) self.addCleanup(self.ws.cancel) @inlineCallbacks def test_DATA_invalid_blocknum(self): self.ws.block_size = 6 data_datagram = DATADatagram(3, b'foobar') yield self.ws.datagramReceived(data_datagram) self.writer.finish() self.assertFalse(self.target.open('r').read()) self.assertFalse(self.transport.disconnecting) err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.assertTrue(isinstance(err_dgram, ERRORDatagram)) self.addCleanup(self.ws.cancel) def test_DATA(self): self.ws.block_size = 6 data_datagram = DATADatagram(1, b'foobar') d = self.ws.datagramReceived(data_datagram) def cb(ign): self.clock.advance(0.1) #self.writer.finish() #self.assertEqual(self.target.open('r').read(), 'foobar') self.assertFalse(self.transport.disconnecting) ack_dgram = TFTPDatagramFactory( *split_opcode(self.transport.value())) self.assertEqual(ack_dgram.blocknum, 1) self.assertFalse( self.ws.completed, "Data length is equal to blocksize, no reason to stop") data_datagram = DATADatagram(2, b'barbaz') self.transport.clear() d = self.ws.datagramReceived(data_datagram) d.addCallback(cb_) self.clock.advance(3) return d def cb_(ign): self.clock.advance(0.1) self.assertFalse(self.transport.disconnecting) ack_dgram = TFTPDatagramFactory( *split_opcode(self.transport.value())) self.assertEqual(ack_dgram.blocknum, 2) self.assertFalse( self.ws.completed, "Data length is equal to blocksize, no reason to stop") d.addCallback(cb) self.addCleanup(self.ws.cancel) self.clock.advance(3) return d def test_DATA_finished(self): self.ws.block_size = 6 # Send a terminating datagram data_datagram = DATADatagram(1, b'foo') d = self.ws.datagramReceived(data_datagram) def cb(res): self.clock.advance(0.1) self.assertEqual(self.target.open('r').read(), b'foo') ack_dgram = TFTPDatagramFactory( *split_opcode(self.transport.value())) self.assertTrue(isinstance(ack_dgram, ACKDatagram)) self.assertTrue( self.ws.completed, "Data length is less, than blocksize, time to stop") self.transport.clear() # Send another datagram after the transfer is considered complete data_datagram = DATADatagram(2, b'foobar') self.ws.datagramReceived(data_datagram) self.assertEqual(self.target.open('r').read(), b'foo') err_dgram = TFTPDatagramFactory( *split_opcode(self.transport.value())) self.assertTrue(isinstance(err_dgram, ERRORDatagram)) # Check for proper disconnection after grace timeout expires self.clock.pump((4, ) * 4) self.assertTrue( self.transport.disconnecting, "We are done and the grace timeout is over, should disconnect") d.addCallback(cb) self.clock.advance(2) return d def test_DATA_backoff(self): self.ws.block_size = 5 data_datagram = DATADatagram(1, b'foobar') d = self.ws.datagramReceived(data_datagram) def cb(ign): self.clock.advance(0.1) ack_datagram = ACKDatagram(1) self.clock.pump((1, ) * 5) # Sent two times - initial send and a retransmit after first timeout self.assertEqual(self.transport.value(), ack_datagram.to_wire() * 2) # Sent three times - initial send and two retransmits self.clock.pump((1, ) * 4) self.assertEqual(self.transport.value(), ack_datagram.to_wire() * 3) # Sent still three times - initial send, two retransmits and the last wait self.clock.pump((1, ) * 4) self.assertEqual(self.transport.value(), ack_datagram.to_wire() * 3) self.assertTrue(self.transport.disconnecting) d.addCallback(cb) self.clock.advance(2.1) return d @inlineCallbacks def test_failed_write(self): self.writer.cancel() self.ws.writer = FailingWriter() data_datagram = DATADatagram(1, b'foobar') yield self.ws.datagramReceived(data_datagram) self.flushLoggedErrors() self.clock.advance(0.1) err_datagram = TFTPDatagramFactory( *split_opcode(self.transport.value())) self.assertTrue(isinstance(err_datagram, ERRORDatagram)) self.assertTrue(self.transport.disconnecting) def test_time_out(self): data_datagram = DATADatagram(1, b'foobar') d = self.ws.datagramReceived(data_datagram) def cb(ign): self.clock.pump((1, ) * 13) self.assertTrue(self.transport.disconnecting) d.addCallback(cb) self.clock.advance(4) return d def tearDown(self): self.temp_dir.remove()
def __init__(self, remote, writer, options=None, _clock=None): TFTPBootstrap.__init__(self, remote, writer, options, _clock) self.session = WriteSession(writer, self._clock)
class WriteSessions(unittest.TestCase): port = 65466 def setUp(self): self.clock = Clock() self.tmp_dir_path = tempfile.mkdtemp() self.target = FilePath(self.tmp_dir_path).child('foo') self.writer = DelayedWriter(self.target, _clock=self.clock, delay=2) self.transport = FakeTransport(hostAddress=('127.0.0.1', self.port)) self.ws = WriteSession(self.writer, _clock=self.clock) self.ws.timeout = (4, 4, 4) self.ws.transport = self.transport self.ws.startProtocol() def test_ERROR(self): err_dgram = ERRORDatagram.from_code(ERR_NOT_DEFINED, 'no reason') self.ws.datagramReceived(err_dgram) self.clock.advance(0.1) self.failIf(self.transport.value()) self.failUnless(self.transport.disconnecting) @inlineCallbacks def test_DATA_stale_blocknum(self): self.ws.block_size = 6 self.ws.blocknum = 2 data_datagram = DATADatagram(1, 'foobar') yield self.ws.datagramReceived(data_datagram) self.writer.finish() self.failIf(self.target.open('r').read()) self.failIf(self.transport.disconnecting) ack_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.assertEqual(ack_dgram.blocknum, 1) self.addCleanup(self.ws.cancel) @inlineCallbacks def test_DATA_invalid_blocknum(self): self.ws.block_size = 6 data_datagram = DATADatagram(3, 'foobar') yield self.ws.datagramReceived(data_datagram) self.writer.finish() self.failIf(self.target.open('r').read()) self.failIf(self.transport.disconnecting) err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.assert_(isinstance(err_dgram, ERRORDatagram)) self.addCleanup(self.ws.cancel) def test_DATA(self): self.ws.block_size = 6 data_datagram = DATADatagram(1, 'foobar') d = self.ws.datagramReceived(data_datagram) def cb(ign): self.clock.advance(0.1) #self.writer.finish() #self.assertEqual(self.target.open('r').read(), 'foobar') self.failIf(self.transport.disconnecting) ack_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.assertEqual(ack_dgram.blocknum, 1) self.failIf(self.ws.completed, "Data length is equal to blocksize, no reason to stop") data_datagram = DATADatagram(2, 'barbaz') self.transport.clear() d = self.ws.datagramReceived(data_datagram) d.addCallback(cb_) self.clock.advance(3) return d def cb_(ign): self.clock.advance(0.1) self.failIf(self.transport.disconnecting) ack_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.assertEqual(ack_dgram.blocknum, 2) self.failIf(self.ws.completed, "Data length is equal to blocksize, no reason to stop") d.addCallback(cb) self.addCleanup(self.ws.cancel) self.clock.advance(3) return d def test_DATA_finished(self): self.ws.block_size = 6 # Send a terminating datagram data_datagram = DATADatagram(1, 'foo') d = self.ws.datagramReceived(data_datagram) def cb(res): self.clock.advance(0.1) self.assertEqual(self.target.open('r').read(), 'foo') ack_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.failUnless(isinstance(ack_dgram, ACKDatagram)) self.failUnless(self.ws.completed, "Data length is less, than blocksize, time to stop") self.transport.clear() # Send another datagram after the transfer is considered complete data_datagram = DATADatagram(2, 'foobar') self.ws.datagramReceived(data_datagram) self.assertEqual(self.target.open('r').read(), 'foo') err_dgram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.failUnless(isinstance(err_dgram, ERRORDatagram)) # Check for proper disconnection after grace timeout expires self.clock.pump((4,)*4) self.failUnless(self.transport.disconnecting, "We are done and the grace timeout is over, should disconnect") d.addCallback(cb) self.clock.advance(2) return d def test_DATA_backoff(self): self.ws.block_size = 5 data_datagram = DATADatagram(1, 'foobar') d = self.ws.datagramReceived(data_datagram) def cb(ign): self.clock.advance(0.1) ack_datagram = ACKDatagram(1) self.clock.pump((1,)*5) # Sent two times - initial send and a retransmit after first timeout self.assertEqual(self.transport.value(), ack_datagram.to_wire()*2) # Sent three times - initial send and two retransmits self.clock.pump((1,)*4) self.assertEqual(self.transport.value(), ack_datagram.to_wire()*3) # Sent still three times - initial send, two retransmits and the last wait self.clock.pump((1,)*4) self.assertEqual(self.transport.value(), ack_datagram.to_wire()*3) self.failUnless(self.transport.disconnecting) d.addCallback(cb) self.clock.advance(2.1) return d @inlineCallbacks def test_failed_write(self): self.writer.cancel() self.ws.writer = FailingWriter() data_datagram = DATADatagram(1, 'foobar') yield self.ws.datagramReceived(data_datagram) self.flushLoggedErrors() self.clock.advance(0.1) err_datagram = TFTPDatagramFactory(*split_opcode(self.transport.value())) self.failUnless(isinstance(err_datagram, ERRORDatagram)) self.failUnless(self.transport.disconnecting) def test_time_out(self): data_datagram = DATADatagram(1, 'foobar') d = self.ws.datagramReceived(data_datagram) def cb(ign): self.clock.pump((1,)*13) self.failUnless(self.transport.disconnecting) d.addCallback(cb) self.clock.advance(4) return d def tearDown(self): shutil.rmtree(self.tmp_dir_path)