snmp-node
Version:
A native Javascript SNMP implementation for Node.js
1,908 lines • 73.9 kB
HTML
<!DOCTYPE html>
<html>
<head>
<title>snmp.js</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To …</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page">
<a class="source" href="example.html">
example.js
</a>
<a class="source" href="asn1ber.html">
asn1ber.js
</a>
<a class="source" href="snmp.html">
snmp.js
</a>
</div>
</li>
</ul>
<ul class="sections">
<li id="title">
<div class="annotation">
<h1>snmp.js</h1>
</div>
</li>
<li id="section-1">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-1">¶</a>
</div>
<h2>Introduction</h2>
</div>
</li>
<li id="section-2">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">¶</a>
</div>
<p>This is <code>node-snmp-native</code>, a native (Javascript) implementation of an SNMP
client library targeted at Node.js. It's MIT licensed and available at
<a href="https://github.com/calmh/node-snmp-native">https://github.com/calmh/node-snmp-native</a></p>
<p>(c) 2012 Jakob Borg, Nym Networks</p>
</div>
<div class="content"><div class='highlight'><pre><span class="string">"use strict"</span>;</pre></div></div>
</li>
<li id="section-3">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-3">¶</a>
</div>
<h2>Code</h2>
</div>
</li>
<li id="section-4">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-4">¶</a>
</div>
<p>This file implements a structure representing an SNMP message
and routines for converting to and from the network representation.</p>
<p>Define our external dependencies.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="keyword">var</span> assert = require(<span class="string">'assert'</span>);
<span class="keyword">var</span> dgram = require(<span class="string">'dgram'</span>);
<span class="keyword">var</span> events = require(<span class="string">'events'</span>);</pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-5">¶</a>
</div>
<p>We also need our ASN.1 BER en-/decoding routines.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="keyword">var</span> asn1ber = require(<span class="string">'./asn1ber'</span>);</pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-6">¶</a>
</div>
<h2>Basic structures</h2>
</div>
</li>
<li id="section-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">¶</a>
</div>
<p>A <code>VarBind</code> is the innermost structure, containing an OID-Value pair.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">VarBind</span><span class="params">()</span> {</span>
<span class="keyword">this</span>.type = <span class="number">5</span>;
<span class="keyword">this</span>.value = <span class="literal">null</span>;
}</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">¶</a>
</div>
<p>The <code>PDU</code> contains the SNMP request or response fields and a list of <code>VarBinds</code>.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">PDU</span><span class="params">()</span> {</span>
<span class="keyword">this</span>.type = asn1ber.pduTypes.GetRequestPDU;
<span class="keyword">this</span>.reqid = <span class="number">1</span>;
<span class="keyword">this</span>.error = <span class="number">0</span>;
<span class="keyword">this</span>.errorIndex = <span class="number">0</span>;
<span class="keyword">this</span>.varbinds = [ <span class="keyword">new</span> VarBind() ];
}</pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-9">¶</a>
</div>
<p>The <code>Packet</code> contains the SNMP version and community and the <code>PDU</code>.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">Packet</span><span class="params">()</span> {</span>
<span class="keyword">this</span>.version = <span class="number">1</span>;
<span class="keyword">this</span>.community = <span class="string">'public'</span>;
<span class="keyword">this</span>.pdu = <span class="keyword">new</span> PDU();
}</pre></div></div>
</li>
<li id="section-10">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-10">¶</a>
</div>
<p>Allow consumers to create packet structures from scratch.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.Packet = Packet;</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-11">¶</a>
</div>
<h2>Private helper functions</h2>
</div>
</li>
<li id="section-12">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-12">¶</a>
</div>
<p>Concatenate several buffers to one.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">concatBuffers</span><span class="params">(buffers)</span> {</span>
<span class="keyword">var</span> total, cur = <span class="number">0</span>, buf;</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-13">¶</a>
</div>
<p>First we calculate the total length,</p>
</div>
<div class="content"><div class='highlight'><pre> total = buffers.reduce(<span class="function"><span class="keyword">function</span> <span class="params">(tot, b)</span> {</span>
<span class="keyword">return</span> tot + b.length;
}, <span class="number">0</span>);</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">¶</a>
</div>
<p>then we allocate a new Buffer large enough to contain all data,</p>
</div>
<div class="content"><div class='highlight'><pre> buf = <span class="keyword">new</span> Buffer(total);
buffers.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(buffer)</span> {</span></pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-15">¶</a>
</div>
<p>finally we copy the data into the new larger buffer.</p>
</div>
<div class="content"><div class='highlight'><pre> buffer.copy(buf, cur, <span class="number">0</span>);
cur += buffer.length;
});
<span class="keyword">return</span> buf;
}</pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">¶</a>
</div>
<p>Clear a pending packet when it times out or is successfully received.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">clearRequest</span><span class="params">(reqs, reqid)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>;
<span class="keyword">var</span> entry = reqs[reqid];
<span class="keyword">if</span> (entry) {
<span class="keyword">if</span> (entry.timeout) {
clearTimeout(entry.timeout);
}
<span class="keyword">delete</span> reqs[reqid];
}
}</pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-17">¶</a>
</div>
<p>Convert a string formatted OID to an array, leaving anything non-string alone.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">parseSingleOid</span><span class="params">(oid)</span> {</span>
<span class="keyword">if</span> (<span class="keyword">typeof</span> oid !== <span class="string">'string'</span>) {
<span class="keyword">return</span> oid;
}
<span class="keyword">if</span> (oid[<span class="number">0</span>] !== <span class="string">'.'</span>) {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Invalid OID format'</span>);
}
oid = oid.split(<span class="string">'.'</span>)
.filter(<span class="function"><span class="keyword">function</span> <span class="params">(s)</span> {</span>
<span class="keyword">return</span> s.length > <span class="number">0</span>;
})
.map(<span class="function"><span class="keyword">function</span> <span class="params">(s)</span> {</span>
<span class="keyword">return</span> parseInt(s, <span class="number">10</span>);
});
<span class="keyword">return</span> oid;
}</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-18">¶</a>
</div>
<p>Fix any OIDs in the 'oid' or 'oids' objects that are passed as strings.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">parseOids</span><span class="params">(options)</span> {</span>
<span class="keyword">if</span> (options.oid) {
options.oid = parseSingleOid(options.oid);
}
<span class="keyword">if</span> (options.oids) {
options.oids = options.oids.map(parseSingleOid);
}
}</pre></div></div>
</li>
<li id="section-19">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-19">¶</a>
</div>
<p>Update targ with attributes from _defs.
Any existing attributes on targ are untouched.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">defaults</span><span class="params">(targ, _defs)</span> {</span>
[].slice.call(arguments, <span class="number">1</span>).forEach(<span class="function"><span class="keyword">function</span> <span class="params">(def)</span> {</span>
Object.keys(def).forEach(<span class="function"><span class="keyword">function</span> <span class="params">(key)</span> {</span>
<span class="keyword">if</span> (!targ.hasOwnProperty(key)) {
targ[key] = def[key];
}
});
});
}</pre></div></div>
</li>
<li id="section-20">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-20">¶</a>
</div>
<h2>Encode structure to ASN.1 BER</h2>
</div>
</li>
<li id="section-21">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-21">¶</a>
</div>
<p>Return an ASN.1 BER encoding of a Packet structure.
This is suitable for transmission on a UDP socket.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">encode</span><span class="params">(pkt)</span> {</span>
<span class="keyword">var</span> version, community, reqid, err, erridx, vbs, pdu, message;</pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">¶</a>
</div>
<p>We only support SNMPv2c, so enforce that version stamp.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (pkt.version !== <span class="number">1</span>) {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Only SNMPv2c is supported.'</span>);
}</pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">¶</a>
</div>
<p>Encode the message header fields.</p>
</div>
<div class="content"><div class='highlight'><pre> version = asn1ber.encodeInteger(pkt.version);
community = asn1ber.encodeOctetString(pkt.community);</pre></div></div>
</li>
<li id="section-24">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-24">¶</a>
</div>
<p>Encode the PDU header fields.</p>
</div>
<div class="content"><div class='highlight'><pre> reqid = asn1ber.encodeInteger(pkt.pdu.reqid);
err = asn1ber.encodeInteger(pkt.pdu.error);
erridx = asn1ber.encodeInteger(pkt.pdu.errorIndex);</pre></div></div>
</li>
<li id="section-25">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-25">¶</a>
</div>
<p>Encode the PDU varbinds.</p>
</div>
<div class="content"><div class='highlight'><pre> vbs = [];
pkt.pdu.varbinds.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(vb)</span> {</span>
<span class="keyword">var</span> oid = asn1ber.encodeOid(vb.oid), val;
<span class="keyword">if</span> (vb.type === asn1ber.types.Null) {
val = asn1ber.encodeNull();
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.Integer) {
val = asn1ber.encodeInteger(vb.value);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.IpAddress) {
val = asn1ber.encodeIpAddress(vb.value);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.OctetString) {
val = asn1ber.encodeOctetString(vb.value);
} <span class="keyword">else</span> {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Unknown varbind type "'</span> + vb.type + <span class="string">'" in encoding.'</span>);
}
vbs.push(asn1ber.encodeSequence(concatBuffers([oid, val])));
});</pre></div></div>
</li>
<li id="section-26">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-26">¶</a>
</div>
<p>Concatenate all the varbinds together.</p>
</div>
<div class="content"><div class='highlight'><pre> vbs = asn1ber.encodeSequence(concatBuffers(vbs));</pre></div></div>
</li>
<li id="section-27">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-27">¶</a>
</div>
<p>Create the PDU by concatenating the inner fields and adding a request structure around it.</p>
</div>
<div class="content"><div class='highlight'><pre> pdu = asn1ber.encodeRequest(pkt.pdu.type, concatBuffers([reqid, err, erridx, vbs]));</pre></div></div>
</li>
<li id="section-28">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">¶</a>
</div>
<p>Create the message by concatenating the header fields and the PDU.</p>
</div>
<div class="content"><div class='highlight'><pre> message = asn1ber.encodeSequence(concatBuffers([version, community, pdu]));
<span class="keyword">return</span> message;
}
exports.encode = encode;</pre></div></div>
</li>
<li id="section-29">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-29">¶</a>
</div>
<h2>Parse ASN.1 BER into a structure</h2>
</div>
</li>
<li id="section-30">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-30">¶</a>
</div>
<p>Parse an SNMP packet into its component fields.
We don't do a lot of validation so a malformed packet will probably just
make us blow up.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">parse</span><span class="params">(buf)</span> {</span>
<span class="keyword">var</span> pkt, oid, bvb, vb, hdr;
pkt = <span class="keyword">new</span> Packet();</pre></div></div>
</li>
<li id="section-31">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-31">¶</a>
</div>
<p>First we have a sequence marker (two bytes).
We don't care about those, so cut them off.</p>
</div>
<div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf);
assert.equal(asn1ber.types.Sequence, hdr.type);
buf = buf.slice(hdr.header);</pre></div></div>
</li>
<li id="section-32">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-32">¶</a>
</div>
<p>Then comes the version field (integer). Parse it and slice it.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.version = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>));
buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div>
</li>
<li id="section-33">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-33">¶</a>
</div>
<p>We then get the community. Parse and slice.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.community = asn1ber.parseOctetString(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>));
buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div>
</li>
<li id="section-34">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-34">¶</a>
</div>
<p>Here's the PDU structure. We're interested in the type. Slice the rest.</p>
</div>
<div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf);
assert.ok(hdr.type >= <span class="number">0xA0</span>);
pkt.pdu.type = hdr.type - <span class="number">0xA0</span>;
buf = buf.slice(hdr.header);</pre></div></div>
</li>
<li id="section-35">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-35">¶</a>
</div>
<p>The request id field.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.pdu.reqid = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>));
buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div>
</li>
<li id="section-36">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-36">¶</a>
</div>
<p>The error field.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.pdu.error = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>));
buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div>
</li>
<li id="section-37">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-37">¶</a>
</div>
<p>The error index field.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.pdu.errorIndex = asn1ber.parseInteger(buf.slice(<span class="number">0</span>, buf[<span class="number">1</span>] + <span class="number">2</span>));
buf = buf.slice(<span class="number">2</span> + buf[<span class="number">1</span>]);</pre></div></div>
</li>
<li id="section-38">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-38">¶</a>
</div>
<p>Here's the varbind list. Not interested.</p>
</div>
<div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf);
assert.equal(asn1ber.types.Sequence, hdr.type);
buf = buf.slice(hdr.header);</pre></div></div>
</li>
<li id="section-39">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-39">¶</a>
</div>
<p>Now comes the varbinds. There might be many, so we loop for as long as we have data.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.pdu.varbinds = [];
<span class="keyword">while</span> (buf[<span class="number">0</span>] === asn1ber.types.Sequence) {
vb = <span class="keyword">new</span> VarBind();</pre></div></div>
</li>
<li id="section-40">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-40">¶</a>
</div>
<p>Slice off the sequence header.</p>
</div>
<div class="content"><div class='highlight'><pre> hdr = asn1ber.typeAndLength(buf);
assert.equal(asn1ber.types.Sequence, hdr.type);
bvb = buf.slice(hdr.header);</pre></div></div>
</li>
<li id="section-41">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-41">¶</a>
</div>
<p>Parse and save the ObjectIdentifier.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.oid = asn1ber.parseOid(bvb);</pre></div></div>
</li>
<li id="section-42">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-42">¶</a>
</div>
<p>Parse the value. We use the type marker to figure out
what kind of value it is and call the appropriate parser
routine. For the SNMPv2c error types, we simply set the
value to a text representation of the error and leave handling
up to the user.</p>
</div>
<div class="content"><div class='highlight'><pre> bvb = bvb.slice(<span class="number">2</span> + bvb[<span class="number">1</span>]);
vb.type = bvb[<span class="number">0</span>];
<span class="keyword">if</span> (vb.type === asn1ber.types.Null) {</pre></div></div>
</li>
<li id="section-43">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-43">¶</a>
</div>
<p>Null type.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = <span class="literal">null</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.OctetString) {</pre></div></div>
</li>
<li id="section-44">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-44">¶</a>
</div>
<p>Octet string type.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseOctetString(bvb);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.Integer ||
vb.type === asn1ber.types.Counter ||
vb.type === asn1ber.types.Counter64 ||
vb.type === asn1ber.types.TimeTicks ||
vb.type === asn1ber.types.Gauge) {</pre></div></div>
</li>
<li id="section-45">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-45">¶</a>
</div>
<p>Integer type and it's derivatives that behave in the same manner.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseInteger(bvb);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.ObjectIdentifier) {</pre></div></div>
</li>
<li id="section-46">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-46">¶</a>
</div>
<p>Object identifier type.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseOid(bvb);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.IpAddress) {</pre></div></div>
</li>
<li id="section-47">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-47">¶</a>
</div>
<p>IP Address type.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseArray(bvb);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.Opaque) {</pre></div></div>
</li>
<li id="section-48">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-48">¶</a>
</div>
<p>Opaque type. The 'parsing' here is very light; basically we return a
string representation of the raw bytes in hex.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = asn1ber.parseOpaque(bvb);
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.EndOfMibView) {</pre></div></div>
</li>
<li id="section-49">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-49">¶</a>
</div>
<p>End of MIB view error, returned when attempting to GetNext beyond the end
of the current view.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = <span class="string">'endOfMibView'</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.NoSuchObject) {</pre></div></div>
</li>
<li id="section-50">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-50">¶</a>
</div>
<p>No such object error, returned when attempting to Get/GetNext an OID that doesn't exist.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = <span class="string">'noSuchObject'</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (vb.type === asn1ber.types.NoSuchInstance) {</pre></div></div>
</li>
<li id="section-51">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-51">¶</a>
</div>
<p>No such instance error, returned when attempting to Get/GetNext an instance
that doesn't exist in a given table.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.value = <span class="string">'noSuchInstance'</span>;
} <span class="keyword">else</span> {</pre></div></div>
</li>
<li id="section-52">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-52">¶</a>
</div>
<p>Something else that we can't handle, so throw an error.
The error will be caught and presented in a useful manner on stderr,
with a dump of the message causing it.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Unrecognized value type '</span> + vb.type);
}</pre></div></div>
</li>
<li id="section-53">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-53">¶</a>
</div>
<p>Take the raw octet string value and preseve it as a buffer and hex string.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.valueRaw = bvb.slice(<span class="number">2</span>);
vb.valueHex = vb.valueRaw.toString(<span class="string">'hex'</span>);</pre></div></div>
</li>
<li id="section-54">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-54">¶</a>
</div>
<p>Add the request id to the varbind (even though it doesn't really belong)
so that it will be availble to the end user.</p>
</div>
<div class="content"><div class='highlight'><pre> vb.requestId = pkt.pdu.reqid;</pre></div></div>
</li>
<li id="section-55">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-55">¶</a>
</div>
<p>Push whatever we parsed to the varbind list.</p>
</div>
<div class="content"><div class='highlight'><pre> pkt.pdu.varbinds.push(vb);</pre></div></div>
</li>
<li id="section-56">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-56">¶</a>
</div>
<p>Go fetch the next varbind, if there seems to be any.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (buf.length > hdr.header + hdr.len) {
buf = buf.slice(hdr.header + hdr.len);
} <span class="keyword">else</span> {
<span class="keyword">break</span>;
}
}
<span class="keyword">return</span> pkt;
}
exports.parse = parse;</pre></div></div>
</li>
<li id="section-57">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-57">¶</a>
</div>
<h2>Utility functions</h2>
</div>
</li>
<li id="section-58">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-58">¶</a>
</div>
<p>Compare two OIDs, returning -1, 0 or +1 depending on the relation between
oidA and oidB.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.compareOids = <span class="function"><span class="keyword">function</span> <span class="params">(oidA, oidB)</span> {</span>
<span class="keyword">var</span> mlen, i;</pre></div></div>
</li>
<li id="section-59">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-59">¶</a>
</div>
<p>The undefined OID, if there is any, is deemed lesser.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (<span class="keyword">typeof</span> oidA === <span class="string">'undefined'</span> && <span class="keyword">typeof</span> oidB !== <span class="string">'undefined'</span>) {
<span class="keyword">return</span> <span class="number">1</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> oidA !== <span class="string">'undefined'</span> && <span class="keyword">typeof</span> oidB === <span class="string">'undefined'</span>) {
<span class="keyword">return</span> -<span class="number">1</span>;
}</pre></div></div>
</li>
<li id="section-60">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-60">¶</a>
</div>
<p>Check each number part of the OIDs individually, and if there is any
position where one OID is larger than the other, return accordingly.
This will only check up to the minimum length of both OIDs.</p>
</div>
<div class="content"><div class='highlight'><pre> mlen = Math.min(oidA.length, oidB.length);
<span class="keyword">for</span> (i = <span class="number">0</span>; i < mlen; i++) {
<span class="keyword">if</span> (oidA[i] > oidB[i]) {
<span class="keyword">return</span> -<span class="number">1</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (oidB[i] > oidA[i]) {
<span class="keyword">return</span> <span class="number">1</span>;
}
}</pre></div></div>
</li>
<li id="section-61">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-61">¶</a>
</div>
<p>If there is one OID that is longer than the other after the above comparison,
consider the shorter OID to be lesser.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (oidA.length > oidB.length) {
<span class="keyword">return</span> -<span class="number">1</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (oidB.length > oidA.length) {
<span class="keyword">return</span> <span class="number">1</span>;
} <span class="keyword">else</span> {</pre></div></div>
</li>
<li id="section-62">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-62">¶</a>
</div>
<p>The OIDs are obviously equal.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">return</span> <span class="number">0</span>;
}
};</pre></div></div>
</li>
<li id="section-63">
<div class="annotation">
<div class="pilwrap for-h2">
<a class="pilcrow" href="#section-63">¶</a>
</div>
<h2>Communication functions</h2>
</div>
</li>
<li id="section-64">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-64">¶</a>
</div>
<p>This is called for when we receive a message.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">msgReceived</span><span class="params">(msg, rinfo)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, now = Date.now(), pkt, entry;
<span class="keyword">if</span> (msg.length === <span class="number">0</span>) {</pre></div></div>
</li>
<li id="section-65">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-65">¶</a>
</div>
<p>Not sure why we sometimes receive an empty message.
As far as I'm concerned it shouldn't happen, but we'll ignore it
and if it's necessary a retransmission of the request will be
made later.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">return</span>;
}</pre></div></div>
</li>
<li id="section-66">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-66">¶</a>
</div>
<p>Parse the packet, or call the informative
parse error display if we fail.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">try</span> {
pkt = parse(msg);
} <span class="keyword">catch</span> (error) {
<span class="keyword">return</span> self.parseError(error, msg);
}</pre></div></div>
</li>
<li id="section-67">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-67">¶</a>
</div>
<p>If this message's request id matches one we've sent,
cancel any outstanding timeout and call the registered
callback.</p>
</div>
<div class="content"><div class='highlight'><pre> entry = self.reqs[pkt.pdu.reqid];
<span class="keyword">if</span> (entry) {
clearRequest(self.reqs, pkt.pdu.reqid);
<span class="keyword">if</span> (<span class="keyword">typeof</span> entry.callback === <span class="string">'function'</span>) {
pkt.pdu.varbinds.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(vb)</span> {</span>
vb.receiveStamp = now;
vb.sendStamp = entry.sendStamp;
});
entry.callback(<span class="literal">null</span>, pkt.pdu.varbinds);
}
} <span class="keyword">else</span> {</pre></div></div>
</li>
<li id="section-68">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-68">¶</a>
</div>
<p>This happens if we receive the response to a message we've already timed out
and removed the request entry for. Maybe we shouldn't even log the warning.</p>
<p>Calculate the approximate send time and how old the packet is.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">var</span> age = (Date.now() & <span class="number">0x1fffff</span>) - (pkt.pdu.reqid >>> <span class="number">10</span>);
<span class="keyword">if</span> (age < <span class="number">0</span>) {
age += <span class="number">0x200000</span>;
}
console.warn(<span class="string">'Response with unknown request ID from '</span> + rinfo.address + <span class="string">'. Consider increasing timeouts ('</span> + age + <span class="string">' ms old?).'</span>);
}
}</pre></div></div>
</li>
<li id="section-69">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-69">¶</a>
</div>
<p>Default options for new sessions and operations.</p>
</div>
<div class="content"><div class='highlight'><pre>exports.defaultOptions = {
host: <span class="string">'localhost'</span>,
port: <span class="number">161</span>,
community: <span class="string">'public'</span>,
family: <span class="string">'udp4'</span>,
timeouts: [ <span class="number">5000</span>, <span class="number">5000</span>, <span class="number">5000</span>, <span class="number">5000</span> ]
};</pre></div></div>
</li>
<li id="section-70">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-70">¶</a>
</div>
<p>This creates a new SNMP session.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">Session</span><span class="params">(options)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>;
self.options = options || {};
defaults(self.options, exports.defaultOptions);
self.reqs = {};
self.socket = dgram.createSocket(self.options.family);
self.socket.on(<span class="string">'message'</span>, msgReceived.bind(self));
self.socket.on(<span class="string">'close'</span>, <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span></pre></div></div>
</li>
<li id="section-71">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-71">¶</a>
</div>
<p>Remove the socket so we don't try to send a message on
it when it's closed.</p>
</div>
<div class="content"><div class='highlight'><pre> self.socket = <span class="literal">undefined</span>;
});
self.socket.on(<span class="string">'error'</span>, <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span></pre></div></div>
</li>
<li id="section-72">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-72">¶</a>
</div>
<p>Errors will be emitted here as well as on the callback to the send function.
We handle them there, so doing anything here is unnecessary.
But having no error handler trips up the test suite.</p>
</div>
<div class="content"><div class='highlight'><pre> });
}</pre></div></div>
</li>
<li id="section-73">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-73">¶</a>
</div>
<p>We inherit from EventEmitter so that we can emit error events
on fatal errors.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype = Object.create(events.EventEmitter.prototype);
exports.Session = Session;</pre></div></div>
</li>
<li id="section-74">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-74">¶</a>
</div>
<p>Generate a request ID. It's best kept within a signed 32 bit integer.
Uses the current time in ms, shifted left ten bits, plus a counter.
This gives us space for 1 transmit every microsecond and wraps every
~1000 seconds. This is OK since we only need to keep unique ID:s for in
flight packets and they should be safely timed out by then.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.requestId = <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, now = Date.now();
<span class="keyword">if</span> (!self.prevTs) {
self.prevTs = now;
self.counter = <span class="number">0</span>;
}
<span class="keyword">if</span> (now === self.prevTs) {
self.counter += <span class="number">1</span>;
<span class="keyword">if</span> (self.counter > <span class="number">1023</span>) {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Request ID counter overflow. Adjust algorithm.'</span>);
}
} <span class="keyword">else</span> {
self.prevTs = now;
self.counter = <span class="number">0</span>;
}
<span class="keyword">return</span> ((now & <span class="number">0x1fffff</span>) <<span class="xml"><span class="tag">< <span class="attribute">10</span>) + <span class="attribute">self.counter</span>;
};
</span></pre></div></div>
</li>
<li id="section-75">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-75">¶</a>
</div>
<p>Display useful debugging information when a parse error occurs.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.parseError = <span class="function"><span class="keyword">function</span> <span class="params">(error, buffer)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, hex;</pre></div></div>
</li>
<li id="section-76">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-76">¶</a>
</div>
<p>Display a friendly introductory text.</p>
</div>
<div class="content"><div class='highlight'><pre> console.error(<span class="string">'Woops! An error occurred while parsing an SNMP message. :('</span>);
console.error(<span class="string">'To have this problem corrected, please report the information below verbatim'</span>);
console.error(<span class="string">'via email to snmp@nym.se or by creating a GitHub issue at'</span>);
console.error(<span class="string">'https://github.com/calmh/node-snmp-native/issues'</span>);
console.error(<span class="string">''</span>);
console.error(<span class="string">'Thanks!'</span>);</pre></div></div>
</li>
<li id="section-77">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-77">¶</a>
</div>
<p>Display the stack backtrace so we know where the exception happened.</p>
</div>
<div class="content"><div class='highlight'><pre> console.error(<span class="string">''</span>);
console.error(error.stack);</pre></div></div>
</li>
<li id="section-78">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-78">¶</a>
</div>
<p>Display the buffer data, nicely formatted so we can replicate the problem.</p>
</div>
<div class="content"><div class='highlight'><pre> console.error(<span class="string">'\nMessage data:'</span>);
hex = buffer.toString(<span class="string">'hex'</span>);
<span class="keyword">while</span> (hex.length > <span class="number">0</span>) {
console.error(<span class="string">' '</span> + hex.slice(<span class="number">0</span>, <span class="number">32</span>).replace(<span class="regexp">/([0-9a-f]{2})/g</span>, <span class="string">'$1 '</span>));
hex = hex.slice(<span class="number">32</span>);
}</pre></div></div>
</li>
<li id="section-79">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-79">¶</a>
</div>
<p>Let the exception bubble upwards.</p>
</div>
<div class="content"><div class='highlight'><pre> self.emit(<span class="string">'error'</span>, error);
};</pre></div></div>
</li>
<li id="section-80">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-80">¶</a>
</div>
<p>Send a message. Can be used after manually constructing a correct Packet structure.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.sendMsg = <span class="function"><span class="keyword">function</span> <span class="params">(pkt, options, callback)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, buf, reqid, retrans = <span class="number">0</span>;
defaults(options, self.options);
reqid = self.requestId();
pkt.pdu.reqid = reqid;
buf = encode(pkt);
<span class="function"><span class="keyword">function</span> <span class="title">transmit</span><span class="params">()</span> {</span>
<span class="keyword">if</span> (!self.socket || !self.reqs[reqid]) {</pre></div></div>
</li>
<li id="section-81">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-81">¶</a>
</div>
<p>The socket has already been closed, perhaps due to an error that ocurred while a timeout
was scheduled. We can't do anything about it now.</p>
</div>
<div class="content"><div class='highlight'><pre> clearRequest(self.reqs, reqid);
<span class="keyword">return</span>;
}</pre></div></div>
</li>
<li id="section-82">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-82">¶</a>
</div>
<p>Send the message.</p>
</div>
<div class="content"><div class='highlight'><pre> self.socket.send(buf, <span class="number">0</span>, buf.length, options.port, options.host, <span class="function"><span class="keyword">function</span> <span class="params">(err, bytes)</span> {</span>
<span class="keyword">var</span> entry = self.reqs[reqid];
<span class="keyword">if</span> (err) {
clearRequest(self.reqs, reqid);
<span class="keyword">return</span> callback(err);
} <span class="keyword">else</span> <span class="keyword">if</span> (entry) {
entry.sendStamp = Date.now();
<span class="keyword">if</span> (options.timeouts[retrans]) {</pre></div></div>
</li>
<li id="section-83">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-83">¶</a>
</div>
<p>Set timeout and record the timer so that we can (attempt to) cancel it when we receive the reply.</p>
</div>
<div class="content"><div class='highlight'><pre> entry.timeout = setTimeout(transmit, options.timeouts[retrans]);
retrans += <span class="number">1</span>;
} <span class="keyword">else</span> {
clearRequest(self.reqs, reqid);
<span class="keyword">return</span> callback(<span class="keyword">new</span> Error(<span class="string">'Timeout'</span>));
}
}
});
}</pre></div></div>
</li>
<li id="section-84">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-84">¶</a>
</div>
<p>Register the callback to call when we receive a reply.</p>
</div>
<div class="content"><div class='highlight'><pre> self.reqs[reqid] = { callback: callback };</pre></div></div>
</li>
<li id="section-85">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-85">¶</a>
</div>
<p>Transmit the message.</p>
</div>
<div class="content"><div class='highlight'><pre> transmit();
};</pre></div></div>
</li>
<li id="section-86">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-86">¶</a>
</div>
<p>Shortcut to create a GetRequest and send it, while registering a callback.
Needs <code>options.oid</code> to be an OID in array form.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.get = <span class="function"><span class="keyword">function</span> <span class="params">(options, callback)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, pkt;
defaults(options, self.options);
parseOids(options);
<span class="keyword">if</span> (!options.oid) {
<span class="keyword">return</span> callback(<span class="literal">null</span>, []);
}
pkt = <span class="keyword">new</span> Packet();
pkt.community = options.community;
pkt.pdu.varbinds[<span class="number">0</span>].oid = options.oid;
self.sendMsg(pkt, options, callback);
};</pre></div></div>
</li>
<li id="section-87">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-87">¶</a>
</div>
<p>Shortcut to create a SetRequest and send it, while registering a callback.
Needs <code>options.oid</code> to be an OID in array form, <code>options.value</code> to be an
integer and <code>options.type</code> to be asn1ber.T.Integer (2).</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.set = <span class="function"><span class="keyword">function</span> <span class="params">(options, callback)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, pkt;
defaults(options, self.options);
parseOids(options);
<span class="keyword">if</span> (!options.oid) {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Missing required option `oid`.'</span>);
} <span class="keyword">else</span> <span class="keyword">if</span> (options.value === <span class="literal">undefined</span>) {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Missing required option `value`.'</span>);
} <span class="keyword">else</span> <span class="keyword">if</span> (!options.type) {
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Missing required option `type`.'</span>);
}
pkt = <span class="keyword">new</span> Packet();
pkt.community = options.community;
pkt.pdu.type = asn1ber.pduTypes.SetRequestPDU;
pkt.pdu.varbinds[<span class="number">0</span>].oid = options.oid;
pkt.pdu.varbinds[<span class="number">0</span>].type = options.type;
pkt.pdu.varbinds[<span class="number">0</span>].value = options.value;
self.sendMsg(pkt, options, callback);
};</pre></div></div>
</li>
<li id="section-88">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-88">¶</a>
</div>
<p>Shortcut to get all OIDs in the <code>options.oids</code> array sequentially. The
callback is called when the entire operation is completed. If
options.abortOnError is truish, an error while getting any of the values
will cause the callback to be called with error status. When
<code>options.abortOnError</code> is falsish (the default), any errors will be ignored
and any successfully retrieved values sent to the callback.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.getAll = <span class="function"><span class="keyword">function</span> <span class="params">(options, callback)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, results = [];
defaults(options, self.options, { abortOnError: <span class="literal">false</span> });
parseOids(options);
<span class="keyword">if</span> (!options.oids || options.oids.length === <span class="number">0</span>) {
<span class="keyword">return</span> callback(<span class="literal">null</span>, []);
}
<span class="function"><span class="keyword">function</span> <span class="title">getOne</span><span class="params">(c)</span> {</span>
<span class="keyword">var</span> oid, pkt, m, vb;
pkt = <span class="keyword">new</span> Packet();
pkt.community = options.community;
pkt.pdu.varbinds = [];</pre></div></div>
</li>
<li id="section-89">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-89">¶</a>
</div>
<p>Push up to 16 varbinds in the same message.
The number 16 isn't really that magical, it's just a nice round
number that usually seems to fit withing a single packet and gets
accepted by the switches I've tested it on.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">for</span> (m = <span class="number">0</span>; m < <span class="number">16</span> && c < options.oids.length; m++) {
vb = <span class="keyword">new</span> VarBind();
vb.oid = options.oids[c];
pkt.pdu.varbinds.push(vb);
c++;
}
self.sendMsg(pkt, options, <span class="function"><span class="keyword">function</span> <span class="params">(err, varbinds)</span> {</span>
<span class="keyword">if</span> (options.abortOnError && err) {
callback(err);
} <span class="keyword">else</span> {
<span class="keyword">if</span> (varbinds) {
results = results.concat(varbinds);
}
<span class="keyword">if</span> (c < options.oids.length) {
getOne(c);
} <span class="keyword">else</span> {
callback(<span class="literal">null</span>, results);
}
}
});
}
getOne(<span class="number">0</span>);
};</pre></div></div>
</li>
<li id="section-90">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-90">¶</a>
</div>
<p>Shortcut to create a GetNextRequest and send it, while registering a callback.
Needs <code>options.oid</code> to be an OID in array form.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.getNext = <span class="function"><span class="keyword">function</span> <span class="params">(options, callback)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, pkt;
defaults(options, self.options);
parseOids(options);
<span class="keyword">if</span> (!options.oid) {
<span class="keyword">return</span> callback(<span class="literal">null</span>, []);
}
pkt = <span class="keyword">new</span> Packet();
pkt.community = options.community;
pkt.pdu.type = <span class="number">1</span>;
pkt.pdu.varbinds[<span class="number">0</span>].oid = options.oid;
self.sendMsg(pkt, options, callback);
};</pre></div></div>
</li>
<li id="section-91">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-91">¶</a>
</div>
<p>Shortcut to get all entries below the specified OID.
The callback will be called once with the list of
varbinds that was collected, or with an error object.
Needs <code>options.oid</code> to be an OID in array form.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.getSubtree = <span class="function"><span class="keyword">function</span> <span class="params">(options, callback)</span> {</span>
<span class="keyword">var</span> self = <span class="keyword">this</span>, vbs = [];
defaults(options, self.options);
parseOids(options);
<span class="keyword">if</span> (!options.oid) {
<span class="keyword">return</span> callback(<span class="literal">null</span>, []);
}
options.startOid = options.oid;</pre></div></div>
</li>
<li id="section-92">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-92">¶</a>
</div>
<p>Helper to check whether <code>oid</code> in inside the tree rooted at
<code>root</code> or not.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="function"><span class="keyword">function</span> <span class="title">inTree</span><span class="params">(root, oid)</span> {</span>
<span class="keyword">var</span> i;
<span class="keyword">if</span> (oid.length <= root.length) {
<span class="keyword">return</span> <span class="literal">false</span>;
}
<span class="keyword">for</span> (i = <span class="number">0</span>; i < root.length; i++) {
<span class="keyword">if</span> (oid[i] !== root[i]) {
<span class="keyword">return</span> <span class="literal">false</span>;
}
}
<span class="keyword">return</span> <span class="literal">true</span>;
}</pre></div></div>
</li>
<li id="section-93">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-93">¶</a>
</div>
<p>Helper to handle the result of getNext and call the user's callback
as appropriate. The callback will see one of the following patterns:
- callback([an Error object], undefined) -- an error ocurred.
- callback(null, [a Packet object]) -- data from under the tree.
- callback(null, null) -- end of tree.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="function"><span class="keyword">function</span> <span class="title">result</span><span class="params">(error, varbinds)</span> {</span>
<span class="keyword">if</span> (error) {
callback(error);
} <span class="keyword">else</span> {
<span class="keyword">if</span> (inTree(options.startOid, varbinds[<span class="number">0</span>].oid)) {
<span class="keyword">if</span> (varbinds[<span class="number">0</span>].value === <span class="string">'endOfMibView'</span> || varbinds[<span class="number">0</span>].value === <span class="string">'noSuchObject'</span> || varbinds[<span class="number">0</span>].value === <span class="string">'noSuchInstance'</span>) {
callback(<span class="literal">null</span>, vbs);
} <span class="keyword">else</span> {
vbs.push(varbinds[<span class="number">0</span>]);
<span class="keyword">var</span> next = { oid: varbinds[<span class="number">0</span>].oid };
defaults(next, options);
self.getNext(next, result);
}
} <span class="keyword">else</span> {
callback(<span class="literal">null</span>, vbs);
}
}
}
self.getNext(options, result);
};</pre></div></div>
</li>
<li id="section-94">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-94">¶</a>
</div>
<p>Close the socket. Necessary to finish the event loop and exit the program.</p>
</div>
<div class="content"><div class='highlight'><pre>Session.prototype.close = <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span>
<span class="keyword">this</span>.socket.close();
};</pre></div></div>
</li>
</ul>
</div>
</body>
</html>