in fbtftp/base_server.py [0:0]
def on_new_data(self):
"""
Deals with incoming RRQ packets. This is called by `run_once` when data
is available on the listening socket.
This method deals with extracting all the relevant information from the
request (like file, transfer mode, path, and options).
If all is good it will run the `get_handler` method, which returns a
`BaseHandler` object. `BaseHandler` is a subclass of a
`multiprocessing.Process` class so calling `start()` on it will cause
a `fork()`.
"""
data, peer = self._listener.recvfrom(constants.DEFAULT_BLKSIZE)
code = struct.unpack("!H", data[:2])[0]
if code != constants.OPCODE_RRQ:
logging.warning(
"unexpected TFTP opcode %d, expected %d" % (code, constants.OPCODE_RRQ)
)
return
# extract options
tokens = list(filter(bool, data[2:].decode("latin-1").split("\x00")))
if len(tokens) < 2 or len(tokens) % 2 != 0:
logging.error(
"Received malformed packet, ignoring "
"(tokens length: {tl})".format(tl=len(tokens))
)
return
path = tokens[0]
options = collections.OrderedDict(
[
("mode", tokens[1].lower()),
("default_timeout", self._timeout),
("retries", self._retries),
]
)
pos = 2
while pos < len(tokens):
options[tokens[pos].lower()] = tokens[pos + 1]
pos += 2
# fork a child process
try:
proc = self.get_handler((self._address, self._port), peer, path, options)
if proc is None:
logging.warning(
"The handler is null! Not serving the request from %s", peer
)
return
proc.daemon = True
proc.start()
except Exception as e:
logging.error(
"creating a handler for %r raised an exception %s" % (path, e)
)
logging.error(traceback.format_exc())
# Increment number of spawned TFTP workers in stats time frame
self._server_stats.increment_counter("process_count")