summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelie <elie>2009-07-31 19:55:03 +0000
committerelie <elie>2009-07-31 19:55:03 +0000
commit35ab3f1b8534b1d99b5163e9f2ea0f9552de21f4 (patch)
treef631e241745feae906aa4c13839c0e6ce9aa7375
parent0d5efc682b4f7b6ce7775d97e3b5f38b83590d60 (diff)
downloadpysnmp-35ab3f1b8534b1d99b5163e9f2ea0f9552de21f4.tar.gz
Twisted support implemented
-rw-r--r--THANKS1
-rw-r--r--examples/v3arch/twisted/agent/ntforg.py88
-rw-r--r--examples/v3arch/twisted/manager/bulkgen.py73
-rw-r--r--examples/v3arch/twisted/manager/getgen.py62
-rw-r--r--examples/v3arch/twisted/manager/nextgen.py73
-rw-r--r--examples/v3arch/twisted/manager/ntfrcv.py48
-rw-r--r--examples/v3arch/twisted/manager/setgen.py64
-rw-r--r--pysnmp/carrier/twisted/__init__.py0
-rw-r--r--pysnmp/carrier/twisted/base.py26
-rw-r--r--pysnmp/carrier/twisted/dgram/__init__.py0
-rw-r--r--pysnmp/carrier/twisted/dgram/base.py44
-rw-r--r--pysnmp/carrier/twisted/dgram/udp.py25
-rw-r--r--pysnmp/carrier/twisted/dgram/unix.py26
-rw-r--r--pysnmp/carrier/twisted/dispatch.py53
-rw-r--r--pysnmp/entity/rfc3413/twisted/__init__.py0
-rw-r--r--pysnmp/entity/rfc3413/twisted/cmdgen.py202
-rw-r--r--pysnmp/entity/rfc3413/twisted/ntforg.py32
-rw-r--r--setup.py3
18 files changed, 820 insertions, 0 deletions
diff --git a/THANKS b/THANKS
index b1b4d91..df55fb7 100644
--- a/THANKS
+++ b/THANKS
@@ -22,6 +22,7 @@ Ivan Zderadicka
Randy Couey
Brian Kyckelhahn
Mark M Evans
+Filippo Giunchedi at Truelite Srl
Thanks to Python Software Foundation for granting financial support
for the project.
diff --git a/examples/v3arch/twisted/agent/ntforg.py b/examples/v3arch/twisted/agent/ntforg.py
new file mode 100644
index 0000000..77df949
--- /dev/null
+++ b/examples/v3arch/twisted/agent/ntforg.py
@@ -0,0 +1,88 @@
+# Notification originator
+from twisted.internet import reactor
+from pysnmp.entity import engine, config
+from pysnmp.carrier.twisted import dispatch
+from pysnmp.carrier.twisted.dgram import udp
+from pysnmp.entity.rfc3413 import context
+from pysnmp.entity.rfc3413.twisted import ntforg
+from pysnmp.proto.api import v2c
+
+# Send either Teap or Inform request
+doInform = 1
+
+snmpEngine = engine.SnmpEngine()
+
+# Set Twisted dispatcher
+snmpEngine.registerTransportDispatcher(dispatch.TwistedDispatcher())
+
+# v1/2 setup
+config.addV1System(snmpEngine, 'test-agent', 'public')
+
+# v3 setup
+config.addV3User(
+ snmpEngine, 'test-user',
+ config.usmHMACMD5AuthProtocol, 'authkey1',
+ config.usmDESPrivProtocol, 'privkey1'
+ )
+
+# Transport params
+config.addTargetParams(snmpEngine, 'myParams', 'test-user', 'authPriv')
+#config.addTargetParams(snmpEngine, 'myParams', 'test-agent', 'noAuthNoPriv', 1)
+
+# Transport addresses
+config.addTargetAddr(
+ snmpEngine, 'myNMS', config.snmpUDPDomain,
+ ('127.0.0.1', 162), 'myParams', tagList='myManagementStations'
+ )
+
+# Notification targets
+if doInform:
+ config.addNotificationTarget(
+ snmpEngine, 'myNotifyName', 'myParams','myManagementStations','inform'
+ )
+else:
+ config.addNotificationTarget(
+ snmpEngine, 'myNotifyName', 'myParams', 'myManagementStations', 'trap'
+ )
+
+# Transport
+config.addSocketTransport(
+ snmpEngine,
+ udp.domainName,
+ udp.UdpTwistedTransport().openClientMode()
+ )
+
+# Agent-side VACM setup
+config.addContext(snmpEngine, '')
+config.addVacmUser(snmpEngine, 1, 'test-agent', 'noAuthNoPriv',
+ (), (), (1,3,6)) # v1
+config.addVacmUser(snmpEngine, 2, 'test-agent', 'noAuthNoPriv',
+ (), (), (1,3,6)) # v2c
+config.addVacmUser(snmpEngine, 3, 'test-user', 'authPriv',
+ (), (), (1,3,6)) # v3
+
+# SNMP context
+snmpContext = context.SnmpContext(snmpEngine)
+
+# Twisted API follows
+
+def receiveResponse((sendRequestHandle, errorIndication)):
+ if errorIndication:
+ print 'Error: ', errorIndication
+ reactor.stop()
+
+ntfOrg = ntforg.NotificationOriginator(snmpContext)
+
+df = ntfOrg.sendNotification(
+ snmpEngine,
+ # Notification targets
+ 'myNotifyName',
+ # Trap OID (SNMPv2-MIB::coldStart)
+ (1,3,6,1,6,3,1,1,5,1),
+ # ((oid, value), ... )
+ (((1,3,6,1,2,1,1,5), v2c.OctetString('Example Notificator')),)
+ )
+
+if doInform:
+ df.addCallback(receiveResponse)
+ reactor.run()
diff --git a/examples/v3arch/twisted/manager/bulkgen.py b/examples/v3arch/twisted/manager/bulkgen.py
new file mode 100644
index 0000000..96201ac
--- /dev/null
+++ b/examples/v3arch/twisted/manager/bulkgen.py
@@ -0,0 +1,73 @@
+# BULK Command Generator
+from twisted.internet import reactor, defer
+from pysnmp.entity import engine, config
+from pysnmp.carrier.twisted import dispatch
+from pysnmp.carrier.twisted.dgram import udp
+from pysnmp.entity.rfc3413.twisted import cmdgen
+
+snmpEngine = engine.SnmpEngine()
+
+# Set Twisted dispatcher
+snmpEngine.registerTransportDispatcher(dispatch.TwistedDispatcher())
+
+# v1/2 setup
+config.addV1System(snmpEngine, 'test-agent', 'public')
+
+# v3 setup
+config.addV3User(
+ snmpEngine, 'test-user',
+ config.usmHMACMD5AuthProtocol, 'authkey1',
+ config.usmDESPrivProtocol, 'privkey1'
+ )
+
+# Transport params
+config.addTargetParams(snmpEngine, 'myParams', 'test-user', 'authPriv')
+#config.addTargetParams(snmpEngine, 'myParams', 'test-agent', 'noAuthNoPriv', 1)
+
+# Transport addresses
+config.addTargetAddr(
+ snmpEngine, 'myRouter', config.snmpUDPDomain,
+ ('127.0.0.1', 161), 'myParams'
+ )
+
+# Transport
+config.addSocketTransport(
+ snmpEngine,
+ udp.domainName,
+ udp.UdpTwistedTransport().openClientMode()
+ )
+
+# Twisted API follows
+
+def receiveResponse(
+ (errorIndication, errorStatus, errorIndex, varBindTable),
+ bulkCmdGen, snmpEngine):
+ if errorIndication or errorStatus:
+ print 'Error: ', errorIndication, errorStatus.prettyPrint(), errorIndex
+ reactor.stop()
+ return
+ for varBindRow in varBindTable:
+ for oid, val in varBindRow:
+ if val is None:
+ print oid.prettyPrint()
+ else:
+ print '%s = %s' % (oid.prettyPrint(), val.prettyPrint())
+ for oid, val in varBindTable[-1]:
+ if val is not None:
+ df = bulkCmdGen.sendReq(
+ snmpEngine, 'myRouter', 0, 25, varBindTable[-1]
+ )
+ df.addCallback(receiveResponse, bulkCmdGen, snmpEngine)
+ return
+ else:
+ reactor.stop()
+
+bulkCmdGen = cmdgen.BulkCommandGenerator()
+
+df = bulkCmdGen.sendReq(
+ snmpEngine, 'myRouter', 0, 25, (((1,3,6,1,2), None),)
+ )
+
+df.addCallback(receiveResponse, bulkCmdGen, snmpEngine)
+
+reactor.run()
diff --git a/examples/v3arch/twisted/manager/getgen.py b/examples/v3arch/twisted/manager/getgen.py
new file mode 100644
index 0000000..a2cb9a4
--- /dev/null
+++ b/examples/v3arch/twisted/manager/getgen.py
@@ -0,0 +1,62 @@
+# GET Command Generator
+from twisted.internet import reactor, defer
+from pysnmp.entity import engine, config
+from pysnmp.carrier.twisted import dispatch
+from pysnmp.carrier.twisted.dgram import udp
+from pysnmp.entity.rfc3413.twisted import cmdgen
+
+snmpEngine = engine.SnmpEngine()
+
+# Set Twisted dispatcher
+snmpEngine.registerTransportDispatcher(dispatch.TwistedDispatcher())
+
+# v1/2 setup
+config.addV1System(snmpEngine, 'test-agent', 'public')
+
+# v3 setup
+config.addV3User(
+ snmpEngine, 'test-user',
+ config.usmHMACMD5AuthProtocol, 'authkey1',
+ config.usmDESPrivProtocol, 'privkey1'
+ )
+
+# Transport params
+config.addTargetParams(snmpEngine, 'myParams', 'test-user', 'authPriv')
+#config.addTargetParams(snmpEngine, 'myParams', 'test-agent', 'noAuthNoPriv', 1)
+
+# Transport addresses
+config.addTargetAddr(
+ snmpEngine, 'myRouter', config.snmpUDPDomain,
+ ('127.0.0.1', 161), 'myParams'
+ )
+
+# Transport
+config.addSocketTransport(
+ snmpEngine,
+ udp.domainName,
+ udp.UdpTwistedTransport().openClientMode()
+ )
+
+# Twisted API follows
+
+def receiveResponse((errorIndication, errorStatus, errorIndex, varBinds)):
+ if errorIndication or errorStatus:
+ print 'Error: ', errorIndication, errorStatus.prettyPrint(), errorIndex
+ reactor.stop()
+ return
+ for oid, val in varBinds:
+ if val is None:
+ print oid.prettyPrint()
+ else:
+ print '%s = %s' % (oid.prettyPrint(), val.prettyPrint())
+ reactor.stop()
+
+getCmdGen = cmdgen.GetCommandGenerator()
+
+df = getCmdGen.sendReq(
+ snmpEngine, 'myRouter', (((1,3,6,1,2,1,1,1,0), None),)
+ )
+
+df.addCallback(receiveResponse)
+
+reactor.run()
diff --git a/examples/v3arch/twisted/manager/nextgen.py b/examples/v3arch/twisted/manager/nextgen.py
new file mode 100644
index 0000000..8fdc3a8
--- /dev/null
+++ b/examples/v3arch/twisted/manager/nextgen.py
@@ -0,0 +1,73 @@
+# GETNEXT Command Generator
+from twisted.internet import reactor, defer
+from pysnmp.entity import engine, config
+from pysnmp.carrier.twisted import dispatch
+from pysnmp.carrier.twisted.dgram import udp
+from pysnmp.entity.rfc3413.twisted import cmdgen
+
+snmpEngine = engine.SnmpEngine()
+
+# Set Twisted dispatcher
+snmpEngine.registerTransportDispatcher(dispatch.TwistedDispatcher())
+
+# v1/2 setup
+config.addV1System(snmpEngine, 'test-agent', 'public')
+
+# v3 setup
+config.addV3User(
+ snmpEngine, 'test-user',
+ config.usmHMACMD5AuthProtocol, 'authkey1',
+ config.usmDESPrivProtocol, 'privkey1'
+ )
+
+# Transport params
+config.addTargetParams(snmpEngine, 'myParams', 'test-user', 'authPriv')
+#config.addTargetParams(snmpEngine, 'myParams', 'test-agent', 'noAuthNoPriv', 1)
+
+# Transport addresses
+config.addTargetAddr(
+ snmpEngine, 'myRouter', config.snmpUDPDomain,
+ ('127.0.0.1', 161), 'myParams'
+ )
+
+# Transport
+config.addSocketTransport(
+ snmpEngine,
+ udp.domainName,
+ udp.UdpTwistedTransport().openClientMode()
+ )
+
+# Twisted API follows
+
+def receiveResponse(
+ (errorIndication, errorStatus, errorIndex, varBindTable),
+ nextCmdGen, snmpEngine):
+ if errorIndication or errorStatus:
+ print 'Error: ', errorIndication, errorStatus.prettyPrint(), errorIndex
+ reactor.stop()
+ return
+ for varBindRow in varBindTable:
+ for oid, val in varBindRow:
+ if val is None:
+ print oid.prettyPrint()
+ else:
+ print '%s = %s' % (oid.prettyPrint(), val.prettyPrint())
+ for oid, val in varBindTable[-1]:
+ if val is not None:
+ df = nextCmdGen.sendReq(
+ snmpEngine, 'myRouter', varBindTable[-1]
+ )
+ df.addCallback(receiveResponse, nextCmdGen, snmpEngine)
+ return
+ else:
+ reactor.stop()
+
+nextCmdGen = cmdgen.NextCommandGenerator()
+
+df = nextCmdGen.sendReq(
+ snmpEngine, 'myRouter', (((1,3,6,1,2,1,1), None),)
+ )
+
+df.addCallback(receiveResponse, nextCmdGen, snmpEngine)
+
+reactor.run()
diff --git a/examples/v3arch/twisted/manager/ntfrcv.py b/examples/v3arch/twisted/manager/ntfrcv.py
new file mode 100644
index 0000000..61bb5ca
--- /dev/null
+++ b/examples/v3arch/twisted/manager/ntfrcv.py
@@ -0,0 +1,48 @@
+# Notification Receiver (TRAP/INFORM)
+from twisted.internet import reactor
+from pysnmp.entity import engine, config
+from pysnmp.carrier.twisted import dispatch
+from pysnmp.carrier.twisted.dgram import udp
+from pysnmp.entity.rfc3413 import ntfrcv
+
+# Create SNMP engine with autogenernated engineID and pre-bound
+# to socket transport dispatcher
+snmpEngine = engine.SnmpEngine()
+
+# Set Twisted dispatcher
+snmpEngine.registerTransportDispatcher(dispatch.TwistedDispatcher())
+
+# v1/2 setup
+config.addV1System(snmpEngine, 'test-agent', 'public')
+
+# v3 setup
+config.addV3User(
+ snmpEngine, 'test-user',
+ config.usmHMACMD5AuthProtocol, 'authkey1',
+ config.usmDESPrivProtocol, 'privkey1'
+ )
+
+# Transport
+config.addSocketTransport(
+ snmpEngine,
+ udp.domainName,
+ udp.UdpTwistedTransport().openServerMode(('127.0.0.1', 1162))
+ )
+
+# Callback function for receiving notifications
+def cbFun(snmpEngine,
+ stateReference,
+ contextEngineId, contextName,
+ varBinds,
+ cbCtx):
+ transportDomain, transportAddress = snmpEngine.msgAndPduDsp.getTransportInfo(stateReference)
+ print 'Notification from %s, SNMP Engine \"%s\", Context \"%s\"' % (
+ transportAddress, contextEngineId, contextName
+ )
+ for name, val in varBinds:
+ print '%s = %s' % (name.prettyPrint(), val.prettyPrint())
+
+# Apps registration
+ntfrcv.NotificationReceiver(snmpEngine, cbFun)
+
+reactor.run()
diff --git a/examples/v3arch/twisted/manager/setgen.py b/examples/v3arch/twisted/manager/setgen.py
new file mode 100644
index 0000000..4bdac57
--- /dev/null
+++ b/examples/v3arch/twisted/manager/setgen.py
@@ -0,0 +1,64 @@
+# SET Command Generator
+from twisted.internet import reactor, defer
+from pysnmp.entity import engine, config
+from pysnmp.carrier.twisted import dispatch
+from pysnmp.carrier.twisted.dgram import udp
+from pysnmp.entity.rfc3413.twisted import cmdgen
+from pysnmp.proto import rfc1902
+
+snmpEngine = engine.SnmpEngine()
+
+# Set Twisted dispatcher
+snmpEngine.registerTransportDispatcher(dispatch.TwistedDispatcher())
+
+# v1/2 setup
+config.addV1System(snmpEngine, 'test-agent', 'public')
+
+# v3 setup
+config.addV3User(
+ snmpEngine, 'test-user',
+ config.usmHMACMD5AuthProtocol, 'authkey1',
+ config.usmDESPrivProtocol, 'privkey1'
+ )
+
+# Transport params
+config.addTargetParams(snmpEngine, 'myParams', 'test-user', 'authPriv')
+#config.addTargetParams(snmpEngine, 'myParams', 'test-agent', 'noAuthNoPriv', 1)
+
+# Transport addresses
+config.addTargetAddr(
+ snmpEngine, 'myRouter', config.snmpUDPDomain,
+ ('127.0.0.1', 161), 'myParams'
+ )
+
+# Transport
+config.addSocketTransport(
+ snmpEngine,
+ udp.domainName,
+ udp.UdpTwistedTransport().openClientMode()
+ )
+
+# Twisted API follows
+
+def receiveResponse((errorIndication, errorStatus, errorIndex, varBinds)):
+ if errorIndication or errorStatus:
+ print 'Error: ', errorIndication, errorStatus.prettyPrint(), errorIndex
+ reactor.stop()
+ return
+ for oid, val in varBinds:
+ if val is None:
+ print oid.prettyPrint()
+ else:
+ print '%s = %s' % (oid.prettyPrint(), val.prettyPrint())
+ reactor.stop()
+
+getCmdGen = cmdgen.SetCommandGenerator()
+
+df = getCmdGen.sendReq(
+ snmpEngine, 'myRouter',
+ (((1,3,6,1,2,1,1,1,0), rfc1902.OctetString('Grinch')),)
+ )
+
+df.addCallback(receiveResponse)
+
+reactor.run()
diff --git a/pysnmp/carrier/twisted/__init__.py b/pysnmp/carrier/twisted/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pysnmp/carrier/twisted/__init__.py
diff --git a/pysnmp/carrier/twisted/base.py b/pysnmp/carrier/twisted/base.py
new file mode 100644
index 0000000..ecceaca
--- /dev/null
+++ b/pysnmp/carrier/twisted/base.py
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2008 Truelite Srl <info@truelite.it>
+# Author: Filippo Giunchedi <filippo@truelite.it>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License Version 2
+# as published by the Free Software Foundation
+#
+# Description: twisted DatagramProtocol UDP transport
+#
+
+class AbstractTwistedTransport:
+ """Base Twisted Transport, to be used with TwistedDispatcher"""
+ def __init__(self):
+ self._writeQ = []
+
+ # AbstractTwistedTransport API
+
+ def registerCbFun(self, cbFun):
+ self._cbFun = cbFun
+
+ def unregisterCbFun(self):
+ self._cbFun = None
+
+ def closeTransport(self):
+ self.unregisterCbFun()
diff --git a/pysnmp/carrier/twisted/dgram/__init__.py b/pysnmp/carrier/twisted/dgram/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pysnmp/carrier/twisted/dgram/__init__.py
diff --git a/pysnmp/carrier/twisted/dgram/base.py b/pysnmp/carrier/twisted/dgram/base.py
new file mode 100644
index 0000000..75dd455
--- /dev/null
+++ b/pysnmp/carrier/twisted/dgram/base.py
@@ -0,0 +1,44 @@
+"""Implements twisted-based generic DGRAM transport"""
+from time import time
+from twisted.internet.protocol import DatagramProtocol
+from twisted.internet import reactor
+from pysnmp.carrier.twisted.base import AbstractTwistedTransport
+from pysnmp.carrier import error
+from pysnmp import debug
+
+class DgramTwistedTransport(DatagramProtocol, AbstractTwistedTransport):
+ """Base Twisted datagram Transport, to be used with TwistedDispatcher"""
+
+ # Twisted Datagram API
+
+ def datagramReceived(self, datagram, address):
+ if self._cbFun is None:
+ raise error.CarrierError('Unable to call cbFun')
+ else:
+ # Callback fun is called through callLater() in attempt
+ # to make Twisted timed calls work under high load.
+ reactor.callLater(0, self._cbFun, self, address, datagram)
+
+ def startProtocol(self):
+ debug.logger & debug.flagIO and debug.logger('startProtocol: invoked')
+ while self._writeQ:
+ outgoingMessage, transportAddress = self._writeQ.pop(0)
+ debug.logger & debug.flagIO and debug.logger('startProtocol: transportAddress %s outgoingMessage %s' % (transportAddress, repr(outgoingMessage)))
+ try:
+ self.transport.write(outgoingMessage, transportAddress)
+ except Exception, why:
+ raise error.CarrierError('Twisted exception: %s' % (why,))
+
+ def stopProtocol(self):
+ debug.logger & debug.flagIO and debug.logger('stopProtocol: invoked')
+ self.closeTransport()
+
+ def sendMessage(self, outgoingMessage, transportAddress):
+ debug.logger & debug.flagIO and debug.logger('startProtocol: %s transportAddress %s outgoingMessage %s' % ((self.transport is None and "queuing" or "sending"), transportAddress, repr(outgoingMessage)))
+ if self.transport is None:
+ self._writeQ.append((outgoingMessage, transportAddress))
+ else:
+ try:
+ self.transport.write(outgoingMessage, transportAddress)
+ except Exception, why:
+ raise error.CarrierError('Twisted exception: %s' % (why,))
diff --git a/pysnmp/carrier/twisted/dgram/udp.py b/pysnmp/carrier/twisted/dgram/udp.py
new file mode 100644
index 0000000..850ff1b
--- /dev/null
+++ b/pysnmp/carrier/twisted/dgram/udp.py
@@ -0,0 +1,25 @@
+"""Implements twisted-based UDP transport"""
+from twisted.internet import reactor
+from pysnmp.carrier.twisted.dgram.base import DgramTwistedTransport
+from pysnmp.carrier import error
+
+domainName = snmpUDPDomain = (1, 3, 6, 1, 6, 1, 1)
+
+class UdpTwistedTransport(DgramTwistedTransport):
+ # AbstractTwistedTransport API
+
+ def openClientMode(self, iface=''):
+ try:
+ self._lport = reactor.listenUDP(0, self, iface)
+ except Exception, why:
+ raise error.CarrierError(why)
+ return self
+
+ def openServerMode(self, iface=None):
+ try:
+ self._lport = reactor.listenUDP(iface[1], self, iface[0])
+ except Exception, why:
+ raise error.CarrierError(why)
+ return self
+
+UdpTransport = UdpTwistedTransport \ No newline at end of file
diff --git a/pysnmp/carrier/twisted/dgram/unix.py b/pysnmp/carrier/twisted/dgram/unix.py
new file mode 100644
index 0000000..75bfe17
--- /dev/null
+++ b/pysnmp/carrier/twisted/dgram/unix.py
@@ -0,0 +1,26 @@
+"""Implements twisted-based UNIX domain socket transport"""
+from twisted.internet import reactor
+from pysnmp.carrier.twisted.dgram.base import DgramTwistedTransport
+from pysnmp.carrier import error
+
+domainName = snmpLocalDomain = (1, 3, 6, 1, 2, 1, 100, 1, 13)
+
+class UnixTwistedTransport(DgramTwistedTransport):
+ # AbstractTwistedTransport API
+
+ def openClientMode(self, iface=''):
+ try:
+ self._lport = reactor.connectUNIXDatagram(iface, self)
+ except Exception, why:
+ raise error.CarrierError(why)
+ return self
+
+ def openServerMode(self, iface=None):
+ try:
+ self._lport = reactor.listenUNIXDatagram(iface, self)
+ except Exception, why:
+ raise error.CarrierError(why)
+
+ return self
+
+UnixTransport = UnixTwistedTransport \ No newline at end of file
diff --git a/pysnmp/carrier/twisted/dispatch.py b/pysnmp/carrier/twisted/dispatch.py
new file mode 100644
index 0000000..36b4ccc
--- /dev/null
+++ b/pysnmp/carrier/twisted/dispatch.py
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2008 Truelite Srl <info@truelite.it>
+# Author: Filippo Giunchedi <filippo@truelite.it>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License Version 2
+# as published by the Free Software Foundation
+#
+# Description: Transport dispatcher based on twisted.internet.reactor
+#
+from time import time
+from twisted.internet import reactor, task
+from pysnmp.carrier.base import AbstractTransportDispatcher
+from pysnmp.carrier import error
+
+class TwistedDispatcher(AbstractTransportDispatcher):
+ """TransportDispatcher based on twisted.internet.reactor"""
+ def __init__(self, *args, **kwargs):
+ AbstractTransportDispatcher.__init__(self)
+ self.__transportCount = 0
+ self.timeout = kwargs.get('timeout', 1.0)
+ self.loopingcall = task.LoopingCall(self.handleTimeout)
+
+ def handleTimeout(self):
+ self.handleTimerTick(time())
+
+ def runDispatcher(self, timeout=0.0):
+ if not reactor.running:
+ try:
+ reactor.run()
+ except Exception, why:
+ raise error.CarrierError(why)
+
+ # jobstarted/jobfinished might be okay as-is
+
+ def registerTransport(self, tDomain, transport):
+ if not self.loopingcall.running and self.timeout > 0:
+ self.loopingcall.start(self.timeout, now = False)
+ AbstractTransportDispatcher.registerTransport(
+ self, tDomain, transport
+ )
+ self.__transportCount = self.__transportCount + 1
+
+ def unregisterTransport(self, tDomain):
+ t = AbstractTransportDispatcher.getTransport(self, tDomain)
+ if t is not None:
+ AbstractTransportDispatcher.unregisterTransport(self, tDomain)
+ t.closeTransport()
+ self.__transportCount = self.__transportCount - 1
+
+ # The last transport has been removed, stop the timeout
+ if self.__transportCount > 0 and self.loopingcall.running:
+ self.loopingcall.stop()
diff --git a/pysnmp/entity/rfc3413/twisted/__init__.py b/pysnmp/entity/rfc3413/twisted/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pysnmp/entity/rfc3413/twisted/__init__.py
diff --git a/pysnmp/entity/rfc3413/twisted/cmdgen.py b/pysnmp/entity/rfc3413/twisted/cmdgen.py
new file mode 100644
index 0000000..297c49d
--- /dev/null
+++ b/pysnmp/entity/rfc3413/twisted/cmdgen.py
@@ -0,0 +1,202 @@
+from twisted.internet import reactor, defer
+from pysnmp.entity.rfc3413 import cmdgen
+
+class GetCommandGenerator(cmdgen.GetCommandGenerator):
+ def sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ varBinds,
+ contextEngineId=None,
+ contextName=''
+ ):
+ df = defer.Deferred()
+ cmdgen.GetCommandGenerator.sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ varBinds,
+ None,
+ df,
+ contextEngineId,
+ contextName
+ )
+ return df
+
+ def _handleResponse(
+ self,
+ snmpEngine,
+ transportDomain,
+ transportAddress,
+ messageProcessingModel,
+ securityModel,
+ securityName,
+ securityLevel,
+ contextEngineId,
+ contextName,
+ pduVersion,
+ PDU,
+ timeout,
+ retryCount,
+ pMod,
+ rspPDU,
+ sendRequestHandle,
+ (cbFun, cbCtx)
+ ):
+ cbCtx.callback(
+ (None,
+ pMod.apiPDU.getErrorStatus(rspPDU),
+ pMod.apiPDU.getErrorIndex(rspPDU),
+ pMod.apiPDU.getVarBinds(rspPDU))
+ )
+
+class SetCommandGenerator(cmdgen.SetCommandGenerator):
+ def sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ varBinds,
+ contextEngineId=None,
+ contextName=''
+ ):
+ df = defer.Deferred()
+ cmdgen.SetCommandGenerator.sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ varBinds,
+ None,
+ df,
+ contextEngineId,
+ contextName
+ )
+ return df
+
+ def _handleResponse(
+ self,
+ snmpEngine,
+ transportDomain,
+ transportAddress,
+ messageProcessingModel,
+ securityModel,
+ securityName,
+ securityLevel,
+ contextEngineId,
+ contextName,
+ pduVersion,
+ PDU,
+ timeout,
+ retryCount,
+ pMod,
+ rspPDU,
+ sendRequestHandle,
+ (cbFun, cbCtx)
+ ):
+ cbCtx.callback(
+ (None,
+ pMod.apiPDU.getErrorStatus(rspPDU),
+ pMod.apiPDU.getErrorIndex(rspPDU),
+ pMod.apiPDU.getVarBinds(rspPDU))
+ )
+
+class NextCommandGenerator(cmdgen.NextCommandGenerator):
+ def sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ varBinds,
+ contextEngineId=None,
+ contextName=''
+ ):
+ df = defer.Deferred()
+ cmdgen.NextCommandGenerator.sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ varBinds,
+ None,
+ df,
+ contextEngineId,
+ contextName
+ )
+ return df
+
+ def _handleResponse(
+ self,
+ snmpEngine,
+ transportDomain,
+ transportAddress,
+ messageProcessingModel,
+ securityModel,
+ securityName,
+ securityLevel,
+ contextEngineId,
+ contextName,
+ pduVersion,
+ PDU,
+ timeout,
+ retryCount,
+ pMod,
+ rspPDU,
+ sendRequestHandle,
+ (cbFun, cbCtx)
+ ):
+ cbCtx.callback(
+ (None,
+ pMod.apiPDU.getErrorStatus(rspPDU),
+ pMod.apiPDU.getErrorIndex(rspPDU),
+ pMod.apiPDU.getVarBindTable(PDU, rspPDU))
+ )
+
+class BulkCommandGenerator(cmdgen.BulkCommandGenerator):
+ def sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ nonRepeaters,
+ maxRepetitions,
+ varBinds,
+ contextEngineId=None,
+ contextName=''
+ ):
+ df = defer.Deferred()
+ cmdgen.BulkCommandGenerator.sendReq(
+ self,
+ snmpEngine,
+ addrName,
+ nonRepeaters,
+ maxRepetitions,
+ varBinds,
+ None,
+ df,
+ contextEngineId=None,
+ contextName=''
+ )
+ return df
+
+ def _handleResponse(
+ self,
+ snmpEngine,
+ transportDomain,
+ transportAddress,
+ messageProcessingModel,
+ securityModel,
+ securityName,
+ securityLevel,
+ contextEngineId,
+ contextName,
+ pduVersion,
+ PDU,
+ timeout,
+ retryCount,
+ pMod,
+ rspPDU,
+ sendRequestHandle,
+ (cbFun, cbCtx)
+ ):
+ cbCtx.callback(
+ (None,
+ pMod.apiBulkPDU.getErrorStatus(rspPDU),
+ pMod.apiBulkPDU.getErrorIndex(rspPDU),
+ pMod.apiBulkPDU.getVarBindTable(PDU, rspPDU))
+ )
diff --git a/pysnmp/entity/rfc3413/twisted/ntforg.py b/pysnmp/entity/rfc3413/twisted/ntforg.py
new file mode 100644
index 0000000..e02f2ab
--- /dev/null
+++ b/pysnmp/entity/rfc3413/twisted/ntforg.py
@@ -0,0 +1,32 @@
+from twisted.internet import reactor, defer
+from pysnmp.entity.rfc3413 import ntforg
+
+class NotificationOriginator(ntforg.NotificationOriginator):
+ def sendNotification(
+ self,
+ snmpEngine,
+ notificationTarget,
+ notificationName,
+ additionalVarBinds=None,
+ contextName=''
+ ):
+ df = defer.Deferred()
+ ntforg.NotificationOriginator.sendNotification(
+ self,
+ snmpEngine,
+ notificationTarget,
+ notificationName,
+ additionalVarBinds,
+ None,
+ df,
+ contextName=''
+ )
+ return df
+
+ def _handleResponse(
+ self,
+ sendRequestHandle,
+ errorIndication,
+ cbFun,
+ cbCtx):
+ cbCtx.callback((sendRequestHandle, errorIndication))
diff --git a/setup.py b/setup.py
index c4a0187..08d379f 100644
--- a/setup.py
+++ b/setup.py
@@ -15,9 +15,12 @@ setup(name="pysnmp",
'pysnmp.v4.carrier',
'pysnmp.v4.carrier.asynsock',
'pysnmp.v4.carrier.asynsock.dgram',
+ 'pysnmp.v4.carrier.twisted',
+ 'pysnmp.v4.carrier.twisted.dgram',
'pysnmp.v4.entity',
'pysnmp.v4.entity.rfc3413',
'pysnmp.v4.entity.rfc3413.oneliner',
+ 'pysnmp.v4.entity.rfc3413.twisted',
'pysnmp.v4.proto',
'pysnmp.v4.proto.mpmod',
'pysnmp.v4.proto.secmod',