summaryrefslogtreecommitdiff
path: root/pysnmp/carrier
diff options
context:
space:
mode:
authorelie <elie>2014-11-04 20:21:48 +0000
committerelie <elie>2014-11-04 20:21:48 +0000
commit2badd13fbc5a16806170deb432a1aeee03b74905 (patch)
tree8ed445ae7de8572557c5d6997839723fe546d08c /pysnmp/carrier
parentd947278e9747fc5d0c198f78b30132b13eb90760 (diff)
downloadpysnmp-2badd13fbc5a16806170deb432a1aeee03b74905.tar.gz
initial support for asyncio network transport added
Diffstat (limited to 'pysnmp/carrier')
-rw-r--r--pysnmp/carrier/asyncio/__init__.py1
-rw-r--r--pysnmp/carrier/asyncio/base.py35
-rw-r--r--pysnmp/carrier/asyncio/dgram/__init__.py1
-rw-r--r--pysnmp/carrier/asyncio/dgram/base.py75
-rw-r--r--pysnmp/carrier/asyncio/dgram/udp.py63
-rw-r--r--pysnmp/carrier/asyncio/dispatch.py78
6 files changed, 253 insertions, 0 deletions
diff --git a/pysnmp/carrier/asyncio/__init__.py b/pysnmp/carrier/asyncio/__init__.py
new file mode 100644
index 0000000..ac0b2c0
--- /dev/null
+++ b/pysnmp/carrier/asyncio/__init__.py
@@ -0,0 +1 @@
+# This file is necessary to make this directory a package.
diff --git a/pysnmp/carrier/asyncio/base.py b/pysnmp/carrier/asyncio/base.py
new file mode 100644
index 0000000..192343f
--- /dev/null
+++ b/pysnmp/carrier/asyncio/base.py
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2014, Zebra Technologies
+# Authors: Matt Hooks <me@matthooks.com>
+# Zachary Lorusso <zlorusso@gmail.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+#
+from pysnmp.carrier.asyncio.dispatch import AsyncioDispatcher
+from pysnmp.carrier.base import AbstractTransport
+
+class AbstractAsyncioTransport(AbstractTransport):
+ protoTransportDispatcher = AsyncioDispatcher
+ """Base Asyncio Transport, to be used with AsyncioDispatcher"""
+ def __init__(self):
+ self._writeQ = []
diff --git a/pysnmp/carrier/asyncio/dgram/__init__.py b/pysnmp/carrier/asyncio/dgram/__init__.py
new file mode 100644
index 0000000..ac0b2c0
--- /dev/null
+++ b/pysnmp/carrier/asyncio/dgram/__init__.py
@@ -0,0 +1 @@
+# This file is necessary to make this directory a package.
diff --git a/pysnmp/carrier/asyncio/dgram/base.py b/pysnmp/carrier/asyncio/dgram/base.py
new file mode 100644
index 0000000..c45e358
--- /dev/null
+++ b/pysnmp/carrier/asyncio/dgram/base.py
@@ -0,0 +1,75 @@
+#
+# Copyright (C) 2014, Zebra Technologies
+# Authors: Matt Hooks <me@matthooks.com>
+# Zachary Lorusso <zlorusso@gmail.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+#
+from pysnmp.carrier.asyncio.base import AbstractAsyncioTransport
+from pysnmp.carrier import error
+from pysnmp import debug
+try:
+ import asyncio
+except ImportError:
+ from pysnmp.error import PySnmpError
+ raise PySnmpError('The asyncio transport is not available')
+
+loop = asyncio.get_event_loop()
+
+class DgramAsyncioProtocol(asyncio.DatagramProtocol, AbstractAsyncioTransport):
+ """Base Asyncio datagram Transport, to be used with AsyncioDispatcher"""
+ transport = None
+
+ def datagram_received(self, datagram, transportAddress):
+ if self._cbFun is None:
+ raise error.CarrierError('Unable to call cbFun')
+ else:
+ loop.call_soon(self._cbFun, self, transportAddress, datagram)
+
+ def connection_made(self, transport):
+ self.transport = transport
+ debug.logger & debug.flagIO and debug.logger('connection_made: invoked')
+ while self._writeQ:
+ outgoingMessage, transportAddress = self._writeQ.pop(0)
+ debug.logger & debug.flagIO and debug.logger('connection_made: transportAddress %r outgoingMessage %s' %
+ (transportAddress, debug.hexdump(outgoingMessage)))
+ try:
+ self.transport.sendto(outgoingMessage, transportAddress)
+ except Exception as err:
+ raise error.CarrierError() from err
+
+ def connection_lost(self, exc):
+ debug.logger & debug.flagIO and debug.logger('connection_lost: invoked')
+
+ def sendMessage(self, outgoingMessage, transportAddress):
+ debug.logger & debug.flagIO and debug.logger('sendMessage: %s transportAddress %r outgoingMessage %s' % (
+ (self.transport is None and "queuing" or "sending"),
+ transportAddress, debug.hexdump(outgoingMessage)
+ ))
+ if self.transport is None:
+ self._writeQ.append((outgoingMessage, transportAddress))
+ else:
+ try:
+ self.transport.sendto(outgoingMessage, transportAddress)
+ except Exception as err:
+ raise error.CarrierError() from err
diff --git a/pysnmp/carrier/asyncio/dgram/udp.py b/pysnmp/carrier/asyncio/dgram/udp.py
new file mode 100644
index 0000000..d29981a
--- /dev/null
+++ b/pysnmp/carrier/asyncio/dgram/udp.py
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2014, Zebra Technologies
+# Authors: Matt Hooks <me@matthooks.com>
+# Zachary Lorusso <zlorusso@gmail.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+#
+from pysnmp.carrier.asyncio.dgram.base import DgramAsyncioProtocol
+from pysnmp.carrier import error
+try:
+ import asyncio
+except ImportError:
+ from pysnmp.error import PySnmpError
+ raise PySnmpError('The asyncio transport is not available')
+
+loop = asyncio.get_event_loop()
+
+domainName = snmpUDPDomain = (1, 3, 6, 1, 6, 1, 1)
+
+class UdpAsyncioTransport(DgramAsyncioProtocol):
+ # AbstractAsyncioTransport API
+
+ def openClientMode(self, iface=('0.0.0.0', 0)):
+ try:
+ c = loop.create_datagram_endpoint(lambda: self, local_addr=iface)
+ self._lport = asyncio.async(c)
+ except Exception as err:
+ raise error.CarrierError() from err
+ return self
+
+ def openServerMode(self, iface=('0.0.0.0', 161)):
+ try:
+ c = loop.create_datagram_endpoint(lambda: self, local_addr=iface)
+ self._lport = asyncio.async(c)
+ except Exception as err:
+ raise error.CarrierError() from err
+ return self
+
+ def closeTransport(self):
+ self._lport.cancel()
+ DgramAsyncioProtocol.closeTransport(self)
+
+UdpTransport = UdpAsyncioTransport
diff --git a/pysnmp/carrier/asyncio/dispatch.py b/pysnmp/carrier/asyncio/dispatch.py
new file mode 100644
index 0000000..7b0b72f
--- /dev/null
+++ b/pysnmp/carrier/asyncio/dispatch.py
@@ -0,0 +1,78 @@
+#
+# Copyright (C) 2014, Zebra Technologies
+# Authors: Matt Hooks <me@matthooks.com>
+# Zachary Lorusso <zlorusso@gmail.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+#
+from pysnmp.carrier.base import AbstractTransportDispatcher
+try:
+ import asyncio
+except ImportError:
+ from pysnmp.error import PySnmpError
+ raise PySnmpError('The asyncio transport is not available')
+
+loop = asyncio.get_event_loop()
+
+class AsyncioDispatcher(AbstractTransportDispatcher):
+ """AsyncioDispatcher based on asyncio event loop"""
+ def __init__(self, *args, **kwargs):
+ AbstractTransportDispatcher.__init__(self)
+ self.__transportCount = 0
+ if 'timeout' in kwargs:
+ self.setTimerResolution(kwargs['timeout'])
+ self.loopingcall = None
+
+ @asyncio.coroutine
+ def handle_timeout(self):
+ while True:
+ yield from asyncio.sleep(self.getTimerResolution())
+ self.handleTimerTick(loop.time())
+
+ def runDispatcher(self, timeout=0.0):
+ if not loop.is_running():
+ try:
+ loop.run_forever()
+ except KeyboardInterrupt:
+ raise
+ except Exception as err:
+ raise PySnmpError('event loop error') from err
+
+ def registerTransport(self, tDomain, transport):
+ if self.loopingcall is None and self.getTimerResolution() > 0:
+ self.loopingcall = asyncio.async(self.handle_timeout())
+ 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)
+ self.__transportCount = self.__transportCount - 1
+
+ # The last transport has been removed, stop the timeout
+ if self.__transportCount == 0 and not self.loopingcall.done():
+ self.loopingcall.cancel()
+ self.loopingcall = None