Started on the server
git-svn-id: https://tftpy.svn.sourceforge.net/svnroot/tftpy/trunk@37 63283fd4-ec1e-0410-9879-cb7f675518da
This commit is contained in:
parent
aece5aaf2e
commit
fc2a587641
3 changed files with 79 additions and 3 deletions
2
README
2
README
|
@ -26,7 +26,7 @@ client and server classes, with sample implementations. Hooks are included for
|
|||
easy inclusion in a UI for populating progress indicators. It supports RFCs
|
||||
1350, 2347 and 2348.
|
||||
|
||||
This library was developed against Python 2.4.1.
|
||||
This library was developed against Python 2.3.
|
||||
|
||||
Project page: http://sourceforge.net/projects/tftpy/
|
||||
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
import sys, logging, os
|
||||
from optparse import OptionParser
|
||||
import tftpy
|
||||
try:
|
||||
import tftpy
|
||||
except ImportError, err:
|
||||
sys.path.append('../lib')
|
||||
import tftpy
|
||||
|
||||
def main():
|
||||
usage=""
|
||||
|
|
74
lib/tftpy.py
74
lib/tftpy.py
|
@ -18,6 +18,7 @@ MAX_BLKSIZE = 65536
|
|||
SOCK_TIMEOUT = 5
|
||||
MAX_DUPS = 20
|
||||
TIMEOUT_RETRIES = 5
|
||||
DEF_TFTP_PORT = 69
|
||||
|
||||
# Initialize the logger.
|
||||
logging.basicConfig(
|
||||
|
@ -484,13 +485,84 @@ class TftpState(object):
|
|||
class TftpSession(object):
|
||||
"""This class is the base class for the tftp client and server. Any shared
|
||||
code should be in this class."""
|
||||
|
||||
def __init__(self):
|
||||
"Class constructor. Note that the state property must be a TftpState object."
|
||||
"Class constructor. Note that the state property must be a TftpState
|
||||
object."
|
||||
self.options = None
|
||||
self.state = TftpState()
|
||||
self.dups = 0
|
||||
self.errors = 0
|
||||
|
||||
class TftpServer(object):
|
||||
"""This class implements a tftp server object."""
|
||||
|
||||
def __init__(self):
|
||||
"Class constructor."
|
||||
self.listenip = None
|
||||
self.listenport = None
|
||||
self.sock = None
|
||||
# A dict of handlers, where each session is keyed by a string like
|
||||
# ip:tid for the remote end.
|
||||
self.handlers = {}
|
||||
|
||||
def listen(self,
|
||||
listenip=socket.INADDR_ANY,
|
||||
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
|
||||
supply a different socket timeout value, if desired."""
|
||||
logger.info("Server requested on ip %s, port %s" % (listenip, listenport))
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
logger.info("Starting receive loop...")
|
||||
while True:
|
||||
(buffer, (raddress, rport)) = self.sock.recvfrom(MAX_BLKSIZE)
|
||||
recvpkt = tftp_factory.parse(buffer)
|
||||
key = "%s:%s" % (raddress, rport)
|
||||
|
||||
if isinstance(recvpkt, TftpPacketRRQ):
|
||||
logger.debug("RRQ packet from %s:%s" % (raddress, rport))
|
||||
if not self.handlers.has_key(key):
|
||||
logger.debug("New download request, session key = %s" % key)
|
||||
self.handlers[key] = TftpServerHandler(key)
|
||||
self.handlers[key].handle(recvpkt)
|
||||
elif isinstance(recvpkt, TftpPacketWRQ):
|
||||
logger.error("Write requests not implemented at this time.")
|
||||
errpkt = TftpPacketERR()
|
||||
errpkt.errorcode = 4
|
||||
self.sock.sendto(errpkt.encode().buffer, (raddress, rport))
|
||||
continue
|
||||
|
||||
if not self.handlers.has_key(key):
|
||||
logger.error("No existing session with key %s" % key)
|
||||
errpkt = TftpPacketERR()
|
||||
errpkt.errorcode = 5
|
||||
self.sock.sendto(errpkt.encode().buffer, (raddress, rport))
|
||||
continue
|
||||
else:
|
||||
self.handlers[key].handle(recvpkt)
|
||||
|
||||
class TftpServerHandler(TftpSession):
|
||||
"""This class implements a handler for a given server session, handling
|
||||
the work for one download."""
|
||||
|
||||
def __init__(self, key):
|
||||
TftpSession.__init__(self)
|
||||
self.key = key
|
||||
self.sock = self.gensock()
|
||||
|
||||
def handle(self, pkt):
|
||||
logger.debug("Handler %s requested to handle packet %s"
|
||||
% (self.key, pkt))
|
||||
|
||||
def gensock(self):
|
||||
"""This method generates a new UDP socket, whose listening port must
|
||||
be randomly generated, and not conflict with any already in use. For
|
||||
now, let the OS do this."""
|
||||
return socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
||||
class TftpClient(TftpSession):
|
||||
"""This class is an implementation of a tftp client."""
|
||||
def __init__(self, host, port, options={}):
|
||||
|
|
Reference in a new issue