summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore9
-rw-r--r--README5
-rwxr-xr-xbin/tftpy_client.py4
-rwxr-xr-xbin/tftpy_server.py3
-rw-r--r--setup.py2
-rw-r--r--t/README.txt0
-rw-r--r--t/test.py30
-rw-r--r--t/testWin.py111
-rw-r--r--tftpy/TftpClient.py22
-rw-r--r--tftpy/TftpContexts.py49
-rw-r--r--tftpy/TftpPacketFactory.py13
-rw-r--r--tftpy/TftpPacketTypes.py90
-rw-r--r--tftpy/TftpServer.py81
-rw-r--r--tftpy/TftpShared.py2
-rw-r--r--tftpy/TftpStates.py64
-rw-r--r--tftpy/__init__.py2
16 files changed, 324 insertions, 163 deletions
diff --git a/.gitignore b/.gitignore
index a04559e..747cea6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,10 @@
+.idea
+.DS_Store
+
*.pyc
+
*.swp
-tags
-.DS_Store
+tags
+build
+
test.log
diff --git a/README b/README
index ad7a871..718b6e4 100644
--- a/README
+++ b/README
@@ -1,5 +1,10 @@
Copyright, Michael P. Soulier, 2010.
+About Release 0.6.3_fork:
+====================
+Maintenance release to fix a couple of bugs.
+Don't try to run t/test.py in Win Environment use instead t/testWin.py
+
About Release 0.6.2:
====================
Maintenance release to fix a couple of reported issues.
diff --git a/bin/tftpy_client.py b/bin/tftpy_client.py
index 1a50b56..9eacd0d 100755
--- a/bin/tftpy_client.py
+++ b/bin/tftpy_client.py
@@ -4,6 +4,7 @@ import sys, logging, os
from optparse import OptionParser
import tftpy
+
def main():
usage=""
parser = OptionParser(usage=usage)
@@ -67,6 +68,7 @@ def main():
def __init__(self, out):
self.progress = 0
self.out = out
+
def progresshook(self, pkt):
if isinstance(pkt, tftpy.TftpPacketDAT):
self.progress += len(pkt.data)
@@ -105,7 +107,7 @@ def main():
tclient.upload(options.upload,
options.input,
progresshook)
- except tftpy.TftpException, err:
+ except tftpy.TftpException as err:
sys.stderr.write("%s\n" % str(err))
sys.exit(1)
except KeyboardInterrupt:
diff --git a/bin/tftpy_server.py b/bin/tftpy_server.py
index 6a1d3a3..8c81def 100755
--- a/bin/tftpy_server.py
+++ b/bin/tftpy_server.py
@@ -4,6 +4,7 @@ import sys, logging
from optparse import OptionParser
import tftpy
+
def main():
usage=""
parser = OptionParser(usage=usage)
@@ -41,7 +42,7 @@ def main():
server = tftpy.TftpServer(options.root)
try:
server.listen(options.ip, options.port)
- except tftpy.TftpException, err:
+ except tftpy.TftpException as err:
sys.stderr.write("%s\n" % str(err))
sys.exit(1)
except KeyboardInterrupt:
diff --git a/setup.py b/setup.py
index 6331994..c3c3459 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
from distutils.core import setup
setup(name='tftpy',
- version='0.6.2',
+ version='0.6.3_fork',
description='Python TFTP library',
author='Michael P. Soulier',
author_email='msoulier@digitaltorque.ca',
diff --git a/t/README.txt b/t/README.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/t/README.txt
diff --git a/t/test.py b/t/test.py
index 844aa5c..dc37bb6 100644
--- a/t/test.py
+++ b/t/test.py
@@ -9,6 +9,7 @@ import threading
log = tftpy.log
+
class TestTftpyClasses(unittest.TestCase):
def setUp(self):
@@ -64,7 +65,6 @@ class TestTftpyClasses(unittest.TestCase):
self.assertEqual(wrq.mode, "octet", "Mode correct")
self.assertEqual(wrq.options['blksize'], '1024', "Blksize correct")
-
def testTftpPacketDAT(self):
log.debug("===> Running testcase testTftpPacketDAT")
dat = tftpy.TftpPacketDAT()
@@ -134,8 +134,9 @@ class TestTftpyClasses(unittest.TestCase):
factory = tftpy.TftpPacketFactory()
for opcode in classes:
self.assert_(isinstance(factory._TftpPacketFactory__create(opcode),
- classes[opcode]),
- "opcode %d returns the correct class" % opcode)
+ classes[opcode]),
+ "opcode %d returns the correct class" % opcode)
+
class TestTftpyState(unittest.TestCase):
@@ -162,12 +163,10 @@ class TestTftpyState(unittest.TestCase):
# parent - let the server start
try:
time.sleep(1)
- client.upload(filename,
- input)
+ client.upload(filename, input)
finally:
os.kill(child_pid, 15)
os.waitpid(child_pid, 0)
-
else:
server.listen('localhost', 20001)
@@ -237,8 +236,7 @@ class TestTftpyState(unittest.TestCase):
timeout,
root)
- self.assertTrue( isinstance(serverstate,
- tftpy.TftpContextServer) )
+ self.assertTrue(isinstance(serverstate, tftpy.TftpContextServer))
rrq = tftpy.TftpPacketRRQ()
rrq.filename = '640KBFILE'
@@ -372,12 +370,13 @@ class TestTftpyState(unittest.TestCase):
signal.alarm(2)
try:
server.listen('localhost', 20001)
- except Exception, err:
+ except Exception as err:
self.assertTrue( err[0] == 4 )
- def testServerDownloadWithStopNotNow(self, output='/tmp/out'):
+ def testServerDownloadWithStopNotNow(self):
log.debug("===> Running testcase testServerDownloadWithStopNotNow")
root = os.path.dirname(os.path.abspath(__file__))
+ output='/tmp/out'
server = tftpy.TftpServer(root)
client = tftpy.TftpClient('localhost',
20001,
@@ -403,17 +402,19 @@ class TestTftpyState(unittest.TestCase):
else:
import signal
+
def handlealarm(signum, frame):
server.stop(now=False)
signal.signal(signal.SIGALRM, handlealarm)
signal.alarm(2)
try:
server.listen('localhost', 20001)
- except Exception, err:
- self.assertTrue( False, "Server should not exit early" )
+ except Exception as err:
+ self.assertTrue(False, "Server should not exit early. %s" % err)
- def testServerDownloadWithDynamicPort(self, output='/tmp/out'):
+ def testServerDownloadWithDynamicPort(self):
log.debug("===> Running testcase testServerDownloadWithDynamicPort")
+ output='/tmp/out'
root = os.path.dirname(os.path.abspath(__file__))
server = tftpy.TftpServer(root)
@@ -426,8 +427,7 @@ class TestTftpyState(unittest.TestCase):
server.is_running.wait()
client = tftpy.TftpClient('localhost', server.listenport, {})
time.sleep(1)
- client.download('640KBFILE',
- output)
+ client.download('640KBFILE', output)
finally:
server.stop(now=False)
server_thread.join()
diff --git a/t/testWin.py b/t/testWin.py
new file mode 100644
index 0000000..46ee0ad
--- /dev/null
+++ b/t/testWin.py
@@ -0,0 +1,111 @@
+"""Unit tests for tftpy."""
+
+import unittest
+import logging
+import tftpy
+import os
+import time
+import threading
+
+log = tftpy.log
+
+
+class TestTftpyState(unittest.TestCase):
+
+ t_path = os.path.dirname(os.path.abspath(__file__))
+ t_640KB = os.path.join(t_path, "640KBFILE")
+ t_out = os.path.join(t_path, "out.tmp")
+
+ def setUp(self):
+ tftpy.setLogLevel(logging.DEBUG)
+
+ def tearDown(self):
+ if os.path.exists(self.t_out):
+ os.remove(self.t_out)
+
+ def _clientServerUploadOptions(self, options, upload_file=None):
+ """Fire up a server and a client and do a upload."""
+ input_path = self.t_640KB
+ if not upload_file:
+ upload_file = input_path
+
+ server = tftpy.TftpServer(self.t_path)
+ client = tftpy.TftpClient('localhost', 20001, options)
+ server_thread = threading.Thread(group=None, target=server.listen,
+ kwargs={'listenip': 'localhost',
+ 'listenport': 20001,
+ 'timeout': 10})
+ server_thread.start()
+ server.is_running.wait()
+ try:
+ time.sleep(1)
+ client.upload("out.tmp", upload_file)
+ finally:
+ server.stop(now=False)
+ server_thread.join()
+
+ def _clientServerDownloadOptions(self, options, output='/tmp/out'):
+ """Fire up a server and a client and do a download."""
+ if isinstance(output, basestring) and not os.path.exists(output):
+ output = self.t_out
+ server = tftpy.TftpServer(self.t_path)
+ client = tftpy.TftpClient('localhost', 20001, options)
+ server_thread = threading.Thread(group=None, target=server.listen,
+ kwargs={'listenip': 'localhost',
+ 'listenport': 20001,
+ 'timeout': 10})
+ server_thread.start()
+ server.is_running.wait()
+ try:
+ time.sleep(1)
+ client.download('640KBFILE', output)
+ finally:
+ server.stop(now=False)
+ server_thread.join()
+
+ def testClientServerUploadNoOptions(self):
+ self._clientServerUploadOptions({})
+
+ def testClientServerUploadFileObj(self):
+ with open(self.t_640KB, 'r') as f:
+ self._clientServerUploadOptions({}, upload_file=f)
+
+ def testClientServerUploadOptions(self):
+ for blksize in [512, 1024, 2048, 4096]:
+ self._clientServerUploadOptions({'blksize': blksize})
+
+ def testClientServerNoOptions(self):
+ self._clientServerDownloadOptions({})
+
+ def testClientFileObject(self):
+ with open(self.t_out, 'wb') as f:
+ self._clientServerDownloadOptions({}, f)
+
+ def testClientServerBlksize(self):
+ for blksize in [512, 1024, 2048, 4096]:
+ self._clientServerDownloadOptions({'blksize': blksize})
+
+ def testClientServerNoOptionsDelay(self):
+ tftpy.TftpStates.DELAY_BLOCK = 10
+ self._clientServerDownloadOptions({})
+ tftpy.TftpStates.DELAY_BLOCK = 0
+
+ def testServerDownloadWithDynamicPort(self):
+ server = tftpy.TftpServer(self.t_path)
+ server_thread = threading.Thread(target=server.listen,
+ kwargs={'listenip': 'localhost',
+ 'listenport': 0})
+ server_thread.start()
+ server.is_running.wait()
+ log.debug("> Tftp Server Listening at {}:{}".format(server.listenip,
+ server.listenport))
+ client = tftpy.TftpClient('localhost', server.listenport, {})
+ try:
+ time.sleep(1)
+ client.download('640KBFILE', self.t_out)
+ finally:
+ server.stop(now=False)
+ server_thread.join()
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tftpy/TftpClient.py b/tftpy/TftpClient.py
index a935b34..a95d023 100644
--- a/tftpy/TftpClient.py
+++ b/tftpy/TftpClient.py
@@ -3,9 +3,15 @@ instance of the client, and then use its upload or download method. Logging is
performed via a standard logging object set in TftpShared."""
import types
-from TftpShared import *
-from TftpPacketTypes import *
-from TftpContexts import TftpContextClientDownload, TftpContextClientUpload
+try:
+ from TftpShared import *
+ from TftpPacketTypes import *
+ from TftpContexts import TftpContextClientDownload, TftpContextClientUpload
+except ImportError:
+ from tftpy.TftpShared import *
+ from tftpy.TftpPacketTypes import *
+ from tftpy.TftpContexts import TftpContextClientDownload, TftpContextClientUpload
+
class TftpClient(TftpSession):
"""This class is an implementation of a tftp client. Once instantiated, a
@@ -19,11 +25,11 @@ class TftpClient(TftpSession):
self.iport = port
self.filename = None
self.options = options
- if self.options.has_key('blksize'):
+ if 'blksize' in self.options:
size = self.options['blksize']
tftpassert(types.IntType == type(size), "blksize must be an int")
if size < MIN_BLKSIZE or size > MAX_BLKSIZE:
- raise TftpException, "Invalid blksize: %d" % size
+ raise TftpException("Invalid blksize: %d" % size)
def download(self, filename, output, packethook=None, timeout=SOCK_TIMEOUT):
"""This method initiates a tftp download from the configured remote
@@ -38,10 +44,8 @@ class TftpClient(TftpSession):
Note: If output is a hyphen, stdout is used."""
# We're downloading.
log.debug("Creating download context with the following params:")
- log.debug("host = %s, port = %s, filename = %s, output = %s",
- self.host, self.iport, filename, output)
- log.debug("options = %s, packethook = %s, timeout = %s",
- self.options, packethook, timeout)
+ log.debug("host = %s, port = %s, filename = %s" % (self.host, self.iport, filename))
+ log.debug("options = %s, packethook = %s, timeout = %s" % (self.options, packethook, timeout))
self.context = TftpContextClientDownload(self.host,
self.iport,
filename,
diff --git a/tftpy/TftpContexts.py b/tftpy/TftpContexts.py
index eed1cd1..9dfe6ee 100644
--- a/tftpy/TftpContexts.py
+++ b/tftpy/TftpContexts.py
@@ -8,11 +8,19 @@ the next packet in the transfer, and returns a state object until the transfer
is complete, at which point it returns None. That is, unless there is a fatal
error, in which case a TftpException is returned instead."""
-from TftpShared import *
-from TftpPacketTypes import *
-from TftpPacketFactory import TftpPacketFactory
-from TftpStates import *
-import socket, time, sys
+import sys
+import time
+import socket
+try:
+ from TftpShared import *
+ from TftpPacketTypes import *
+ from TftpPacketFactory import TftpPacketFactory
+ from TftpStates import *
+except ImportError:
+ from tftpy.TftpShared import *
+ from tftpy.TftpPacketTypes import *
+ from tftpy.TftpPacketFactory import TftpPacketFactory
+ from tftpy.TftpStates import *
###############################################################################
# Utility classes
@@ -112,10 +120,10 @@ class TftpContext(object):
if we're over the timeout time."""
log.debug("checking for timeout on session %s", self)
if now - self.last_update > self.timeout:
- raise TftpTimeout, "Timeout waiting for traffic"
+ raise TftpTimeout("Timeout waiting for traffic")
def start(self):
- raise NotImplementedError, "Abstract method"
+ raise NotImplementedError("Abstract method")
def end(self):
"""Perform session cleanup, since the end method should always be
@@ -157,7 +165,7 @@ class TftpContext(object):
(buffer, (raddress, rport)) = self.sock.recvfrom(MAX_BLKSIZE)
except socket.timeout:
log.warn("Timeout waiting for traffic, retrying...")
- raise TftpTimeout, "Timed-out waiting for traffic"
+ raise TftpTimeout("Timed-out waiting for traffic")
# Ok, we've received a packet. Log it.
log.debug("Received %d bytes from %s:%s",
@@ -265,8 +273,8 @@ class TftpContextClientUpload(TftpContext):
self.fileobj = open(input, "rb")
log.debug("TftpContextClientUpload.__init__()")
- log.debug("file_to_transfer = %s, options = %s",
- self.file_to_transfer, self.options)
+ log.debug("file_to_transfer = %s, options = %s" %
+ (self.file_to_transfer, self.options))
def __str__(self):
return "%s:%s %s" % (self.host, self.port, self.state)
@@ -277,7 +285,7 @@ class TftpContextClientUpload(TftpContext):
log.info(" options -> %s" % self.options)
self.metrics.start_time = time.time()
- log.debug("Set metrics.start_time to %s", self.metrics.start_time)
+ log.debug("Set metrics.start_time to %s" % self.metrics.start_time)
# FIXME: put this in a sendWRQ method?
pkt = TftpPacketWRQ()
@@ -294,9 +302,9 @@ class TftpContextClientUpload(TftpContext):
while self.state:
try:
- log.debug("State is %s", self.state)
+ log.debug("State is %s" % self.state)
self.cycle()
- except TftpTimeout, err:
+ except TftpTimeout as err:
log.error(str(err))
self.retry_count += 1
if self.retry_count >= TIMEOUT_RETRIES:
@@ -310,9 +318,10 @@ class TftpContextClientUpload(TftpContext):
"""Finish up the context."""
TftpContext.end(self)
self.metrics.end_time = time.time()
- log.debug("Set metrics.end_time to %s", self.metrics.end_time)
+ log.debug("Set metrics.end_time to %s" % self.metrics.end_time)
self.metrics.compute()
+
class TftpContextClientDownload(TftpContext):
"""The download context for the client during a download.
Note: If output is a hyphen, then the output will be sent to stdout."""
@@ -343,8 +352,8 @@ class TftpContextClientDownload(TftpContext):
self.fileobj = open(output, "wb")
log.debug("TftpContextClientDownload.__init__()")
- log.debug("file_to_transfer = %s, options = %s",
- self.file_to_transfer, self.options)
+ log.debug("file_to_transfer = %s, options = %s" %
+ (self.file_to_transfer, self.options))
def __str__(self):
return "%s:%s %s" % (self.host, self.port, self.state)
@@ -356,7 +365,7 @@ class TftpContextClientDownload(TftpContext):
log.info(" options -> %s" % self.options)
self.metrics.start_time = time.time()
- log.debug("Set metrics.start_time to %s", self.metrics.start_time)
+ log.debug("Set metrics.start_time to %s" % self.metrics.start_time)
# FIXME: put this in a sendRRQ method?
pkt = TftpPacketRRQ()
@@ -371,9 +380,9 @@ class TftpContextClientDownload(TftpContext):
while self.state:
try:
- log.debug("State is %s", self.state)
+ log.debug("State is %s" % self.state)
self.cycle()
- except TftpTimeout, err:
+ except TftpTimeout as err:
log.error(str(err))
self.retry_count += 1
if self.retry_count >= TIMEOUT_RETRIES:
@@ -387,5 +396,5 @@ class TftpContextClientDownload(TftpContext):
"""Finish up the context."""
TftpContext.end(self)
self.metrics.end_time = time.time()
- log.debug("Set metrics.end_time to %s", self.metrics.end_time)
+ log.debug("Set metrics.end_time to %s" % self.metrics.end_time)
self.metrics.compute()
diff --git a/tftpy/TftpPacketFactory.py b/tftpy/TftpPacketFactory.py
index 154aec8..f32f6ad 100644
--- a/tftpy/TftpPacketFactory.py
+++ b/tftpy/TftpPacketFactory.py
@@ -2,8 +2,13 @@
buffer, and return the appropriate TftpPacket object to represent it, via the
parse() method."""
-from TftpShared import *
-from TftpPacketTypes import *
+try:
+ from TftpShared import *
+ from TftpPacketTypes import *
+except ImportError:
+ from tftpy.TftpShared import *
+ from tftpy.TftpPacketTypes import *
+
class TftpPacketFactory(object):
"""This class generates TftpPacket objects. It is responsible for parsing
@@ -23,9 +28,9 @@ class TftpPacketFactory(object):
"""This method is used to parse an existing datagram into its
corresponding TftpPacket object. The buffer is the raw bytes off of
the network."""
- log.debug("parsing a %d byte packet", len(buffer))
+ log.debug("parsing a %d byte packet" % len(buffer))
(opcode,) = struct.unpack("!H", buffer[:2])
- log.debug("opcode is %d", opcode)
+ log.debug("opcode is %d" % opcode)
packet = self.__create(opcode)
packet.buffer = buffer
return packet.decode()
diff --git a/tftpy/TftpPacketTypes.py b/tftpy/TftpPacketTypes.py
index 4a2a0f1..66759cf 100644
--- a/tftpy/TftpPacketTypes.py
+++ b/tftpy/TftpPacketTypes.py
@@ -2,7 +2,10 @@
corresponding encode and decode methods for them."""
import struct
-from TftpShared import *
+try:
+ from TftpShared import *
+except ImportError:
+ from tftpy.TftpShared import *
class TftpSession(object):
"""This class is the base class for the tftp client and server. Any shared
@@ -20,15 +23,15 @@ class TftpPacketWithOptions(object):
def setoptions(self, options):
log.debug("in TftpPacketWithOptions.setoptions")
- log.debug("options: %s", str(options))
+ log.debug("options: %s" % options)
myoptions = {}
for key in options:
newkey = str(key)
myoptions[newkey] = str(options[key])
- log.debug("populated myoptions with %s = %s",
- newkey, myoptions[newkey])
+ log.debug("populated myoptions with %s = %s"
+ % (newkey, myoptions[newkey]))
- log.debug("setting options hash to: %s", str(myoptions))
+ log.debug("setting options hash to: %s" % myoptions)
self._options = myoptions
def getoptions(self):
@@ -47,8 +50,8 @@ class TftpPacketWithOptions(object):
format = "!"
options = {}
- log.debug("decode_options: buffer is: %s", repr(buffer))
- log.debug("size of buffer is %d bytes", len(buffer))
+ log.debug("decode_options: buffer is: %s" % repr(buffer))
+ log.debug("size of buffer is %d bytes" % len(buffer))
if len(buffer) == 0:
log.debug("size of buffer is zero, returning empty hash")
return {}
@@ -58,22 +61,22 @@ class TftpPacketWithOptions(object):
length = 0
for c in buffer:
if ord(c) == 0:
- log.debug("found a null at length %d", length)
+ log.debug("found a null at length %d" % length)
if length > 0:
format += "%dsx" % length
length = -1
else:
- raise TftpException, "Invalid options in buffer"
+ raise TftpException("Invalid options in buffer")
length += 1
- log.debug("about to unpack, format is: %s", format)
+ log.debug("about to unpack, format is: %s" % format)
mystruct = struct.unpack(format, buffer)
tftpassert(len(mystruct) % 2 == 0,
"packet with odd number of option/value pairs")
for i in range(0, len(mystruct), 2):
- log.debug("setting option %s to %s", mystruct[i], mystruct[i+1])
+ log.debug("setting option %s to %s" % (mystruct[i], mystruct[i+1]))
options[mystruct[i]] = mystruct[i+1]
return options
@@ -92,7 +95,7 @@ class TftpPacket(object):
order suitable for sending over the wire.
This is an abstract method."""
- raise NotImplementedError, "Abstract method"
+ raise NotImplementedError("Abstract method")
def decode(self):
"""The decode method of a TftpPacket takes a buffer off of the wire in
@@ -102,7 +105,7 @@ class TftpPacket(object):
datagram.
This is an abstract method."""
- raise NotImplementedError, "Abstract method"
+ raise NotImplementedError("Abstract method")
class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
"""This class is a common parent class for the RRQ and WRQ packets, as
@@ -121,17 +124,17 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
ptype = None
if self.opcode == 1: ptype = "RRQ"
else: ptype = "WRQ"
- log.debug("Encoding %s packet, filename = %s, mode = %s",
- ptype, self.filename, self.mode)
+ log.debug("Encoding %s packet, filename = %s, mode = %s"
+ % (ptype, self.filename, self.mode))
for key in self.options:
- log.debug(" Option %s = %s", key, self.options[key])
+ log.debug(" Option %s = %s" % (key, self.options[key]))
format = "!H"
format += "%dsx" % len(self.filename)
if self.mode == "octet":
format += "5sx"
else:
- raise AssertionError, "Unsupported mode: %s" % mode
+ raise AssertionError("Unsupported mode: %s" % mode)
# Add options.
options_list = []
if self.options.keys() > 0:
@@ -144,9 +147,9 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
format += "%dsx" % len(str(self.options[key]))
options_list.append(str(self.options[key]))
- log.debug("format is %s", format)
- log.debug("options_list is %s", options_list)
- log.debug("size of struct is %d", struct.calcsize(format))
+ log.debug("format is %s" % format)
+ log.debug("options_list is %s" % options_list)
+ log.debug("size of struct is %d" % struct.calcsize(format))
self.buffer = struct.pack(format,
self.opcode,
@@ -154,7 +157,7 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
self.mode,
*options_list)
- log.debug("buffer is %s", repr(self.buffer))
+ log.debug("buffer is %s" % repr(self.buffer))
return self
def decode(self):
@@ -169,7 +172,8 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
for c in subbuf:
if ord(c) == 0:
nulls += 1
- log.debug("found a null at length %d, now have %d", length, nulls)
+ log.debug("found a null at length %d, now have %d"
+ % (length, nulls))
format += "%dsx" % length
length = -1
# At 2 nulls, we want to mark that position for decoding.
@@ -178,19 +182,19 @@ class TftpPacketInitial(TftpPacket, TftpPacketWithOptions):
length += 1
tlength += 1
- log.debug("hopefully found end of mode at length %d", tlength)
+ log.debug("hopefully found end of mode at length %d" % tlength)
# length should now be the end of the mode.
tftpassert(nulls == 2, "malformed packet")
shortbuf = subbuf[:tlength+1]
- log.debug("about to unpack buffer with format: %s", format)
- log.debug("unpacking buffer: %s", repr(shortbuf))
+ log.debug("about to unpack buffer with format: %s" % format)
+ log.debug("unpacking buffer: " + repr(shortbuf))
mystruct = struct.unpack(format, shortbuf)
tftpassert(len(mystruct) == 2, "malformed packet")
self.filename = mystruct[0]
self.mode = mystruct[1].lower() # force lc - bug 17
- log.debug("set filename to %s", self.filename)
- log.debug("set mode to %s", self.mode)
+ log.debug("set filename to %s" % self.filename)
+ log.debug("set mode to %s" % self.mode)
self.options = self.decode_options(subbuf[tlength+1:])
return self
@@ -274,11 +278,13 @@ class TftpPacketDAT(TftpPacket):
# We know the first 2 bytes are the opcode. The second two are the
# block number.
(self.blocknumber,) = struct.unpack("!H", self.buffer[2:4])
- log.debug("decoding DAT packet, block number %d", self.blocknumber)
- log.debug("should be %d bytes in the packet total", len(self.buffer))
+ log.debug("decoding DAT packet, block number %d" % self.blocknumber)
+ log.debug("should be %d bytes in the packet total"
+ % len(self.buffer))
# Everything else is data.
self.data = self.buffer[4:]
- log.debug("found %d bytes of data", len(self.data))
+ log.debug("found %d bytes of data"
+ % len(self.data))
return self
class TftpPacketACK(TftpPacket):
@@ -299,15 +305,15 @@ class TftpPacketACK(TftpPacket):
return 'ACK packet: block %d' % self.blocknumber
def encode(self):
- log.debug("encoding ACK: opcode = %d, block = %d",
- self.opcode, self.blocknumber)
+ log.debug("encoding ACK: opcode = %d, block = %d"
+ % (self.opcode, self.blocknumber))
self.buffer = struct.pack("!HH", self.opcode, self.blocknumber)
return self
def decode(self):
self.opcode, self.blocknumber = struct.unpack("!HH", self.buffer)
- log.debug("decoded ACK packet: opcode = %d, block = %d",
- self.opcode, self.blocknumber)
+ log.debug("decoded ACK packet: opcode = %d, block = %d"
+ % (self.opcode, self.blocknumber))
return self
class TftpPacketERR(TftpPacket):
@@ -360,7 +366,7 @@ class TftpPacketERR(TftpPacket):
"""Encode the DAT packet based on instance variables, populating
self.buffer, returning self."""
format = "!HH%dsx" % len(self.errmsgs[self.errorcode])
- log.debug("encoding ERR packet with format %s", format)
+ log.debug("encoding ERR packet with format %s" % format)
self.buffer = struct.pack(format,
self.opcode,
self.errorcode,
@@ -371,17 +377,17 @@ class TftpPacketERR(TftpPacket):
"Decode self.buffer, populating instance variables and return self."
buflen = len(self.buffer)
tftpassert(buflen >= 4, "malformed ERR packet, too short")
- log.debug("Decoding ERR packet, length %s bytes", buflen)
+ log.debug("Decoding ERR packet, length %s bytes" % buflen)
if buflen == 4:
log.debug("Allowing this affront to the RFC of a 4-byte packet")
format = "!HH"
- log.debug("Decoding ERR packet with format: %s", format)
+ log.debug("Decoding ERR packet with format: %s" % format)
self.opcode, self.errorcode = struct.unpack(format,
self.buffer)
else:
log.debug("Good ERR packet > 4 bytes")
format = "!HH%dsx" % (len(self.buffer) - 5)
- log.debug("Decoding ERR packet with format: %s", format)
+ log.debug("Decoding ERR packet with format: %s" % format)
self.opcode, self.errorcode, self.errmsg = struct.unpack(format,
self.buffer)
log.error("ERR packet - errorcode: %d, message: %s"
@@ -409,8 +415,8 @@ class TftpPacketOACK(TftpPacket, TftpPacketWithOptions):
options_list = []
log.debug("in TftpPacketOACK.encode")
for key in self.options:
- log.debug("looping on option key %s", key)
- log.debug("value is %s", self.options[key])
+ log.debug("looping on option key %s" % key)
+ log.debug("value is %s" % self.options[key])
format += "%dsx" % len(key)
format += "%dsx" % len(self.options[key])
options_list.append(key)
@@ -434,8 +440,8 @@ class TftpPacketOACK(TftpPacket, TftpPacketWithOptions):
# We can accept anything between the min and max values.
size = self.options[name]
if size >= MIN_BLKSIZE and size <= MAX_BLKSIZE:
- log.debug("negotiated blksize of %d bytes", size)
+ log.debug("negotiated blksize of %d bytes" % size)
options[blksize] = size
else:
- raise TftpException, "Unsupported option: %s" % name
+ raise TftpException("Unsupported option: %s" % name)
return True
diff --git a/tftpy/TftpServer.py b/tftpy/TftpServer.py
index 12491a0..a119a1e 100644
--- a/tftpy/TftpServer.py
+++ b/tftpy/TftpServer.py
@@ -3,13 +3,22 @@ instance of the server, and then run the listen() method to listen for client
requests. Logging is performed via a standard logging object set in
TftpShared."""
-import socket, os, time
+import os
+import time
+import socket
import select
import threading
-from TftpShared import *
-from TftpPacketTypes import *
-from TftpPacketFactory import TftpPacketFactory
-from TftpContexts import TftpContextServer
+try:
+ from TftpShared import *
+ from TftpPacketTypes import *
+ from TftpPacketFactory import TftpPacketFactory
+ from TftpContexts import TftpContextServer
+except ImportError:
+ from tftpy.TftpShared import *
+ from tftpy.TftpPacketTypes import *
+ from tftpy.TftpPacketFactory import TftpPacketFactory
+ from tftpy.TftpContexts import TftpContextServer
+
class TftpServer(TftpSession):
"""This class implements a tftp server object. Run the listen() method to
@@ -38,27 +47,26 @@ class TftpServer(TftpSession):
if self.dyn_file_func:
if not callable(self.dyn_file_func):
- raise TftpException, "A dyn_file_func supplied, but it is not callable."
+ raise TftpException("A dyn_file_func supplied, "
+ "but it is not callable.")
elif os.path.exists(self.root):
- log.debug("tftproot %s does exist", self.root)
+ log.debug("tftproot %s does exist" % self.root)
if not os.path.isdir(self.root):
- raise TftpException, "The tftproot must be a directory."
+ raise TftpException("The tftproot must be a directory.")
else:
- log.debug("tftproot %s is a directory", self.root)
+ log.debug("tftproot %s is a directory" % self.root)
if os.access(self.root, os.R_OK):
- log.debug("tftproot %s is readable", self.root)
+ log.debug("tftproot %s is readable" % self.root)
else:
- raise TftpException, "The tftproot must be readable"
+ raise TftpException("The tftproot must be readable")
if os.access(self.root, os.W_OK):
- log.debug("tftproot %s is writable", self.root)
+ log.debug("tftproot %s is writable" % self.root)
else:
log.warning("The tftproot %s is not writable" % self.root)
else:
- raise TftpException, "The tftproot does not exist."
+ raise TftpException("The tftproot does not exist.")
- def listen(self,
- listenip="",
- listenport=DEF_TFTP_PORT,
+ def listen(self, listenip="", listenport=DEF_TFTP_PORT,
timeout=SOCK_TIMEOUT):
"""Start a server listening on the supplied interface and port. This
defaults to INADDR_ANY (all interfaces) and UDP port 69. You can also
@@ -68,25 +76,25 @@ class TftpServer(TftpSession):
# Don't use new 2.5 ternary operator yet
# listenip = listenip if listenip else '0.0.0.0'
if not listenip: listenip = '0.0.0.0'
- log.info("Server requested on ip %s, port %s"
- % (listenip, listenport))
+ log.info("Server requested on ip %s, port %s" % (listenip, listenport))
try:
# FIXME - sockets should be non-blocking
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind((listenip, listenport))
_, self.listenport = self.sock.getsockname()
- except socket.error, err:
+ except socket.error as err:
# Reraise it for now.
- raise
+ raise err
self.is_running.set()
log.info("Starting receive loop...")
while True:
- log.debug("shutdown_immediately is %s", self.shutdown_immediately)
- log.debug("shutdown_gracefully is %s", self.shutdown_gracefully)
+ log.debug("shutdown_immediately is %s" % self.shutdown_immediately)
+ log.debug("shutdown_gracefully is %s" % self.shutdown_gracefully)
if self.shutdown_immediately:
- log.warn("Shutting down now. Session count: %d" % len(self.sessions))
+ log.warn("Shutting down now. Session count: %d" %
+ len(self.sessions))
self.sock.close()
for key in self.sessions:
self.sessions[key].end()
@@ -95,7 +103,8 @@ class TftpServer(TftpSession):
elif self.shutdown_gracefully:
if not self.sessions:
- log.warn("In graceful shutdown mode and all sessions complete.")
+ log.warn("In graceful shutdown mode and all "
+ "sessions complete.")
self.sock.close()
break
@@ -124,7 +133,8 @@ class TftpServer(TftpSession):
log.debug("Read %d bytes", len(buffer))
if self.shutdown_gracefully:
- log.warn("Discarding data on main port, in graceful shutdown mode")
+ log.warn("Discarding data on main port, "
+ "in graceful shutdown mode")
continue
# Forge a session key based on the client's IP and port,
@@ -133,7 +143,7 @@ class TftpServer(TftpSession):
if not self.sessions.has_key(key):
log.debug("Creating new server context for "
- "session key = %s", key)
+ "session key = %s" % key)
self.sessions[key] = TftpContextServer(raddress,
rport,
timeout,
@@ -141,7 +151,7 @@ class TftpServer(TftpSession):
self.dyn_file_func)
try:
self.sessions[key].start(buffer)
- except TftpException, err:
+ except TftpException as err:
deletion_list.append(key)
log.error("Fatal exception thrown from "
"session %s: %s" % (key, str(err)))
@@ -163,7 +173,7 @@ class TftpServer(TftpSession):
if self.sessions[key].state == None:
log.info("Successful transfer.")
deletion_list.append(key)
- except TftpException, err:
+ except TftpException as err:
deletion_list.append(key)
log.error("Fatal exception thrown from "
"session %s: %s"
@@ -171,7 +181,6 @@ class TftpServer(TftpSession):
# Break out of for loop since we found the correct
# session.
break
-
else:
log.error("Can't find the owner for this packet. "
"Discarding.")
@@ -181,15 +190,15 @@ class TftpServer(TftpSession):
for key in self.sessions:
try:
self.sessions[key].checkTimeout(now)
- except TftpTimeout, err:
+ except TftpTimeout as err:
log.error(str(err))
self.sessions[key].retry_count += 1
if self.sessions[key].retry_count >= TIMEOUT_RETRIES:
- log.debug("hit max retries on %s, giving up",
+ log.debug("hit max retries on %s, giving up" %
self.sessions[key])
deletion_list.append(key)
else:
- log.debug("resending on session %s", self.sessions[key])
+ log.debug("resending on session %s" % self.sessions[key])
self.sessions[key].state.resendLast()
log.debug("Iterating deletion list.")
@@ -208,12 +217,12 @@ class TftpServer(TftpSession):
log.info("Average rate: %.2f kbps" % metrics.kbps)
log.info("%.2f bytes in resent data" % metrics.resent_bytes)
log.info("%d duplicate packets" % metrics.dupcount)
- log.debug("Deleting session %s", key)
+ log.debug("Deleting session %s" % key)
del self.sessions[key]
- log.debug("Session list is now %s", self.sessions)
+ log.debug("Session list is now %s" % self.sessions)
else:
- log.warn("Strange, session %s is not on the deletion list"
- % key)
+ log.warn(
+ "Strange, session %s is not on the deletion list" % key)
self.is_running.clear()
diff --git a/tftpy/TftpShared.py b/tftpy/TftpShared.py
index d09d8bd..171ec1c 100644
--- a/tftpy/TftpShared.py
+++ b/tftpy/TftpShared.py
@@ -26,7 +26,7 @@ def tftpassert(condition, msg):
with the message passed. This just makes the code throughout cleaner
by refactoring."""
if not condition:
- raise TftpException, msg
+ raise TftpException(msg)
def setLogLevel(level):
"""This function is a utility function for setting the internal log level.
diff --git a/tftpy/TftpStates.py b/tftpy/TftpStates.py
index 1ea6c31..fe1a681 100644
--- a/tftpy/TftpStates.py
+++ b/tftpy/TftpStates.py
@@ -8,9 +8,13 @@ the next packet in the transfer, and returns a state object until the transfer
is complete, at which point it returns None. That is, unless there is a fatal
error, in which case a TftpException is returned instead."""
-from TftpShared import *
-from TftpPacketTypes import *
import os
+try:
+ from TftpShared import *
+ from TftpPacketTypes import *
+except:
+ from tftpy.TftpShared import *
+ from tftpy.TftpPacketTypes import *
###############################################################################
# State classes
@@ -28,7 +32,7 @@ class TftpState(object):
def handle(self, pkt, raddress, rport):
"""An abstract method for handling a packet. It is expected to return
a TftpState object, either itself or a new state."""
- raise NotImplementedError, "Abstract method"
+ raise NotImplementedError("Abstract method")
def handleOACK(self, pkt):
"""This method handles an OACK from the server, syncing any accepted
@@ -42,9 +46,9 @@ class TftpState(object):
log.info(" %s = %s" % (key, self.context.options[key]))
else:
log.error("Failed to negotiate options")
- raise TftpException, "Failed to negotiate options"
+ raise TftpException("Failed to negotiate options")
else:
- raise TftpException, "No options found in OACK"
+ raise TftpException("No options found in OACK")
def returnSupportedOptions(self, options):
"""This method takes a requested options list from a client, and
@@ -181,7 +185,7 @@ class TftpState(object):
if pkt.blocknumber == 0:
log.warn("There is no block zero!")
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "There is no block zero!"
+ raise TftpException("There is no block zero!")
log.warn("Dropping duplicate block %d" % pkt.blocknumber)
self.context.metrics.add_dup(pkt)
log.debug("ACKing block %d again, just in case", pkt.blocknumber)
@@ -192,7 +196,7 @@ class TftpState(object):
msg = "Whoa! Received future block %d but expected %d" \
% (pkt.blocknumber, self.context.next_block)
log.error(msg)
- raise TftpException, msg
+ raise TftpException(msg)
# Default is to ack
return TftpStateExpectDAT(self.context)
@@ -231,8 +235,8 @@ class TftpServerState(TftpState):
# FIXME - only octet mode is supported at this time.
if pkt.mode != 'octet':
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, \
- "Only octet transfers are supported at this time."
+ raise TftpException(
+ "Only octet transfers are supported at this time.")
# test host/port of client end
if self.context.host != raddress or self.context.port != rport:
@@ -276,7 +280,7 @@ class TftpServerState(TftpState):
else:
log.warn("requested file is not within the server root - bad")
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "bad file path"
+ raise TftpException("bad file path")
self.context.file_to_transfer = pkt.filename
@@ -305,10 +309,10 @@ class TftpStateServerRecvRRQ(TftpServerState):
log.debug("dyn_file_func returned 'None', treating as "
"FileNotFound")
self.sendError(TftpErrors.FileNotFound)
- raise TftpException, "File not found: %s" % path
+ raise TftpException("File not found: %s" % path)
else:
self.sendError(TftpErrors.FileNotFound)
- raise TftpException, "File not found: %s" % path
+ raise TftpException("File not found: %s" % path)
# Options negotiation.
if sendoack:
@@ -348,7 +352,7 @@ class TftpStateServerRecvWRQ(TftpServerState):
if os.path.isdir(current):
log.debug("%s is already an existing directory", current)
else:
- os.mkdir(current, 0700)
+ os.mkdir(current, 0o700)
def handle(self, pkt, raddress, rport):
"Handle an initial WRQ packet as a server."
@@ -401,8 +405,8 @@ class TftpStateServerStart(TftpState):
rport)
else:
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, \
- "Invalid packet to begin up/download: %s" % pkt
+ raise TftpException(
+ "Invalid packet to begin up/download: %s" % pkt)
class TftpStateExpectACK(TftpState):
"""This class represents the state of the transfer when a DAT was just
@@ -437,8 +441,8 @@ class TftpStateExpectACK(TftpState):
return self
elif isinstance(pkt, TftpPacketERR):
log.error("Received ERR packet from peer: %s" % str(pkt))
- raise TftpException, \
- "Received ERR packet from peer: %s" % str(pkt)
+ raise TftpException(
+ "Received ERR packet from peer: %s" % str(pkt))
else:
log.warn("Discarding unsupported packet: %s" % str(pkt))
return self
@@ -454,19 +458,19 @@ class TftpStateExpectDAT(TftpState):
elif isinstance(pkt, TftpPacketACK):
# Umm, we ACK, you don't.
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received ACK from peer when expecting DAT"
+ raise TftpException("Received ACK from peer when expecting DAT")
elif isinstance(pkt, TftpPacketWRQ):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received WRQ from peer when expecting DAT"
+ raise TftpException("Received WRQ from peer when expecting DAT")
elif isinstance(pkt, TftpPacketERR):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received ERR from peer: " + str(pkt)
+ raise TftpException("Received ERR from peer: " + str(pkt))
else:
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received unknown packet type from peer: " + str(pkt)
+ raise TftpException("Received unknown packet type from peer: " + str(pkt))
class TftpStateSentWRQ(TftpState):
"""Just sent an WRQ packet for an upload."""
@@ -509,19 +513,19 @@ class TftpStateSentWRQ(TftpState):
elif isinstance(pkt, TftpPacketERR):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received ERR from server: " + str(pkt)
+ raise TftpException("Received ERR from server: %s" % pkt)
elif isinstance(pkt, TftpPacketRRQ):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received RRQ from server while in upload"
+ raise TftpException("Received RRQ from server while in upload")
elif isinstance(pkt, TftpPacketDAT):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received DAT from server while in upload"
+ raise TftpException("Received DAT from server while in upload")
else:
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received unknown packet type from server: " + str(pkt)
+ raise TftpException("Received unknown packet type from server: %s" % pkt)
# By default, no state change.
return self
@@ -539,7 +543,7 @@ class TftpStateSentRRQ(TftpState):
log.info("Received OACK from server")
try:
self.handleOACK(pkt)
- except TftpException, err:
+ except TftpException as err:
log.error("Failed to negotiate options: %s" % str(err))
self.sendError(TftpErrors.FailedNegotiation)
raise
@@ -564,19 +568,19 @@ class TftpStateSentRRQ(TftpState):
elif isinstance(pkt, TftpPacketACK):
# Umm, we ACK, the server doesn't.
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received ACK from server while in download"
+ raise TftpException("Received ACK from server while in download")
elif isinstance(pkt, TftpPacketWRQ):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received WRQ from server while in download"
+ raise TftpException("Received WRQ from server while in download")
elif isinstance(pkt, TftpPacketERR):
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received ERR from server: " + str(pkt)
+ raise TftpException("Received ERR from server: %s" % pkt)
else:
self.sendError(TftpErrors.IllegalTftpOp)
- raise TftpException, "Received unknown packet type from server: " + str(pkt)
+ raise TftpException("Received unknown packet type from server: %s" % pkt)
# By default, no state change.
return self
diff --git a/tftpy/__init__.py b/tftpy/__init__.py
index fba9a9f..a0b0f85 100644
--- a/tftpy/__init__.py
+++ b/tftpy/__init__.py
@@ -13,7 +13,7 @@ import sys
# Make sure that this is at least Python 2.3
required_version = (2, 3)
if sys.version_info < required_version:
- raise ImportError, "Requires at least Python 2.3"
+ raise ImportError("Requires at least Python 2.3")
from tftpy.TftpShared import *
from tftpy.TftpPacketTypes import *