Download presentation
Presentation is loading. Please wait.
1
A Python TFTP server Bernie Network engineer
Needed a GUI driven TFTP server Wrote it several years ago when learning Python Was a god awful mess, but recently updated
2
TFTP -why? Trivial File Transfer Protocol
A way of passing files to and from a server in an easy fashion. Used to store and get Router and switch config files. No passwords, just an ip address of a server and: Get filename Put filename
3
GUI – why? No password access, so insecure
Network engineer needs a simple GUI driven server for his laptop, only enabled when needed Easy to install (standard library, pure python, no dependencies, put it anywhere and run) Easy to uninstall – delete directory and files Python 2 and Python 3 versions, Linux and Windows
4
TFTP - what? Trivial File Transfer Protocol TFTP - uses UDP port 69
TFTP Protocol (revision 2) RFC 1350 TFTP Option Extension RFC 2347 TFTP Blocksize Option RFC 2348 TFTP Timeout Interval and Transfer Size Options RFC 2349
5
Summary Client calls with a request to get or put a file
Server acknowledges Files transferred with acknowledgements, the acks contain an incrementing block count. UDP not TCP - connectionless Up to the application to create a 'connection' with acknowledgements, timeouts and error packets.
6
Uniquely identify the connection: 192.168.1.50/2002 - 192.168.1.1/69
Client Client 15037 2002 26004 69 69 69 Server Uniquely identify the connection: / /69 / /69 / /69
7
The problem A 'connection' is defined by:
Server address/port + Client address/port TFTP server listens on 69, but can reply on any port, creating a connection suitable for a threaded application. But not Firwall friendly If server replies with port 69, must implement multiplexing for simultaneous connections.
8
Asyncore UDP listenning socket Create a dispatcher class
Use __init__ to bind a socket Whenever asyncore.poll() is called: Dispatcher handle_read method called when data is available Dispatcher handle_write method called to send data
9
import asyncore, socket
class MyServer(asyncore.dispatcher): def __init__(self, local_addr, local_port): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_DGRAM) self.bind((local_addr, local_port)) def handle_read(self): rx_data, (addr,port) = self.recvfrom(1024) def handle_write(self): sent = self.sendto(tx_data, (addr,port)) def handle_connect(self): pass def handle_error(self):
10
myserver = MyServer(addr, port)
While True: asyncore.poll() myserver.close()
11
Read command line options and configuration file
Create server GUI? NO YES GUI Loop New Thread Server Loop EXIT
12
ServerState class Has an asyncore dispatcher class as an attribute
Maintains a dictionary of connections Each dictionary key is the remote client (address, port) tuple, and value is a 'Connection' object. Has a poll() method to call asyncore.poll() and also to check each connection for timeouts Maintains a text attribute, which can be read by a GUI and produces logs
13
Checks 'serving' attribute value and turns on and off dispatcher
ServerState Dispatcher Dictionary of Connections poll() method Checks 'serving' attribute value and turns on and off dispatcher So this can be changed by the GUI If serving: Calls asyncore.poll() Calls each connection poll() for each connection in the dictionary
14
Connection class On initialising, parses requested filename, sets options such as blksize, keeps blksize counter Has a poll method to check timeouts and re-tries Has a senddata method, called from the dispatcher handle_write method, to send any data in the tx_data attribute Acts as a parent to two child classes: SendData – for sending a file ReceiveData – for receiving a file
15
sends any data in tx_data poll() method checks timers
Connection class Parse filename Parse blksize option Keep blkcount send_data method sends any data in tx_data poll() method checks timers SendData class incoming_data method checks acknowledgements if ok reads file and puts data in tx_data ReceiveData class incoming_data method writes to file, creates acknowledgement and puts it in tx_data
16
SendData class Inherits from the Connection class
Opens the requested file for reading Has an incoming_data method which is called from the dispatcher handle_read method, and handles the acknowledgements from the remote client. Puts data read from the file into tx_data
17
ReceiveData class Inherits fromn the Connection class
Opens the requested file for writing Has an incoming_data method which is called from the dispatcher handle_read method, and handles the file data received from the remote client. Puts acknowledgements into tx_data
18
If remote ipaddress/port is a key in the connections dictionary
Dispatcher handle_read() If remote ipaddress/port is a key in the connections dictionary Call the connection.incoming_data() If not Create a new connections object either a SendData or a ReceiveData connection dependent on header in received packet handle_write() For each Connection object in the Dictionary If the connection object has data in its tx_data Attribute Call the connection.send_data()
19
If no response received within a timeout period
Connection.poll() Check timer If no response received within a timeout period re-transmit by setting tx_data to previous contents Or if too many timeouts, close the connection Stopwatch class Measures average response time between packets, and sets a TTL value used to measure if a timeout has occurred. So each connection instance uses a Stopwatch instance.
20
GUI Used Tkinter – note the font and general looks are much better with later versions of Python The gui loop is started in the main thread and has access to the ServerState instance to read/write attributes. The ServerState instance poll is called in a loop in a second thread. Any change to attributes are then acted upon in the poll() method, to keep everything thread safe.
21
Python 2 to 3 Bytes far better, much more clarity as the received data is a bytes object One gotcha which surprised me: >>>x = b'hello' >>>x[0] == b'h' False >>>x[0] 104
22
Tkinter structure changed
Python 2: import Tkinter, tkFileDialog, tkMessageBox Python 3: import tkinter, tkinter.filedialog, tkinter.messagebox
23
Threading Python 2: thread.start_new_thread(tftp_engine.loop, (server,)) Python 3: threading.Thread(target=tftp_engine.loop, args=(server,)).start()
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.