Example #1
0
 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()
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
 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()
Example #6
0
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)
Example #7
0
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()
Example #8
0
 def __init__(self, remote, writer, options=None, _clock=None):
     TFTPBootstrap.__init__(self, remote, writer, options, _clock)
     self.session = WriteSession(writer, self._clock)
Example #9
0
 def __init__(self, remote, writer, options=None, _clock=None):
     TFTPBootstrap.__init__(self, remote, writer, options, _clock)
     self.session = WriteSession(writer, self._clock)
Example #10
0
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)