import time
import string
import socket
from types import ClassType
import asyncore
import asynchat
import getopt
# Import PySNMP modules
from pysnmp import asn1, v1, v2c
from pysnmp import asynrole, error
# Initialize a dictionary of running telnet engines
global_engines = {}
class telnet_engine(asynchat.async_chat):
"""Telnet engine class. Implements command line user interface and
SNMP request queue management.
Each new SNMP request message context is put into a pool of pending
requests. As response arrives, it's matched against each of pending
message contexts.
"""
def __init__ (self, sock):
# Call constructor of the parent class
asynchat.async_chat.__init__ (self, sock)
# Set up input line terminator
self.set_terminator ('\n')
# Initialize input data buffer
self.data = ''
# Create async SNMP transport manager
self.manager = asynrole.manager(self.request_done_fun)
# A queue of pending requests
self.pending = []
# Run our own source of SNMP message serial number to preserve its
# sequentiality
self.request_id = 1
# Register this instance of telnet engine at a global dictionary
# used for their periodic invocations for timeout purposes
global_engines[self] = 1
# User interface goodies
self.prompt = 'query> '
self.welcome = 'Example Telnet server / SNMP manager ready.\n'
# Commands help messages
commands = 'Commands:\n'
for mod in (v1, v2c):
rtypes = dir(mod)
for rtype in rtypes:
if rtype[-7:] == 'REQUEST':
commands = commands + ' ' + '%-14s' % rtype[:-7] + \
' issue SNMP (%s) %s request\n' % \
(mod.__name__[7:], rtype[:-7])
# Options help messages
options = 'Options:\n'
options = options + ' -p port to communicate with at the agent. Default is 161.\n'
options = options + ' -t response timeout. Default is 1.'
self.usage = 'Syntax: [options] ' + str(val) + '\n'
# Send reply back to user
self.push(reply + self.prompt)
def tick(self, now):
"""This method gets invoked periodically from upper scope for
generic housekeeping purposes.
"""
# Walk over pending message context
for (req, dst, expire) in self.pending:
# Expire long pending contexts
if expire < now:
# Send a notice on expired request context
self.push('WARNING: expiring long pending request %s destined %s\n' % (req, dst))
# Expire context
self.pending.remove((req, dst, expire))
class telnet_server(asyncore.dispatcher):
"""Telnet server class. Listens for incoming requests and creates
instances of telnet engine classes for handling new session.
"""
def __init__(self, port=8989):
"""Takes optional TCP port number for the server to bind to.
"""
# Call parent class constructor explicitly
asyncore.dispatcher.__init__(self)
# Create socket of requested type
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
# Set it to re-use address
self.set_reuse_addr()
# Bind to all interfaces of this host at specified port
self.bind(('', port))
# Start listening for incoming requests
self.listen(5)
def handle_accept(self):
"""Called by asyncore engine when new connection arrives
"""
# Accept new connection
(sock, addr) = self.accept()
# Create an instance of Telnet engine class to handle this new user
# session and pass it socket object to use any further
telnet_engine(sock)
# Run the module if it's invoked for execution
if __name__ == '__main__':
# Create an instance of Telnet superserver
server = telnet_server ()
# Start the select() I/O multiplexing loop
while 1:
# Deliver 'tick' event to every instance of telnet engine
map(lambda x: x.tick(time.time()), global_engines.keys())
# Do the I/O on active sockets
asyncore.poll(1.0)
Need help? Try PySNMP mailing lists.
|