diff --git a/lib/agent.js b/lib/agent.js index 821633c..33a24b7 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -382,8 +382,76 @@ Agent.prototype._do_getnext = function _do_getnext(req, rsp) { }); }; +Agent.prototype._do_bulkget_one = function (req, rsp, oid, cb, first) { + var self = this; + var node = this._getnext_lookup(oid, first); + var nvb = req.pdu.varbinds.length; + var prq = new ProviderRequest(req.pdu.op, oid, node); + var handler; + + if (!node || !node.decor('_agent').instancePossible()) { + handler = [ function _getset_nsohandler(pr) { + var rsd = data.createData({ type: 'Null', + value: data.endOfMibView }); + var rsvb = varbind.createVarbind({ + oid: pr.oid, data: rsd }); + pr.done(rsvb); + } ]; + } else { + handler = node.decor('_agent')._handler; + } + + prq._done = function _getnext_done(rsvb) { + if (rsvb !== undefined) { + cb(rsvb); + return; + } + self._do_bulkget_one(req, rsp, prq.node.oid, cb, false); + }; + + handler.forEach(function (h) { + h(prq); + }); +}; + +function belongsTo(oid, baseAddr) { + var target = data.canonicalizeOID(oid); + return baseAddr.every(function (d, i) { + return target[i] === d; + }); +} + Agent.prototype._do_getbulk = function _do_getbulk(req, rsp) { - /* XXX yuck */ + var self = this; + + function createCallback (baseAddr) { + return function callback (rsvb) { + if (typeof rsvb === 'object' && varbind.isSnmpVarbind(rsvb)) { + if (rsp.pdu.varbinds.length > 0 && rsp.pdu.varbinds.slice(-1)[0].oid === rsvb.oid) { + // We just got a response from the same valid node twice, there are no more providers to be found + // Force the OID to be something that does not match with our base requested OID + var bogusAddr = Array.apply([], baseAddr); + bogusAddr.push(bogusAddr.pop() + 1, 0); + rsvb.oid = bogusAddr.join('.'); + } + if (belongsTo(rsvb.oid, baseAddr)) { + rsp.pdu.varbinds.push(rsvb); + } else { + rsvb.data = data.createData({ type: 'Null', value: data.endOfMibView }); + rsp.pdu.varbinds.push(rsvb); + + self._transmit_response(req._conn_recv, rsp); + return; + } + self._do_bulkget_one(req, rsp, rsvb.oid, callback, true); + } + }; + } + + // It makes no sense to pass multiple getBulk requests in one PDU. snmpbulkwalk won't even do it. If a manager + // happens to do it, we ignore all but the first varbind. + var vb = req.pdu.varbinds[0]; + self._do_bulkget_one(req, rsp, vb.oid, createCallback(data.canonicalizeOID(vb.oid)), true); }; Agent.prototype._process_req = function _process_req(req) {