This repository has been archived on 2023-10-10. You can view files and clone it, but cannot push or open issues/pull-requests.
khepri-tftpy/tftpy/TftpShared.py

111 lines
3.6 KiB
Python
Raw Normal View History

import logging
LOG_LEVEL = logging.NOTSET
MIN_BLKSIZE = 8
DEF_BLKSIZE = 512
MAX_BLKSIZE = 65536
SOCK_TIMEOUT = 5
MAX_DUPS = 20
TIMEOUT_RETRIES = 5
DEF_TFTP_PORT = 69
# Initialize the logger.
logging.basicConfig(
level=LOG_LEVEL,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M:%S')
# The logger used by this library. Feel free to clobber it with your own, if you like, as
# long as it conforms to Python's logging.
logger = logging.getLogger('tftpy')
def tftpassert(condition, msg):
"""This function is a simple utility that will check the condition
passed for a false state. If it finds one, it throws a TftpException
with the message passed. This just makes the code throughout cleaner
by refactoring."""
if not condition:
raise TftpException, msg
def setLogLevel(level):
"""This function is a utility function for setting the internal log level.
The log level defaults to logging.NOTSET, so unwanted output to stdout is
not created."""
global logger
logger.setLevel(level)
class TftpErrors(object):
"""This class is a convenience for defining the common tftp error codes, and making
them more readable in the code."""
NotDefined = 0
FileNotFound = 1
AccessViolation = 2
DiskFull = 3
IllegalTftpOp = 4
UnknownTID = 5
FileAlreadyExists = 6
NoSuchUser = 7
FailedNegotiation = 8
class TftpException(Exception):
"""This class is the parent class of all exceptions regarding the handling
of the TFTP protocol."""
pass
class TftpState(object):
"""This class represents a particular state for a TFTP Session. It encapsulates a
state, kind of like an enum. The states mean the following:
nil - Client/Server - Session not yet established
rrq - Client - Just sent RRQ in a download, waiting for response
Server - Just received an RRQ
wrq - Client - Just sent WRQ in an upload, waiting for response
Server - Just received a WRQ
dat - Client/Server - Transferring data
oack - Client - Just received oack
Server - Just sent OACK
ack - Client - Acknowledged oack, awaiting response
Server - Just received ACK to OACK
err - Client/Server - Fatal problems, giving up
fin - Client/Server - Transfer completed
"""
states = ['nil',
'rrq',
'wrq',
'dat',
'oack',
'ack',
'err',
'fin']
def __init__(self, state='nil'):
self.state = state
def getState(self):
return self.__state
def setState(self, state):
if state in TftpState.states:
self.__state = state
state = property(getState, setState)
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."""
self.options = None
self.state = TftpState()
self.dups = 0
self.errors = 0
def senderror(self, sock, errorcode, address, port):
"""This method uses the socket passed, and uses the errorcode, address and port to
compose and send an error packet."""
logger.debug("In senderror, being asked to send error %d to %s:%s"
% (errorcode, address, port))
errpkt = TftpPacketERR()
errpkt.errorcode = errorcode
self.sock.sendto(errpkt.encode().buffer, (address, port))