summaryrefslogtreecommitdiff
path: root/pysnmp/hlapi
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2018-08-12 17:22:58 +0200
committerGitHub <noreply@github.com>2018-08-12 17:22:58 +0200
commitac0b956d006a4b7b32780e852740b56ecd826c7e (patch)
tree4576911add0e18525991109acdb2a91bc4b2fde8 /pysnmp/hlapi
parent488ec26798a4493ee0fc45e730f88f1365f56df7 (diff)
downloadpysnmp-git-ac0b956d006a4b7b32780e852740b56ecd826c7e.tar.gz
Add `hlapi.v1arch` API (#186)
* Add `hlapi.v1arch` API Introduce new sub-package `pysnmp.hlapi.v1arch` which wraps otherwise very detailed packet-level SNMP messaging into a handful of convenience functions. As a side effect, the `pysnmp.hlapi.*` sub-packages moved under `pysnmp.hlapi.v3arch` though `pysnmp.hlapi` still exposes `pysnmp.hlappi.v3arch.*` symbols to retain some degree of backward compatibility. The signature of the hlapi `.sendNotification()` call has changed to accept `*varBinds` instead of a sequence of `varBinds`. The rationale is to unify this method call with similar methods of CommandGenerator. * Add v1arch docs and reshuffle hlapi docs
Diffstat (limited to 'pysnmp/hlapi')
-rw-r--r--pysnmp/hlapi/__init__.py8
-rw-r--r--pysnmp/hlapi/asyncore/sync/__init__.py19
-rw-r--r--pysnmp/hlapi/twisted/__init__.py8
-rw-r--r--pysnmp/hlapi/v1arch/__init__.py14
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/__init__.py13
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/cmdgen.py627
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/dispatch.py29
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/ntforg.py188
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/sync/__init__.py21
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py570
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/sync/ntforg.py140
-rw-r--r--pysnmp/hlapi/v1arch/asyncore/transport.py111
-rw-r--r--pysnmp/hlapi/v1arch/auth.py45
-rw-r--r--pysnmp/hlapi/v1arch/dispatch.py168
-rw-r--r--pysnmp/hlapi/v3arch/__init__.py15
-rw-r--r--pysnmp/hlapi/v3arch/asyncio/__init__.py (renamed from pysnmp/hlapi/asyncio/__init__.py)10
-rw-r--r--pysnmp/hlapi/v3arch/asyncio/cmdgen.py (renamed from pysnmp/hlapi/asyncio/cmdgen.py)27
-rw-r--r--pysnmp/hlapi/v3arch/asyncio/ntforg.py (renamed from pysnmp/hlapi/asyncio/ntforg.py)45
-rw-r--r--pysnmp/hlapi/v3arch/asyncio/transport.py (renamed from pysnmp/hlapi/asyncio/transport.py)3
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/__init__.py (renamed from pysnmp/hlapi/asyncore/__init__.py)10
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/cmdgen.py (renamed from pysnmp/hlapi/asyncore/cmdgen.py)45
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/ntforg.py (renamed from pysnmp/hlapi/asyncore/ntforg.py)84
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/sync/__init__.py19
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py (renamed from pysnmp/hlapi/asyncore/sync/cmdgen.py)9
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/sync/compat/__init__.py (renamed from pysnmp/hlapi/asyncore/sync/compat/__init__.py)0
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/sync/compat/cmdgen.py (renamed from pysnmp/hlapi/asyncore/sync/compat/cmdgen.py)6
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/sync/compat/ntforg.py (renamed from pysnmp/hlapi/asyncore/sync/compat/ntforg.py)2
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py (renamed from pysnmp/hlapi/asyncore/sync/ntforg.py)64
-rw-r--r--pysnmp/hlapi/v3arch/asyncore/transport.py (renamed from pysnmp/hlapi/asyncore/transport.py)7
-rw-r--r--pysnmp/hlapi/v3arch/auth.py (renamed from pysnmp/hlapi/auth.py)0
-rw-r--r--pysnmp/hlapi/v3arch/context.py (renamed from pysnmp/hlapi/context.py)0
-rw-r--r--pysnmp/hlapi/v3arch/lcd.py (renamed from pysnmp/hlapi/lcd.py)2
-rw-r--r--pysnmp/hlapi/v3arch/twisted/__init__.py8
-rw-r--r--pysnmp/hlapi/v3arch/twisted/cmdgen.py (renamed from pysnmp/hlapi/twisted/cmdgen.py)28
-rw-r--r--pysnmp/hlapi/v3arch/twisted/ntforg.py (renamed from pysnmp/hlapi/twisted/ntforg.py)68
-rw-r--r--pysnmp/hlapi/v3arch/twisted/transport.py (renamed from pysnmp/hlapi/twisted/transport.py)6
-rw-r--r--pysnmp/hlapi/varbinds.py70
37 files changed, 2279 insertions, 210 deletions
diff --git a/pysnmp/hlapi/__init__.py b/pysnmp/hlapi/__init__.py
index f60b0ed4..da9788e3 100644
--- a/pysnmp/hlapi/__init__.py
+++ b/pysnmp/hlapi/__init__.py
@@ -4,12 +4,6 @@
# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysnmp/license.html
#
-from pysnmp.proto.rfc1902 import *
-from pysnmp.proto.rfc1905 import NoSuchInstance, NoSuchObject, EndOfMibView
-from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.entity.engine import *
# default is synchronous asyncore-based API
-from pysnmp.hlapi.asyncore.sync import *
+from pysnmp.hlapi.v3arch import *
diff --git a/pysnmp/hlapi/asyncore/sync/__init__.py b/pysnmp/hlapi/asyncore/sync/__init__.py
deleted file mode 100644
index f412713a..00000000
--- a/pysnmp/hlapi/asyncore/sync/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# This file is part of pysnmp software.
-#
-# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
-# License: http://snmplabs.com/pysnmp/license.html
-#
-from pysnmp.proto.rfc1902 import *
-from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.asyncore.transport import *
-from pysnmp.entity.engine import *
-
-try:
- from pysnmp.hlapi.asyncore.sync.cmdgen import *
- from pysnmp.hlapi.asyncore.sync.ntforg import *
-except SyntaxError:
- from pysnmp.hlapi.asyncore.sync.compat.cmdgen import *
- from pysnmp.hlapi.asyncore.sync.compat.ntforg import *
diff --git a/pysnmp/hlapi/twisted/__init__.py b/pysnmp/hlapi/twisted/__init__.py
deleted file mode 100644
index 4e3e129f..00000000
--- a/pysnmp/hlapi/twisted/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from pysnmp.proto.rfc1902 import *
-from pysnmp.smi.rfc1902 import *
-from pysnmp.entity.engine import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.twisted.transport import *
-from pysnmp.hlapi.twisted.cmdgen import *
-from pysnmp.hlapi.twisted.ntforg import *
diff --git a/pysnmp/hlapi/v1arch/__init__.py b/pysnmp/hlapi/v1arch/__init__.py
new file mode 100644
index 00000000..22290a8f
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/__init__.py
@@ -0,0 +1,14 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.proto.rfc1902 import *
+from pysnmp.proto.rfc1905 import NoSuchInstance, NoSuchObject, EndOfMibView
+from pysnmp.smi.rfc1902 import *
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.v1arch.asyncore.dispatch import *
+
+# default is synchronous asyncore-based API
+from pysnmp.hlapi.v1arch.asyncore.sync import *
diff --git a/pysnmp/hlapi/v1arch/asyncore/__init__.py b/pysnmp/hlapi/v1arch/asyncore/__init__.py
new file mode 100644
index 00000000..d58bee7b
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/__init__.py
@@ -0,0 +1,13 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.proto.rfc1902 import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.v1arch.asyncore.transport import *
+from pysnmp.hlapi.v1arch.asyncore.cmdgen import *
+from pysnmp.hlapi.v1arch.asyncore.ntforg import *
+from pysnmp.hlapi.v1arch.asyncore.dispatch import *
diff --git a/pysnmp/hlapi/v1arch/asyncore/cmdgen.py b/pysnmp/hlapi/v1arch/asyncore/cmdgen.py
new file mode 100644
index 00000000..ddce3b7e
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/cmdgen.py
@@ -0,0 +1,627 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+
+from pysnmp.hlapi.varbinds import *
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.v1arch.asyncore import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.proto import api
+from pysnmp import error
+
+__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd']
+
+vbProcessor = CommandGeneratorVarBinds()
+
+
+def getCmd(snmpDispatcher, authData, transportTarget, *varBinds, **options):
+ """Initiate SNMP GET query over SNMPv1/v2c.
+
+ Based on passed parameters, prepares SNMP GET packet
+ (:RFC:`1905#section-4.2.1`) and schedules its transmission by
+ I/O framework at a later point of time.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMPv1/v2c credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncore.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncore.Udp6TransportTarget` Class instance representing
+ transport type along with SNMP peer address.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`.
+ * `cbFun` (callable) - user-supplied callable that is invoked
+ to pass SNMP response data or error to user at a later point
+ of time. Default is `None`.
+ * `cbCtx` (object) - user-supplied object passing additional
+ parameters to/from `cbFun`. Default is `None`.
+
+ Note
+ ----
+ The `SnmpDispatcher` object may be expensive to create, therefore it is
+ advised to maintain it for the lifecycle of the application/thread for
+ as long as possible.
+
+ Note
+ ----
+ User-supplied `cbFun` callable must have the following call
+ signature:
+
+ * snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+ * stateHandle (int): Unique request identifier. Can be used
+ for matching multiple ongoing requests with received responses.
+ * errorIndication (str): evaluates to `True` to indicate SNMP dispatcher
+ error.
+ * errorStatus (int): evaluates to `True` to indicate SNMP PDU error.
+ * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]`
+ * varBinds (tuple): A sequence of
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ representing MIB variables returned in SNMP response in exactly
+ the same order as `varBinds` in request.
+ * `cbCtx` (object): Original user-supplied object.
+
+ Returns
+ -------
+ stateHandle: int
+ Unique request identifier. Can be used for matching received
+ responses with ongoing requests.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import *
+ >>>
+ >>> def cbFun(snmpDispatcher, stateHandle, errorIndication,
+ >>> errorStatus, errorIndex, varBinds, cbCtx):
+ >>> print(errorIndication, errorStatus, errorIndex, varBinds)
+ >>>
+ >>> snmpDispatcher = SnmpDispatcher()
+ >>>
+ >>> stateHandle = getCmd(
+ >>> snmpDispatcher,
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)),
+ >>> cbFun=cbFun
+ >>> )
+ >>>
+ >>> snmpDispatcher.transportDispatcher.runDispatcher()
+ """
+
+ def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if not cbFun:
+ return
+
+ if errorIndication:
+ cbFun(errorIndication, pMod.Integer(0), pMod.Integer(0), None,
+ cbCtx=cbCtx, snmpDispatcher=snmpDispatcher, stateHandle=stateHandle)
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBinds = pMod.apiPDU.getVarBinds(rspPdu)
+
+ if lookupMib:
+ varBinds = vbProcessor.unmakeVarBinds(snmpDispatcher.cache, varBinds)
+
+ nextStateHandle = pMod.getNextRequestID()
+
+ nextVarBinds = cbFun(errorIndication, errorStatus, errorIndex, varBinds,
+ cbCtx=cbCtx,
+ snmpDispatcher=snmpDispatcher,
+ stateHandle=stateHandle,
+ nextStateHandle=nextStateHandle)
+
+ if not nextVarBinds:
+ return
+
+ pMod.apiPDU.setRequestID(reqPdu, nextStateHandle)
+ pMod.apiPDU.setVarBinds(reqPdu, nextVarBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ lookupMib, cbFun, cbCtx = [options.get(x) for x in ('lookupMib', 'cbFun', 'cbCtx')]
+
+ if lookupMib:
+ varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.protoModules[authData.mpModel]
+
+ reqPdu = pMod.GetRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+
+def setCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Initiate SNMP SET query over SNMPv1/v2c.
+
+ Based on passed parameters, prepares SNMP SET packet
+ (:RFC:`1905#section-4.2.5`) and schedules its transmission by
+ I/O framework at a later point of time.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
+ Class instance representing SNMP credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.v1arch.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer
+ address.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`.
+ * `cbFun` (callable) - user-supplied callable that is invoked
+ to pass SNMP response data or error to user at a later point
+ of time. Default is `None`.
+ * `cbCtx` (object) - user-supplied object passing additional
+ parameters to/from `cbFun`. Default is `None`.
+
+ Note
+ ----
+ The `SnmpDispatcher` object may be expensive to create, therefore it is
+ advised to maintain it for the lifecycle of the application/thread for
+ as long as possible.
+
+ Note
+ ----
+ User-supplied `cbFun` callable must have the following call
+ signature:
+
+ * snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+ * stateHandle (int): Unique request identifier. Can be used
+ for matching multiple ongoing requests with received responses.
+ * errorIndication (str): evaluates to `True` to indicate SNMP dispatcher
+ error.
+ * errorStatus (int): evaluates to `True` to indicate SNMP PDU error.
+ * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]`
+ * varBinds (tuple): A sequence of
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ representing MIB variables returned in SNMP response in exactly
+ the same order as `varBinds` in request.
+ * `cbCtx` (object): Original user-supplied object.
+
+ Returns
+ -------
+ stateHandle: int
+ Unique request identifier. Can be used for matching received
+ responses with ongoing requests.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import *
+ >>>
+ >>> def cbFun(snmpDispatcher, stateHandle, errorIndication,
+ >>> errorStatus, errorIndex, varBinds, cbCtx):
+ >>> print(errorIndication, errorStatus, errorIndex, varBinds)
+ >>>
+ >>> snmpDispatcher = SnmpDispatcher()
+ >>>
+ >>> stateHandle = setCmd(
+ >>> snmpDispatcher,
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> ('1.3.6.1.2.1.1.4.0', OctetString('info@snmplabs.com')),
+ >>> cbFun=cbFun
+ >>> )
+ >>>
+ >>> snmpDispatcher.transportDispatcher.runDispatcher()
+ """
+
+ def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if not cbFun:
+ return
+
+ if errorIndication:
+ cbFun(errorIndication, pMod.Integer(0), pMod.Integer(0), None,
+ cbCtx=cbCtx, snmpDispatcher=snmpDispatcher, stateHandle=stateHandle)
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBinds = pMod.apiPDU.getVarBinds(rspPdu)
+
+ if lookupMib:
+ varBinds = vbProcessor.unmakeVarBinds(snmpDispatcher.cache, varBinds)
+
+ nextStateHandle = pMod.getNextRequestID()
+
+ nextVarBinds = cbFun(errorIndication, errorStatus, errorIndex, varBinds,
+ cbCtx=cbCtx,
+ snmpDispatcher=snmpDispatcher,
+ stateHandle=stateHandle,
+ nextStateHandle=nextStateHandle)
+
+ if not nextVarBinds:
+ return
+
+ pMod.apiPDU.setRequestID(reqPdu, nextStateHandle)
+ pMod.apiPDU.setVarBinds(reqPdu, nextVarBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ lookupMib, cbFun, cbCtx = [options.get(x) for x in ('lookupMib', 'cbFun', 'cbCtx')]
+
+ if lookupMib:
+ varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.protoModules[authData.mpModel]
+
+ reqPdu = pMod.SetRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+
+def nextCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Initiate SNMP GETNEXT query over SNMPv1/v2c.
+
+ Based on passed parameters, prepares SNMP GETNEXT packet
+ (:RFC:`1905#section-4.2.2`) and schedules its transmission by
+ I/O framework at a later point of time.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing SNMP dispatcher.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData` or :py:class:`~pysnmp.hlapi.v1arch.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.v1arch.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer
+ address.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ * `cbFun` (callable) - user-supplied callable that is invoked
+ to pass SNMP response data or error to user at a later point
+ of time. Default is `None`.
+ * `cbCtx` (object) - user-supplied object passing additional
+ parameters to/from `cbFun`. Default is `None`.
+
+ Notes
+ -----
+ User-supplied `cbFun` callable must have the following call
+ signature:
+
+ * snmpDispatcher (:py:class:`~pysnmp.hlapi.v1arch.snmpDispatcher`):
+ Class instance representing SNMP dispatcher.
+ * stateHandle (int): Unique request identifier. Can be used
+ for matching multiple ongoing requests with received responses.
+ * errorIndication (str): True value indicates SNMP dispatcher error.
+ * errorStatus (str): True value indicates SNMP PDU error.
+ * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]`
+ * varBindTable (tuple): A sequence of sequences (e.g. 2-D array) of
+ variable-bindings represented as :class:`tuple` or
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ representing a table of MIB variables returned in SNMP response.
+ Inner sequences represent table rows and ordered exactly the same
+ as `varBinds` in request. Response to GETNEXT always contain a
+ single row.
+ * `cbCtx` (object): Original user-supplied object.
+
+ Returns
+ -------
+ stateHandle: int
+ Unique request identifier. Can be used for matching received
+ responses with ongoing requests.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import *
+ >>>
+ >>> def cbFun(snmpDispatcher, stateHandle, errorIndication,
+ >>> errorStatus, errorIndex, varBinds, cbCtx):
+ >>> print(errorIndication, errorStatus, errorIndex, varBinds)
+ >>>
+ >>> snmpDispatcher = snmpDispatcher()
+ >>>
+ >>> stateHandle = nextCmd(
+ >>> snmpDispatcher,
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> ('1.3.6.1.2.1.1', None),
+ >>> cbFun=cbFun
+ >>> )
+ >>>
+ >>> snmpDispatcher.transportDispatcher.runDispatcher()
+ """
+
+ def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if not cbFun:
+ return
+
+ if errorIndication:
+ cbFun(errorIndication, pMod.Integer(0), pMod.Integer(0), None,
+ cbCtx=cbCtx, snmpDispatcher=snmpDispatcher, stateHandle=stateHandle)
+ return
+
+ errorStatus = pMod.apiPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiPDU.getErrorIndex(rspPdu)
+
+ varBindTable = pMod.apiPDU.getVarBindTable(reqPdu, rspPdu)
+
+ errorIndication, nextVarBinds = pMod.apiPDU.getNextVarBinds(
+ varBindTable[-1], errorIndex=errorIndex
+ )
+
+ if options.get('lookupMib'):
+ varBindTable = [
+ vbProcessor.unmakeVarBinds(snmpDispatcher.cache, vbs) for vbs in varBindTable
+ ]
+
+ nextStateHandle = pMod.getNextRequestID()
+
+ nextVarBinds = cbFun(errorIndication, errorStatus, errorIndex, varBindTable,
+ cbCtx=cbCtx,
+ snmpDispatcher=snmpDispatcher,
+ stateHandle=stateHandle,
+ nextStateHandle=nextStateHandle,
+ nextVarBinds=nextVarBinds)
+
+ if not nextVarBinds:
+ return
+
+ pMod.apiPDU.setRequestID(reqPdu, nextStateHandle)
+ pMod.apiPDU.setVarBinds(reqPdu, nextVarBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ lookupMib, cbFun, cbCtx = [options.get(x) for x in ('lookupMib', 'cbFun', 'cbCtx')]
+
+ if lookupMib:
+ varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.protoModules[authData.mpModel]
+
+ reqPdu = pMod.GetNextRequestPDU()
+ pMod.apiPDU.setDefaults(reqPdu)
+ pMod.apiPDU.setVarBinds(reqPdu, varBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+
+def bulkCmd(snmpDispatcher, authData, transportTarget,
+ nonRepeaters, maxRepetitions, *varBinds, **options):
+ """Initiate SNMP GETBULK query over SNMPv2c.
+
+ Based on passed parameters, prepares SNMP GETBULK packet
+ (:RFC:`1905#section-4.2.3`) and schedules its transmission by
+ I/O framework at a later point of time.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing SNMP dispatcher.
+
+ authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData` or :py:class:`~pysnmp.hlapi.v1arch.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.v1arch.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer
+ address.
+
+ nonRepeaters: int
+ One MIB variable is requested in response for the first
+ `nonRepeaters` MIB variables in request.
+
+ maxRepetitions: int
+ `maxRepetitions` MIB variables are requested in response for each
+ of the remaining MIB variables in the request (e.g. excluding
+ `nonRepeaters`). Remote SNMP dispatcher may choose lesser value than
+ requested.
+
+ \*varBinds: :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ * `cbFun` (callable) - user-supplied callable that is invoked
+ to pass SNMP response data or error to user at a later point
+ of time. Default is `None`.
+ * `cbCtx` (object) - user-supplied object passing additional
+ parameters to/from `cbFun`. Default is `None`.
+
+ Notes
+ -----
+ User-supplied `cbFun` callable must have the following call
+ signature:
+
+ * snmpDispatcher (:py:class:`~pysnmp.hlapi.v1arch.snmpDispatcher`):
+ Class instance representing SNMP dispatcher.
+ * stateHandle (int): Unique request identifier. Can be used
+ for matching multiple ongoing requests with received responses.
+ * errorIndication (str): True value indicates SNMP dispatcher error.
+ * errorStatus (str): True value indicates SNMP PDU error.
+ * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]`
+ * varBindTable (tuple): A sequence of sequences (e.g. 2-D array) of
+ variable-bindings represented as :class:`tuple` or
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ representing a table of MIB variables returned in SNMP response, with
+ up to ``maxRepetitions`` rows, i.e. ``len(varBindTable) <= maxRepetitions``.
+
+ For ``0 <= i < len(varBindTable)`` and ``0 <= j < len(varBinds)``,
+ ``varBindTable[i][j]`` represents:
+
+ - For non-repeaters (``j < nonRepeaters``), the first lexicographic
+ successor of ``varBinds[j]``, regardless the value of ``i``, or an
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` instance with the
+ :py:obj:`~pysnmp.proto.rfc1905.endOfMibView` value if no such successor
+ exists;
+ - For repeaters (``j >= nonRepeaters``), the ``i``-th lexicographic
+ successor of ``varBinds[j]``, or an
+ :py:class:`~pysnmp.smi.rfc1902.ObjectType` instance with the
+ :py:obj:`~pysnmp.proto.rfc1905.endOfMibView` value if no such successor
+ exists.
+
+ See :rfc:`3416#section-4.2.3` for details on the underlying
+ ``GetBulkRequest-PDU`` and the associated ``GetResponse-PDU``, such as
+ specific conditions under which the server may truncate the response,
+ causing ``varBindTable`` to have less than ``maxRepetitions`` rows.
+ * `cbCtx` (object): Original user-supplied object.
+
+ Returns
+ -------
+ stateHandle : int
+ Unique request identifier. Can be used for matching received
+ responses with ongoing requests.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import *
+ >>>
+ >>> def cbFun(snmpDispatcher, stateHandle, errorIndication,
+ >>> errorStatus, errorIndex, varBinds, cbCtx):
+ >>> print(errorIndication, errorStatus, errorIndex, varBinds)
+ >>>
+ >>> snmpDispatcher = snmpDispatcher()
+ >>>
+ >>> stateHandle = bulkCmd(
+ >>> snmpDispatcher,
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> 0, 2,
+ >>> ('1.3.6.1.2.1.1', None),
+ >>> cbFun=cbFun
+ >>> )
+ >>>
+ >>> snmpDispatcher.transportDispatcher.runDispatcher()
+ """
+
+ def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if not cbFun:
+ return
+
+ if errorIndication:
+ cbFun(errorIndication, pMod.Integer(0), pMod.Integer(0), None,
+ cbCtx=cbCtx, snmpDispatcher=snmpDispatcher, stateHandle=stateHandle)
+ return
+
+ errorStatus = pMod.apiBulkPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiBulkPDU.getErrorIndex(rspPdu)
+
+ varBindTable = pMod.apiBulkPDU.getVarBindTable(reqPdu, rspPdu)
+
+ errorIndication, nextVarBinds = pMod.apiBulkPDU.getNextVarBinds(
+ varBindTable[-1], errorIndex=errorIndex
+ )
+
+ if options.get('lookupMib'):
+ varBindTable = [
+ vbProcessor.unmakeVarBinds(snmpDispatcher.cache, vbs) for vbs in varBindTable
+ ]
+
+ nextStateHandle = pMod.getNextRequestID()
+
+ nextVarBinds = cbFun(errorIndication, errorStatus, errorIndex, varBindTable,
+ cbCtx=cbCtx,
+ snmpDispatcher=snmpDispatcher,
+ stateHandle=stateHandle,
+ nextStateHandle=nextStateHandle,
+ nextVarBinds=nextVarBinds)
+
+ if not nextVarBinds:
+ return
+
+ pMod.apiBulkPDU.setRequestID(reqPdu, nextStateHandle)
+ pMod.apiBulkPDU.setVarBinds(reqPdu, nextVarBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ if authData.mpModel < 1:
+ raise error.PySnmpError('GETBULK PDU is only supported in SNMPv2c and SNMPv3')
+
+ lookupMib, cbFun, cbCtx = [options.get(x) for x in ('lookupMib', 'cbFun', 'cbCtx')]
+
+ if lookupMib:
+ varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ pMod = api.protoModules[authData.mpModel]
+
+ reqPdu = pMod.GetBulkRequestPDU()
+ pMod.apiBulkPDU.setDefaults(reqPdu)
+ pMod.apiBulkPDU.setNonRepeaters(reqPdu, nonRepeaters)
+ pMod.apiBulkPDU.setMaxRepetitions(reqPdu, maxRepetitions)
+ pMod.apiBulkPDU.setVarBinds(reqPdu, varBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
diff --git a/pysnmp/hlapi/v1arch/asyncore/dispatch.py b/pysnmp/hlapi/v1arch/asyncore/dispatch.py
new file mode 100644
index 00000000..d77b8551
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/dispatch.py
@@ -0,0 +1,29 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.carrier.asyncore.dispatch import AsyncoreDispatcher
+from pysnmp.hlapi.v1arch.dispatch import AbstractSnmpDispatcher
+
+__all__ = ['SnmpDispatcher']
+
+
+class SnmpDispatcher(AbstractSnmpDispatcher):
+ """Creates SNMP message dispatcher object.
+
+ `SnmpDispatcher` object manages send and receives SNMP PDU
+ messages through underlying transport dispatcher and dispatches
+ them to the callers.
+
+ `SnmpDispatcher` is the only stateful object, all `hlapi.v1arch` SNMP
+ operations require an instance of `SnmpDispatcher`. Users do not normally
+ request services directly from `SnmpDispather`, but pass it around to
+ other `hlapi.v1arch` interfaces.
+
+ It is possible to run multiple instances of `SnmpDispatcher` in the
+ application. In a multithreaded environment, each thread that
+ works with SNMP must have its own `SnmpDispatcher` instance.
+ """
+ protoDispatcher = AsyncoreDispatcher
diff --git a/pysnmp/hlapi/v1arch/asyncore/ntforg.py b/pysnmp/hlapi/v1arch/asyncore/ntforg.py
new file mode 100644
index 00000000..a7767051
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/ntforg.py
@@ -0,0 +1,188 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.hlapi.varbinds import *
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.v1arch.asyncore import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.proto import api
+from pysnmp.proto.proxy import rfc2576
+from pysnmp import error
+
+__all__ = ['sendNotification']
+
+vbProcessor = NotificationOriginatorVarBinds()
+
+
+def sendNotification(snmpDispatcher, authData, transportTarget,
+ notifyType, *varBinds, **options):
+ """Send SNMP notification.
+
+ Based on passed parameters, prepares SNMP TRAP or INFORM
+ notification (:RFC:`1905#section-4.2.6`) and schedules its
+ transmission by I/O framework at a later point of time.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer address.
+
+ notifyType: str
+ Indicates type of notification to be sent. Recognized literal
+ values are *trap* or *inform*.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU places rigid requirement on the ordering of
+ the variable-bindings.
+
+ Mandatory variable-bindings:
+
+ 0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ 1. SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Optional variable-bindings (applicable to SNMP v1 TRAP):
+
+ 2. SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ 3. SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ 4. SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ Informational variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`.
+ * `cbFun` (callable) - user-supplied callable that is invoked
+ to pass SNMP response data or error to user at a later point
+ of time. Default is `None`.
+ * `cbCtx` (object) - user-supplied object passing additional
+ parameters to/from `cbFun`. Default is `None`.
+
+ Note
+ ----
+ The `SnmpDispatcher` object may be expensive to create, therefore it is
+ advised to maintain it for the lifecycle of the application/thread for
+ as long as possible.
+
+
+ Returns
+ -------
+ sendRequestHandle: int
+ Unique request identifier. Can be used for matching received
+ responses with ongoing *INFORM* requests. Returns `None` for
+ *TRAP* notifications.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import *
+ >>>
+ >>> snmpDispatcher = SnmpDispatcher()
+ >>>
+ >>> sendNotification(
+ >>> snmpDispatcher,
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 162)),
+ >>> 'trap',
+ >>> NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')),
+ >>> lookupMib=True
+ >>> )
+ >>> snmpDispatcher.transportDispatcher.runDispatcher()
+ """
+
+ def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
+ if not cbFun:
+ return
+
+ if errorIndication:
+ cbFun(errorIndication, pMod.Integer(0), pMod.Integer(0), None,
+ cbCtx=cbCtx, snmpDispatcher=snmpDispatcher, stateHandle=stateHandle)
+ return
+
+ errorStatus = pMod.apiTrapPDU.getErrorStatus(rspPdu)
+ errorIndex = pMod.apiTrapPDU.getErrorIndex(rspPdu)
+
+ varBinds = pMod.apiTrapPDU.getVarBinds(rspPdu)
+
+ if lookupMib:
+ varBinds = vbProcessor.unmakeVarBinds(snmpDispatcher.cache, varBinds)
+
+ nextStateHandle = pMod.getNextRequestID()
+
+ nextVarBinds = cbFun(errorIndication, errorStatus, errorIndex, varBinds,
+ cbCtx=cbCtx,
+ snmpDispatcher=snmpDispatcher,
+ stateHandle=stateHandle,
+ nextStateHandle=nextStateHandle)
+
+ if not nextVarBinds:
+ return
+
+ pMod.apiTrapPDU.setRequestID(reqPdu, nextStateHandle)
+ pMod.apiTrapPDU.setVarBinds(reqPdu, nextVarBinds)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
+ lookupMib, cbFun, cbCtx = [options.get(x) for x in ('lookupMib', 'cbFun', 'cbCtx')]
+
+ if lookupMib:
+ varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ # # make sure required PDU payload is in place
+ # completeVarBinds = []
+ #
+ # # ensure sysUpTime
+ # if len(varBinds) < 1 or varBinds[0][0] != pMod.apiTrapPDU.sysUpTime:
+ # varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
+ #
+ # # ensure sysUpTime
+ # if len(varBinds) < 1 or varBinds[0][0] != pMod.apiTrapPDU.sysUpTime:
+ # varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
+ #
+ # # ensure snmpTrapOID
+ # if len(varBinds) < 2 or varBinds[1][0] != pMod.apiTrapPDU.snmpTrapOID:
+ # varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
+
+ # input PDU is always v2c
+ pMod = api.protoModules[api.protoVersion2c]
+
+ if notifyType == 'trap':
+ reqPdu = pMod.TrapPDU()
+ else:
+ reqPdu = pMod.InformRequestPDU()
+
+ pMod.apiTrapPDU.setDefaults(reqPdu)
+ pMod.apiTrapPDU.setVarBinds(reqPdu, varBinds)
+
+ if authData.mpModel == 0:
+ reqPdu = rfc2576.v2ToV1(reqPdu)
+
+ return snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)
+
diff --git a/pysnmp/hlapi/v1arch/asyncore/sync/__init__.py b/pysnmp/hlapi/v1arch/asyncore/sync/__init__.py
new file mode 100644
index 00000000..5481cb96
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/sync/__init__.py
@@ -0,0 +1,21 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.proto.rfc1902 import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.hlapi.v1arch.auth import *
+from pysnmp.hlapi.v1arch.asyncore.transport import *
+from pysnmp.hlapi.v1arch.asyncore.cmdgen import *
+from pysnmp.hlapi.v1arch.asyncore.ntforg import *
+from pysnmp.hlapi.v1arch.asyncore.dispatch import *
+
+try:
+ from pysnmp.hlapi.v1arch.asyncore.sync.cmdgen import *
+ from pysnmp.hlapi.v1arch.asyncore.sync.ntforg import *
+
+except SyntaxError:
+ from pysnmp.hlapi.v1arch.asyncore.sync.compat.cmdgen import *
+ from pysnmp.hlapi.v1arch.asyncore.sync.compat.ntforg import *
diff --git a/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py b/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py
new file mode 100644
index 00000000..9b6b2b24
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/sync/cmdgen.py
@@ -0,0 +1,570 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from sys import version_info
+from pysnmp.hlapi.v1arch.asyncore import cmdgen
+from pysnmp.hlapi.varbinds import *
+from pysnmp.proto.rfc1905 import endOfMibView
+from pysnmp.proto import errind
+from pyasn1.type.univ import Null
+
+__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd']
+
+if version_info[:2] < (2, 6):
+ __all__.append('next')
+
+ # noinspection PyShadowingBuiltins
+ def next(iter):
+ return iter.next()
+
+vbProcessor = CommandGeneratorVarBinds()
+
+
+def getCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Creates a generator to perform one or more SNMP GET queries.
+
+ On each iteration, new SNMP GET request is send (:RFC:`1905#section-4.2.1`).
+ The iterator blocks waiting for response to arrive or error to occur.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer address.
+
+ \*varBinds: :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options:
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`.
+
+ Yields
+ ------
+ errorIndication: str
+ True value indicates local SNMP error.
+ errorStatus: str
+ True value indicates SNMP PDU error reported by remote.
+ errorIndex: int
+ Non-zero value refers to `varBinds[errorIndex-1]`
+ varBinds: tuple
+ A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class
+ instances representing MIB variables returned in SNMP response.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Notes
+ -----
+ The `getCmd` generator will be exhausted immediately unless
+ a new sequence of `varBinds` are send back into running generator
+ (supported since Python 2.6).
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch import *
+ >>>
+ >>> g = getCmd(snmpDispatcher(),
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))
+ >>>
+ >>> next(g)
+ (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')),
+ DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))])
+ """
+
+ def cbFun(*args, **kwargs):
+ response[:] = args
+
+ options['cbFun'] = cbFun
+
+ errorIndication, errorStatus, errorIndex = None, 0, 0
+ response = []
+
+ while True:
+ if varBinds:
+ cmdgen.getCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options)
+
+ snmpDispatcher.transportDispatcher.runDispatcher()
+
+ errorIndication, errorStatus, errorIndex, varBinds = response
+
+ varBinds = (yield errorIndication, errorStatus, errorIndex, varBinds)
+
+ if not varBinds:
+ break
+
+
+def setCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Creates a generator to perform one or more SNMP SET queries.
+
+ On each iteration, new SNMP SET request is send (:RFC:`1905#section-4.2.5`).
+ The iterator blocks waiting for response to arrive or error to occur.
+
+ Parameters
+ ----------
+ snmpDispatcher : :py:class:`~pysnmp.hlapi.snmpDispatcher`
+ Class instance representing SNMP engine.
+
+ authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer address.
+
+ \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ Default is `True`.
+
+ Yields
+ ------
+ errorIndication : str
+ True value indicates SNMP engine error.
+ errorStatus : str
+ True value indicates SNMP PDU error.
+ errorIndex : int
+ Non-zero value refers to `varBinds[errorIndex-1]`
+ varBinds : tuple
+ A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class
+ instances representing MIB variables returned in SNMP response.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Notes
+ -----
+ The `setCmd` generator will be exhausted immidiately unless
+ a new sequence of `varBinds` are send back into running generator
+ (supported since Python 2.6).
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch import *
+ >>>
+ >>> g = setCmd(snmpDispatcher(),
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386'))
+ >>>
+ >>> next(g)
+ (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')),
+ DisplayString('Linux i386'))])
+ """
+
+ def cbFun(*args, **kwargs):
+ response[:] = args
+
+ options['cbFun'] = cbFun
+
+ errorIndication, errorStatus, errorIndex = None, 0, 0
+ response = []
+
+ while True:
+ if varBinds:
+ cmdgen.setCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options)
+
+ snmpDispatcher.transportDispatcher.runDispatcher()
+
+ errorIndication, errorStatus, errorIndex, varBinds = response
+
+ varBinds = (yield errorIndication, errorStatus, errorIndex, varBinds)
+
+ if not varBinds:
+ break
+
+
+def nextCmd(snmpDispatcher, authData, transportTarget,
+ *varBinds, **options):
+ """Create a generator to perform one or more SNMP GETNEXT queries.
+
+ On each iteration, new SNMP GETNEXT request is send
+ (:RFC:`1905#section-4.2.2`). The iterator blocks waiting for response
+ to arrive or error to occur.
+
+ Parameters
+ ----------
+ snmpDispatcher : :py:class:`~pysnmp.hlapi.snmpDispatcher`
+ Class instance representing SNMP engine.
+
+ authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer address.
+
+ \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ Default is `True`.
+ * `lexicographicMode` - walk SNMP agent's MIB till the end (if `True`),
+ otherwise (if `False`) stop iteration when all response MIB
+ variables leave the scope of initial MIB variables in
+ `varBinds`. Default is `True`.
+ * `ignoreNonIncreasingOid` - continue iteration even if response
+ MIB variables (OIDs) are not greater then request MIB variables.
+ Be aware that setting it to `True` may cause infinite loop between
+ SNMP management and agent applications. Default is `False`.
+ * `maxRows` - stop iteration once this generator instance processed
+ `maxRows` of SNMP conceptual table. Default is `0` (no limit).
+ * `maxCalls` - stop iteration once this generator instance processed
+ `maxCalls` responses. Default is 0 (no limit).
+
+ Yields
+ ------
+ errorIndication: str
+ True value indicates SNMP engine error.
+ errorStatus: str
+ True value indicates SNMP PDU error.
+ errorIndex: int
+ Non-zero value refers to `varBinds[errorIndex-1]`
+ varBindTable: tuple
+ A 2-dimensional array of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class
+ instances representing a table of MIB variables returned in SNMP response.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Notes
+ -----
+ The `nextCmd` generator will be exhausted on any of the following
+ conditions:
+
+ * SNMP engine error occurs thus `errorIndication` is `True`
+ * SNMP PDU `errorStatus` is reported as `True`
+ * SNMP :py:class:`~pysnmp.proto.rfc1905.EndOfMibView` values
+ (also known as *SNMP exception values*) are reported for all
+ MIB variables in `varBinds`
+ * *lexicographicMode* option is `True` and SNMP agent reports
+ end-of-mib or *lexicographicMode* is `False` and all
+ response MIB variables leave the scope of `varBinds`
+
+ At any moment a new sequence of `varBinds` could be send back into
+ running generator (supported since Python 2.6).
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch import *
+ >>>
+ >>> g = nextCmd(snmpDispatcher(),
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')))
+ >>> next(g)
+ (None, 0, 0, [[ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]])
+ >>> g.send([ObjectType(ObjectIdentity('IF-MIB', 'ifInOctets'))])
+ (None, 0, 0, [(ObjectName('1.3.6.1.2.1.2.2.1.10.1'), Counter32(284817787))])
+ """
+
+ def cbFun(*args, **kwargs):
+ response[:] = args + (kwargs.get('nextVarBinds', ()),)
+
+ options['cbFun'] = cbFun
+
+ lexicographicMode = options.pop('lexicographicMode', True)
+ maxRows = options.pop('maxRows', 0)
+ maxCalls = options.pop('maxCalls', 0)
+
+ initialVarBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ totalRows = totalCalls = 0
+
+ errorIndication, errorStatus, errorIndex, varBindTable = None, 0, 0, ()
+ response = []
+
+ while True:
+ if not varBinds:
+ yield (errorIndication, errorStatus, errorIndex, varBindTable)
+ return
+
+ cmdgen.nextCmd(snmpDispatcher, authData, transportTarget,
+ *[(x[0], Null('')) for x in varBinds], **options)
+
+ snmpDispatcher.transportDispatcher.runDispatcher()
+
+ errorIndication, errorStatus, errorIndex, varBindTable, varBinds = response
+
+ if errorIndication:
+ yield (errorIndication, errorStatus, errorIndex, varBindTable)
+ return
+
+ elif errorStatus:
+ if errorStatus == 2:
+ # Hide SNMPv1 noSuchName error which leaks in here
+ # from SNMPv1 Agent through internal pysnmp proxy.
+ errorStatus = errorStatus.clone(0)
+ errorIndex = errorIndex.clone(0)
+ yield (errorIndication, errorStatus, errorIndex, varBindTable)
+ return
+
+ else:
+ varBindRow = varBindTable and varBindTable[-1]
+
+ if not lexicographicMode:
+ for idx, varBind in enumerate(varBindRow):
+ name, val = varBind
+ if not isinstance(val, Null):
+ if initialVarBinds[idx][0].isPrefixOf(name):
+ break
+ else:
+ return
+
+ for varBindRow in varBindTable:
+ nextVarBinds = (yield errorIndication, errorStatus, errorIndex, varBindRow)
+
+ if nextVarBinds:
+ initialVarBinds = varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, nextVarBinds)
+
+ totalRows += 1
+ totalCalls += 1
+
+ if maxRows and totalRows >= maxRows:
+ return
+
+ if maxCalls and totalCalls >= maxCalls:
+ return
+
+
+def bulkCmd(snmpDispatcher, authData, transportTarget,
+ nonRepeaters, maxRepetitions, *varBinds, **options):
+ """Creates a generator to perform one or more SNMP GETBULK queries.
+
+ On each iteration, new SNMP GETBULK request is send
+ (:RFC:`1905#section-4.2.3`). The iterator blocks waiting for response
+ to arrive or error to occur.
+
+ Parameters
+ ----------
+ snmpDispatcher : :py:class:`~pysnmp.hlapi.snmpDispatcher`
+ Class instance representing SNMP engine.
+
+ authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget : :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer address.
+
+ nonRepeaters : int
+ One MIB variable is requested in response for the first
+ `nonRepeaters` MIB variables in request.
+
+ maxRepetitions : int
+ `maxRepetitions` MIB variables are requested in response for each
+ of the remaining MIB variables in the request (e.g. excluding
+ `nonRepeaters`). Remote SNMP engine may choose lesser value than
+ requested.
+
+ \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ One or more class instances representing MIB variables to place
+ into SNMP request.
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ Default is `True`.
+ * `lexicographicMode` - walk SNMP agent's MIB till the end (if `True`),
+ otherwise (if `False`) stop iteration when all response MIB
+ variables leave the scope of initial MIB variables in
+ `varBinds`. Default is `True`.
+ * `ignoreNonIncreasingOid` - continue iteration even if response
+ MIB variables (OIDs) are not greater then request MIB variables.
+ Be aware that setting it to `True` may cause infinite loop between
+ SNMP management and agent applications. Default is `False`.
+ * `maxRows` - stop iteration once this generator instance processed
+ `maxRows` of SNMP conceptual table. Default is `0` (no limit).
+ * `maxCalls` - stop iteration once this generator instance processed
+ `maxCalls` responses. Default is 0 (no limit).
+
+ Yields
+ ------
+ errorIndication : str
+ True value indicates SNMP engine error.
+ errorStatus : str
+ True value indicates SNMP PDU error.
+ errorIndex : int
+ Non-zero value refers to \*varBinds[errorIndex-1]
+ varBinds: tuple
+ A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class
+ instances representing MIB variables returned in SNMP response.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Notes
+ -----
+ The `bulkCmd` generator will be exhausted on any of the following
+ conditions:
+
+ * SNMP engine error occurs thus `errorIndication` is `True`
+ * SNMP PDU `errorStatus` is reported as `True`
+ * SNMP :py:class:`~pysnmp.proto.rfc1905.EndOfMibView` values
+ (also known as *SNMP exception values*) are reported for all
+ MIB variables in `varBinds`
+ * *lexicographicMode* option is `True` and SNMP agent reports
+ end-of-mib or *lexicographicMode* is `False` and all
+ response MIB variables leave the scope of `varBinds`
+
+ At any moment a new sequence of `varBinds` could be send back into
+ running generator (supported since Python 2.6).
+
+ Setting `maxRepetitions` value to 15..50 might significantly improve
+ system performance, as many MIB variables get packed into a single
+ response message at once.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch import *
+ >>>
+ >>> g = bulkCmd(snmpDispatcher(),
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161)),
+ >>> 0, 25,
+ >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')))
+ >>> next(g)
+ (None, 0, 0, [[ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]])
+ >>> g.send([ObjectType(ObjectIdentity('IF-MIB', 'ifInOctets'))])
+ (None, 0, 0, [[(ObjectName('1.3.6.1.2.1.2.2.1.10.1'), Counter32(284817787))]])
+ """
+
+ def cbFun(*args, **kwargs):
+ response[:] = args + (kwargs.get('nextVarBinds', ()),)
+
+ options['cbFun'] = cbFun
+
+ lexicographicMode = options.pop('lexicographicMode', True)
+ maxRows = options.pop('maxRows', 0)
+ maxCalls = options.pop('maxCalls', 0)
+
+ initialVarBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, varBinds)
+
+ nullVarBinds = [False] * len(initialVarBinds)
+
+ totalRows = totalCalls = 0
+
+ errorIndication, errorStatus, errorIndex, varBindTable = None, 0, 0, ()
+ response = []
+
+ stopFlag = False
+
+ while not stopFlag:
+ if not varBinds:
+ yield (errorIndication, errorStatus, errorIndex, varBinds)
+ return
+
+ if maxRows and totalRows < maxRows:
+ maxRepetitions = min(maxRepetitions, maxRows - totalRows)
+
+ cmdgen.bulkCmd(snmpDispatcher, authData, transportTarget,
+ nonRepeaters, maxRepetitions,
+ *[(x[0], Null('')) for x in varBinds], **options)
+
+ snmpDispatcher.transportDispatcher.runDispatcher()
+
+ errorIndication, errorStatus, errorIndex, varBindTable, varBinds = response
+
+ if errorIndication:
+ yield (errorIndication, errorStatus, errorIndex, ())
+ return
+
+ elif errorStatus:
+ if errorStatus == 2:
+ # Hide SNMPv1 noSuchName error which leaks in here
+ # from SNMPv1 Agent through internal pysnmp proxy.
+ errorStatus = errorStatus.clone(0)
+ errorIndex = errorIndex.clone(0)
+ yield (errorIndication, errorStatus, errorIndex, varBindTable and varBindTable[0] or [])
+ return
+
+ else:
+ for rowIdx, varBindRow in enumerate(varBindTable):
+ stopFlag = True
+ if len(varBindRow) != len(initialVarBinds):
+ varBindTable = rowIdx and varBindTable[:rowIdx - 1] or []
+ break
+
+ for colIdx, varBind in enumerate(varBindRow):
+ name, val = varBind
+ if nullVarBinds[colIdx]:
+ varBindRow[colIdx] = name, endOfMibView
+ continue
+
+ stopFlag = False
+
+ if isinstance(val, Null):
+ nullVarBinds[colIdx] = True
+
+ elif not lexicographicMode and not initialVarBinds[colIdx][0].isPrefixOf(name):
+ varBindRow[colIdx] = name, endOfMibView
+ nullVarBinds[colIdx] = True
+
+ if stopFlag:
+ varBindTable = rowIdx and varBindTable[:rowIdx - 1] or []
+ break
+
+ totalRows += len(varBindTable)
+ totalCalls += 1
+
+ if maxRows and totalRows >= maxRows:
+ if totalRows > maxRows:
+ varBindTable = varBindTable[:-(totalRows - maxRows)]
+ stopFlag = True
+
+ if maxCalls and totalCalls >= maxCalls:
+ stopFlag = True
+
+ for varBindRow in varBindTable:
+ nextVarBinds = (yield errorIndication, errorStatus, errorIndex, varBindRow)
+
+ if nextVarBinds:
+ initialVarBinds = varBinds = vbProcessor.makeVarBinds(snmpDispatcher.cache, nextVarBinds)
diff --git a/pysnmp/hlapi/v1arch/asyncore/sync/ntforg.py b/pysnmp/hlapi/v1arch/asyncore/sync/ntforg.py
new file mode 100644
index 00000000..25912ff4
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/sync/ntforg.py
@@ -0,0 +1,140 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from sys import version_info
+from pysnmp.hlapi.v1arch.asyncore import ntforg
+from pysnmp.hlapi.varbinds import *
+from pysnmp.proto import errind
+from pyasn1.type.univ import Null
+
+__all__ = ['sendNotification']
+
+if version_info[:2] < (2, 6):
+ __all__.append('next')
+
+ # noinspection PyShadowingBuiltins
+ def next(iter):
+ return iter.next()
+
+
+def sendNotification(snmpDispatcher, authData, transportTarget,
+ notifyType, *varBinds, **options):
+ """Creates a generator to send one or more SNMP notifications.
+
+ On each iteration, new SNMP TRAP or INFORM notification is send
+ (:RFC:`1905#section-4,2,6`). The iterator blocks waiting for
+ INFORM acknowledgement to arrive or error to occur.
+
+ Parameters
+ ----------
+ snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
+ Class instance representing asyncore-based asynchronous event loop and
+ associated state information.
+
+ authData: :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ Class instance representing SNMP credentials.
+
+ transportTarget: :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or
+ :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
+ Class instance representing transport type along with SNMP peer address.
+
+ notifyType: str
+ Indicates type of notification to be sent. Recognized literal
+ values are *trap* or *inform*.
+
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU places rigid requirement on the ordering of
+ the variable-bindings.
+
+ Mandatory variable-bindings:
+
+ 0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ 1. SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Optional variable-bindings (applicable to SNMP v1 TRAP):
+
+ 2. SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ 3. SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ 4. SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ Informational variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
+
+ Other Parameters
+ ----------------
+ \*\*options :
+ Request options:
+
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `False`.
+
+ Yields
+ ------
+ errorIndication: str
+ True value indicates local SNMP error.
+ errorStatus: str
+ True value indicates SNMP PDU error reported by remote.
+ errorIndex: int
+ Non-zero value refers to `varBinds[errorIndex-1]`
+ varBinds: tuple
+ A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class
+ instances representing MIB variables returned in SNMP response.
+
+ Raises
+ ------
+ PySnmpError
+ Or its derivative indicating that an error occurred while
+ performing SNMP operation.
+
+ Notes
+ -----
+ The `sendNotification` generator will be exhausted immediately unless
+ an instance of :py:class:`~pysnmp.smi.rfc1902.NotificationType` class
+ or a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` `varBinds`
+ are send back into running generator (supported since Python 2.6).
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch import *
+ >>>
+ >>> g = sendNotification(SnmpDispatcher(),
+ >>> CommunityData('public'),
+ >>> UdpTransportTarget(('demo.snmplabs.com', 162)),
+ >>> 'trap',
+ >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown')))
+ >>> next(g)
+ (None, 0, 0, [])
+ """
+
+ def cbFun(*args, **kwargs):
+ response[:] = args
+
+ options['cbFun'] = cbFun
+
+ errorIndication, errorStatus, errorIndex = None, 0, 0
+
+ response = [None, 0, 0, []]
+
+ while True:
+ if varBinds:
+ ntforg.sendNotification(snmpDispatcher, authData, transportTarget,
+ notifyType, *varBinds, **options)
+
+ snmpDispatcher.transportDispatcher.runDispatcher()
+
+ errorIndication, errorStatus, errorIndex, varBinds = response
+
+ varBinds = (yield errorIndication, errorStatus, errorIndex, varBinds)
+
+ if not varBinds:
+ break
diff --git a/pysnmp/hlapi/v1arch/asyncore/transport.py b/pysnmp/hlapi/v1arch/asyncore/transport.py
new file mode 100644
index 00000000..be5e336d
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/asyncore/transport.py
@@ -0,0 +1,111 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+import socket
+import sys
+
+from pysnmp import error
+from pysnmp.carrier.asyncore.dgram import udp, udp6
+from pysnmp.hlapi.transport import AbstractTransportTarget
+
+__all__ = ['Udp6TransportTarget', 'UdpTransportTarget']
+
+
+class UdpTransportTarget(AbstractTransportTarget):
+ """Represent UDP/IPv4 transport endpoint.
+
+ This object can be used for passing UDP/IPv4 configuration information
+ to the low-level SNMP applications.
+
+ See :RFC:`1906#section-3` for more information on the UDP transport mapping.
+
+ Parameters
+ ----------
+ transportAddr: :py:class:`tuple`
+ Indicates remote address in Python :py:mod:`socket` module format
+ which is a tuple of FQDN, port where FQDN is a string representing
+ either hostname or IPv4 address in quad-dotted form, port is an
+ integer.
+ timeout: :py:class:`int`
+ Response timeout in seconds.
+ retries: :py:class:`int`
+ Maximum number of request retries, 0 retries means just a single
+ request.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import UdpTransportTarget
+ >>> UdpTransportTarget(('demo.snmplabs.com', 161))
+ UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5)
+ >>>
+
+ """
+ transportDomain = udp.domainName
+ protoTransport = udp.UdpSocketTransport
+
+ def _resolveAddr(self, transportAddr):
+ try:
+ return socket.getaddrinfo(transportAddr[0],
+ transportAddr[1],
+ socket.AF_INET,
+ socket.SOCK_DGRAM,
+ socket.IPPROTO_UDP)[0][4][:2]
+ except socket.gaierror:
+ raise error.PySnmpError('Bad IPv4/UDP transport address %s: %s' % (
+ '@'.join([str(x) for x in transportAddr]), sys.exc_info()[1]))
+
+
+class Udp6TransportTarget(AbstractTransportTarget):
+ """Represent UDP/IPv6 transport endpoint.
+
+ This object can be used for passing UDP/IPv4 configuration information
+ to the low-level SNMP applications.
+
+ See :RFC:`1906#section-3`, :RFC:`2851#section-4` for more information
+ on the UDP and IPv6 transport mapping.
+
+ Parameters
+ ----------
+ transportAddr : tuple
+ Indicates remote address in Python :py:mod:`socket` module format
+ which is a tuple of FQDN, port where FQDN is a string representing
+ either hostname or IPv6 address in one of three conventional forms
+ (:RFC:`1924#section-3`), port is an integer.
+ timeout : int
+ Response timeout in seconds.
+ retries : int
+ Maximum number of request retries, 0 retries means just a single
+ request.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch.asyncore import Udp6TransportTarget
+ >>> Udp6TransportTarget(('google.com', 161))
+ Udp6TransportTarget(('2a00:1450:4014:80a::100e', 161), timeout=1, retries=5)
+ >>> Udp6TransportTarget(('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 161))
+ Udp6TransportTarget(('fedc:ba98:7654:3210:fedc:ba98:7654:3210', 161), timeout=1, retries=5)
+ >>> Udp6TransportTarget(('1080:0:0:0:8:800:200C:417A', 161))
+ Udp6TransportTarget(('1080::8:800:200c:417a', 161), timeout=1, retries=5)
+ >>> Udp6TransportTarget(('::0', 161))
+ Udp6TransportTarget(('::', 161), timeout=1, retries=5)
+ >>> Udp6TransportTarget(('::', 161))
+ Udp6TransportTarget(('::', 161), timeout=1, retries=5)
+ >>>
+
+ """
+ transportDomain = udp6.domainName
+ protoTransport = udp6.Udp6SocketTransport
+
+ def _resolveAddr(self, transportAddr):
+ try:
+ return socket.getaddrinfo(transportAddr[0],
+ transportAddr[1],
+ socket.AF_INET6,
+ socket.SOCK_DGRAM,
+ socket.IPPROTO_UDP)[0][4][:2]
+ except socket.gaierror:
+ raise error.PySnmpError('Bad IPv6/UDP transport address %s: %s' % (
+ '@'.join([str(x) for x in transportAddr]), sys.exc_info()[1]))
diff --git a/pysnmp/hlapi/v1arch/auth.py b/pysnmp/hlapi/v1arch/auth.py
new file mode 100644
index 00000000..761f9738
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/auth.py
@@ -0,0 +1,45 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+
+__all__ = ['CommunityData']
+
+
+class CommunityData(object):
+ """Creates SNMP v1/v2c configuration entry.
+
+ This object can be used by
+ :py:class:`~pysnmp.hlapi.v1arch.asyncore.AsyncCommandGenerator` or
+ :py:class:`~pysnmp.hlapi.v1arch.asyncore.AsyncNotificationOriginator`
+ and their derivatives for conveying SNMP v1/v2c configuration.
+
+ Parameters
+ ----------
+ communityName: py:class:`str`
+ SNMP v1/v2c community string.
+ mpModel: py:class:`int`
+ SNMP version - 0 for SNMPv1 and 1 for SNMPv2c.
+
+ Examples
+ --------
+ >>> from pysnmp.hlapi.v1arch import CommunityData
+ >>> CommunityData('public')
+ CommunityData(communityName=<COMMUNITY>, mpModel=1)
+ """
+
+ def __init__(self, communityName, mpModel=1):
+ self.mpModel = mpModel
+ self.communityName = communityName
+
+ def __hash__(self):
+ return hash((self.communityName, self.mpModel))
+
+ def __repr__(self):
+ return '%s(communityName=<COMMUNITY>, mpModel=%r)' % (
+ self.__class__.__name__,
+ self.communityName,
+ self.mpModel,
+ )
diff --git a/pysnmp/hlapi/v1arch/dispatch.py b/pysnmp/hlapi/v1arch/dispatch.py
new file mode 100644
index 00000000..0c222281
--- /dev/null
+++ b/pysnmp/hlapi/v1arch/dispatch.py
@@ -0,0 +1,168 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from time import time
+
+from pysnmp.proto.api import verdec
+from pysnmp.proto import api
+from pysnmp.proto import error
+from pysnmp import debug
+
+from pyasn1.codec.ber import encoder, decoder
+
+__all__ = []
+
+
+class AbstractSnmpDispatcher(object):
+ """Creates SNMP message dispatcher object.
+
+ `SnmpDispatcher` object manages send and receives SNMP PDU
+ messages through underlying transport dispatcher and dispatches
+ them to the callers.
+
+ `SnmpDispatcher` is the only stateful object, all `hlapi.v1arch` SNMP
+ operations require an instance of `SnmpDispatcher`. Users do not normally
+ request services directly from `SnmpDispather`, but pass it around to
+ other `hlapi.v1arch` interfaces.
+
+ It is possible to run multiple instances of `SnmpDispatcher` in the
+ application. In a multithreaded environment, each thread that
+ works with SNMP must have its own `SnmpDispatcher` instance.
+ """
+
+ protoDispatcher = None
+
+ def __init__(self, transportDispatcher=None):
+ if transportDispatcher:
+ self.transportDispatcher = transportDispatcher
+ else:
+ self.transportDispatcher = self.protoDispatcher()
+
+ self._automaticDispatcher = transportDispatcher is not self.transportDispatcher
+ self._configuredTransports = set()
+
+ self._pendingReqs = {}
+
+ self.transportDispatcher.registerRecvCbFun(self._recvCb)
+ self.transportDispatcher.registerTimerCbFun(self._timerCb)
+
+ self.cache = {}
+
+ def __repr__(self):
+ return '%s(transportDispatcher=%s)' % (self.__class__.__name__, self.transportDispatcher)
+
+ def close(self):
+ self.transportDispatcher.unregisterRecvCbFun()
+ self.transportDispatcher.unregisterTimerCbFun()
+ if self._automaticDispatcher:
+ self.transportDispatcher.close()
+
+ for requestId, stateInfo in self._pendingReqs.items():
+ cbFun = stateInfo['cbFun']
+ cbCtx = stateInfo['cbCtx']
+
+ if cbFun:
+ cbFun(self, 'Request #%d terminated' % requestId, None, cbCtx)
+
+ self._pendingReqs.clear()
+
+ def sendPdu(self, authData, transportTarget, reqPdu, cbFun=None, cbCtx=None):
+ if (self._automaticDispatcher and
+ transportTarget.transportDomain not in self._configuredTransports):
+ self.transportDispatcher.registerTransport(
+ transportTarget.transportDomain, transportTarget.protoTransport().openClientMode()
+ )
+ self._configuredTransports.add(transportTarget.transportDomain)
+
+ pMod = api.protoModules[authData.mpModel]
+
+ reqMsg = pMod.Message()
+ pMod.apiMessage.setDefaults(reqMsg)
+ pMod.apiMessage.setCommunity(reqMsg, authData.communityName)
+ pMod.apiMessage.setPDU(reqMsg, reqPdu)
+
+ outgoingMsg = encoder.encode(reqMsg)
+
+ requestId = pMod.apiPDU.getRequestID(reqPdu)
+
+ self._pendingReqs[requestId] = dict(
+ outgoingMsg=outgoingMsg,
+ transportTarget=transportTarget,
+ cbFun=cbFun, cbCtx=cbCtx,
+ timestamp=time() + transportTarget.timeout, retries=0
+ )
+
+ self.transportDispatcher.sendMessage(
+ outgoingMsg, transportTarget.transportDomain, transportTarget.transportAddr
+ )
+
+ if (reqPdu.__class__ is getattr(pMod, 'SNMPv2TrapPDU', None) or
+ reqPdu.__class__ is getattr(pMod, 'TrapPDU', None)):
+ return requestId
+
+ self.transportDispatcher.jobStarted(id(self))
+
+ return requestId
+
+ def _recvCb(self, snmpEngine, transportDomain, transportAddress, wholeMsg):
+ try:
+ mpModel = verdec.decodeMessageVersion(wholeMsg)
+
+ except error.ProtocolError:
+ return null # n.b the whole buffer gets dropped
+
+ debug.logger & debug.flagDsp and debug.logger('receiveMessage: msgVersion %s, msg decoded' % mpModel)
+
+ pMod = api.protoModules[mpModel]
+
+ while wholeMsg:
+ rspMsg, wholeMsg = decoder.decode(wholeMsg, asn1Spec=pMod.Message())
+ rspPdu = pMod.apiMessage.getPDU(rspMsg)
+
+ requestId = pMod.apiPDU.getRequestID(rspPdu)
+
+ try:
+ stateInfo = self._pendingReqs.pop(requestId)
+
+ except KeyError:
+ continue
+
+ self.transportDispatcher.jobFinished(id(self))
+
+ cbFun = stateInfo['cbFun']
+ cbCtx = stateInfo['cbCtx']
+
+ if cbFun:
+ cbFun(self, requestId, None, rspPdu, cbCtx)
+
+ return wholeMsg
+
+ def _timerCb(self, timeNow):
+ for requestId, stateInfo in self._pendingReqs.items():
+ if stateInfo['timestamp'] < timeNow:
+ continue
+
+ retries = stateInfo['retries']
+ transportTarget = stateInfo['transportTarget']
+
+ if retries == transportTarget.retries:
+ cbFun = stateInfo['cbFun']
+ cbCtx = stateInfo['cbCtx']
+
+ if cbFun:
+ del self._pendingReqs[requestId]
+ cbFun(self, requestId, 'Request #%d timed out' % requestId, None, cbCtx)
+ self.transportDispatcher.jobFinished(id(self))
+ continue
+
+ stateInfo['retries'] += 1
+ stateInfo['timestamp'] = timeNow + transportTarget.timeout
+
+ outgoingMsg = stateInfo['outgoingMsg']
+
+ self.transportDispatcher.sendMessage(
+ outgoingMsg, transportTarget.transportDomain, transportTarget.transportAddr
+ )
diff --git a/pysnmp/hlapi/v3arch/__init__.py b/pysnmp/hlapi/v3arch/__init__.py
new file mode 100644
index 00000000..8f36181c
--- /dev/null
+++ b/pysnmp/hlapi/v3arch/__init__.py
@@ -0,0 +1,15 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.proto.rfc1902 import *
+from pysnmp.proto.rfc1905 import NoSuchInstance, NoSuchObject, EndOfMibView
+from pysnmp.smi.rfc1902 import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.entity.engine import *
+
+# default is synchronous asyncore-based API
+from pysnmp.hlapi.v3arch.asyncore.sync import *
diff --git a/pysnmp/hlapi/asyncio/__init__.py b/pysnmp/hlapi/v3arch/asyncio/__init__.py
index 24e71f7c..98f67187 100644
--- a/pysnmp/hlapi/asyncio/__init__.py
+++ b/pysnmp/hlapi/v3arch/asyncio/__init__.py
@@ -7,8 +7,8 @@
from pysnmp.proto.rfc1902 import *
from pysnmp.smi.rfc1902 import *
from pysnmp.entity.engine import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.asyncio.transport import *
-from pysnmp.hlapi.asyncio.cmdgen import *
-from pysnmp.hlapi.asyncio.ntforg import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.asyncio.transport import *
+from pysnmp.hlapi.v3arch.asyncio.cmdgen import *
+from pysnmp.hlapi.v3arch.asyncio.ntforg import *
diff --git a/pysnmp/hlapi/asyncio/cmdgen.py b/pysnmp/hlapi/v3arch/asyncio/cmdgen.py
index e449d477..bf97bcd4 100644
--- a/pysnmp/hlapi/asyncio/cmdgen.py
+++ b/pysnmp/hlapi/v3arch/asyncio/cmdgen.py
@@ -32,12 +32,13 @@
# THE POSSIBILITY OF SUCH DAMAGE.
#
from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.lcd import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.lcd import *
from pysnmp.hlapi.varbinds import *
-from pysnmp.hlapi.asyncio.transport import *
+from pysnmp.hlapi.v3arch.asyncio.transport import *
from pysnmp.entity.rfc3413 import cmdgen
+from pysnmp.proto.api import v2c
try:
import asyncio
@@ -49,7 +50,7 @@ __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib']
vbProcessor = CommandGeneratorVarBinds()
lcd = CommandGeneratorLcdConfigurator()
-isEndOfMib = lambda x: not cmdgen.getNextVarBinds(x)[1]
+isEndOfMib = lambda varBinds: not v2c.apiPDU.getNextVarBinds(varBinds)
@asyncio.coroutine
@@ -135,7 +136,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
if future.cancelled():
return
try:
- varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine, varBinds,
+ varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine.cache, varBinds,
lookupMib)
except Exception as e:
future.set_exception(e)
@@ -151,7 +152,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.GetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), future)
)
return future
@@ -240,7 +241,7 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
if future.cancelled():
return
try:
- varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine, varBinds,
+ varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine.cache, varBinds,
lookupMib)
except Exception as e:
future.set_exception(e)
@@ -256,7 +257,7 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.SetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), future)
)
return future
@@ -349,7 +350,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
if future.cancelled():
return
try:
- varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine,
+ varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine.cache,
varBindTableRow,
lookupMib)
for varBindTableRow in varBindTable]
@@ -367,7 +368,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.NextCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), future)
)
return future
@@ -489,7 +490,7 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
if future.cancelled():
return
try:
- varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine,
+ varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine.cache,
varBindTableRow,
lookupMib)
for varBindTableRow in varBindTable]
@@ -507,7 +508,7 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.BulkCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName, nonRepeaters, maxRepetitions,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), future)
)
return future
diff --git a/pysnmp/hlapi/asyncio/ntforg.py b/pysnmp/hlapi/v3arch/asyncio/ntforg.py
index 0bd59b7e..d43bf979 100644
--- a/pysnmp/hlapi/asyncio/ntforg.py
+++ b/pysnmp/hlapi/v3arch/asyncio/ntforg.py
@@ -9,11 +9,11 @@
# Zachary Lorusso <zlorusso@gmail.com>
#
from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.lcd import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.lcd import *
from pysnmp.hlapi.varbinds import *
-from pysnmp.hlapi.asyncio.transport import *
+from pysnmp.hlapi.v3arch.asyncio.transport import *
from pysnmp.entity.rfc3413 import ntforg
try:
@@ -29,7 +29,7 @@ lcd = NotificationOriginatorLcdConfigurator()
@asyncio.coroutine
def sendNotification(snmpEngine, authData, transportTarget, contextData,
- notifyType, varBinds, **options):
+ notifyType, *varBinds, **options):
"""Creates a generator to send SNMP notification.
When iterator gets advanced by :py:mod:`asyncio` main loop,
@@ -55,13 +55,30 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
Indicates type of notification to be sent. Recognized literal
values are *trap* or *inform*.
- varBinds: tuple
- Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance
- representing a minimum sequence of MIB variables required for
- particular notification type.
- Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
- objects could be passed instead. In the latter case it is up to
- the user to ensure proper Notification PDU contents.
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU places rigid requirement on the ordering of
+ the variable-bindings.
+
+ Mandatory variable-bindings:
+
+ 0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ 1. SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Optional variable-bindings (applicable to SNMP v1 TRAP):
+
+ 2. SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ 3. SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ 4. SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ Informational variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
Other Parameters
----------------
@@ -125,7 +142,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
if future.cancelled():
return
try:
- varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine, varBinds,
+ varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine.cache, varBinds,
lookupMib)
except Exception as e:
future.set_exception(e)
@@ -145,7 +162,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
notifyName,
contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds),
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds),
__cbFun,
(options.get('lookupMib', True), future)
)
diff --git a/pysnmp/hlapi/asyncio/transport.py b/pysnmp/hlapi/v3arch/asyncio/transport.py
index 4e7b9110..86423dfc 100644
--- a/pysnmp/hlapi/asyncio/transport.py
+++ b/pysnmp/hlapi/v3arch/asyncio/transport.py
@@ -6,9 +6,10 @@
#
import socket
import sys
+
from pysnmp.carrier.asyncio.dgram import udp, udp6
-from pysnmp.hlapi.transport import AbstractTransportTarget
from pysnmp.error import PySnmpError
+from pysnmp.hlapi.transport import AbstractTransportTarget
__all__ = ['Udp6TransportTarget', 'UdpTransportTarget']
diff --git a/pysnmp/hlapi/asyncore/__init__.py b/pysnmp/hlapi/v3arch/asyncore/__init__.py
index 303b4b84..9cef379f 100644
--- a/pysnmp/hlapi/asyncore/__init__.py
+++ b/pysnmp/hlapi/v3arch/asyncore/__init__.py
@@ -6,9 +6,9 @@
#
from pysnmp.proto.rfc1902 import *
from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.asyncore.transport import *
-from pysnmp.hlapi.asyncore.cmdgen import *
-from pysnmp.hlapi.asyncore.ntforg import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.asyncore.transport import *
+from pysnmp.hlapi.v3arch.asyncore.cmdgen import *
+from pysnmp.hlapi.v3arch.asyncore.ntforg import *
from pysnmp.entity.engine import *
diff --git a/pysnmp/hlapi/asyncore/cmdgen.py b/pysnmp/hlapi/v3arch/asyncore/cmdgen.py
index 4cedfa82..fac237e2 100644
--- a/pysnmp/hlapi/asyncore/cmdgen.py
+++ b/pysnmp/hlapi/v3arch/asyncore/cmdgen.py
@@ -6,18 +6,19 @@
#
from pysnmp.entity.rfc3413 import cmdgen
from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.lcd import *
from pysnmp.hlapi.varbinds import *
-from pysnmp.hlapi.asyncore.transport import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.lcd import *
+from pysnmp.hlapi.v3arch.asyncore.transport import *
+from pysnmp.proto.api import v2c
__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib']
vbProcessor = CommandGeneratorVarBinds()
lcd = CommandGeneratorLcdConfigurator()
-isEndOfMib = lambda x: not cmdgen.getNextVarBinds(x)[1]
+isEndOfMib = lambda varBinds: not v2c.apiPDU.getNextVarBinds(varBinds)
def getCmd(snmpEngine, authData, transportTarget, contextData,
@@ -51,15 +52,14 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
Other Parameters
----------------
\*\*options :
- Request options:
- * `lookupMib` - load MIB and resolve response MIB variables at
- the cost of slightly reduced performance. Default is `True`.
- * `cbFun` (callable) - user-supplied callable that is invoked
- to pass SNMP response data or error to user at a later point
- of time. Default is `None`.
- * `cbCtx` (object) - user-supplied object passing additional
- parameters to/from `cbFun`. Default is `None`.
+ * `lookupMib` (bool) - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ * `cbFun` (callable) - user-supplied callable that is invoked
+ to pass SNMP response data or error to user at a later point
+ of time. Default is `None`
+ * `cbCtx` (object) - user-supplied object passing additional
+ parameters to/from `cbFun`. Default is `None`.
Notes
-----
@@ -118,7 +118,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
return cbFun(snmpEngine, sendRequestHandle, errorIndication,
errorStatus, errorIndex,
vbProcessor.unmakeVarBinds(
- snmpEngine, varBinds, lookupMib
+ snmpEngine.cache, varBinds, lookupMib
), cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
@@ -126,7 +126,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
return cmdgen.GetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True),
options.get('cbFun'), options.get('cbCtx'))
)
@@ -229,14 +229,14 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
return cbFun(snmpEngine, sendRequestHandle, errorIndication,
errorStatus, errorIndex,
vbProcessor.unmakeVarBinds(
- snmpEngine, varBinds, lookupMib
+ snmpEngine.cache, varBinds, lookupMib
), cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
return cmdgen.SetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
- contextData.contextName, vbProcessor.makeVarBinds(snmpEngine, varBinds),
+ contextData.contextName, vbProcessor.makeVarBinds(snmpEngine.cache, varBinds),
__cbFun, (options.get('lookupMib', True),
options.get('cbFun'), options.get('cbCtx'))
)
@@ -339,7 +339,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
lookupMib, cbFun, cbCtx = cbCtx
return cbFun(snmpEngine, sendRequestHandle, errorIndication,
errorStatus, errorIndex,
- [vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in
+ [vbProcessor.unmakeVarBinds(snmpEngine.cache, varBindTableRow, lookupMib) for varBindTableRow in
varBindTable],
cbCtx)
@@ -347,7 +347,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
return cmdgen.NextCommandGenerator().sendVarBinds(
snmpEngine, addrName,
contextData.contextEngineId, contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds),
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds),
__cbFun, (options.get('lookupMib', True),
options.get('cbFun'), options.get('cbCtx'))
)
@@ -478,16 +478,17 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
errorIndication, errorStatus, errorIndex,
varBindTable, cbCtx):
lookupMib, cbFun, cbCtx = cbCtx
- return cbFun(snmpEngine, sendRequestHandle, errorIndication,
+ return cbFun(snmpEngine.cache, sendRequestHandle, errorIndication,
errorStatus, errorIndex,
- [vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in
+ [vbProcessor.unmakeVarBinds(snmpEngine.cache, varBindTableRow, lookupMib) for varBindTableRow in
varBindTable], cbCtx)
addrName, paramsName = lcd.configure(snmpEngine, authData, transportTarget)
+
return cmdgen.BulkCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName, nonRepeaters, maxRepetitions,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True),
options.get('cbFun'), options.get('cbCtx'))
)
diff --git a/pysnmp/hlapi/asyncore/ntforg.py b/pysnmp/hlapi/v3arch/asyncore/ntforg.py
index ecd418c1..09cb6dfc 100644
--- a/pysnmp/hlapi/asyncore/ntforg.py
+++ b/pysnmp/hlapi/v3arch/asyncore/ntforg.py
@@ -6,11 +6,11 @@
#
from pysnmp.smi.rfc1902 import *
from pysnmp.entity.rfc3413 import ntforg
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.lcd import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.lcd import *
from pysnmp.hlapi.varbinds import *
-from pysnmp.hlapi.asyncore.transport import *
+from pysnmp.hlapi.v3arch.asyncore.transport import *
__all__ = ['sendNotification']
@@ -19,8 +19,7 @@ lcd = NotificationOriginatorLcdConfigurator()
def sendNotification(snmpEngine, authData, transportTarget, contextData,
- notifyType, varBinds, cbFun=None, cbCtx=None,
- lookupMib=False):
+ notifyType, *varBinds, **options):
"""Send SNMP notification.
Based on passed parameters, prepares SNMP TRAP or INFORM
@@ -47,26 +46,58 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
Indicates type of notification to be sent. Recognized literal
values are *trap* or *inform*.
- varBinds : tuple
- Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class
- instance representing a minimum sequence of MIB variables
- required for particular notification type. Alternatively,
- a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
- objects could be passed instead. In the latter case it is up to
- the user to ensure proper Notification PDU contents.
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU includes some housekeeping items that
+ are required for SNMP to function.
+
+ Agent information:
+
+ * SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ * SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Applicable to SNMP v1 TRAP:
+
+ * SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ * SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ * SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ .. note::
+
+ Unless user passes some of these variable-bindings, `.sendNotification()`
+ call will fill in the missing items.
+
+ User variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
+
+ .. note::
+
+ The :py:class:`~pysnmp.smi.rfc1902.NotificationType` object ensures
+ properly formed SNMP notification (to comply MIB definition). If you
+ build notification PDU out of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ objects or simple tuples of OID-value objects, it is your responsibility
+ to provide well-formed notificaton payload.
Other Parameters
----------------
- cbFun : callable
- user-supplied callable that is invoked to pass SNMP response
- to *INFORM* notification or error to user at a later point of
- time. The `cbFun` callable is never invoked for *TRAP* notifications.
- cbCtx : object
- user-supplied object passing additional parameters to/from
- `cbFun`.
- lookupMib : bool
- `lookupMib` - load MIB and resolve response MIB variables at
- the cost of slightly reduced performance. Default is `True`.
+ \*\*options:
+
+ * lookupMib: bool
+ `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
+ * cbFun: callable
+ user-supplied callable that is invoked to pass SNMP response
+ to *INFORM* notification or error to user at a later point of
+ time. The `cbFun` callable is never invoked for *TRAP* notifications.
+ * cbCtx: object
+ user-supplied object passing additional parameters to/from
+ `cbFun`
Notes
-----
@@ -126,7 +157,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
snmpEngine, sendRequestHandle, errorIndication,
errorStatus, errorIndex,
vbProcessor.unmakeVarBinds(
- snmpEngine, varBinds, lookupMib
+ snmpEngine.cache, varBinds, lookupMib
), cbCtx
)
@@ -136,6 +167,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
return ntforg.NotificationOriginator().sendVarBinds(
snmpEngine, notifyName,
contextData.contextEngineId, contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds),
- __cbFun, (lookupMib, cbFun, cbCtx)
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
+ (options.get('lookupMib', True),
+ options.get('cbFun'), options.get('cbCtx'))
)
diff --git a/pysnmp/hlapi/v3arch/asyncore/sync/__init__.py b/pysnmp/hlapi/v3arch/asyncore/sync/__init__.py
new file mode 100644
index 00000000..be6f9ec1
--- /dev/null
+++ b/pysnmp/hlapi/v3arch/asyncore/sync/__init__.py
@@ -0,0 +1,19 @@
+#
+# This file is part of pysnmp software.
+#
+# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
+# License: http://snmplabs.com/pysnmp/license.html
+#
+from pysnmp.proto.rfc1902 import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.asyncore.transport import *
+from pysnmp.entity.engine import *
+
+try:
+ from pysnmp.hlapi.v3arch.asyncore.sync.cmdgen import *
+ from pysnmp.hlapi.v3arch.asyncore.sync.ntforg import *
+except SyntaxError:
+ from pysnmp.hlapi.v3arch.asyncore.sync.compat.cmdgen import *
+ from pysnmp.hlapi.v3arch.asyncore.sync.compat.ntforg import *
diff --git a/pysnmp/hlapi/asyncore/sync/cmdgen.py b/pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py
index 3868ac66..00848e52 100644
--- a/pysnmp/hlapi/asyncore/sync/cmdgen.py
+++ b/pysnmp/hlapi/v3arch/asyncore/sync/cmdgen.py
@@ -5,7 +5,7 @@
# License: http://snmplabs.com/pysnmp/license.html
#
from sys import version_info
-from pysnmp.hlapi.asyncore import cmdgen
+from pysnmp.hlapi.v3arch.asyncore import cmdgen
from pysnmp.hlapi.varbinds import *
from pysnmp.proto.rfc1905 import endOfMibView
from pysnmp.proto import errind
@@ -346,7 +346,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
vbProcessor = CommandGeneratorVarBinds()
- initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
+ initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine.cache, varBinds)]
totalRows = totalCalls = 0
@@ -408,7 +408,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
if initialVarBinds:
varBinds = initialVarBinds
- initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
+ initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine.cache, varBinds)]
if maxRows and totalRows >= maxRows:
return
@@ -546,7 +546,7 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
vbProcessor = CommandGeneratorVarBinds()
- initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
+ initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine.cache, varBinds)]
nullVarBinds = [False] * len(initialVars)
totalRows = totalCalls = 0
@@ -632,4 +632,3 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
varBinds = initialVarBinds
initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
nullVarBinds = [False] * len(initialVars)
-
diff --git a/pysnmp/hlapi/asyncore/sync/compat/__init__.py b/pysnmp/hlapi/v3arch/asyncore/sync/compat/__init__.py
index 8c3066b2..8c3066b2 100644
--- a/pysnmp/hlapi/asyncore/sync/compat/__init__.py
+++ b/pysnmp/hlapi/v3arch/asyncore/sync/compat/__init__.py
diff --git a/pysnmp/hlapi/asyncore/sync/compat/cmdgen.py b/pysnmp/hlapi/v3arch/asyncore/sync/compat/cmdgen.py
index 066d1d9f..ff760ee5 100644
--- a/pysnmp/hlapi/asyncore/sync/compat/cmdgen.py
+++ b/pysnmp/hlapi/v3arch/asyncore/sync/compat/cmdgen.py
@@ -6,7 +6,7 @@
#
# This is a Python 2.6- version of the same file at level up
#
-from pysnmp.hlapi.asyncore import cmdgen
+from pysnmp.hlapi.v3arch.asyncore import cmdgen
from pysnmp.hlapi.varbinds import *
from pysnmp.proto.rfc1905 import endOfMibView
from pysnmp.proto import errind
@@ -100,7 +100,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
vbProcessor = CommandGeneratorVarBinds()
- initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
+ initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine.cache, varBinds)]
totalRows = totalCalls = 0
@@ -172,7 +172,7 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
vbProcessor = CommandGeneratorVarBinds()
- initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds)]
+ initialVars = [x[0] for x in vbProcessor.makeVarBinds(snmpEngine.cache, varBinds)]
nullVarBinds = [False] * len(initialVars)
totalRows = totalCalls = 0
diff --git a/pysnmp/hlapi/asyncore/sync/compat/ntforg.py b/pysnmp/hlapi/v3arch/asyncore/sync/compat/ntforg.py
index 80221713..173dbc95 100644
--- a/pysnmp/hlapi/asyncore/sync/compat/ntforg.py
+++ b/pysnmp/hlapi/v3arch/asyncore/sync/compat/ntforg.py
@@ -6,7 +6,7 @@
#
# This is a Python 2.6- version of the same file at level up
#
-from pysnmp.hlapi.asyncore import ntforg
+from pysnmp.hlapi.v3arch.asyncore import ntforg
__all__ = ['sendNotification', 'next']
diff --git a/pysnmp/hlapi/asyncore/sync/ntforg.py b/pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py
index 6f732d75..8e80a740 100644
--- a/pysnmp/hlapi/asyncore/sync/ntforg.py
+++ b/pysnmp/hlapi/v3arch/asyncore/sync/ntforg.py
@@ -5,7 +5,7 @@
# License: http://snmplabs.com/pysnmp/license.html
#
from sys import version_info
-from pysnmp.hlapi.asyncore import ntforg
+from pysnmp.hlapi.v3arch.asyncore import ntforg
__all__ = ['sendNotification']
@@ -18,12 +18,12 @@ if version_info[:2] < (2, 6):
def sendNotification(snmpEngine, authData, transportTarget, contextData,
- notifyType, varBinds, **options):
+ notifyType, *varBinds, **options):
"""Creates a generator to send one or more SNMP notifications.
On each iteration, new SNMP TRAP or INFORM notification is send
(:RFC:`1905#section-4,2,6`). The iterator blocks waiting for
- INFORM acknowlegement to arrive or error to occur.
+ INFORM acknowledgement to arrive or error to occur.
Parameters
----------
@@ -43,21 +43,49 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
Indicates type of notification to be sent. Recognized literal
values are *trap* or *inform*.
- varBinds: tuple
- Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance
- representing a minimum sequence of MIB variables required for
- particular notification type.
- Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
- objects could be passed instead. In the latter case it is up to
- the user to ensure proper Notification PDU contents.
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU includes some housekeeping items that
+ are required for SNMP to function.
+
+ Agent information:
+
+ * SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ * SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Applicable to SNMP v1 TRAP:
+
+ * SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ * SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ * SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ .. note::
+
+ Unless user passes some of these variable-bindings, `.sendNotification()`
+ call will fill in the missing items.
+
+ User variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
+
+ .. note::
+
+ The :py:class:`~pysnmp.smi.rfc1902.NotificationType` object ensures
+ properly formed SNMP notification (to comply MIB definition). If you
+ build notification PDU out of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ objects or simple tuples of OID-value objects, it is your responsibility
+ to provide well-formed notificaton payload.
Other Parameters
----------------
- \*\*options :
- Request options:
-
- * `lookupMib` - load MIB and resolve response MIB variables at
- the cost of slightly reduced performance. Default is `True`.
+ \*\*options:
+ * `lookupMib` - load MIB and resolve response MIB variables at
+ the cost of slightly reduced performance. Default is `True`.
Yields
------
@@ -79,7 +107,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
Notes
-----
- The `sendNotification` generator will be exhausted immidiately unless
+ The `sendNotification` generator will be exhausted immediately unless
an instance of :py:class:`~pysnmp.smi.rfc1902.NotificationType` class
or a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` `varBinds`
are send back into running generator (supported since Python 2.6).
@@ -113,8 +141,8 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
while True:
if varBinds:
ntforg.sendNotification(snmpEngine, authData, transportTarget,
- contextData, notifyType, varBinds,
- cbFun, cbCtx,
+ contextData, notifyType, *varBinds,
+ cbFun=cbFun, cbCtx=cbCtx,
lookupMib=options.get('lookupMib', True))
snmpEngine.transportDispatcher.runDispatcher()
diff --git a/pysnmp/hlapi/asyncore/transport.py b/pysnmp/hlapi/v3arch/asyncore/transport.py
index 2c103632..6019bd02 100644
--- a/pysnmp/hlapi/asyncore/transport.py
+++ b/pysnmp/hlapi/v3arch/asyncore/transport.py
@@ -6,9 +6,10 @@
#
import socket
import sys
+
+from pysnmp import error
from pysnmp.carrier.asyncore.dgram import udp, udp6
from pysnmp.hlapi.transport import AbstractTransportTarget
-from pysnmp import error
__all__ = ['Udp6TransportTarget', 'UdpTransportTarget']
@@ -42,7 +43,7 @@ class UdpTransportTarget(AbstractTransportTarget):
Examples
--------
- >>> from pysnmp.hlapi.asyncore import UdpTransportTarget
+ >>> from pysnmp.hlapi.v3arch.asyncore import UdpTransportTarget
>>> UdpTransportTarget(('demo.snmplabs.com', 161))
UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5, tagList='')
>>>
@@ -92,7 +93,7 @@ class Udp6TransportTarget(AbstractTransportTarget):
Examples
--------
- >>> from pysnmp.hlapi.asyncore import Udp6TransportTarget
+ >>> from pysnmp.hlapi.v3arch.asyncore import Udp6TransportTarget
>>> Udp6TransportTarget(('google.com', 161))
Udp6TransportTarget(('2a00:1450:4014:80a::100e', 161), timeout=1, retries=5, tagList='')
>>> Udp6TransportTarget(('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 161))
diff --git a/pysnmp/hlapi/auth.py b/pysnmp/hlapi/v3arch/auth.py
index e4650f4b..e4650f4b 100644
--- a/pysnmp/hlapi/auth.py
+++ b/pysnmp/hlapi/v3arch/auth.py
diff --git a/pysnmp/hlapi/context.py b/pysnmp/hlapi/v3arch/context.py
index 754c43cc..754c43cc 100644
--- a/pysnmp/hlapi/context.py
+++ b/pysnmp/hlapi/v3arch/context.py
diff --git a/pysnmp/hlapi/lcd.py b/pysnmp/hlapi/v3arch/lcd.py
index 94c10abf..3c11635e 100644
--- a/pysnmp/hlapi/lcd.py
+++ b/pysnmp/hlapi/v3arch/lcd.py
@@ -6,7 +6,7 @@
#
from pysnmp.entity import config
from pysnmp import nextid, error
-from pysnmp.hlapi.auth import *
+from pysnmp.hlapi.v3arch.auth import *
__all__ = ['CommandGeneratorLcdConfigurator',
'NotificationOriginatorLcdConfigurator']
diff --git a/pysnmp/hlapi/v3arch/twisted/__init__.py b/pysnmp/hlapi/v3arch/twisted/__init__.py
new file mode 100644
index 00000000..f141bf55
--- /dev/null
+++ b/pysnmp/hlapi/v3arch/twisted/__init__.py
@@ -0,0 +1,8 @@
+from pysnmp.proto.rfc1902 import *
+from pysnmp.smi.rfc1902 import *
+from pysnmp.entity.engine import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.twisted.transport import *
+from pysnmp.hlapi.v3arch.twisted.cmdgen import *
+from pysnmp.hlapi.v3arch.twisted.ntforg import *
diff --git a/pysnmp/hlapi/twisted/cmdgen.py b/pysnmp/hlapi/v3arch/twisted/cmdgen.py
index 94490527..745ce9d2 100644
--- a/pysnmp/hlapi/twisted/cmdgen.py
+++ b/pysnmp/hlapi/v3arch/twisted/cmdgen.py
@@ -5,13 +5,14 @@
# License: http://snmplabs.com/pysnmp/license.html
#
from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.lcd import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.lcd import *
from pysnmp.hlapi.varbinds import *
-from pysnmp.hlapi.twisted.transport import *
+from pysnmp.hlapi.v3arch.twisted.transport import *
from pysnmp.entity.rfc3413 import cmdgen
from pysnmp.proto import errind
+from pysnmp.proto.api import v2c
from twisted.internet.defer import Deferred
from twisted.python.failure import Failure
@@ -20,7 +21,8 @@ __all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'isEndOfMib']
vbProcessor = CommandGeneratorVarBinds()
lcd = CommandGeneratorLcdConfigurator()
-isEndOfMib = lambda x: not cmdgen.getNextVarBinds(x)[1]
+isEndOfMib = lambda varBinds: not v2c.apiPDU.getNextVarBinds(varBinds)
+
def getCmd(snmpEngine, authData, transportTarget, contextData,
*varBinds, **options):
@@ -118,7 +120,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
deferred.errback(Failure(errorIndication))
else:
try:
- varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)
+ varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib)
except Exception as e:
deferred.errback(Failure(e))
@@ -133,7 +135,7 @@ def getCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.GetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), deferred)
)
return deferred
@@ -234,7 +236,7 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
deferred.errback(Failure(errorIndication))
else:
try:
- varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)
+ varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib)
except Exception as e:
deferred.errback(Failure(e))
@@ -249,7 +251,7 @@ def setCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.SetCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), deferred)
)
return deferred
@@ -361,7 +363,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
deferred.errback(Failure(errorIndication))
else:
try:
- varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine,
+ varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine.cache,
varBindTableRow,
lookupMib)
for varBindTableRow in varBindTable]
@@ -379,7 +381,7 @@ def nextCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.NextCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun,
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun,
(options.get('lookupMib', True), deferred)
)
return deferred
@@ -519,7 +521,7 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
deferred.errback(Failure(errorIndication))
else:
try:
- varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine,
+ varBindsUnmade = [vbProcessor.unmakeVarBinds(snmpEngine.cache,
varBindTableRow,
lookupMib)
for varBindTableRow in varBindTable]
@@ -537,7 +539,7 @@ def bulkCmd(snmpEngine, authData, transportTarget, contextData,
cmdgen.BulkCommandGenerator().sendVarBinds(
snmpEngine, addrName, contextData.contextEngineId,
contextData.contextName, nonRepeaters, maxRepetitions,
- vbProcessor.makeVarBinds(snmpEngine, varBinds),
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds),
__cbFun,
(options.get('lookupMib', True), deferred)
)
diff --git a/pysnmp/hlapi/twisted/ntforg.py b/pysnmp/hlapi/v3arch/twisted/ntforg.py
index fbbdc0f1..0f57068d 100644
--- a/pysnmp/hlapi/twisted/ntforg.py
+++ b/pysnmp/hlapi/v3arch/twisted/ntforg.py
@@ -5,11 +5,11 @@
# License: http://snmplabs.com/pysnmp/license.html
#
from pysnmp.smi.rfc1902 import *
-from pysnmp.hlapi.auth import *
-from pysnmp.hlapi.context import *
-from pysnmp.hlapi.lcd import *
+from pysnmp.hlapi.v3arch.auth import *
+from pysnmp.hlapi.v3arch.context import *
+from pysnmp.hlapi.v3arch.lcd import *
from pysnmp.hlapi.varbinds import *
-from pysnmp.hlapi.twisted.transport import *
+from pysnmp.hlapi.v3arch.twisted.transport import *
from pysnmp.entity.rfc3413 import ntforg
from twisted.internet import reactor
from twisted.internet.defer import Deferred
@@ -21,7 +21,7 @@ vbProcessor = NotificationOriginatorVarBinds()
lcd = NotificationOriginatorLcdConfigurator()
def sendNotification(snmpEngine, authData, transportTarget, contextData,
- notifyType, varBinds, **options):
+ notifyType, *varBinds, **options):
"""Sends SNMP notification.
Based on passed parameters, prepares SNMP TRAP or INFORM message
@@ -30,29 +30,59 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
Parameters
----------
- snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine`
+ snmpEngine: :py:class:`~pysnmp.hlapi.SnmpEngine`
Class instance representing SNMP engine.
- authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
+ authData: :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
Class instance representing SNMP credentials.
transportTarget : :py:class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.twisted.Udp6TransportTarget`
Class instance representing transport type along with SNMP peer address.
- contextData : :py:class:`~pysnmp.hlapi.ContextData`
+ contextData: :py:class:`~pysnmp.hlapi.ContextData`
Class instance representing SNMP ContextEngineId and ContextName values.
- notifyType : str
+ notifyType: str
Indicates type of notification to be sent. Recognized literal
values are *trap* or *inform*.
- varBinds: tuple
- Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance
- representing a minimum sequence of MIB variables required for
- particular notification type.
- Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
- objects could be passed instead. In the latter case it is up to
- the user to ensure proper Notification PDU contents.
+ \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
+ One or more objects representing MIB variables to place
+ into SNMP notification. It could be tuples of OID-values
+ or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
+ of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.
+
+ SNMP Notification PDU includes some housekeeping items that
+ are required for SNMP to function.
+
+ Agent information:
+
+ * SNMPv2-MIB::sysUpTime.0 = <agent uptime>
+ * SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}
+
+ Applicable to SNMP v1 TRAP:
+
+ * SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
+ * SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
+ * SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>
+
+ .. note::
+
+ Unless user passes some of these variable-bindings, `.sendNotification()`
+ call will fill in the missing items.
+
+ User variable-bindings:
+
+ * SNMPv2-SMI::NOTIFICATION-TYPE
+ * SNMPv2-SMI::OBJECT-TYPE
+
+ .. note::
+
+ The :py:class:`~pysnmp.smi.rfc1902.NotificationType` object ensures
+ properly formed SNMP notification (to comply MIB definition). If you
+ build notification PDU out of :py:class:`~pysnmp.smi.rfc1902.ObjectType`
+ objects or simple tuples of OID-value objects, it is your responsibility
+ to provide well-formed notificaton payload.
Other Parameters
----------------
@@ -126,7 +156,9 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
deferred.errback(Failure(errorIndication))
else:
try:
- varBindsUnmade = vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib)
+ varBindsUnmade = vbProcessor.unmakeVarBinds(
+ snmpEngine.cache, varBinds, lookupMib
+ )
except Exception as e:
deferred.errback(Failure(e))
@@ -148,7 +180,7 @@ def sendNotification(snmpEngine, authData, transportTarget, contextData,
notifyName,
contextData.contextEngineId,
contextData.contextName,
- vbProcessor.makeVarBinds(snmpEngine, varBinds),
+ vbProcessor.makeVarBinds(snmpEngine.cache, varBinds),
__cbFun,
(options.get('lookupMib', True), deferred)
)
diff --git a/pysnmp/hlapi/twisted/transport.py b/pysnmp/hlapi/v3arch/twisted/transport.py
index aeea22da..0db45a70 100644
--- a/pysnmp/hlapi/twisted/transport.py
+++ b/pysnmp/hlapi/v3arch/twisted/transport.py
@@ -4,10 +4,12 @@
# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysnmp/license.html
#
-import socket, sys
+import socket
+import sys
+
from pysnmp.carrier.twisted.dgram import udp
-from pysnmp.hlapi.transport import AbstractTransportTarget
from pysnmp.error import PySnmpError
+from pysnmp.hlapi.transport import AbstractTransportTarget
__all__ = ['UdpTransportTarget']
diff --git a/pysnmp/hlapi/varbinds.py b/pysnmp/hlapi/varbinds.py
index ac9151a8..6c0c2905 100644
--- a/pysnmp/hlapi/varbinds.py
+++ b/pysnmp/hlapi/varbinds.py
@@ -4,68 +4,86 @@
# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysnmp/license.html
#
-from pysnmp.smi import view
from pysnmp.smi.rfc1902 import *
+from pysnmp.smi import builder
+from pysnmp.smi import view
__all__ = ['CommandGeneratorVarBinds', 'NotificationOriginatorVarBinds']
-class AbstractVarBinds(object):
+class MibViewControllerManager(object):
@staticmethod
- def getMibViewController(snmpEngine):
- mibViewController = snmpEngine.getUserContext('mibViewController')
- if not mibViewController:
- mibViewController = view.MibViewController(
- snmpEngine.getMibBuilder()
- )
- snmpEngine.setUserContext(mibViewController=mibViewController)
+ def getMibViewController(userCache):
+ try:
+ mibViewController = userCache['mibViewController']
+
+ except KeyError:
+ mibViewController = view.MibViewController(builder.MibBuilder())
+ userCache['mibViewController'] = mibViewController
+
return mibViewController
-class CommandGeneratorVarBinds(AbstractVarBinds):
- def makeVarBinds(self, snmpEngine, varBinds):
- mibViewController = self.getMibViewController(snmpEngine)
- __varBinds = []
+class CommandGeneratorVarBinds(MibViewControllerManager):
+ def makeVarBinds(self, userCache, varBinds):
+ mibViewController = self.getMibViewController(userCache)
+
+ resolvedVarBinds = []
+
for varBind in varBinds:
if isinstance(varBind, ObjectType):
pass
+
elif isinstance(varBind[0], ObjectIdentity):
varBind = ObjectType(*varBind)
+
elif isinstance(varBind[0][0], tuple): # legacy
varBind = ObjectType(ObjectIdentity(varBind[0][0][0], varBind[0][0][1], *varBind[0][1:]), varBind[1])
+
else:
varBind = ObjectType(ObjectIdentity(varBind[0]), varBind[1])
- __varBinds.append(varBind.resolveWithMib(mibViewController))
+ resolvedVarBinds.append(varBind.resolveWithMib(mibViewController))
- return __varBinds
+ return resolvedVarBinds
- def unmakeVarBinds(self, snmpEngine, varBinds, lookupMib=True):
+ def unmakeVarBinds(self, userCache, varBinds, lookupMib=True):
if lookupMib:
- mibViewController = self.getMibViewController(snmpEngine)
+ mibViewController = self.getMibViewController(userCache)
varBinds = [ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController) for x in varBinds]
return varBinds
-class NotificationOriginatorVarBinds(AbstractVarBinds):
- def makeVarBinds(self, snmpEngine, varBinds):
- mibViewController = self.getMibViewController(snmpEngine)
+class NotificationOriginatorVarBinds(MibViewControllerManager):
+ def makeVarBinds(self, userCache, varBinds):
+ mibViewController = self.getMibViewController(userCache)
+
if isinstance(varBinds, NotificationType):
- varBinds.resolveWithMib(mibViewController)
- __varBinds = []
+ return varBinds.resolveWithMib(mibViewController)
+
+ resolvedVarBinds = []
+
for varBind in varBinds:
+ if isinstance(varBind, NotificationType):
+ resolvedVarBinds.extend(varBind.resolveWithMib(mibViewController))
+ continue
+
if isinstance(varBind, ObjectType):
pass
+
elif isinstance(varBind[0], ObjectIdentity):
varBind = ObjectType(*varBind)
+
else:
varBind = ObjectType(ObjectIdentity(varBind[0]), varBind[1])
- __varBinds.append(varBind.resolveWithMib(mibViewController))
- return __varBinds
- def unmakeVarBinds(self, snmpEngine, varBinds, lookupMib=False):
+ resolvedVarBinds.append(varBind.resolveWithMib(mibViewController))
+
+ return resolvedVarBinds
+
+ def unmakeVarBinds(self, userCache, varBinds, lookupMib=False):
if lookupMib:
- mibViewController = self.getMibViewController(snmpEngine)
+ mibViewController = self.getMibViewController(userCache)
varBinds = [ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController) for x in varBinds]
return varBinds