import sys from pysnmp.entity.rfc3413 import config from pysnmp.proto import rfc1905, errind from pysnmp.proto.api import v2c from pysnmp.proto.proxy import rfc2576 from pysnmp import error, nextid, debug from pysnmp.proto.error import StatusInformation from pyasn1.type import univ getNextHandle = nextid.Integer(0x7fffffff) __null = univ.Null('') def getNextVarBinds(origVarBinds, varBinds): errorIndication = None idx = nonNulls = len(varBinds) rspVarBinds = [] while idx: idx = idx - 1 if varBinds[idx][1].tagSet in (rfc1905.NoSuchObject.tagSet, rfc1905.NoSuchInstance.tagSet, rfc1905.EndOfMibView.tagSet): nonNulls = nonNulls - 1 elif v2c.ObjectIdentifier(origVarBinds[idx][0]).asTuple() >= varBinds[idx][0].asTuple(): errorIndication = errind.oidNotIncreasing rspVarBinds.insert(0, (varBinds[idx][0], __null)) if not nonNulls: rspVarBinds = [] return errorIndication, rspVarBinds class CommandGenerator: _null = univ.Null('') def __init__(self): self.__pendingReqs = {} def processResponsePdu(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, statusInformation, sendPduHandle, cbCtx): origSendRequestHandle, cbFun, cbCtx = cbCtx # 3.1.1 if sendPduHandle not in self.__pendingReqs: raise error.PySnmpError('Missing sendPduHandle %s' % sendPduHandle) ( origTransportDomain, origTransportAddress, origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, origPduVersion, origPdu, origTimeout, origRetryCount, origRetries ) = self.__pendingReqs.pop(sendPduHandle) snmpEngine.transportDispatcher.jobFinished(id(self)) # 3.1.3 if statusInformation: debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendPduHandle %s, statusInformation %s' % (sendPduHandle, statusInformation)) errorIndication = statusInformation['errorIndication'] # SNMP engine discovery will take extra retries, allow that if errorIndication in (errind.notInTimeWindow, errind.unknownEngineID) and \ origRetries == origRetryCount + 2 or \ errorIndication not in (errind.notInTimeWindow, errind.unknownEngineID) and \ origRetries == origRetryCount: debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendPduHandle %s, retry count %d exceeded' % (sendPduHandle, origRetries)) cbFun(snmpEngine, origSendRequestHandle, statusInformation['errorIndication'], None, cbCtx) return try: cbCtx = origSendRequestHandle, cbFun, cbCtx cbFun = self.processResponsePdu sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, origTransportDomain, origTransportAddress, origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, origPduVersion, origPdu, True, # expectResponse origTimeout, # already in ticks cbFun, cbCtx ) snmpEngine.transportDispatcher.jobStarted(id(self)) self.__pendingReqs[sendPduHandle] = ( origTransportDomain, origTransportAddress, origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, origPduVersion, origPdu, origTimeout, origRetryCount, origRetries + 1 ) return except StatusInformation: statusInformation = sys.exc_info()[1] debug.logger & debug.flagApp and debug.logger('processResponsePdu: origSendRequestHandle %s, _sendPdu() failed with %r' % (sendPduHandle, statusInformation)) origSendRequestHandle, cbFun, cbCtx = cbCtx cbFun(snmpEngine, origSendRequestHandle, statusInformation['errorIndication'], None, cbCtx) return if origMessageProcessingModel != messageProcessingModel or \ origSecurityModel != securityModel or \ origSecurityName != origSecurityName or \ origContextEngineId and origContextEngineId != contextEngineId or \ origContextName and origContextName != contextName or \ origPduVersion != pduVersion: debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendPduHandle %s, request/response data mismatch' % sendPduHandle) cbFun(snmpEngine, origSendRequestHandle, 'badResponse', # errorIndication None, cbCtx) return # User-side API assumes SMIv2 if messageProcessingModel == 0: PDU = rfc2576.v1ToV2(PDU, origPdu) # 3.1.2 if v2c.apiPDU.getRequestID(PDU) != v2c.apiPDU.getRequestID(origPdu): debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendPduHandle %s, request-id/response-id mismatch' % sendPduHandle) cbFun(snmpEngine, origSendRequestHandle, 'badResponse', # errorIndication None, cbCtx) return cbFun(snmpEngine, origSendRequestHandle, None, # errorIndication PDU, cbCtx) def sendPdu(self, snmpEngine, targetName, contextEngineId, contextName, PDU, cbFun, cbCtx): ( transportDomain, transportAddress, timeout, retryCount, messageProcessingModel, securityModel, securityName, securityLevel ) = config.getTargetInfo(snmpEngine, targetName) # Convert timeout in seconds into timeout in timer ticks timeoutInTicks = float(timeout)/100/snmpEngine.transportDispatcher.getTimerResolution() SnmpEngineID, SnmpAdminString = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-FRAMEWORK-MIB', 'SnmpEngineID', 'SnmpAdminString') # Cast possible strings into bytes if contextEngineId: contextEngineId = SnmpEngineID(contextEngineId) contextName = SnmpAdminString(contextName) origPDU = PDU # User-side API assumes SMIv2 if messageProcessingModel == 0: PDU = rfc2576.v2ToV1(PDU) pduVersion = 0 else: pduVersion = 1 sendRequestHandle = getNextHandle() cbCtx = sendRequestHandle, cbFun, cbCtx cbFun = self.processResponsePdu # 3.1 sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, 1, # expectResponse timeoutInTicks, cbFun, cbCtx ) snmpEngine.transportDispatcher.jobStarted(id(self)) self.__pendingReqs[sendPduHandle] = ( transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, origPDU, timeoutInTicks, retryCount, 0 ) debug.logger & debug.flagApp and debug.logger('sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry 0 of %d' % (sendPduHandle, timeout, timeoutInTicks, retryCount)) return sendRequestHandle # backward compatibility stub CommandGeneratorBase = CommandGenerator class GetCommandGenerator(CommandGenerator): def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): cbFun, cbCtx = cbCtx cbFun(snmpEngine, sendRequestHandle, errorIndication, PDU and v2c.apiPDU.getErrorStatus(PDU) or 0, PDU and v2c.apiPDU.getErrorIndex(PDU, muteErrors=True) or 0, PDU and v2c.apiPDU.getVarBinds(PDU) or (), cbCtx) def sendVarBinds(self, snmpEngine, targetName, contextEngineId, contextName, varBinds, cbFun, cbCtx=None): reqPDU = v2c.GetRequestPDU() v2c.apiPDU.setDefaults(reqPDU) v2c.apiPDU.setVarBinds(reqPDU, varBinds) cbCtx = cbFun, cbCtx cbFun = self.processResponseVarBinds return self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx) class SetCommandGenerator(CommandGenerator): def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): cbFun, cbCtx = cbCtx cbFun(snmpEngine, sendRequestHandle, errorIndication, PDU and v2c.apiPDU.getErrorStatus(PDU) or 0, PDU and v2c.apiPDU.getErrorIndex(PDU, muteErrors=True) or 0, PDU and v2c.apiPDU.getVarBinds(PDU) or (), cbCtx) def sendVarBinds(self, snmpEngine, targetName, contextEngineId, contextName, varBinds, cbFun, cbCtx=None): reqPDU = v2c.SetRequestPDU() v2c.apiPDU.setDefaults(reqPDU) v2c.apiPDU.setVarBinds(reqPDU, varBinds) cbCtx = cbFun, cbCtx cbFun = self.processResponseVarBinds return self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx) class NextCommandGeneratorSingleRun(CommandGenerator): def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx = cbCtx cbFun(snmpEngine, sendRequestHandle, errorIndication, PDU and v2c.apiPDU.getErrorStatus(PDU) or 0, PDU and v2c.apiPDU.getErrorIndex(PDU, muteErrors=True) or 0, PDU and v2c.apiPDU.getVarBinds(PDU) or (), cbCtx) def sendVarBinds(self, snmpEngine, targetName, contextEngineId, contextName, varBinds, cbFun, cbCtx=None): reqPDU = v2c.GetNextRequestPDU() v2c.apiPDU.setDefaults(reqPDU) v2c.apiPDU.setVarBinds(reqPDU, varBinds) cbCtx = targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx cbFun = self.processResponseVarBinds return self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx) class NextCommandGenerator(NextCommandGeneratorSingleRun): def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx = cbCtx if errorIndication: cbFun(snmpEngine, sendRequestHandle, errorIndication, 0, 0, (), cbCtx) return varBindTable = v2c.apiPDU.getVarBindTable(reqPDU, PDU) if v2c.apiPDU.getErrorStatus(PDU): errorIndication, varBinds = None, () elif not varBindTable: errorIndication, varBinds = errind.emptyResponse, () else: errorIndication, varBinds = getNextVarBinds( v2c.apiPDU.getVarBinds(reqPDU), varBindTable[-1] ) if not cbFun(snmpEngine, sendRequestHandle, errorIndication, v2c.apiPDU.getErrorStatus(PDU), v2c.apiPDU.getErrorIndex(PDU, muteErrors=True), varBindTable, cbCtx): debug.logger & debug.flagApp and debug.logger('processResponseVarBinds: sendRequestHandle %s, app says to stop walking' % sendRequestHandle) return # app says enough if not varBinds: return # no more objects available v2c.apiPDU.setRequestID(reqPDU, v2c.getNextRequestID()) v2c.apiPDU.setVarBinds(reqPDU, varBinds) cbCtx = targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx cbFun = self.processResponseVarBinds try: self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx) except StatusInformation: statusInformation = sys.exc_info()[1] debug.logger & debug.flagApp and debug.logger('sendVarBinds: sendPduHandle %s: sendPdu() failed with %r' % (sendRequestHandle, statusInformation)) cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx) class BulkCommandGeneratorSingleRun(CommandGenerator): def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): ( targetName, nonRepeaters, maxRepetitions, contextEngineId, contextName, reqPDU, cbFun, cbCtx ) = cbCtx cbFun(snmpEngine, sendRequestHandle, errorIndication, PDU and v2c.apiPDU.getErrorStatus(PDU) or 0, PDU and v2c.apiPDU.getErrorIndex(PDU, muteErrors=True) or 0, PDU and v2c.apiPDU.getVarBinds(PDU) or (), cbCtx) def sendVarBinds(self, snmpEngine, targetName, contextEngineId, contextName, nonRepeaters, maxRepetitions, varBinds, cbFun, cbCtx=None): reqPDU = v2c.GetBulkRequestPDU() v2c.apiBulkPDU.setDefaults(reqPDU) v2c.apiBulkPDU.setNonRepeaters(reqPDU, nonRepeaters) v2c.apiBulkPDU.setMaxRepetitions(reqPDU, maxRepetitions) v2c.apiBulkPDU.setVarBinds(reqPDU, varBinds) cbCtx = ( targetName, nonRepeaters, maxRepetitions, contextEngineId, contextName, reqPDU, cbFun, cbCtx ) cbFun = self.processResponseVarBinds return self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx) class BulkCommandGenerator(BulkCommandGeneratorSingleRun): def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): ( targetName, nonRepeaters, maxRepetitions, contextEngineId, contextName, reqPDU, cbFun, cbCtx ) = cbCtx if errorIndication: cbFun(snmpEngine, sendRequestHandle, errorIndication, 0, 0, (), cbCtx) return varBindTable = v2c.apiBulkPDU.getVarBindTable(reqPDU, PDU) if v2c.apiBulkPDU.getErrorStatus(PDU): errorIndication, varBinds = None, () elif not varBindTable: errorIndication, varBinds = errind.emptyResponse, () else: errorIndication, varBinds = getNextVarBinds( v2c.apiBulkPDU.getVarBinds(reqPDU), varBindTable[-1] ) nonRepeaters = v2c.apiBulkPDU.getNonRepeaters(reqPDU) if nonRepeaters: varBinds = v2c.apiBulkPDU.getVarBinds(reqPDU)[:int(nonRepeaters)] + varBinds[int(nonRepeaters):] if not cbFun(snmpEngine, sendRequestHandle, errorIndication, v2c.apiBulkPDU.getErrorStatus(PDU), v2c.apiBulkPDU.getErrorIndex(PDU, muteErrors=True), varBindTable, cbCtx): debug.logger & debug.flagApp and debug.logger('processResponseVarBinds: sendRequestHandle %s, app says to stop walking' % sendRequestHandle) return # app says enough if not varBinds: return # no more objects available v2c.apiBulkPDU.setRequestID(reqPDU, v2c.getNextRequestID()) v2c.apiBulkPDU.setVarBinds(reqPDU, varBinds) cbCtx = ( targetName, nonRepeaters, maxRepetitions, contextEngineId, contextName, reqPDU, cbFun, cbCtx ) cbFun = self.processResponseVarBinds try: self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx) except StatusInformation: statusInformation = sys.exc_info()[1] debug.logger & debug.flagApp and debug.logger('processResponseVarBinds: sendPduHandle %s: _sendPdu() failed with %r' % (sendRequestHandle, statusInformation)) cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx) # # Obsolete, compatibility interfaces. # def __sendReqCbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): cbFun, cbCtx = cbCtx return cbFun(sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx) def _sendReq(self, snmpEngine, targetName, varBinds, cbFun, cbCtx=None, contextEngineId=None, contextName=''): cbCtx = cbFun, cbCtx cbFun = __sendReqCbFun return self.sendVarBinds(snmpEngine, targetName, contextEngineId, contextName, varBinds, cbFun, cbCtx) def _sendBulkReq(self, snmpEngine, targetName, nonRepeaters, maxRepetitions, varBinds, cbFun, cbCtx=None, contextEngineId=None, contextName=''): cbCtx = cbFun, cbCtx cbFun = __sendReqCbFun return self.sendVarBinds(snmpEngine, targetName, contextEngineId, contextName, nonRepeaters, maxRepetitions, varBinds, cbFun, cbCtx) # install compatibility wrappers GetCommandGenerator.sendReq = _sendReq SetCommandGenerator.sendReq = _sendReq NextCommandGenerator.sendReq = _sendReq NextCommandGeneratorSingleRun.sendReq = _sendReq BulkCommandGenerator.sendReq = _sendBulkReq BulkCommandGeneratorSingleRun.sendReq = _sendBulkReq