Full Code of calmh/node-snmp-native for AI

master 46e7780c4ad7 cached
18 files
404.5 KB
122.8k tokens
25 symbols
1 requests
Download .txt
Showing preview only (417K chars total). Download the full file or copy to clipboard to get everything.
Repository: calmh/node-snmp-native
Branch: master
Commit: 46e7780c4ad7
Files: 18
Total size: 404.5 KB

Directory structure:
gitextract_v45mz64j/

├── .gitignore
├── .jshintrc
├── .travis.yml
├── LICENSE
├── README.md
├── docs/
│   ├── asn1ber.html
│   ├── coverage.html
│   ├── docco.css
│   ├── example.html
│   ├── public/
│   │   └── stylesheets/
│   │       └── normalize.css
│   └── snmp.html
├── example.js
├── lib/
│   ├── asn1ber.js
│   └── snmp.js
├── package.json
└── test/
    ├── asn1ber.js
    ├── integration.js
    └── snmp.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.*.swp
gmon.out
node_modules
lib-cov


================================================
FILE: .jshintrc
================================================
{
    "curly": true,
    "eqeqeq": true,
    "forin": true,
    "immed": true,
    "latedef": true,
    "newcap": true,
    "noarg": true,
    "noempty": true,
    "undef": true,
    "trailing": true,
    "node": true,
    "nomen": false,
    "plusplus": false
}


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - node
  - lts/*
  - '12'
  - '10'
  - '8'
cache: yarn


================================================
FILE: LICENSE
================================================
Copyright (C) 2012 Jakob Borg

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

- The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
                                                                 __
                                                                /\ \__  __
      ____    ___     ___ ___   _____              ___      __  \ \ ,_\/\_\   __  __     __
     /',__\ /' _ `\ /' __` __`\/\ '__`\  _______ /' _ `\  /'__`\ \ \ \/\/\ \ /\ \/\ \  /'__`\
    /\__, `\/\ \/\ \/\ \/\ \/\ \ \ \L\ \/\______\/\ \/\ \/\ \L\.\_\ \ \_\ \ \\ \ \_/ |/\  __/
    \/\____/\ \_\ \_\ \_\ \_\ \_\ \ ,__/\/______/\ \_\ \_\ \__/.\_\\ \__\\ \_\\ \___/ \ \____\
     \/___/  \/_/\/_/\/_/\/_/\/_/\ \ \/           \/_/\/_/\/__/\/_/ \/__/ \/_/ \/__/   \/____/
                                  \ \_\
                                   \/_/

snmp-native  [![Build Status](https://secure.travis-ci.org/calmh/node-snmp-native.png)](http://travis-ci.org/calmh/node-snmp-native)
===========

This is a native SNMP library for Node.js. The purpose is to provide enough
functionality to perform large scale monitoring of network equipment. Current
features towards this end are:

 - Full implementation of SNMPv2c, including 64 bit data types.
 - Support for Get, GetNext and Set requests, with optimizations such as GetAll
   and GetSubtree.
 - No unusual external dependencies, no non-JavaScript code.
 - Very high performance, unlimited parallellism. (There are always limits.
   However, there are no arbitrary such imposed by this code and you at least
   won't run out of file descriptors.)
 - De facto standards compliance. Generated packets are compared against
   Net-SNMP and should be identical in all relevant aspects.
 - Well tested. Test coverage should be at or close to 100% for all important
   code paths.

It specifically does *not* include:

 - Compatibility with SNMPv1, SNMPv2u or SNMPv3. These are (in order)
   deprecated, weird, and too complicated. Yes, it's an opinionated library.
 - MIB parsing. Do this in your client app if it's necessary.

It's optimized for polling tens of thousands of counters on hundreds or
thousands of hosts in a parallell manner. This is known to work (although
performance might be limited by less than optimal SNMP agent implementations in
random network gear).

Documentation
=============

Installation
------------

    $ npm install snmp-native

Usage
-----

### Import

```javascript
var snmp = require('snmp-native');
```

### new Session(options)

Create a `Session`. The `Session` constructor, like most of the other
functions, take an `options` object. The options passed to the `Session` will
be the defaults for any subsequent function calls on that session, but can be
overridden as needed. Useful parameters here are `host`, `port` and `family`.

```javascript
// Create a Session with default settings.
var session = new snmp.Session();

// Create a Session with explicit default host, port, and community.
var session = new snmp.Session({ host: 'device.example.com', port: 161, community: 'special' });

// Create an IPv6 Session.
var session = new snmp.Session({ host: '2001:db8::42', family: 'udp6', community: 'private' });
```

The following options are recognized as properties in the options object. All
can be specified in the `Session` constructor and optionally overridden at a
later time by setting them in the option object to a method call.

For optimum performance when polling many hosts, create a session without
specifying the `host`. Reuse this session for all hosts and specify the `host`
on each `get`, `getAll`, etc.

 - `host`: The host to send the request to. An resolvable name is allowed in
   addition to IP addresses. Default: `'localhost'`.
 - `port`: The UDP port number to send the request to. Default: `161`.
 - `community`: The SNMP community name. Default: `'public'`.
 - `family`: Address family to bind to. This is only used by the `Session`
   constructor since that is when the bind is done. It cannot be changed or
   overridden after construction. Default: `'udp4'`. Valid values: `'udp4'` or
   `'udp6'`.
 - `timeouts`: An array of timeout values. Values are times in milliseconds,
   the length of the array is the total number of transmissions that will
   occur. Default: `[5000, 5000, 5000, 5000]` (four attempts, with five seconds
   between each). A backoff can be implemented by timeouts along the lines of
   `[ 1000, 2000, 4000, 8000 ]`. Retransmissions can be disabled by using only
   a single timeout value: `[ 5000 ]`.
 - `bindPort`: UDP port used to bind the socket locally. Default: `0` (random port)
 - `msgReceived`: A `(message, rinfo) => {}` function responsible to handle incoming
   messages and sending UDP responses back. If nothing is given here, the default implementation
   is used. This is useful if you want to implement custom logic in your application

### VarBind objects

All of the `get*` functions return arrays of `VarBind` as the result to the
callback. The `VarBind` objects have the following properties:

 - `oid`: The OID they represent (in array form).
 - `type`: The integer type code for the returned value.
 - `value`: The value, in decoded form. This will be an integer for integer,
   gauge, counter and timetick types, a string for an octet string value, an
   array for array or IP number types.
 - `valueRaw`: For octet string values, this is a raw `Buffer` representing the string.
 - `valueHex`: For octet string values, this is a hex string representation of the value.
 - `sendStamp`: The timestamp (in milliseconds) when the request was transmitted.
 - `receiveStamp`: The timestamp (in milliseconds) when the response was received.

### get(options, callback)

Perform a simple GetRequest. Options (in addition to the ones defined above for `Session`):

 - `oid`: The OID to get. Example: `[1, 3, 6, 1, 4, 1, 1, 2, 3, 4]` or
   `'.1.3.6.1.4.1.1.2.3.4'`. Both forms are accepted, but the string form will
   need to be parsed to an array, slightly increasing CPU usage.

Will call the specified `callback` with an `error` object (`null` on success)
and the varbind that was received.

```javascript
session.get({ oid: [1, 3, 6, 1, 4, 1, 42, 1, 0] }, function (error, varbinds) {
    if (error) {
        console.log('Fail :(');
    } else {
        console.log(varbinds[0].oid + ' = ' + varbinds[0].value + ' (' + varbinds[0].type + ')');
    }
});
```

You can also specify host, community, etc explicitly.

```javascript
session.get({ oid: [1, 3, 6, 1, 4, 1, 42, 1, 0], host: 'localhost', community: 'test' }, ...);
```

### getNext(options, callback)

Perform a simple GetNextRequest. Options:

 - `oid`: The OID to get. Example: `[1, 3, 6, 1, 4, 1, 1, 2, 3, 4]` or `'.1.3.6.1.4.1.1.2.3.4'`.

Will call the specified `callback` with an `error` object (`null` on success)
and the varbind that was received.

```javascript
session.getNext({ oid: [1, 3, 6, 1, 4, 1, 42, 1, 0] }, function (error, varbinds) {
    if (error) {
        console.log('Fail :(');
    } else {
        console.log(varbinds[0].oid + ' = ' + varbinds[0].value + ' (' + varbinds[0].type + ')');
    }
});
```

### getAll(options, callback)

Perform repeated GetRequests to fetch all the required values. Multiple OIDs
will get packed into as few GetRequest packets as possible to minimize
roundtrip delays. Gets will be issued serially (not in parallell) to avoid
flooding hosts. Options:

 - `oids`: An array of OIDs to get. Example: `[[1, 3, 6, 1, 4, 1, 1, 2, 3], [1,
   3, 6, 1, 4, 1, 1, 2, 4]]` or `['.1.3.6.1.4.1.1.2.3.4',
   '.1.3.6.1.4.1.2.3.4.5']`.
 - `abortOnError`: Whether to stop or continue when an error is encountered.
   Default: `false`.
 - `combinedTimeout`: Timeout in milliseconds that the getAll() may take.
   Default: no timeout.

The callback will be called with an error object or a list of varbinds. If the
options property `abortOnError` is false (default) any variables that couldn't
be fetched will simply be omitted from the results. If it is true, the callback
will be called with an error object on any failure. If the `combinedTimeout` is
triggered, the callback is called with an error and the partial results.

```javascript
var oids = [ [1, 3, 6, 1, 4, 1, 42, 1, 0], [1, 3, 6, 1, 4, 1, 42, 2, 0], ... ];
session.getAll({ oids: oids }, function (error, varbinds) {
    varbinds.forEach(function (vb) {
        console.log(vb.oid + ' = ' + vb.value + ' (' + vb.type + ')');
    });
});
```

### getSubtree(options, callback)

Perform repeated GetNextRequests to fetch all values in the specified tree. Options:

 - `oid`: The OID to get. Example: `[1, 3, 6, 1, 4, 1, 1, 2, 3, 4]` or `'.1.3.6.1.4.1.1.2.3.4'`.
 - `combinedTimeout`: Timeout in milliseconds that the getSubtree() may take.
   Default: no timeout.

Will call the specified `callback` with an `error` object (`null` on success)
and the list of varbinds that was fetched. If the `combinedTimeout` is triggered,
the callback is called with an error and the partial results.

```javascript
session.getSubtree({ oid: [1, 3, 6, 1, 4, 1, 42] }, function (error, varbinds) {
    if (error) {
        console.log('Fail :(');
    } else {
        varbinds.forEach(function (vb) {
            console.log(vb.oid + ' = ' + vb.value + ' (' + vb.type + ')');
        });
    }
});
```

### set(options, callback)

Perform a simple SetRequest. Options:

 - `oid`: The OID to perform the set on. Example: `[1, 3, 6, 1, 4, 1, 1, 2, 3, 4]`
   or `'.1.3.6.1.4.1.1.2.3.4'`.
 - `value`: The value to set. Example: `42`.
 - `type`: The type of the value. Currently supports `asn1ber.T.Integer` (2), `asn1ber.T.Gauge` (66),
   `asn1ber.T.IpAddress` (64), `asn1ber.T.OctetString` (4) and `asn1ber.T.Null` (5).
   Example: `2`.

Example:

```javascript
session.set({ oid: [1, 3, 6, 1, 4, 1, 42, 1, 0], value: 42, type: 2 }, function (error, varbind) {
    if (error) {
        console.log('Fail :(');
    } else {
        console.log('The set is done.');
    }
});
```

If you're not really interested in the outcome of the set (and if you are, why
aren't you using scripted telnet or ssh instead to begin with?), you can call
it without a callback:

```javascript
session.set({ oid: [1, 3, 6, 1, 4, 1, 42, 1, 0], value: 42, type: 2 });
```

### close()

Cancels all outstanding requests and frees used OS resources. Outstanding
requests will call their callback with the "Cancelled" error set.

Example:

```javascript
session.close();
```

License
=======

MIT



================================================
FILE: docs/asn1ber.html
================================================
<!DOCTYPE html>

<html>
<head>
  <title>asn1ber.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 &hellip;</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>asn1ber.js</h1>
              </div>
          </li>
        
        
        
        <li id="section-1">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-1">&#182;</a>
              </div>
              <p>This file implements a minimal subset of Abstract Syntax Notation One (<strong>ASN.1</strong>)
Basic Encoding Rules (<strong>BER</strong>), namely the parts that are necessary for sending
and receiving SNMPv2c messages.</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-2">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-2">&#182;</a>
              </div>
              <p>We define constants for the commonly used ASN.1 types in SNMP.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="keyword">var</span> T = {
    Integer: <span class="number">0x02</span>,
    OctetString: <span class="number">0x04</span>,
    Null: <span class="number">0x05</span>,
    ObjectIdentifier: <span class="number">0x06</span>,
    Sequence: <span class="number">0x30</span>,
    IpAddress: <span class="number">0x40</span>,
    Counter: <span class="number">0x41</span>,
    Gauge: <span class="number">0x42</span>,
    TimeTicks: <span class="number">0x43</span>,
    Opaque: <span class="number">0x44</span>,
    NsapAddress: <span class="number">0x45</span>,
    Counter64: <span class="number">0x46</span>,
    NoSuchObject: <span class="number">0x80</span>,
    NoSuchInstance: <span class="number">0x81</span>,
    EndOfMibView: <span class="number">0x82</span>,
    PDUBase: <span class="number">0xA0</span>
};

<span class="keyword">var</span> P = {
    GetRequestPDU: <span class="number">0x00</span>,
    GetNextRequestPDU: <span class="number">0x01</span>,
    GetResponsePDU: <span class="number">0x02</span>,
    SetRequestPDU: <span class="number">0x03</span>
};</pre></div></div>
            
        </li>
        
        
        <li id="section-3">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-3">&#182;</a>
              </div>
              <p>The types are also available for consumers of the library.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.types = T;
exports.pduTypes = P;
exports.unittest = {};</pre></div></div>
            
        </li>
        
        
        <li id="section-4">
            <div class="annotation">
              
              <div class="pilwrap for-h2">
                <a class="pilcrow" href="#section-4">&#182;</a>
              </div>
              <h2>Private helper functions</h2>

            </div>
            
        </li>
        
        
        <li id="section-5">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-5">&#182;</a>
              </div>
              <p>Encode a length as it should be encoded.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">lengthArray</span><span class="params">(len)</span> {</span>
    <span class="keyword">var</span> arr = [];

    <span class="keyword">if</span> (len &lt;= <span class="number">127</span>) {</pre></div></div>
            
        </li>
        
        
        <li id="section-6">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-6">&#182;</a>
              </div>
              <p>Return a single byte if the value is 127 or less.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>        <span class="keyword">return</span> [ len ];
    } <span class="keyword">else</span> {</pre></div></div>
            
        </li>
        
        
        <li id="section-7">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-7">&#182;</a>
              </div>
              <p>Otherwise encode it as a MSB base-256 integer.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>        <span class="keyword">while</span> (len &gt; <span class="number">0</span>) {
            arr.push(len % <span class="number">256</span>);
            len = parseInt(len / <span class="number">256</span>, <span class="number">10</span>);
        }</pre></div></div>
            
        </li>
        
        
        <li id="section-8">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-8">&#182;</a>
              </div>
              <p>Add a length byte in front and set the high bit to indicate
that this is a longer value than one byte.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>        arr.push(<span class="number">128</span> + arr.length);
        arr.reverse();
        <span class="keyword">return</span> arr;
    }
}

exports.unittest.lengthArray = lengthArray;</pre></div></div>
            
        </li>
        
        
        <li id="section-9">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-9">&#182;</a>
              </div>
              <p>Return a wrapped copy of the passed <code>contents</code>, with the specified wrapper type.
This is used for Sequence and other constructed types.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">wrapper</span><span class="params">(type, contents)</span> {</span>
    <span class="keyword">var</span> buf, len, i;</pre></div></div>
            
        </li>
        
        
        <li id="section-10">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-10">&#182;</a>
              </div>
              <p>Get the encoded length of the contents</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    len = lengthArray(contents.length);</pre></div></div>
            
        </li>
        
        
        <li id="section-11">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-11">&#182;</a>
              </div>
              <p>Set up a buffer with the type and length bytes plus a straight copy of the content.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    buf = <span class="keyword">new</span> Buffer(<span class="number">1</span> + contents.length + len.length);
    buf[<span class="number">0</span>] = type;
    <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; len.length + <span class="number">1</span>; i++) {
        buf[i] = len[i - <span class="number">1</span>];
    }
    contents.copy(buf, len.length + <span class="number">1</span>, <span class="number">0</span>);
    <span class="keyword">return</span> buf;
}</pre></div></div>
            
        </li>
        
        
        <li id="section-12">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-12">&#182;</a>
              </div>
              <p>Get the encoded representation of a number in an OID.
If the number is less than 128, pass it as it is.
Otherwise return an array of base-128 digits, most significant first,
with the high bit set on all octets except the last one.
This encoding should be used for all number in an OID except the first
two (.1.3) which are handled specially.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">oidInt</span><span class="params">(val)</span> {</span>
    <span class="keyword">var</span> bytes = [];

    bytes.push(val % <span class="number">128</span>);
    val = parseInt(val / <span class="number">128</span>, <span class="number">10</span>);
    <span class="keyword">while</span> (val &gt; <span class="number">127</span>) {
        bytes.push(<span class="number">128</span> + val % <span class="number">128</span>);
        val = parseInt(val / <span class="number">128</span>, <span class="number">10</span>);
    }
    bytes.push(val + <span class="number">128</span>);
    <span class="keyword">return</span> bytes.reverse();
}</pre></div></div>
            
        </li>
        
        
        <li id="section-13">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-13">&#182;</a>
              </div>
              <p>Encode an OID. The first two number are encoded specially
in the first octet, then the rest are encoded as one octet per number
unless the number exceeds 127. If so, it&#39;s encoded as several base-127
octets with the high bit set to indicate continuation.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">oidArray</span><span class="params">(oid)</span> {</span>
    <span class="keyword">var</span> bytes, i, val;</pre></div></div>
            
        </li>
        
        
        <li id="section-14">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-14">&#182;</a>
              </div>
              <p>Enforce some minimum requirements on the OID.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">if</span> (oid.length &lt; <span class="number">2</span>) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"Minimum OID length is two."</span>);
    } <span class="keyword">else</span> <span class="keyword">if</span> (oid[<span class="number">0</span>] !== <span class="number">1</span> || oid[<span class="number">1</span>] !== <span class="number">3</span>) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"SNMP OIDs always start with .1.3."</span>);
    }</pre></div></div>
            
        </li>
        
        
        <li id="section-15">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-15">&#182;</a>
              </div>
              <p>Calculate the first byte of the encoded OID according to the &#39;special&#39; rule.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    bytes = [ <span class="number">40</span> * oid[<span class="number">0</span>] + oid[<span class="number">1</span>] ];</pre></div></div>
            
        </li>
        
        
        <li id="section-16">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-16">&#182;</a>
              </div>
              <p>For the rest of the OID, encode each number individually and add the
resulting bytes to the buffer.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">for</span> (i = <span class="number">2</span>; i &lt; oid.length; i++) {
        val = oid[i];
        <span class="keyword">if</span> (val &gt; <span class="number">127</span>) {
            bytes = bytes.concat(oidInt(val));
        } <span class="keyword">else</span> {
            bytes.push(val);
        }
    }

    <span class="keyword">return</span> bytes;
}</pre></div></div>
            
        </li>
        
        
        <li id="section-17">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-17">&#182;</a>
              </div>
              <p>Divide an integer into base-256 bytes.
Most significant byte first.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">intArray</span><span class="params">(val)</span> {</span>
    <span class="keyword">var</span> array = [];

    <span class="keyword">if</span> (val === <span class="number">0</span>) {
        array.push(<span class="number">0</span>);
    } <span class="keyword">else</span> {
        <span class="keyword">while</span> (val &gt; <span class="number">0</span>) {
            array.push(val % <span class="number">256</span>);
            val = parseInt(val / <span class="number">256</span>, <span class="number">10</span>);
        }
    }</pre></div></div>
            
        </li>
        
        
        <li id="section-18">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-18">&#182;</a>
              </div>
              <p>Do not produce integers that look negative (high bit
of first byte set).</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">if</span> (array[array.length - <span class="number">1</span>] &gt;= <span class="number">0x80</span>) {
        array.push(<span class="number">0</span>);
    }

    <span class="keyword">return</span> array.reverse();
}</pre></div></div>
            
        </li>
        
        
        <li id="section-19">
            <div class="annotation">
              
              <div class="pilwrap for-h2">
                <a class="pilcrow" href="#section-19">&#182;</a>
              </div>
              <h2>Functions to encode ASN.1 from native objects</h2>

            </div>
            
        </li>
        
        
        <li id="section-20">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-20">&#182;</a>
              </div>
              <p>Encode a simple integer.
Integers are encoded as a simple base-256 byte sequence, most significant byte first,
prefixed with a length byte. In principle we support arbitrary integer sizes, in practice
Javascript doesn&#39;t even <strong>have</strong> integers so some precision might get lost.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeInteger = <span class="function"><span class="keyword">function</span> <span class="params">(val)</span> {</span>
    <span class="keyword">var</span> i, arr, buf;</pre></div></div>
            
        </li>
        
        
        <li id="section-21">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-21">&#182;</a>
              </div>
              <p>Get the bytes that we&#39;re going to encode.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    arr = intArray(val);</pre></div></div>
            
        </li>
        
        
        <li id="section-22">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-22">&#182;</a>
              </div>
              <p>Now that we know the length, we allocate a buffer of the required size.
We set the type and length bytes appropriately.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    buf = <span class="keyword">new</span> Buffer(<span class="number">2</span> + arr.length);
    buf[<span class="number">0</span>] = T.Integer;
    buf[<span class="number">1</span>] = arr.length;</pre></div></div>
            
        </li>
        
        
        <li id="section-23">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-23">&#182;</a>
              </div>
              <p>Copy the bytes into the array.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; arr.length; i++) {
        buf[i + <span class="number">2</span>] = arr[i];
    }

    <span class="keyword">return</span> buf;
};</pre></div></div>
            
        </li>
        
        
        <li id="section-24">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-24">&#182;</a>
              </div>
              <p>Create the representation of a Null, <code>05 00</code>.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeNull = <span class="function"><span class="keyword">function</span> <span class="params">()</span> {</span>
    <span class="keyword">var</span> buf = <span class="keyword">new</span> Buffer(<span class="number">2</span>);
    buf[<span class="number">0</span>] = T.Null;
    buf[<span class="number">1</span>] = <span class="number">0</span>;
    <span class="keyword">return</span> buf;
};</pre></div></div>
            
        </li>
        
        
        <li id="section-25">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-25">&#182;</a>
              </div>
              <p>Encode a Sequence, which is a wrapper of type <code>30</code>.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeSequence = <span class="function"><span class="keyword">function</span> <span class="params">(contents)</span> {</span>
    <span class="keyword">return</span> wrapper(T.Sequence, contents);
};</pre></div></div>
            
        </li>
        
        
        <li id="section-26">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-26">&#182;</a>
              </div>
              <p>Encode an OctetString, which is a wrapper of type <code>04</code>.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeOctetString = <span class="function"><span class="keyword">function</span> <span class="params">(string)</span> {</span>
    <span class="keyword">var</span> buf, contents;

    <span class="keyword">if</span> (<span class="keyword">typeof</span> string === <span class="string">'string'</span>) {
        contents = <span class="keyword">new</span> Buffer(string);
    } <span class="keyword">else</span> <span class="keyword">if</span> (Buffer.isBuffer(string)) {
        contents = string;
    } <span class="keyword">else</span> {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Only Buffer and string types are acceptable as OctetString.'</span>);
    }

    <span class="keyword">return</span> wrapper(T.OctetString, contents);
};</pre></div></div>
            
        </li>
        
        
        <li id="section-27">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-27">&#182;</a>
              </div>
              <p>Encode an IpAddress, which is a wrapper of type <code>40</code>.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeIpAddress = <span class="function"><span class="keyword">function</span> <span class="params">(address)</span> {</span>
    <span class="keyword">var</span> contents, octets, value = [];

    <span class="keyword">if</span> (<span class="keyword">typeof</span> address !== <span class="string">'string'</span> &amp;&amp; !Buffer.isBuffer(address)) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Only Buffer and string types are acceptable as OctetString.'</span>);
    }</pre></div></div>
            
        </li>
        
        
        <li id="section-28">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-28">&#182;</a>
              </div>
              <p>assume that the string is in dotted decimal format ipv4
also, use toString in case a buffer was passed in.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    octets = address.toString().split(<span class="string">'.'</span>);
    <span class="keyword">if</span> (octets.length !== <span class="number">4</span>) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'IP Addresses must be specified in dotted decimal format.'</span>);
    }
    octets.forEach(<span class="function"><span class="keyword">function</span> <span class="params">(octet)</span> {</span>
        <span class="keyword">var</span> octetValue = parseInt(octet, <span class="number">10</span>);
        <span class="keyword">if</span> (octet &lt; <span class="number">0</span> || octet &gt; <span class="number">255</span>) {
            <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'IP Address octets must be between 0 and 255 inclusive.'</span> + JSON.stringify(octets));
        }
        value.push(octetValue);
    });

    contents = <span class="keyword">new</span> Buffer(value);

    <span class="keyword">return</span> wrapper(T.IpAddress, contents);
};</pre></div></div>
            
        </li>
        
        
        <li id="section-29">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-29">&#182;</a>
              </div>
              <p>Encode an ObjectId.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeOid = <span class="function"><span class="keyword">function</span> <span class="params">(oid)</span> {</span>
    <span class="keyword">var</span> buf, bytes, i, len;</pre></div></div>
            
        </li>
        
        
        <li id="section-30">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-30">&#182;</a>
              </div>
              <p>Get the encoded format of the OID.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    bytes = oidArray(oid);</pre></div></div>
            
        </li>
        
        
        <li id="section-31">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-31">&#182;</a>
              </div>
              <p>Get the encoded format of the length</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    len = lengthArray(bytes.length);</pre></div></div>
            
        </li>
        
        
        <li id="section-32">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-32">&#182;</a>
              </div>
              <p>Fill in the buffer with type, length and OID data.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    buf = <span class="keyword">new</span> Buffer(<span class="number">1</span> + bytes.length + len.length);
    buf[<span class="number">0</span>] = T.ObjectIdentifier;
    <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; len.length + <span class="number">1</span>; i++) {
        buf[i] = len[i - <span class="number">1</span>];
    }
    <span class="keyword">for</span> (i = len.length + <span class="number">1</span>; i &lt; bytes.length + len.length + <span class="number">1</span>; i++) {
        buf[i] = bytes[i - len.length - <span class="number">1</span>];
    }

    <span class="keyword">return</span> buf;
};</pre></div></div>
            
        </li>
        
        
        <li id="section-33">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-33">&#182;</a>
              </div>
              <p>Encode an SNMP request with specified <code>contents</code>.
The <code>type</code> code is 0 for <code>GetRequest</code>, 1 for <code>GetNextRequest</code>.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.encodeRequest = <span class="function"><span class="keyword">function</span> <span class="params">(type, contents)</span> {</span>
    <span class="keyword">return</span> wrapper(T.PDUBase + type, contents);
};</pre></div></div>
            
        </li>
        
        
        <li id="section-34">
            <div class="annotation">
              
              <div class="pilwrap for-h2">
                <a class="pilcrow" href="#section-34">&#182;</a>
              </div>
              <h2>Functions to parse ASN.1 to native objects</h2>

            </div>
            
        </li>
        
        
        <li id="section-35">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-35">&#182;</a>
              </div>
              <p>Parse and return type, data length and header length.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">typeAndLength</span><span class="params">(buf)</span> {</span>
    <span class="keyword">var</span> res, len, i;

    res = { type: buf[<span class="number">0</span>], len: <span class="number">0</span>, header: <span class="number">1</span> };
    <span class="keyword">if</span> (buf[<span class="number">1</span>] &lt; <span class="number">128</span>) {</pre></div></div>
            
        </li>
        
        
        <li id="section-36">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-36">&#182;</a>
              </div>
              <p>If bit 8 is zero, this byte indicates the content length (up to 127 bytes).</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>        res.len = buf[<span class="number">1</span>];
        res.header += <span class="number">1</span>;
    } <span class="keyword">else</span> {</pre></div></div>
            
        </li>
        
        
        <li id="section-37">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-37">&#182;</a>
              </div>
              <p>If bit 8 is 1, bits 0 to 7 indicate the number of following legth bytes.
These bytes are a simple msb base-256 integer indicating the content length.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; buf[<span class="number">1</span>] - <span class="number">128</span>; i++) {
            res.len += buf[i + <span class="number">1</span>];
            res.len *= <span class="number">256</span>;
        }
        res.header += buf[<span class="number">1</span>] - <span class="number">128</span> + <span class="number">1</span>;
    }
    <span class="keyword">return</span> res;
}

exports.typeAndLength = typeAndLength;</pre></div></div>
            
        </li>
        
        
        <li id="section-38">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-38">&#182;</a>
              </div>
              <p>Parse a buffer containing a representation of an integer.
Verifies the type, then multiplies in each byte as it comes.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.parseInteger = <span class="function"><span class="keyword">function</span> <span class="params">(buf)</span> {</span>
    <span class="keyword">var</span> i, val;

    <span class="keyword">if</span> (buf[<span class="number">0</span>] !== T.Integer &amp;&amp; buf[<span class="number">0</span>] !== T.Counter &amp;&amp;
        buf[<span class="number">0</span>] !== T.Counter64 &amp;&amp; buf[<span class="number">0</span>] !== T.Gauge &amp;&amp;
        buf[<span class="number">0</span>] !== T.TimeTicks) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Buffer '</span> + buf.toString(<span class="string">'hex'</span>) + <span class="string">' does not appear to be an Integer'</span>);
    }

    val = <span class="number">0</span>;
    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; buf[<span class="number">1</span>]; i++) {
        val *= <span class="number">256</span>;
        val += buf[i + <span class="number">2</span>];
    }

    <span class="keyword">return</span> val;
};</pre></div></div>
            
        </li>
        
        
        <li id="section-39">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-39">&#182;</a>
              </div>
              <p>Parse a buffer containing a representation of an OctetString.
Verify the type, then just grab the string out of the buffer.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.parseOctetString = <span class="function"><span class="keyword">function</span> <span class="params">(buf)</span> {</span>
    <span class="keyword">if</span> (buf[<span class="number">0</span>] !== T.OctetString) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Buffer does not appear to be an OctetString'</span>);
    }</pre></div></div>
            
        </li>
        
        
        <li id="section-40">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-40">&#182;</a>
              </div>
              <p>SNMP doesn&#39;t specify an encoding so I pick UTF-8 as the &#39;most standard&#39;
encoding. We&#39;ll see if that assumption survives contact with actual reality.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">return</span> buf.toString(<span class="string">'utf-8'</span>, <span class="number">2</span>, <span class="number">2</span> + buf[<span class="number">1</span>]);
};</pre></div></div>
            
        </li>
        
        
        <li id="section-41">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-41">&#182;</a>
              </div>
              <p>Parse a buffer containing a representation of an ObjectIdentifier.
Verify the type, then apply the relevent encoding rules.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.parseOid = <span class="function"><span class="keyword">function</span> <span class="params">(buf)</span> {</span>
    <span class="keyword">var</span> oid, val, i;

    <span class="keyword">if</span> (buf[<span class="number">0</span>] !== T.ObjectIdentifier) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Buffer does not appear to be an ObjectIdentifier'</span>);
    }</pre></div></div>
            
        </li>
        
        
        <li id="section-42">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-42">&#182;</a>
              </div>
              <p>The first byte contains the first two numbers in the OID</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    oid = [ parseInt(buf[<span class="number">2</span>] / <span class="number">40</span>, <span class="number">10</span>), buf[<span class="number">2</span>] % <span class="number">40</span> ];</pre></div></div>
            
        </li>
        
        
        <li id="section-43">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-43">&#182;</a>
              </div>
              <p>The rest of the data is a base-128-encoded OID</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; buf[<span class="number">1</span>] - <span class="number">1</span>; i++) {
        val = <span class="number">0</span>;
        <span class="keyword">while</span> (buf[i + <span class="number">3</span>] &gt;= <span class="number">128</span>) {
            val += buf[i + <span class="number">3</span>] - <span class="number">128</span>;
            val *= <span class="number">128</span>;
            i++;
        }
        val += buf[i + <span class="number">3</span>];
        oid.push(val);
    }

    <span class="keyword">return</span> oid;
};</pre></div></div>
            
        </li>
        
        
        <li id="section-44">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-44">&#182;</a>
              </div>
              <p>Parse a buffer containing a representation of an array type.
This is for example an IpAddress.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.parseArray = <span class="function"><span class="keyword">function</span> <span class="params">(buf)</span> {</span>
    <span class="keyword">var</span> i, nelem, array;

    <span class="keyword">if</span> (buf[<span class="number">0</span>] !== T.IpAddress) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Buffer does not appear to be an array type.'</span>);
    }

    nelem = buf[<span class="number">1</span>];
    array = [];

    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; buf[<span class="number">1</span>]; i++) {
        array.push(buf[i + <span class="number">2</span>]);
    }

    <span class="keyword">return</span> array;
};</pre></div></div>
            
        </li>
        
        
        <li id="section-45">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-45">&#182;</a>
              </div>
              <p>Parse a buffer containing a representation of an opaque type.
This is for example an IpAddress.</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>exports.parseOpaque = <span class="function"><span class="keyword">function</span> <span class="params">(buf)</span> {</span>
    <span class="keyword">var</span> hdr;

    hdr = typeAndLength(buf);

    <span class="keyword">if</span> (hdr.type !== T.Opaque) {
        <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'Buffer does not appear to be an opaque type.'</span>);
    }

    <span class="keyword">return</span> <span class="string">'0x'</span> + buf.slice(hdr.header).toString(<span class="string">'hex'</span>);
};

<span class="comment">/*globals exports: false*/</span></pre></div></div>
            
        </li>
        
    </ul>
  </div>
</body>
</html>


================================================
FILE: docs/coverage.html
================================================
<!DOCTYPE html><html><head><title>Coverage</title><script>

headings = [];

onload = function(){
  headings = document.querySelectorAll('h2');
};

onscroll = function(e){
  var heading = find(window.scrollY);
  if (!heading) return;
  var links = document.querySelectorAll('#menu a')
    , link;

  for (var i = 0, len = links.length; i < len; ++i) {
    link = links[i];
    link.className = link.getAttribute('href') == '#' + heading.id
      ? 'active'
      : '';
  }
};

function find(y) {
  var i = headings.length
    , heading;

  while (i--) {
    heading = headings[i];
    if (y >= heading.offsetTop) {
      return heading;
    }
  }
}
</script>
<style>

body {
  font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: 0;
  color: #2C2C2C;
  border-top: 2px solid #ddd;
}

#coverage {
  padding: 60px;
}

h1 a {
  color: inherit;
  font-weight: inherit;
}

h1 a:hover {
  text-decoration: none;
}

.onload h1 {
  opacity: 1;
}

h2 {
  width: 80%;
  margin-top: 80px;
  margin-bottom: 0;
  font-weight: 100;
  letter-spacing: 1px;
  border-bottom: 1px solid #eee;
}

a {
  color: #8A6343;
  font-weight: bold;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

ul {
  margin-top: 20px;
  padding: 0 15px;
  width: 100%;
}

ul li {
  float: left;
  width: 40%;
  margin-top: 5px;
  margin-right: 60px;
  list-style: none;
  border-bottom: 1px solid #eee;
  padding: 5px 0;
  font-size: 12px;
}

ul::after {
  content: '.';
  height: 0;
  display: block;
  visibility: hidden;
  clear: both;
}

code {
  font: 12px monaco, monospace;
}

pre {
  margin: 30px;
  padding: 30px;
  border: 1px solid #eee;
  border-bottom-color: #ddd;
  -webkit-border-radius: 2px;
  -moz-border-radius: 2px;
  -webkit-box-shadow: inset 0 0 10px #eee;
  -moz-box-shadow: inset 0 0 10px #eee;
  overflow-x: auto;
}

img {
  margin: 30px;
  padding: 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  -webkit-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
  -moz-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
  max-width: 100%;
}

footer {
  background: #eee;
  width: 100%;
  padding: 50px 0;
  text-align: right;
  border-top: 1px solid #ddd;
}

footer span {
  display: block;
  margin-right: 30px;
  color: #888;
  font-size: 12px;
}

#menu {
  position: fixed;
  font-size: 12px;
  overflow-y: auto;
  top: 0;
  right: 0;
  margin: 0;
  height: 100%;
  padding: 15px 0;
  text-align: right;
  border-left: 1px solid #eee;
  -moz-box-shadow: 0 0 2px #888
     , inset 5px 0 20px rgba(0,0,0,.5)
     , inset 5px 0 3px rgba(0,0,0,.3);
  -webkit-box-shadow: 0 0 2px #888
     , inset 5px 0 20px rgba(0,0,0,.5)
     , inset 5px 0 3px rgba(0,0,0,.3);
  -webkit-font-smoothing: antialiased;
  background: url("data:image/png;base64,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");
}

#menu::after {
  display: block;
  content: '';
  padding-top: 80px;
}

#logo {
  position: fixed;
  bottom: 10px;
  right: 10px;
  background: rgba(255,255,255,.1);
  font-size: 11px;
  display: block;
  width: 20px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  -webkit-border-radius: 20px;
  -moz-border-radius: 20px;
  -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
  -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
  color: inherit;
}

#menu li a {
  display: block;
  color: white;
  padding: 0 35px 0 25px;
  -webkit-transition: background 300ms;
  -moz-transition: background 300ms;
}

#menu li {
  position: relative;
  list-style: none;
}

#menu a:hover,
#menu a.active {
  text-decoration: none;
  background: rgba(255,255,255,.1);
}

#menu li:hover .cov {
  opacity: 1;
}

#menu li .dirname {
  opacity: .60;
  padding-right: 2px;
}

#menu li .basename {
  opacity: 1;
}

#menu .cov {
  background: rgba(0,0,0,.4);
  position: absolute;
  top: 0;
  right: 8px;
  font-size: 9px;
  opacity: .6;
  text-align: left;
  width: 17px;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  padding: 2px 3px;
  text-align: center;
}

#stats:nth-child(2n) {
  display: inline-block;
  margin-top: 15px;
  border: 1px solid #eee;
  padding: 10px;
  -webkit-box-shadow: inset 0 0 2px #eee;
  -moz-box-shadow: inset 0 0 2px #eee;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
}

#stats div {
  float: left;
  padding: 0 5px;
}

#stats::after {
  display: block;
  content: '';
  clear: both;
}

#stats .sloc::after {
  content: ' SLOC';
  color: #b6b6b6;
}

#stats .percentage::after {
  content: ' coverage';
  color: #b6b6b6;
}

#stats .hits,
#stats .misses {
  display: none;
}

.high {
  color: #00d4b4;
}
.medium {
  color: #e87d0d;
}
.low {
  color: #d4081a;
}
.terrible {
  color: #d4081a;
  font-weight: bold;
}

table {
  width: 80%;
  margin-top: 10px;
  border-collapse: collapse;
  border: 1px solid #cbcbcb;
  color: #363636;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
}

table thead {
  display: none;
}

table td.line,
table td.hits {
  width: 20px;
  background: #eaeaea;
  text-align: center;
  font-size: 11px;
  padding: 0 10px;
  color: #949494;
}

table td.hits {
  width: 10px;
  padding: 2px 5px;
  color: rgba(0,0,0,.2);
  background: #f0f0f0;
}

tr.miss td.line,
tr.miss td.hits {
  background: #e6c3c7;
}

tr.miss td {
  background: #f8d5d8;
}

td.source {
  padding-left: 15px;
  line-height: 15px;
  white-space: pre;
  font: 12px monaco, monospace;
}

code .comment { color: #ddd }
code .init { color: #2F6FAD }
code .string { color: #5890AD }
code .keyword { color: #8A6343 }
code .number { color: #2F6FAD }
</style></head><body><div id="coverage"><h1 id="overview">Coverage</h1><div id="menu"><li><a href="#overview">overview</a></li><li><span class="cov high">98</span><a href="#lib/asn1ber.js"><span class="dirname">lib/</span><span class="basename">asn1ber.js</span></a></li><li><span class="cov high">95</span><a href="#lib/snmp.js"><span class="dirname">lib/</span><span class="basename">snmp.js</span></a></li><a id="logo" href="http://visionmedia.github.com/mocha/">m</a></div><div id="stats" class="high"><div class="percentage">96%</div><div class="sloc">473</div><div class="hits">457</div><div class="misses">16</div></div><div id="files"><div class="file"><h2 id="lib/asn1ber.js">lib/asn1ber.js</h2><div id="stats" class="high"><div class="percentage">98%</div><div class="sloc">156</div><div class="hits">153</div><div class="misses">3</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">// This file implements a minimal subset of Abstract Syntax Notation One (**ASN.1**)</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source">// Basic Encoding Rules (**BER**), namely the parts that are necessary for sending</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source">// and receiving SNMPv2c messages.</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source">//</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source">// (c) 2012 Jakob Borg, Nym Networks</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source">&quot;use strict&quot;;</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source">// We define constants for the commonly used ASN.1 types in SNMP.</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">11</td><td class="hits">1</td><td class="source">var T = {</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">    Integer: 0x02,</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">    OctetString: 0x04,</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">    Null: 0x05,</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">    ObjectIdentifier: 0x06,</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">    Sequence: 0x30,</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">    IpAddress: 0x40,</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">    Counter: 0x41,</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">    Gauge: 0x42,</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">    TimeTicks: 0x43,</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">    Opaque: 0x44,</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">    NsapAddress: 0x45,</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">    Counter64: 0x46,</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">    NoSuchObject: 0x80,</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">    NoSuchInstance: 0x81,</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">    EndOfMibView: 0x82,</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">    PDUBase: 0xA0</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">30</td><td class="hits">1</td><td class="source">var P = {</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">    GetRequestPDU: 0x00,</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">    GetNextRequestPDU: 0x01,</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">    GetResponsePDU: 0x02,</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">    SetRequestPDU: 0x03</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">// The types are also available for consumers of the library.</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">39</td><td class="hits">1</td><td class="source">exports.types = T;</td></tr><tr class="hit"><td class="line">40</td><td class="hits">1</td><td class="source">exports.pduTypes = P;</td></tr><tr class="hit"><td class="line">41</td><td class="hits">1</td><td class="source">exports.unittest = {};</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">// Private helper functions</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">// Encode a length as it should be encoded.</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">function lengthArray(len) {</td></tr><tr class="hit"><td class="line">49</td><td class="hits">345</td><td class="source">    var arr = [];</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">51</td><td class="hits">345</td><td class="source">    if (len &lt;= 127) {</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">        // Return a single byte if the value is 127 or less.</td></tr><tr class="hit"><td class="line">53</td><td class="hits">339</td><td class="source">        return [ len ];</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">        // Otherwise encode it as a MSB base-256 integer.</td></tr><tr class="hit"><td class="line">56</td><td class="hits">6</td><td class="source">        while (len &gt; 0) {</td></tr><tr class="hit"><td class="line">57</td><td class="hits">8</td><td class="source">            arr.push(len % 256);</td></tr><tr class="hit"><td class="line">58</td><td class="hits">8</td><td class="source">            len = parseInt(len / 256, 10);</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source">        // Add a length byte in front and set the high bit to indicate</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">        // that this is a longer value than one byte.</td></tr><tr class="hit"><td class="line">62</td><td class="hits">6</td><td class="source">        arr.push(128 + arr.length);</td></tr><tr class="hit"><td class="line">63</td><td class="hits">6</td><td class="source">        arr.reverse();</td></tr><tr class="hit"><td class="line">64</td><td class="hits">6</td><td class="source">        return arr;</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">68</td><td class="hits">1</td><td class="source">exports.unittest.lengthArray = lengthArray;</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">// Return a wrapped copy of the passed `contents`, with the specified wrapper type.</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">// This is used for Sequence and other constructed types.</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">function wrapper(type, contents) {</td></tr><tr class="hit"><td class="line">74</td><td class="hits">266</td><td class="source">    var buf, len, i;</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">    // Get the encoded length of the contents</td></tr><tr class="hit"><td class="line">77</td><td class="hits">266</td><td class="source">    len = lengthArray(contents.length);</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">    // Set up a buffer with the type and length bytes plus a straight copy of the content.</td></tr><tr class="hit"><td class="line">80</td><td class="hits">266</td><td class="source">    buf = new Buffer(1 + contents.length + len.length);</td></tr><tr class="hit"><td class="line">81</td><td class="hits">266</td><td class="source">    buf[0] = type;</td></tr><tr class="hit"><td class="line">82</td><td class="hits">266</td><td class="source">    for (i = 1; i &lt; len.length + 1; i++) {</td></tr><tr class="hit"><td class="line">83</td><td class="hits">271</td><td class="source">        buf[i] = len[i - 1];</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">85</td><td class="hits">266</td><td class="source">    contents.copy(buf, len.length + 1, 0);</td></tr><tr class="hit"><td class="line">86</td><td class="hits">266</td><td class="source">    return buf;</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">// Get the encoded representation of a number in an OID.</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">// If the number is less than 128, pass it as it is.</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">// Otherwise return an array of base-128 digits, most significant first,</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">// with the high bit set on all octets except the last one.</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source">// This encoding should be used for all number in an OID except the first</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">// two (.1.3) which are handled specially.</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">function oidInt(val) {</td></tr><tr class="hit"><td class="line">97</td><td class="hits">3</td><td class="source">    var bytes = [];</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">99</td><td class="hits">3</td><td class="source">    bytes.push(val % 128);</td></tr><tr class="hit"><td class="line">100</td><td class="hits">3</td><td class="source">    val = parseInt(val / 128, 10);</td></tr><tr class="hit"><td class="line">101</td><td class="hits">3</td><td class="source">    while (val &gt; 127) {</td></tr><tr class="hit"><td class="line">102</td><td class="hits">1</td><td class="source">        bytes.push(128 + val % 128);</td></tr><tr class="hit"><td class="line">103</td><td class="hits">1</td><td class="source">        val = parseInt(val / 128, 10);</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">105</td><td class="hits">3</td><td class="source">    bytes.push(val + 128);</td></tr><tr class="hit"><td class="line">106</td><td class="hits">3</td><td class="source">    return bytes.reverse();</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">108</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">// Encode an OID. The first two number are encoded specially</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">// in the first octet, then the rest are encoded as one octet per number</td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">// unless the number exceeds 127. If so, it's encoded as several base-127</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">// octets with the high bit set to indicate continuation.</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">function oidArray(oid) {</td></tr><tr class="hit"><td class="line">115</td><td class="hits">76</td><td class="source">    var bytes, i, val;</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source">    // Enforce some minimum requirements on the OID.</td></tr><tr class="hit"><td class="line">118</td><td class="hits">76</td><td class="source">    if (oid.length &lt; 2) {</td></tr><tr class="hit"><td class="line">119</td><td class="hits">1</td><td class="source">        throw new Error(&quot;Minimum OID length is two.&quot;);</td></tr><tr class="hit"><td class="line">120</td><td class="hits">75</td><td class="source">    } else if (oid[0] !== 1 || oid[1] !== 3) {</td></tr><tr class="hit"><td class="line">121</td><td class="hits">1</td><td class="source">        throw new Error(&quot;SNMP OIDs always start with .1.3.&quot;);</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">    // Calculate the first byte of the encoded OID according to the 'special' rule.</td></tr><tr class="hit"><td class="line">125</td><td class="hits">74</td><td class="source">    bytes = [ 40 * oid[0] + oid[1] ];</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">    // For the rest of the OID, encode each number individually and add the</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">    // resulting bytes to the buffer.</td></tr><tr class="hit"><td class="line">129</td><td class="hits">74</td><td class="source">    for (i = 2; i &lt; oid.length; i++) {</td></tr><tr class="hit"><td class="line">130</td><td class="hits">511</td><td class="source">        val = oid[i];</td></tr><tr class="hit"><td class="line">131</td><td class="hits">511</td><td class="source">        if (val &gt; 127) {</td></tr><tr class="hit"><td class="line">132</td><td class="hits">3</td><td class="source">            bytes = bytes.concat(oidInt(val));</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="hit"><td class="line">134</td><td class="hits">508</td><td class="source">            bytes.push(val);</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">138</td><td class="hits">74</td><td class="source">    return bytes;</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">// Divide an integer into base-256 bytes.</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source">// Most significant byte first.</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">function intArray(val) {</td></tr><tr class="hit"><td class="line">144</td><td class="hits">198</td><td class="source">    var array = [];</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">146</td><td class="hits">198</td><td class="source">    if (val === 0) {</td></tr><tr class="hit"><td class="line">147</td><td class="hits">94</td><td class="source">        array.push(0);</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">149</td><td class="hits">104</td><td class="source">        while (val &gt; 0) {</td></tr><tr class="hit"><td class="line">150</td><td class="hits">246</td><td class="source">            array.push(val % 256);</td></tr><tr class="hit"><td class="line">151</td><td class="hits">246</td><td class="source">            val = parseInt(val / 256, 10);</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source">    // Do not produce integers that look negative (high bit</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source">    // of first byte set).</td></tr><tr class="hit"><td class="line">157</td><td class="hits">198</td><td class="source">    if (array[array.length - 1] &gt;= 0x80) {</td></tr><tr class="hit"><td class="line">158</td><td class="hits">2</td><td class="source">        array.push(0);</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">161</td><td class="hits">198</td><td class="source">    return array.reverse();</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source">// Functions to encode ASN.1 from native objects</td></tr><tr><td class="line">165</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">// Encode a simple integer.</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">// Integers are encoded as a simple base-256 byte sequence, most significant byte first,</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">// prefixed with a length byte. In principle we support arbitrary integer sizes, in practice</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source">// Javascript doesn't even **have** integers so some precision might get lost.</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">172</td><td class="hits">1</td><td class="source">exports.encodeInteger = function (val) {</td></tr><tr class="hit"><td class="line">173</td><td class="hits">198</td><td class="source">    var i, arr, buf;</td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source">    // Get the bytes that we're going to encode.</td></tr><tr class="hit"><td class="line">176</td><td class="hits">198</td><td class="source">    arr = intArray(val);</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source">    // Now that we know the length, we allocate a buffer of the required size.</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source">    // We set the type and length bytes appropriately.</td></tr><tr class="hit"><td class="line">180</td><td class="hits">198</td><td class="source">    buf = new Buffer(2 + arr.length);</td></tr><tr class="hit"><td class="line">181</td><td class="hits">198</td><td class="source">    buf[0] = T.Integer;</td></tr><tr class="hit"><td class="line">182</td><td class="hits">198</td><td class="source">    buf[1] = arr.length;</td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source">    // Copy the bytes into the array.</td></tr><tr class="hit"><td class="line">185</td><td class="hits">198</td><td class="source">    for (i = 0; i &lt; arr.length; i++) {</td></tr><tr class="hit"><td class="line">186</td><td class="hits">342</td><td class="source">        buf[i + 2] = arr[i];</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">189</td><td class="hits">198</td><td class="source">    return buf;</td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source">// Create the representation of a Null, `05 00`.</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">194</td><td class="hits">1</td><td class="source">exports.encodeNull = function () {</td></tr><tr class="hit"><td class="line">195</td><td class="hits">67</td><td class="source">    var buf = new Buffer(2);</td></tr><tr class="hit"><td class="line">196</td><td class="hits">67</td><td class="source">    buf[0] = T.Null;</td></tr><tr class="hit"><td class="line">197</td><td class="hits">67</td><td class="source">    buf[1] = 0;</td></tr><tr class="hit"><td class="line">198</td><td class="hits">67</td><td class="source">    return buf;</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">// Encode a Sequence, which is a wrapper of type `30`.</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">203</td><td class="hits">1</td><td class="source">exports.encodeSequence = function (contents) {</td></tr><tr class="hit"><td class="line">204</td><td class="hits">168</td><td class="source">    return wrapper(T.Sequence, contents);</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">// Encode an OctetString, which is a wrapper of type `04`.</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">209</td><td class="hits">1</td><td class="source">exports.encodeOctetString = function (string) {</td></tr><tr class="hit"><td class="line">210</td><td class="hits">52</td><td class="source">    var buf, contents;</td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">212</td><td class="hits">52</td><td class="source">    if (typeof string === 'string') {</td></tr><tr class="hit"><td class="line">213</td><td class="hits">49</td><td class="source">        contents = new Buffer(string);</td></tr><tr class="hit"><td class="line">214</td><td class="hits">3</td><td class="source">    } else if (Buffer.isBuffer(string)) {</td></tr><tr class="hit"><td class="line">215</td><td class="hits">1</td><td class="source">        contents = string;</td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">217</td><td class="hits">2</td><td class="source">        throw new Error('Only Buffer and string types are acceptable as OctetString.');</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">220</td><td class="hits">50</td><td class="source">    return wrapper(T.OctetString, contents);</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source">// Encode an IpAddress, which is a wrapper of type `40`.</td></tr><tr><td class="line">224</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">225</td><td class="hits">1</td><td class="source">exports.encodeIpAddress = function (address) {</td></tr><tr class="hit"><td class="line">226</td><td class="hits">1</td><td class="source">    var contents, octets, value = [];</td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">228</td><td class="hits">1</td><td class="source">    if (typeof address !== 'string' &amp;&amp; !Buffer.isBuffer(address)) {</td></tr><tr class="miss"><td class="line">229</td><td class="hits">0</td><td class="source">        throw new Error('Only Buffer and string types are acceptable as OctetString.');</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">232</td><td class="hits"></td><td class="source">    // assume that the string is in dotted decimal format ipv4</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source">    // also, use toString in case a buffer was passed in.</td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">235</td><td class="hits">1</td><td class="source">    octets = address.toString().split('.');</td></tr><tr class="hit"><td class="line">236</td><td class="hits">1</td><td class="source">    if (octets.length !== 4) {</td></tr><tr class="miss"><td class="line">237</td><td class="hits">0</td><td class="source">        throw new Error('IP Addresses must be specified in dotted decimal format.');</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">239</td><td class="hits">1</td><td class="source">    octets.forEach(function (octet) {</td></tr><tr class="hit"><td class="line">240</td><td class="hits">4</td><td class="source">        var octetValue = parseInt(octet, 10);</td></tr><tr class="hit"><td class="line">241</td><td class="hits">4</td><td class="source">        if (octet &lt; 0 || octet &gt; 255) {</td></tr><tr class="miss"><td class="line">242</td><td class="hits">0</td><td class="source">            throw new Error('IP Address octets must be between 0 and 255 inclusive.' + JSON.stringify(octets));</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">244</td><td class="hits">4</td><td class="source">        value.push(octetValue);</td></tr><tr><td class="line">245</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">247</td><td class="hits">1</td><td class="source">    contents = new Buffer(value);</td></tr><tr><td class="line">248</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">249</td><td class="hits">1</td><td class="source">    return wrapper(T.IpAddress, contents);</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source">// Encode an ObjectId.</td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">254</td><td class="hits">1</td><td class="source">exports.encodeOid = function (oid) {</td></tr><tr class="hit"><td class="line">255</td><td class="hits">76</td><td class="source">    var buf, bytes, i, len;</td></tr><tr><td class="line">256</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">    // Get the encoded format of the OID.</td></tr><tr class="hit"><td class="line">258</td><td class="hits">76</td><td class="source">    bytes = oidArray(oid);</td></tr><tr><td class="line">259</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">    // Get the encoded format of the length</td></tr><tr class="hit"><td class="line">261</td><td class="hits">74</td><td class="source">    len = lengthArray(bytes.length);</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source">    // Fill in the buffer with type, length and OID data.</td></tr><tr class="hit"><td class="line">264</td><td class="hits">74</td><td class="source">    buf = new Buffer(1 + bytes.length + len.length);</td></tr><tr class="hit"><td class="line">265</td><td class="hits">74</td><td class="source">    buf[0] = T.ObjectIdentifier;</td></tr><tr class="hit"><td class="line">266</td><td class="hits">74</td><td class="source">    for (i = 1; i &lt; len.length + 1; i++) {</td></tr><tr class="hit"><td class="line">267</td><td class="hits">74</td><td class="source">        buf[i] = len[i - 1];</td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">269</td><td class="hits">74</td><td class="source">    for (i = len.length + 1; i &lt; bytes.length + len.length + 1; i++) {</td></tr><tr class="hit"><td class="line">270</td><td class="hits">589</td><td class="source">        buf[i] = bytes[i - len.length - 1];</td></tr><tr><td class="line">271</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">272</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">273</td><td class="hits">74</td><td class="source">    return buf;</td></tr><tr><td class="line">274</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">276</td><td class="hits"></td><td class="source">// Encode an SNMP request with specified `contents`.</td></tr><tr><td class="line">277</td><td class="hits"></td><td class="source">// The `type` code is 0 for `GetRequest`, 1 for `GetNextRequest`.</td></tr><tr><td class="line">278</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">279</td><td class="hits">1</td><td class="source">exports.encodeRequest = function (type, contents) {</td></tr><tr class="hit"><td class="line">280</td><td class="hits">47</td><td class="source">    return wrapper(T.PDUBase + type, contents);</td></tr><tr><td class="line">281</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">282</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source">// Functions to parse ASN.1 to native objects</td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">285</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source">// Parse and return type, data length and header length.</td></tr><tr><td class="line">287</td><td class="hits"></td><td class="source">function typeAndLength(buf) {</td></tr><tr class="hit"><td class="line">288</td><td class="hits">268</td><td class="source">    var res, len, i;</td></tr><tr><td class="line">289</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">290</td><td class="hits">268</td><td class="source">    res = { type: buf[0], len: 0, header: 1 };</td></tr><tr class="hit"><td class="line">291</td><td class="hits">268</td><td class="source">    if (buf[1] &lt; 128) {</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source">        // If bit 8 is zero, this byte indicates the content length (up to 127 bytes).</td></tr><tr class="hit"><td class="line">293</td><td class="hits">261</td><td class="source">        res.len = buf[1];</td></tr><tr class="hit"><td class="line">294</td><td class="hits">261</td><td class="source">        res.header += 1;</td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">296</td><td class="hits"></td><td class="source">        // If bit 8 is 1, bits 0 to 7 indicate the number of following legth bytes.</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source">        // These bytes are a simple msb base-256 integer indicating the content length.</td></tr><tr class="hit"><td class="line">298</td><td class="hits">7</td><td class="source">        for (i = 0; i &lt; buf[1] - 128; i++) {</td></tr><tr class="hit"><td class="line">299</td><td class="hits">10</td><td class="source">            res.len += buf[i + 1];</td></tr><tr class="hit"><td class="line">300</td><td class="hits">10</td><td class="source">            res.len *= 256;</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">302</td><td class="hits">7</td><td class="source">        res.header += buf[1] - 128 + 1;</td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">304</td><td class="hits">268</td><td class="source">    return res;</td></tr><tr><td class="line">305</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">306</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">307</td><td class="hits">1</td><td class="source">exports.typeAndLength = typeAndLength;</td></tr><tr><td class="line">308</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">309</td><td class="hits"></td><td class="source">// Parse a buffer containing a representation of an integer.</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source">// Verifies the type, then multiplies in each byte as it comes.</td></tr><tr><td class="line">311</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">312</td><td class="hits">1</td><td class="source">exports.parseInteger = function (buf) {</td></tr><tr class="hit"><td class="line">313</td><td class="hits">281</td><td class="source">    var i, val;</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">315</td><td class="hits">281</td><td class="source">    if (buf[0] !== T.Integer &amp;&amp; buf[0] !== T.Counter &amp;&amp;</td></tr><tr><td class="line">316</td><td class="hits"></td><td class="source">        buf[0] !== T.Counter64 &amp;&amp; buf[0] !== T.Gauge &amp;&amp;</td></tr><tr><td class="line">317</td><td class="hits"></td><td class="source">        buf[0] !== T.TimeTicks) {</td></tr><tr class="hit"><td class="line">318</td><td class="hits">1</td><td class="source">        throw new Error('Buffer ' + buf.toString('hex') + ' does not appear to be an Integer');</td></tr><tr><td class="line">319</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">321</td><td class="hits">280</td><td class="source">    val = 0;</td></tr><tr class="hit"><td class="line">322</td><td class="hits">280</td><td class="source">    for (i = 0; i &lt; buf[1]; i++) {</td></tr><tr class="hit"><td class="line">323</td><td class="hits">547</td><td class="source">        val *= 256;</td></tr><tr class="hit"><td class="line">324</td><td class="hits">547</td><td class="source">        val += buf[i + 2];</td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">327</td><td class="hits">280</td><td class="source">    return val;</td></tr><tr><td class="line">328</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">330</td><td class="hits"></td><td class="source">// Parse a buffer containing a representation of an OctetString.</td></tr><tr><td class="line">331</td><td class="hits"></td><td class="source">// Verify the type, then just grab the string out of the buffer.</td></tr><tr><td class="line">332</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">333</td><td class="hits">1</td><td class="source">exports.parseOctetString = function (buf) {</td></tr><tr class="hit"><td class="line">334</td><td class="hits">78</td><td class="source">    if (buf[0] !== T.OctetString) {</td></tr><tr class="hit"><td class="line">335</td><td class="hits">1</td><td class="source">        throw new Error('Buffer does not appear to be an OctetString');</td></tr><tr><td class="line">336</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">337</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">338</td><td class="hits"></td><td class="source">    // SNMP doesn't specify an encoding so I pick UTF-8 as the 'most standard'</td></tr><tr><td class="line">339</td><td class="hits"></td><td class="source">    // encoding. We'll see if that assumption survives contact with actual reality.</td></tr><tr class="hit"><td class="line">340</td><td class="hits">77</td><td class="source">    return buf.toString('utf-8', 2, 2 + buf[1]);</td></tr><tr><td class="line">341</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">342</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">343</td><td class="hits"></td><td class="source">// Parse a buffer containing a representation of an ObjectIdentifier.</td></tr><tr><td class="line">344</td><td class="hits"></td><td class="source">// Verify the type, then apply the relevent encoding rules.</td></tr><tr><td class="line">345</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">346</td><td class="hits">1</td><td class="source">exports.parseOid = function (buf) {</td></tr><tr class="hit"><td class="line">347</td><td class="hits">90</td><td class="source">    var oid, val, i;</td></tr><tr><td class="line">348</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">349</td><td class="hits">90</td><td class="source">    if (buf[0] !== T.ObjectIdentifier) {</td></tr><tr class="hit"><td class="line">350</td><td class="hits">1</td><td class="source">        throw new Error('Buffer does not appear to be an ObjectIdentifier');</td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">353</td><td class="hits"></td><td class="source">    // The first byte contains the first two numbers in the OID</td></tr><tr class="hit"><td class="line">354</td><td class="hits">89</td><td class="source">    oid = [ parseInt(buf[2] / 40, 10), buf[2] % 40 ];</td></tr><tr><td class="line">355</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">356</td><td class="hits"></td><td class="source">    // The rest of the data is a base-128-encoded OID</td></tr><tr class="hit"><td class="line">357</td><td class="hits">89</td><td class="source">    for (i = 0; i &lt; buf[1] - 1; i++) {</td></tr><tr class="hit"><td class="line">358</td><td class="hits">681</td><td class="source">        val = 0;</td></tr><tr class="hit"><td class="line">359</td><td class="hits">681</td><td class="source">        while (buf[i + 3] &gt;= 128) {</td></tr><tr class="hit"><td class="line">360</td><td class="hits">17</td><td class="source">            val += buf[i + 3] - 128;</td></tr><tr class="hit"><td class="line">361</td><td class="hits">17</td><td class="source">            val *= 128;</td></tr><tr class="hit"><td class="line">362</td><td class="hits">17</td><td class="source">            i++;</td></tr><tr><td class="line">363</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">364</td><td class="hits">681</td><td class="source">        val += buf[i + 3];</td></tr><tr class="hit"><td class="line">365</td><td class="hits">681</td><td class="source">        oid.push(val);</td></tr><tr><td class="line">366</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">367</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">368</td><td class="hits">89</td><td class="source">    return oid;</td></tr><tr><td class="line">369</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">370</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">371</td><td class="hits"></td><td class="source">// Parse a buffer containing a representation of an array type.</td></tr><tr><td class="line">372</td><td class="hits"></td><td class="source">// This is for example an IpAddress.</td></tr><tr><td class="line">373</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">374</td><td class="hits">1</td><td class="source">exports.parseArray = function (buf) {</td></tr><tr class="hit"><td class="line">375</td><td class="hits">3</td><td class="source">    var i, nelem, array;</td></tr><tr><td class="line">376</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">377</td><td class="hits">3</td><td class="source">    if (buf[0] !== T.IpAddress) {</td></tr><tr class="hit"><td class="line">378</td><td class="hits">1</td><td class="source">        throw new Error('Buffer does not appear to be an array type.');</td></tr><tr><td class="line">379</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">380</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">381</td><td class="hits">2</td><td class="source">    nelem = buf[1];</td></tr><tr class="hit"><td class="line">382</td><td class="hits">2</td><td class="source">    array = [];</td></tr><tr><td class="line">383</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">384</td><td class="hits">2</td><td class="source">    for (i = 0; i &lt; buf[1]; i++) {</td></tr><tr class="hit"><td class="line">385</td><td class="hits">8</td><td class="source">        array.push(buf[i + 2]);</td></tr><tr><td class="line">386</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">387</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">388</td><td class="hits">2</td><td class="source">    return array;</td></tr><tr><td class="line">389</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">390</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">391</td><td class="hits"></td><td class="source">// Parse a buffer containing a representation of an opaque type.</td></tr><tr><td class="line">392</td><td class="hits"></td><td class="source">// This is for example an IpAddress.</td></tr><tr><td class="line">393</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">394</td><td class="hits">1</td><td class="source">exports.parseOpaque = function (buf) {</td></tr><tr class="hit"><td class="line">395</td><td class="hits">4</td><td class="source">    var hdr;</td></tr><tr><td class="line">396</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">397</td><td class="hits">4</td><td class="source">    hdr = typeAndLength(buf);</td></tr><tr><td class="line">398</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">399</td><td class="hits">4</td><td class="source">    if (hdr.type !== T.Opaque) {</td></tr><tr class="hit"><td class="line">400</td><td class="hits">1</td><td class="source">        throw new Error('Buffer does not appear to be an opaque type.');</td></tr><tr><td class="line">401</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">402</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">403</td><td class="hits">3</td><td class="source">    return '0x' + buf.slice(hdr.header).toString('hex');</td></tr><tr><td class="line">404</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">405</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">406</td><td class="hits"></td><td class="source">/*globals exports: false*/</td></tr><tr><td class="line">407</td><td class="hits"></td><td class="source"> </td></tr></tbody></table></div><div class="file"><h2 id="lib/snmp.js">lib/snmp.js</h2><div id="stats" class="high"><div class="percentage">95%</div><div class="sloc">317</div><div class="hits">304</div><div class="misses">13</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">// Introduction</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source">// This is `node-snmp-native`, a native (Javascript) implementation of an SNMP</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source">// client library targeted at Node.js. It's MIT licensed and available at</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source">// https://github.com/calmh/node-snmp-native</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source">//</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source">// (c) 2012 Jakob Borg, Nym Networks</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source">&quot;use strict&quot;;</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">// Code</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">// This file implements a structure representing an SNMP message</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">// and routines for converting to and from the network representation.</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">// Define our external dependencies.</td></tr><tr class="hit"><td class="line">17</td><td class="hits">1</td><td class="source">var assert = require('assert');</td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">var dgram = require('dgram');</td></tr><tr class="hit"><td class="line">19</td><td class="hits">1</td><td class="source">var events = require('events');</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">// We also need our ASN.1 BER en-/decoding routines.</td></tr><tr class="hit"><td class="line">22</td><td class="hits">1</td><td class="source">var asn1ber = require('./asn1ber');</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">// Basic structures</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">// ----</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">// A `VarBind` is the innermost structure, containing an OID-Value pair.</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">function VarBind() {</td></tr><tr class="hit"><td class="line">29</td><td class="hits">223</td><td class="source">    this.type = 5;</td></tr><tr class="hit"><td class="line">30</td><td class="hits">223</td><td class="source">    this.value = null;</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">// The `PDU` contains the SNMP request or response fields and a list of `VarBinds`.</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">function PDU() {</td></tr><tr class="hit"><td class="line">35</td><td class="hits">108</td><td class="source">    this.type = asn1ber.pduTypes.GetRequestPDU;</td></tr><tr class="hit"><td class="line">36</td><td class="hits">108</td><td class="source">    this.reqid = 1;</td></tr><tr class="hit"><td class="line">37</td><td class="hits">108</td><td class="source">    this.error = 0;</td></tr><tr class="hit"><td class="line">38</td><td class="hits">108</td><td class="source">    this.errorIndex = 0;</td></tr><tr class="hit"><td class="line">39</td><td class="hits">108</td><td class="source">    this.varbinds = [ new VarBind() ];</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">// The `Packet` contains the SNMP version and community and the `PDU`.</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">function Packet() {</td></tr><tr class="hit"><td class="line">44</td><td class="hits">108</td><td class="source">    this.version = 1;</td></tr><tr class="hit"><td class="line">45</td><td class="hits">108</td><td class="source">    this.community = 'public';</td></tr><tr class="hit"><td class="line">46</td><td class="hits">108</td><td class="source">    this.pdu = new PDU();</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">// Allow consumers to create packet structures from scratch.</td></tr><tr class="hit"><td class="line">50</td><td class="hits">1</td><td class="source">exports.Packet = Packet;</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">// Private helper functions</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">// ----</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">// Concatenate several buffers to one.</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">function concatBuffers(buffers) {</td></tr><tr class="hit"><td class="line">57</td><td class="hits">210</td><td class="source">    var total, cur = 0, buf;</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">    // First we calculate the total length,</td></tr><tr class="hit"><td class="line">60</td><td class="hits">210</td><td class="source">    total = buffers.reduce(function (tot, b) {</td></tr><tr class="hit"><td class="line">61</td><td class="hits">538</td><td class="source">        return tot + b.length;</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">    }, 0);</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">    // then we allocate a new Buffer large enough to contain all data,</td></tr><tr class="hit"><td class="line">65</td><td class="hits">210</td><td class="source">    buf = new Buffer(total);</td></tr><tr class="hit"><td class="line">66</td><td class="hits">210</td><td class="source">    buffers.forEach(function (buffer) {</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source">        // finally we copy the data into the new larger buffer.</td></tr><tr class="hit"><td class="line">68</td><td class="hits">538</td><td class="source">        buffer.copy(buf, cur, 0);</td></tr><tr class="hit"><td class="line">69</td><td class="hits">538</td><td class="source">        cur += buffer.length;</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">72</td><td class="hits">210</td><td class="source">    return buf;</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">// Clear a pending packet when it times out or is successfully received.</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">function clearRequest(reqs, reqid) {</td></tr><tr class="hit"><td class="line">78</td><td class="hits">43</td><td class="source">    var self = this;</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">80</td><td class="hits">43</td><td class="source">    var entry = reqs[reqid];</td></tr><tr class="hit"><td class="line">81</td><td class="hits">43</td><td class="source">    if (entry) {</td></tr><tr class="hit"><td class="line">82</td><td class="hits">43</td><td class="source">        if (entry.timeout) {</td></tr><tr class="hit"><td class="line">83</td><td class="hits">42</td><td class="source">            clearTimeout(entry.timeout);</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">85</td><td class="hits">43</td><td class="source">        delete reqs[reqid];</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">// Convert a string formatted OID to an array, leaving anything non-string alone.</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">function parseSingleOid(oid) {</td></tr><tr class="hit"><td class="line">92</td><td class="hits">79</td><td class="source">    if (typeof oid !== 'string') {</td></tr><tr class="hit"><td class="line">93</td><td class="hits">59</td><td class="source">        return oid;</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">96</td><td class="hits">20</td><td class="source">    if (oid[0] !== '.') {</td></tr><tr class="hit"><td class="line">97</td><td class="hits">4</td><td class="source">        throw new Error('Invalid OID format');</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">100</td><td class="hits">16</td><td class="source">    oid = oid.split('.')</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">        .filter(function (s) {</td></tr><tr class="hit"><td class="line">102</td><td class="hits">154</td><td class="source">            return s.length &gt; 0;</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">        })</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source">        .map(function (s) {</td></tr><tr class="hit"><td class="line">105</td><td class="hits">138</td><td class="source">            return parseInt(s, 10);</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">108</td><td class="hits">16</td><td class="source">    return oid;</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">// Fix any OIDs in the 'oid' or 'oids' objects that are passed as strings.</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">function parseOids(options) {</td></tr><tr class="hit"><td class="line">114</td><td class="hits">58</td><td class="source">    if (options.oid) {</td></tr><tr class="hit"><td class="line">115</td><td class="hits">48</td><td class="source">        options.oid = parseSingleOid(options.oid);</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">117</td><td class="hits">55</td><td class="source">    if (options.oids) {</td></tr><tr class="hit"><td class="line">118</td><td class="hits">5</td><td class="source">        options.oids = options.oids.map(parseSingleOid);</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">// Update targ with attributes from _defs.</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">// Any existing attributes on targ are untouched.</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">function defaults(targ, _defs) {</td></tr><tr class="hit"><td class="line">126</td><td class="hits">159</td><td class="source">    [].slice.call(arguments, 1).forEach(function (def) {</td></tr><tr class="hit"><td class="line">127</td><td class="hits">164</td><td class="source">        Object.keys(def).forEach(function (key) {</td></tr><tr class="hit"><td class="line">128</td><td class="hits">818</td><td class="source">            if (!targ.hasOwnProperty(key)) {</td></tr><tr class="hit"><td class="line">129</td><td class="hits">468</td><td class="source">                targ[key] = def[key];</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">// Encode structure to ASN.1 BER</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">// ----</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source">// Return an ASN.1 BER encoding of a Packet structure.</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">// This is suitable for transmission on a UDP socket.</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">function encode(pkt) {</td></tr><tr class="hit"><td class="line">141</td><td class="hits">47</td><td class="source">    var version, community, reqid, err, erridx, vbs, pdu, message;</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">    // We only support SNMPv2c, so enforce that version stamp.</td></tr><tr class="hit"><td class="line">144</td><td class="hits">47</td><td class="source">    if (pkt.version !== 1) {</td></tr><tr class="miss"><td class="line">145</td><td class="hits">0</td><td class="source">        throw new Error('Only SNMPv2c is supported.');</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    // Encode the message header fields.</td></tr><tr class="hit"><td class="line">149</td><td class="hits">47</td><td class="source">    version = asn1ber.encodeInteger(pkt.version);</td></tr><tr class="hit"><td class="line">150</td><td class="hits">47</td><td class="source">    community = asn1ber.encodeOctetString(pkt.community);</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source">    // Encode the PDU header fields.</td></tr><tr class="hit"><td class="line">153</td><td class="hits">47</td><td class="source">    reqid = asn1ber.encodeInteger(pkt.pdu.reqid);</td></tr><tr class="hit"><td class="line">154</td><td class="hits">47</td><td class="source">    err = asn1ber.encodeInteger(pkt.pdu.error);</td></tr><tr class="hit"><td class="line">155</td><td class="hits">47</td><td class="source">    erridx = asn1ber.encodeInteger(pkt.pdu.errorIndex);</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source">    // Encode the PDU varbinds.</td></tr><tr class="hit"><td class="line">158</td><td class="hits">47</td><td class="source">    vbs = [];</td></tr><tr class="hit"><td class="line">159</td><td class="hits">47</td><td class="source">    pkt.pdu.varbinds.forEach(function (vb) {</td></tr><tr class="hit"><td class="line">160</td><td class="hits">73</td><td class="source">        var oid = asn1ber.encodeOid(vb.oid), val;</td></tr><tr><td class="line">161</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">162</td><td class="hits">73</td><td class="source">        if (vb.type === asn1ber.types.Null) {</td></tr><tr class="hit"><td class="line">163</td><td class="hits">66</td><td class="source">            val = asn1ber.encodeNull();</td></tr><tr class="hit"><td class="line">164</td><td class="hits">7</td><td class="source">        } else if (vb.type === asn1ber.types.Integer) {</td></tr><tr class="hit"><td class="line">165</td><td class="hits">5</td><td class="source">            val = asn1ber.encodeInteger(vb.value);</td></tr><tr class="hit"><td class="line">166</td><td class="hits">2</td><td class="source">        } else if (vb.type === asn1ber.types.IpAddress) {</td></tr><tr class="hit"><td class="line">167</td><td class="hits">1</td><td class="source">            val = asn1ber.encodeIpAddress(vb.value);</td></tr><tr class="hit"><td class="line">168</td><td class="hits">1</td><td class="source">        } else if (vb.type === asn1ber.types.OctetString) {</td></tr><tr class="hit"><td class="line">169</td><td class="hits">1</td><td class="source">            val = asn1ber.encodeOctetString(vb.value);</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">171</td><td class="hits">0</td><td class="source">            throw new Error('Unknown varbind type &quot;' + vb.type + '&quot; in encoding.');</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">173</td><td class="hits">72</td><td class="source">        vbs.push(asn1ber.encodeSequence(concatBuffers([oid, val])));</td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source">    // Concatenate all the varbinds together.</td></tr><tr class="hit"><td class="line">177</td><td class="hits">46</td><td class="source">    vbs = asn1ber.encodeSequence(concatBuffers(vbs));</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source">    // Create the PDU by concatenating the inner fields and adding a request structure around it.</td></tr><tr class="hit"><td class="line">180</td><td class="hits">46</td><td class="source">    pdu = asn1ber.encodeRequest(pkt.pdu.type, concatBuffers([reqid, err, erridx, vbs]));</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source">    // Create the message by concatenating the header fields and the PDU.</td></tr><tr class="hit"><td class="line">183</td><td class="hits">46</td><td class="source">    message = asn1ber.encodeSequence(concatBuffers([version, community, pdu]));</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">185</td><td class="hits">46</td><td class="source">    return message;</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">188</td><td class="hits">1</td><td class="source">exports.encode = encode;</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source">// Parse ASN.1 BER into a structure</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source">// Parse an SNMP packet into its component fields.</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">// We don't do a lot of validation so a malformed packet will probably just</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source">// make us blow up.</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source">function parse(buf) {</td></tr><tr class="hit"><td class="line">198</td><td class="hits">61</td><td class="source">    var pkt, oid, bvb, vb, hdr;</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">200</td><td class="hits">61</td><td class="source">    pkt = new Packet();</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source">    // First we have a sequence marker (two bytes).</td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">    // We don't care about those, so cut them off.</td></tr><tr class="hit"><td class="line">204</td><td class="hits">61</td><td class="source">    hdr = asn1ber.typeAndLength(buf);</td></tr><tr class="hit"><td class="line">205</td><td class="hits">61</td><td class="source">    assert.equal(asn1ber.types.Sequence, hdr.type);</td></tr><tr class="hit"><td class="line">206</td><td class="hits">59</td><td class="source">    buf = buf.slice(hdr.header);</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">    // Then comes the version field (integer). Parse it and slice it.</td></tr><tr class="hit"><td class="line">209</td><td class="hits">59</td><td class="source">    pkt.version = asn1ber.parseInteger(buf.slice(0, buf[1] + 2));</td></tr><tr class="hit"><td class="line">210</td><td class="hits">59</td><td class="source">    buf = buf.slice(2 + buf[1]);</td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">    // We then get the community. Parse and slice.</td></tr><tr class="hit"><td class="line">213</td><td class="hits">59</td><td class="source">    pkt.community = asn1ber.parseOctetString(buf.slice(0, buf[1] + 2));</td></tr><tr class="hit"><td class="line">214</td><td class="hits">59</td><td class="source">    buf = buf.slice(2 + buf[1]);</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source">    // Here's the PDU structure. We're interested in the type. Slice the rest.</td></tr><tr class="hit"><td class="line">217</td><td class="hits">59</td><td class="source">    hdr = asn1ber.typeAndLength(buf);</td></tr><tr class="hit"><td class="line">218</td><td class="hits">59</td><td class="source">    assert.ok(hdr.type &gt;= 0xA0);</td></tr><tr class="hit"><td class="line">219</td><td class="hits">59</td><td class="source">    pkt.pdu.type = hdr.type - 0xA0;</td></tr><tr class="hit"><td class="line">220</td><td class="hits">59</td><td class="source">    buf = buf.slice(hdr.header);</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source">    // The request id field.</td></tr><tr class="hit"><td class="line">223</td><td class="hits">59</td><td class="source">    pkt.pdu.reqid = asn1ber.parseInteger(buf.slice(0, buf[1] + 2));</td></tr><tr class="hit"><td class="line">224</td><td class="hits">59</td><td class="source">    buf = buf.slice(2 + buf[1]);</td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source">    // The error field.</td></tr><tr class="hit"><td class="line">227</td><td class="hits">59</td><td class="source">    pkt.pdu.error = asn1ber.parseInteger(buf.slice(0, buf[1] + 2));</td></tr><tr class="hit"><td class="line">228</td><td class="hits">59</td><td class="source">    buf = buf.slice(2 + buf[1]);</td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source">    // The error index field.</td></tr><tr class="hit"><td class="line">231</td><td class="hits">59</td><td class="source">    pkt.pdu.errorIndex = asn1ber.parseInteger(buf.slice(0, buf[1] + 2));</td></tr><tr class="hit"><td class="line">232</td><td class="hits">59</td><td class="source">    buf = buf.slice(2 + buf[1]);</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source">    // Here's the varbind list. Not interested.</td></tr><tr class="hit"><td class="line">235</td><td class="hits">59</td><td class="source">    hdr = asn1ber.typeAndLength(buf);</td></tr><tr class="hit"><td class="line">236</td><td class="hits">59</td><td class="source">    assert.equal(asn1ber.types.Sequence, hdr.type);</td></tr><tr class="hit"><td class="line">237</td><td class="hits">59</td><td class="source">    buf = buf.slice(hdr.header);</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source">    // Now comes the varbinds. There might be many, so we loop for as long as we have data.</td></tr><tr class="hit"><td class="line">240</td><td class="hits">59</td><td class="source">    pkt.pdu.varbinds = [];</td></tr><tr class="hit"><td class="line">241</td><td class="hits">59</td><td class="source">    while (buf[0] === asn1ber.types.Sequence) {</td></tr><tr class="hit"><td class="line">242</td><td class="hits">85</td><td class="source">        vb = new VarBind();</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source">        // Slice off the sequence header.</td></tr><tr class="hit"><td class="line">245</td><td class="hits">85</td><td class="source">        hdr = asn1ber.typeAndLength(buf);</td></tr><tr class="hit"><td class="line">246</td><td class="hits">85</td><td class="source">        assert.equal(asn1ber.types.Sequence, hdr.type);</td></tr><tr class="hit"><td class="line">247</td><td class="hits">85</td><td class="source">        bvb = buf.slice(hdr.header);</td></tr><tr><td class="line">248</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">249</td><td class="hits"></td><td class="source">        // Parse and save the ObjectIdentifier.</td></tr><tr class="hit"><td class="line">250</td><td class="hits">85</td><td class="source">        vb.oid = asn1ber.parseOid(bvb);</td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source">        // Parse the value. We use the type marker to figure out</td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source">        // what kind of value it is and call the appropriate parser</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source">        // routine. For the SNMPv2c error types, we simply set the</td></tr><tr><td class="line">255</td><td class="hits"></td><td class="source">        // value to a text representation of the error and leave handling</td></tr><tr><td class="line">256</td><td class="hits"></td><td class="source">        // up to the user.</td></tr><tr class="hit"><td class="line">257</td><td class="hits">85</td><td class="source">        bvb = bvb.slice(2 + bvb[1]);</td></tr><tr class="hit"><td class="line">258</td><td class="hits">85</td><td class="source">        vb.type = bvb[0];</td></tr><tr class="hit"><td class="line">259</td><td class="hits">85</td><td class="source">        if (vb.type === asn1ber.types.Null) {</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">            // Null type.</td></tr><tr class="hit"><td class="line">261</td><td class="hits">16</td><td class="source">            vb.value = null;</td></tr><tr class="hit"><td class="line">262</td><td class="hits">69</td><td class="source">        } else if (vb.type === asn1ber.types.OctetString) {</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source">            // Octet string type.</td></tr><tr class="hit"><td class="line">264</td><td class="hits">16</td><td class="source">            vb.value = asn1ber.parseOctetString(bvb);</td></tr><tr class="hit"><td class="line">265</td><td class="hits">53</td><td class="source">        } else if (vb.type === asn1ber.types.Integer ||</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source">            vb.type === asn1ber.types.Counter ||</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source">            vb.type === asn1ber.types.Counter64 ||</td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source">            vb.type === asn1ber.types.TimeTicks ||</td></tr><tr><td class="line">269</td><td class="hits"></td><td class="source">            vb.type === asn1ber.types.Gauge) {</td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source">            // Integer type and it's derivatives that behave in the same manner.</td></tr><tr class="hit"><td class="line">271</td><td class="hits">41</td><td class="source">            vb.value = asn1ber.parseInteger(bvb);</td></tr><tr class="hit"><td class="line">272</td><td class="hits">12</td><td class="source">        } else if (vb.type === asn1ber.types.ObjectIdentifier) {</td></tr><tr><td class="line">273</td><td class="hits"></td><td class="source">            // Object identifier type.</td></tr><tr class="hit"><td class="line">274</td><td class="hits">1</td><td class="source">            vb.value = asn1ber.parseOid(bvb);</td></tr><tr class="hit"><td class="line">275</td><td class="hits">11</td><td class="source">        } else if (vb.type === asn1ber.types.IpAddress) {</td></tr><tr><td class="line">276</td><td class="hits"></td><td class="source">            // IP Address type.</td></tr><tr class="hit"><td class="line">277</td><td class="hits">1</td><td class="source">            vb.value = asn1ber.parseArray(bvb);</td></tr><tr class="hit"><td class="line">278</td><td class="hits">10</td><td class="source">        } else if (vb.type === asn1ber.types.Opaque) {</td></tr><tr><td class="line">279</td><td class="hits"></td><td class="source">            // Opaque type. The 'parsing' here is very light; basically we return a</td></tr><tr><td class="line">280</td><td class="hits"></td><td class="source">            // string representation of the raw bytes in hex.</td></tr><tr class="hit"><td class="line">281</td><td class="hits">2</td><td class="source">            vb.value = asn1ber.parseOpaque(bvb);</td></tr><tr class="hit"><td class="line">282</td><td class="hits">8</td><td class="source">        } else if (vb.type === asn1ber.types.EndOfMibView) {</td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source">            // End of MIB view error, returned when attempting to GetNext beyond the end</td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">            // of the current view.</td></tr><tr class="hit"><td class="line">285</td><td class="hits">1</td><td class="source">            vb.value = 'endOfMibView';</td></tr><tr class="hit"><td class="line">286</td><td class="hits">7</td><td class="source">        } else if (vb.type === asn1ber.types.NoSuchObject) {</td></tr><tr><td class="line">287</td><td class="hits"></td><td class="source">            // No such object error, returned when attempting to Get/GetNext an OID that doesn't exist.</td></tr><tr class="hit"><td class="line">288</td><td class="hits">1</td><td class="source">            vb.value = 'noSuchObject';</td></tr><tr class="hit"><td class="line">289</td><td class="hits">6</td><td class="source">        } else if (vb.type === asn1ber.types.NoSuchInstance) {</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source">            // No such instance error, returned when attempting to Get/GetNext an instance</td></tr><tr><td class="line">291</td><td class="hits"></td><td class="source">            // that doesn't exist in a given table.</td></tr><tr class="hit"><td class="line">292</td><td class="hits">6</td><td class="source">            vb.value = 'noSuchInstance';</td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source">        } else {</td></tr><tr><td class="line">294</td><td class="hits"></td><td class="source">            // Something else that we can't handle, so throw an error.</td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source">            // The error will be caught and presented in a useful manner on stderr,</td></tr><tr><td class="line">296</td><td class="hits"></td><td class="source">            // with a dump of the message causing it.</td></tr><tr class="miss"><td class="line">297</td><td class="hits">0</td><td class="source">            throw new Error('Unrecognized value type ' + vb.type);</td></tr><tr><td class="line">298</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">299</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">300</td><td class="hits"></td><td class="source">        // Take the raw octet string value and preseve it as a buffer and hex string.</td></tr><tr class="hit"><td class="line">301</td><td class="hits">85</td><td class="source">        vb.valueRaw = bvb.slice(2);</td></tr><tr class="hit"><td class="line">302</td><td class="hits">85</td><td class="source">        vb.valueHex = vb.valueRaw.toString('hex');</td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">304</td><td class="hits"></td><td class="source">        // Add the request id to the varbind (even though it doesn't really belong)</td></tr><tr><td class="line">305</td><td class="hits"></td><td class="source">        // so that it will be availble to the end user.</td></tr><tr class="hit"><td class="line">306</td><td class="hits">85</td><td class="source">        vb.requestId = pkt.pdu.reqid;</td></tr><tr><td class="line">307</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">308</td><td class="hits"></td><td class="source">        // Push whatever we parsed to the varbind list.</td></tr><tr class="hit"><td class="line">309</td><td class="hits">85</td><td class="source">        pkt.pdu.varbinds.push(vb);</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">311</td><td class="hits"></td><td class="source">        // Go fetch the next varbind, if there seems to be any.</td></tr><tr class="hit"><td class="line">312</td><td class="hits">85</td><td class="source">        if (buf.length &gt; hdr.header + hdr.len) {</td></tr><tr class="hit"><td class="line">313</td><td class="hits">26</td><td class="source">            buf = buf.slice(hdr.header + hdr.len);</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="hit"><td class="line">315</td><td class="hits">59</td><td class="source">            break;</td></tr><tr><td class="line">316</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">317</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">318</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">319</td><td class="hits">59</td><td class="source">    return pkt;</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">321</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">322</td><td class="hits">1</td><td class="source">exports.parse = parse;</td></tr><tr><td class="line">323</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">324</td><td class="hits"></td><td class="source">// Utility functions</td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">327</td><td class="hits"></td><td class="source">// Compare two OIDs, returning -1, 0 or +1 depending on the relation between</td></tr><tr><td class="line">328</td><td class="hits"></td><td class="source">// oidA and oidB.</td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">330</td><td class="hits">1</td><td class="source">exports.compareOids = function (oidA, oidB) {</td></tr><tr class="hit"><td class="line">331</td><td class="hits">9</td><td class="source">    var mlen, i;</td></tr><tr><td class="line">332</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">333</td><td class="hits"></td><td class="source">    // The undefined OID, if there is any, is deemed lesser.</td></tr><tr class="hit"><td class="line">334</td><td class="hits">9</td><td class="source">    if (typeof oidA === 'undefined' &amp;&amp; typeof oidB !== 'undefined') {</td></tr><tr class="hit"><td class="line">335</td><td class="hits">1</td><td class="source">        return 1;</td></tr><tr class="hit"><td class="line">336</td><td class="hits">8</td><td class="source">    } else if (typeof oidA !== 'undefined' &amp;&amp; typeof oidB === 'undefined') {</td></tr><tr class="hit"><td class="line">337</td><td class="hits">1</td><td class="source">        return -1;</td></tr><tr><td class="line">338</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">339</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">340</td><td class="hits"></td><td class="source">    // Check each number part of the OIDs individually, and if there is any</td></tr><tr><td class="line">341</td><td class="hits"></td><td class="source">    // position where one OID is larger than the other, return accordingly.</td></tr><tr><td class="line">342</td><td class="hits"></td><td class="source">    // This will only check up to the minimum length of both OIDs.</td></tr><tr class="hit"><td class="line">343</td><td class="hits">7</td><td class="source">    mlen = Math.min(oidA.length, oidB.length);</td></tr><tr class="hit"><td class="line">344</td><td class="hits">7</td><td class="source">    for (i = 0; i &lt; mlen; i++) {</td></tr><tr class="hit"><td class="line">345</td><td class="hits">26</td><td class="source">        if (oidA[i] &gt; oidB[i]) {</td></tr><tr class="hit"><td class="line">346</td><td class="hits">1</td><td class="source">            return -1;</td></tr><tr class="hit"><td class="line">347</td><td class="hits">25</td><td class="source">        } else if (oidB[i] &gt; oidA[i]) {</td></tr><tr class="hit"><td class="line">348</td><td class="hits">1</td><td class="source">            return 1;</td></tr><tr><td class="line">349</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">350</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source">    // If there is one OID that is longer than the other after the above comparison,</td></tr><tr><td class="line">353</td><td class="hits"></td><td class="source">    // consider the shorter OID to be lesser.</td></tr><tr class="hit"><td class="line">354</td><td class="hits">5</td><td class="source">    if (oidA.length &gt; oidB.length) {</td></tr><tr class="hit"><td class="line">355</td><td class="hits">2</td><td class="source">        return -1;</td></tr><tr class="hit"><td class="line">356</td><td class="hits">3</td><td class="source">    } else if (oidB.length &gt; oidA.length) {</td></tr><tr class="hit"><td class="line">357</td><td class="hits">2</td><td class="source">        return 1;</td></tr><tr><td class="line">358</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">359</td><td class="hits"></td><td class="source">        // The OIDs are obviously equal.</td></tr><tr class="hit"><td class="line">360</td><td class="hits">1</td><td class="source">        return 0;</td></tr><tr><td class="line">361</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">362</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">363</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">364</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">365</td><td class="hits"></td><td class="source">// Communication functions</td></tr><tr><td class="line">366</td><td class="hits"></td><td class="source">// -----</td></tr><tr><td class="line">367</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">368</td><td class="hits"></td><td class="source">// This is called for when we receive a message.</td></tr><tr><td class="line">369</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">370</td><td class="hits"></td><td class="source">function msgReceived(msg, rinfo) {</td></tr><tr class="hit"><td class="line">371</td><td class="hits">44</td><td class="source">    var self = this, now = Date.now(), pkt, entry;</td></tr><tr><td class="line">372</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">373</td><td class="hits">44</td><td class="source">    if (msg.length === 0) {</td></tr><tr><td class="line">374</td><td class="hits"></td><td class="source">        // Not sure why we sometimes receive an empty message.</td></tr><tr><td class="line">375</td><td class="hits"></td><td class="source">        // As far as I'm concerned it shouldn't happen, but we'll ignore it</td></tr><tr><td class="line">376</td><td class="hits"></td><td class="source">        // and if it's necessary a retransmission of the request will be</td></tr><tr><td class="line">377</td><td class="hits"></td><td class="source">        // made later.</td></tr><tr class="miss"><td class="line">378</td><td class="hits">0</td><td class="source">        return;</td></tr><tr><td class="line">379</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">380</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">381</td><td class="hits"></td><td class="source">    // Parse the packet, or call the informative</td></tr><tr><td class="line">382</td><td class="hits"></td><td class="source">    // parse error display if we fail.</td></tr><tr class="hit"><td class="line">383</td><td class="hits">44</td><td class="source">    try {</td></tr><tr class="hit"><td class="line">384</td><td class="hits">44</td><td class="source">        pkt = parse(msg);</td></tr><tr><td class="line">385</td><td class="hits"></td><td class="source">    } catch (error) {</td></tr><tr class="hit"><td class="line">386</td><td class="hits">1</td><td class="source">        return self.parseError(error, msg);</td></tr><tr><td class="line">387</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">388</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">389</td><td class="hits"></td><td class="source">    // If this message's request id matches one we've sent,</td></tr><tr><td class="line">390</td><td class="hits"></td><td class="source">    // cancel any outstanding timeout and call the registered</td></tr><tr><td class="line">391</td><td class="hits"></td><td class="source">    // callback.</td></tr><tr class="hit"><td class="line">392</td><td class="hits">43</td><td class="source">    entry = self.reqs[pkt.pdu.reqid];</td></tr><tr class="hit"><td class="line">393</td><td class="hits">43</td><td class="source">    if (entry) {</td></tr><tr class="hit"><td class="line">394</td><td class="hits">40</td><td class="source">        clearRequest(self.reqs, pkt.pdu.reqid);</td></tr><tr><td class="line">395</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">396</td><td class="hits">40</td><td class="source">        if (typeof entry.callback === 'function') {</td></tr><tr class="hit"><td class="line">397</td><td class="hits">39</td><td class="source">            pkt.pdu.varbinds.forEach(function (vb) {</td></tr><tr class="hit"><td class="line">398</td><td class="hits">65</td><td class="source">                vb.receiveStamp = now;</td></tr><tr class="hit"><td class="line">399</td><td class="hits">65</td><td class="source">                vb.sendStamp = entry.sendStamp;</td></tr><tr><td class="line">400</td><td class="hits"></td><td class="source">            });</td></tr><tr><td class="line">401</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">402</td><td class="hits">39</td><td class="source">            entry.callback(null, pkt.pdu.varbinds);</td></tr><tr><td class="line">403</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">404</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">405</td><td class="hits"></td><td class="source">        // This happens if we receive the response to a message we've already timed out</td></tr><tr><td class="line">406</td><td class="hits"></td><td class="source">        // and removed the request entry for. Maybe we shouldn't even log the warning.</td></tr><tr><td class="line">407</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">408</td><td class="hits"></td><td class="source">        // Calculate the approximate send time and how old the packet is.</td></tr><tr class="hit"><td class="line">409</td><td class="hits">3</td><td class="source">        var age = (Date.now() &amp; 0x1fffff) - (pkt.pdu.reqid &gt;&gt;&gt; 10);</td></tr><tr class="hit"><td class="line">410</td><td class="hits">3</td><td class="source">        if (age &lt; 0) {</td></tr><tr class="miss"><td class="line">411</td><td class="hits">0</td><td class="source">            age += 0x200000;</td></tr><tr><td class="line">412</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">413</td><td class="hits">3</td><td class="source">        console.warn('Response with unknown request ID from ' + rinfo.address + '. Consider increasing timeouts (' + age + ' ms old?).');</td></tr><tr><td class="line">414</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">415</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">416</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">417</td><td class="hits"></td><td class="source">// Default options for new sessions and operations.</td></tr><tr class="hit"><td class="line">418</td><td class="hits">1</td><td class="source">exports.defaultOptions = {</td></tr><tr><td class="line">419</td><td class="hits"></td><td class="source">    host: 'localhost',</td></tr><tr><td class="line">420</td><td class="hits"></td><td class="source">    port: 161,</td></tr><tr><td class="line">421</td><td class="hits"></td><td class="source">    community: 'public',</td></tr><tr><td class="line">422</td><td class="hits"></td><td class="source">    family: 'udp4',</td></tr><tr><td class="line">423</td><td class="hits"></td><td class="source">    timeouts: [ 5000, 5000, 5000, 5000 ]</td></tr><tr><td class="line">424</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">425</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">426</td><td class="hits"></td><td class="source">// This creates a new SNMP session.</td></tr><tr><td class="line">427</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">428</td><td class="hits"></td><td class="source">function Session(options) {</td></tr><tr class="hit"><td class="line">429</td><td class="hits">47</td><td class="source">    var self = this;</td></tr><tr><td class="line">430</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">431</td><td class="hits">47</td><td class="source">    self.options = options || {};</td></tr><tr class="hit"><td class="line">432</td><td class="hits">47</td><td class="source">    defaults(self.options, exports.defaultOptions);</td></tr><tr><td class="line">433</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">434</td><td class="hits">47</td><td class="source">    self.reqs = {};</td></tr><tr class="hit"><td class="line">435</td><td class="hits">47</td><td class="source">    self.socket = dgram.createSocket(self.options.family);</td></tr><tr class="hit"><td class="line">436</td><td class="hits">47</td><td class="source">    self.socket.on('message', msgReceived.bind(self));</td></tr><tr class="hit"><td class="line">437</td><td class="hits">47</td><td class="source">    self.socket.on('close', function () {</td></tr><tr><td class="line">438</td><td class="hits"></td><td class="source">        // Remove the socket so we don't try to send a message on</td></tr><tr><td class="line">439</td><td class="hits"></td><td class="source">        // it when it's closed.</td></tr><tr class="miss"><td class="line">440</td><td class="hits">0</td><td class="source">        self.socket = undefined;</td></tr><tr><td class="line">441</td><td class="hits"></td><td class="source">    });</td></tr><tr class="hit"><td class="line">442</td><td class="hits">47</td><td class="source">    self.socket.on('error', function () {</td></tr><tr><td class="line">443</td><td class="hits"></td><td class="source">        // Errors will be emitted here as well as on the callback to the send function.</td></tr><tr><td class="line">444</td><td class="hits"></td><td class="source">        // We handle them there, so doing anything here is unnecessary.</td></tr><tr><td class="line">445</td><td class="hits"></td><td class="source">        // But having no error handler trips up the test suite.</td></tr><tr><td class="line">446</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">447</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">448</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">449</td><td class="hits"></td><td class="source">// We inherit from EventEmitter so that we can emit error events</td></tr><tr><td class="line">450</td><td class="hits"></td><td class="source">// on fatal errors.</td></tr><tr class="hit"><td class="line">451</td><td class="hits">1</td><td class="source">Session.prototype = Object.create(events.EventEmitter.prototype);</td></tr><tr class="hit"><td class="line">452</td><td class="hits">1</td><td class="source">exports.Session = Session;</td></tr><tr><td class="line">453</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">454</td><td class="hits"></td><td class="source">// Generate a request ID. It's best kept within a signed 32 bit integer.</td></tr><tr><td class="line">455</td><td class="hits"></td><td class="source">// Uses the current time in ms, shifted left ten bits, plus a counter.</td></tr><tr><td class="line">456</td><td class="hits"></td><td class="source">// This gives us space for 1 transmit every microsecond and wraps every</td></tr><tr><td class="line">457</td><td class="hits"></td><td class="source">// ~1000 seconds. This is OK since we only need to keep unique ID:s for in</td></tr><tr><td class="line">458</td><td class="hits"></td><td class="source">// flight packets and they should be safely timed out by then.</td></tr><tr><td class="line">459</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">460</td><td class="hits">1</td><td class="source">Session.prototype.requestId = function () {</td></tr><tr class="hit"><td class="line">461</td><td class="hits">45</td><td class="source">    var self = this, now = Date.now();</td></tr><tr><td class="line">462</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">463</td><td class="hits">45</td><td class="source">    if (!self.prevTs) {</td></tr><tr class="hit"><td class="line">464</td><td class="hits">35</td><td class="source">        self.prevTs = now;</td></tr><tr class="hit"><td class="line">465</td><td class="hits">35</td><td class="source">        self.counter = 0;</td></tr><tr><td class="line">466</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">467</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">468</td><td class="hits">45</td><td class="source">    if (now === self.prevTs) {</td></tr><tr class="hit"><td class="line">469</td><td class="hits">35</td><td class="source">        self.counter += 1;</td></tr><tr class="hit"><td class="line">470</td><td class="hits">35</td><td class="source">        if (self.counter &gt; 1023) {</td></tr><tr class="miss"><td class="line">471</td><td class="hits">0</td><td class="source">            throw new Error('Request ID counter overflow. Adjust algorithm.');</td></tr><tr><td class="line">472</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">473</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">474</td><td class="hits">10</td><td class="source">        self.prevTs = now;</td></tr><tr class="hit"><td class="line">475</td><td class="hits">10</td><td class="source">        self.counter = 0;</td></tr><tr><td class="line">476</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">477</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">478</td><td class="hits">45</td><td class="source">    return ((now &amp; 0x1fffff) &lt;&lt; 10) + self.counter;</td></tr><tr><td class="line">479</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">480</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">481</td><td class="hits"></td><td class="source">// Display useful debugging information when a parse error occurs.</td></tr><tr><td class="line">482</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">483</td><td class="hits">1</td><td class="source">Session.prototype.parseError = function (error, buffer) {</td></tr><tr class="hit"><td class="line">484</td><td class="hits">1</td><td class="source">    var self = this, hex;</td></tr><tr><td class="line">485</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">486</td><td class="hits"></td><td class="source">    // Display a friendly introductory text.</td></tr><tr class="hit"><td class="line">487</td><td class="hits">1</td><td class="source">    console.error('Woops! An error occurred while parsing an SNMP message. :(');</td></tr><tr class="hit"><td class="line">488</td><td class="hits">1</td><td class="source">    console.error('To have this problem corrected, please report the information below verbatim');</td></tr><tr class="hit"><td class="line">489</td><td class="hits">1</td><td class="source">    console.error('via email to snmp@nym.se or by creating a GitHub issue at');</td></tr><tr class="hit"><td class="line">490</td><td class="hits">1</td><td class="source">    console.error('https://github.com/calmh/node-snmp-native/issues');</td></tr><tr class="hit"><td class="line">491</td><td class="hits">1</td><td class="source">    console.error('');</td></tr><tr class="hit"><td class="line">492</td><td class="hits">1</td><td class="source">    console.error('Thanks!');</td></tr><tr><td class="line">493</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">494</td><td class="hits"></td><td class="source">    // Display the stack backtrace so we know where the exception happened.</td></tr><tr class="hit"><td class="line">495</td><td class="hits">1</td><td class="source">    console.error('');</td></tr><tr class="hit"><td class="line">496</td><td class="hits">1</td><td class="source">    console.error(error.stack);</td></tr><tr><td class="line">497</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">498</td><td class="hits"></td><td class="source">    // Display the buffer data, nicely formatted so we can replicate the problem.</td></tr><tr class="hit"><td class="line">499</td><td class="hits">1</td><td class="source">    console.error('\nMessage data:');</td></tr><tr class="hit"><td class="line">500</td><td class="hits">1</td><td class="source">    hex = buffer.toString('hex');</td></tr><tr class="hit"><td class="line">501</td><td class="hits">1</td><td class="source">    while (hex.length &gt; 0) {</td></tr><tr class="hit"><td class="line">502</td><td class="hits">7</td><td class="source">        console.error('    ' + hex.slice(0, 32).replace(/([0-9a-f]{2})/g, '$1 '));</td></tr><tr class="hit"><td class="line">503</td><td class="hits">7</td><td class="source">        hex = hex.slice(32);</td></tr><tr><td class="line">504</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">505</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">506</td><td class="hits"></td><td class="source">    // Let the exception bubble upwards.</td></tr><tr class="hit"><td class="line">507</td><td class="hits">1</td><td class="source">    self.emit('error', error);</td></tr><tr><td class="line">508</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">509</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">510</td><td class="hits"></td><td class="source">// Send a message. Can be used after manually constructing a correct Packet structure.</td></tr><tr><td class="line">511</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">512</td><td class="hits">1</td><td class="source">Session.prototype.sendMsg = function (pkt, options, callback) {</td></tr><tr class="hit"><td class="line">513</td><td class="hits">45</td><td class="source">    var self = this, buf, reqid, retrans = 0;</td></tr><tr><td class="line">514</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">515</td><td class="hits">45</td><td class="source">    defaults(options, self.options);</td></tr><tr><td class="line">516</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">517</td><td class="hits">45</td><td class="source">    reqid = self.requestId();</td></tr><tr class="hit"><td class="line">518</td><td class="hits">45</td><td class="source">    pkt.pdu.reqid = reqid;</td></tr><tr><td class="line">519</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">520</td><td class="hits">45</td><td class="source">    buf = encode(pkt);</td></tr><tr><td class="line">521</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">522</td><td class="hits"></td><td class="source">    function transmit() {</td></tr><tr class="hit"><td class="line">523</td><td class="hits">47</td><td class="source">        if (!self.socket || !self.reqs[reqid]) {</td></tr><tr><td class="line">524</td><td class="hits"></td><td class="source">            // The socket has already been closed, perhaps due to an error that ocurred while a timeout</td></tr><tr><td class="line">525</td><td class="hits"></td><td class="source">            // was scheduled. We can't do anything about it now.</td></tr><tr class="miss"><td class="line">526</td><td class="hits">0</td><td class="source">            clearRequest(self.reqs, reqid);</td></tr><tr class="miss"><td class="line">527</td><td class="hits">0</td><td class="source">            return;</td></tr><tr><td class="line">528</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">529</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">530</td><td class="hits"></td><td class="source">        // Send the message.</td></tr><tr class="hit"><td class="line">531</td><td class="hits">47</td><td class="source">        self.socket.send(buf, 0, buf.length, options.port, options.host, function (err, bytes) {</td></tr><tr class="hit"><td class="line">532</td><td class="hits">47</td><td class="source">            var entry = self.reqs[reqid];</td></tr><tr><td class="line">533</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">534</td><td class="hits">47</td><td class="source">            if (err) {</td></tr><tr class="hit"><td class="line">535</td><td class="hits">1</td><td class="source">                clearRequest(self.reqs, reqid);</td></tr><tr class="hit"><td class="line">536</td><td class="hits">1</td><td class="source">                return callback(err);</td></tr><tr class="hit"><td class="line">537</td><td class="hits">46</td><td class="source">            } else if (entry) {</td></tr><tr class="hit"><td class="line">538</td><td class="hits">46</td><td class="source">                entry.sendStamp = Date.now();</td></tr><tr><td class="line">539</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">540</td><td class="hits">46</td><td class="source">                if (options.timeouts[retrans]) {</td></tr><tr><td class="line">541</td><td class="hits"></td><td class="source">                    // Set timeout and record the timer so that we can (attempt to) cancel it when we receive the reply.</td></tr><tr class="hit"><td class="line">542</td><td class="hits">44</td><td class="source">                    entry.timeout = setTimeout(transmit, options.timeouts[retrans]);</td></tr><tr class="hit"><td class="line">543</td><td class="hits">44</td><td class="source">                    retrans += 1;</td></tr><tr><td class="line">544</td><td class="hits"></td><td class="source">                } else {</td></tr><tr class="hit"><td class="line">545</td><td class="hits">2</td><td class="source">                    clearRequest(self.reqs, reqid);</td></tr><tr class="hit"><td class="line">546</td><td class="hits">2</td><td class="source">                    return callback(new Error('Timeout'));</td></tr><tr><td class="line">547</td><td class="hits"></td><td class="source">                }</td></tr><tr><td class="line">548</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">549</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">550</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">551</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">552</td><td class="hits"></td><td class="source">    // Register the callback to call when we receive a reply.</td></tr><tr class="hit"><td class="line">553</td><td class="hits">44</td><td class="source">    self.reqs[reqid] = { callback: callback };</td></tr><tr><td class="line">554</td><td class="hits"></td><td class="source">    // Transmit the message.</td></tr><tr class="hit"><td class="line">555</td><td class="hits">44</td><td class="source">    transmit();</td></tr><tr><td class="line">556</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">557</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">558</td><td class="hits"></td><td class="source">// Shortcut to create a GetRequest and send it, while registering a callback.</td></tr><tr><td class="line">559</td><td class="hits"></td><td class="source">// Needs `options.oid` to be an OID in array form.</td></tr><tr><td class="line">560</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">561</td><td class="hits">1</td><td class="source">Session.prototype.get = function (options, callback) {</td></tr><tr class="hit"><td class="line">562</td><td class="hits">24</td><td class="source">    var self = this, pkt;</td></tr><tr><td class="line">563</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">564</td><td class="hits">24</td><td class="source">    defaults(options, self.options);</td></tr><tr class="hit"><td class="line">565</td><td class="hits">24</td><td class="source">    parseOids(options);</td></tr><tr><td class="line">566</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">567</td><td class="hits">23</td><td class="source">    if (!options.oid) {</td></tr><tr class="hit"><td class="line">568</td><td class="hits">1</td><td class="source">        return callback(null, []);</td></tr><tr><td class="line">569</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">570</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">571</td><td class="hits">22</td><td class="source">    pkt = new Packet();</td></tr><tr class="hit"><td class="line">572</td><td class="hits">22</td><td class="source">    pkt.community = options.community;</td></tr><tr class="hit"><td class="line">573</td><td class="hits">22</td><td class="source">    pkt.pdu.varbinds[0].oid = options.oid;</td></tr><tr class="hit"><td class="line">574</td><td class="hits">22</td><td class="source">    self.sendMsg(pkt, options, callback);</td></tr><tr><td class="line">575</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">576</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">577</td><td class="hits"></td><td class="source">// Shortcut to create a SetRequest and send it, while registering a callback.</td></tr><tr><td class="line">578</td><td class="hits"></td><td class="source">// Needs `options.oid` to be an OID in array form, `options.value` to be an</td></tr><tr><td class="line">579</td><td class="hits"></td><td class="source">// integer and `options.type` to be asn1ber.T.Integer (2).</td></tr><tr><td class="line">580</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">581</td><td class="hits">1</td><td class="source">Session.prototype.set = function (options, callback) {</td></tr><tr class="hit"><td class="line">582</td><td class="hits">10</td><td class="source">    var self = this, pkt;</td></tr><tr><td class="line">583</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">584</td><td class="hits">10</td><td class="source">    defaults(options, self.options);</td></tr><tr class="hit"><td class="line">585</td><td class="hits">10</td><td class="source">    parseOids(options);</td></tr><tr><td class="line">586</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">587</td><td class="hits">9</td><td class="source">    if (!options.oid) {</td></tr><tr class="hit"><td class="line">588</td><td class="hits">1</td><td class="source">        throw new Error('Missing required option `oid`.');</td></tr><tr class="hit"><td class="line">589</td><td class="hits">8</td><td class="source">    } else if (options.value === undefined) {</td></tr><tr class="hit"><td class="line">590</td><td class="hits">1</td><td class="source">        throw new Error('Missing required option `value`.');</td></tr><tr class="hit"><td class="line">591</td><td class="hits">7</td><td class="source">    } else if (!options.type) {</td></tr><tr class="hit"><td class="line">592</td><td class="hits">1</td><td class="source">        throw new Error('Missing required option `type`.');</td></tr><tr><td class="line">593</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">594</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">595</td><td class="hits">6</td><td class="source">    pkt = new Packet();</td></tr><tr class="hit"><td class="line">596</td><td class="hits">6</td><td class="source">    pkt.community = options.community;</td></tr><tr class="hit"><td class="line">597</td><td class="hits">6</td><td class="source">    pkt.pdu.type = asn1ber.pduTypes.SetRequestPDU;</td></tr><tr class="hit"><td class="line">598</td><td class="hits">6</td><td class="source">    pkt.pdu.varbinds[0].oid = options.oid;</td></tr><tr class="hit"><td class="line">599</td><td class="hits">6</td><td class="source">    pkt.pdu.varbinds[0].type = options.type;</td></tr><tr class="hit"><td class="line">600</td><td class="hits">6</td><td class="source">    pkt.pdu.varbinds[0].value = options.value;</td></tr><tr class="hit"><td class="line">601</td><td class="hits">6</td><td class="source">    self.sendMsg(pkt, options, callback);</td></tr><tr><td class="line">602</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">603</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">604</td><td class="hits"></td><td class="source">// Shortcut to get all OIDs in the `options.oids` array sequentially. The</td></tr><tr><td class="line">605</td><td class="hits"></td><td class="source">// callback is called when the entire operation is completed.  If</td></tr><tr><td class="line">606</td><td class="hits"></td><td class="source">// options.abortOnError is truish, an error while getting any of the values</td></tr><tr><td class="line">607</td><td class="hits"></td><td class="source">// will cause the callback to be called with error status. When</td></tr><tr><td class="line">608</td><td class="hits"></td><td class="source">// `options.abortOnError` is falsish (the default), any errors will be ignored</td></tr><tr><td class="line">609</td><td class="hits"></td><td class="source">// and any successfully retrieved values sent to the callback.</td></tr><tr><td class="line">610</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">611</td><td class="hits">1</td><td class="source">Session.prototype.getAll = function (options, callback) {</td></tr><tr class="hit"><td class="line">612</td><td class="hits">5</td><td class="source">    var self = this, results = [];</td></tr><tr><td class="line">613</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">614</td><td class="hits">5</td><td class="source">    defaults(options, self.options, { abortOnError: false });</td></tr><tr class="hit"><td class="line">615</td><td class="hits">5</td><td class="source">    parseOids(options);</td></tr><tr><td class="line">616</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">617</td><td class="hits">5</td><td class="source">    if (!options.oids || options.oids.length === 0) {</td></tr><tr class="hit"><td class="line">618</td><td class="hits">2</td><td class="source">        return callback(null, []);</td></tr><tr><td class="line">619</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">620</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">621</td><td class="hits"></td><td class="source">    function getOne(c) {</td></tr><tr class="hit"><td class="line">622</td><td class="hits">4</td><td class="source">        var oid, pkt, m, vb;</td></tr><tr><td class="line">623</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">624</td><td class="hits">4</td><td class="source">        pkt = new Packet();</td></tr><tr class="hit"><td class="line">625</td><td class="hits">4</td><td class="source">        pkt.community = options.community;</td></tr><tr class="hit"><td class="line">626</td><td class="hits">4</td><td class="source">        pkt.pdu.varbinds = [];</td></tr><tr><td class="line">627</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">628</td><td class="hits"></td><td class="source">        // Push up to 16 varbinds in the same message.</td></tr><tr><td class="line">629</td><td class="hits"></td><td class="source">        // The number 16 isn't really that magical, it's just a nice round</td></tr><tr><td class="line">630</td><td class="hits"></td><td class="source">        // number that usually seems to fit withing a single packet and gets</td></tr><tr><td class="line">631</td><td class="hits"></td><td class="source">        // accepted by the switches I've tested it on.</td></tr><tr class="hit"><td class="line">632</td><td class="hits">4</td><td class="source">        for (m = 0; m &lt; 16 &amp;&amp; c &lt; options.oids.length; m++) {</td></tr><tr class="hit"><td class="line">633</td><td class="hits">30</td><td class="source">            vb = new VarBind();</td></tr><tr class="hit"><td class="line">634</td><td class="hits">30</td><td class="source">            vb.oid = options.oids[c];</td></tr><tr class="hit"><td class="line">635</td><td class="hits">30</td><td class="source">            pkt.pdu.varbinds.push(vb);</td></tr><tr class="hit"><td class="line">636</td><td class="hits">30</td><td class="source">            c++;</td></tr><tr><td class="line">637</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">638</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">639</td><td class="hits">4</td><td class="source">        self.sendMsg(pkt, options, function (err, varbinds) {</td></tr><tr class="hit"><td class="line">640</td><td class="hits">4</td><td class="source">            if (options.abortOnError &amp;&amp; err) {</td></tr><tr class="miss"><td class="line">641</td><td class="hits">0</td><td class="source">                callback(err);</td></tr><tr><td class="line">642</td><td class="hits"></td><td class="source">            } else {</td></tr><tr class="hit"><td class="line">643</td><td class="hits">4</td><td class="source">                if (varbinds) {</td></tr><tr class="hit"><td class="line">644</td><td class="hits">4</td><td class="source">                    results = results.concat(varbinds);</td></tr><tr><td class="line">645</td><td class="hits"></td><td class="source">                }</td></tr><tr class="hit"><td class="line">646</td><td class="hits">4</td><td class="source">                if (c &lt; options.oids.length) {</td></tr><tr class="hit"><td class="line">647</td><td class="hits">1</td><td class="source">                    getOne(c);</td></tr><tr><td class="line">648</td><td class="hits"></td><td class="source">                } else {</td></tr><tr class="hit"><td class="line">649</td><td class="hits">3</td><td class="source">                    callback(null, results);</td></tr><tr><td class="line">650</td><td class="hits"></td><td class="source">                }</td></tr><tr><td class="line">651</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">652</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">653</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">654</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">655</td><td class="hits">3</td><td class="source">    getOne(0);</td></tr><tr><td class="line">656</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">657</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">658</td><td class="hits"></td><td class="source">// Shortcut to create a GetNextRequest and send it, while registering a callback.</td></tr><tr><td class="line">659</td><td class="hits"></td><td class="source">// Needs `options.oid` to be an OID in array form.</td></tr><tr><td class="line">660</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">661</td><td class="hits">1</td><td class="source">Session.prototype.getNext = function (options, callback) {</td></tr><tr class="hit"><td class="line">662</td><td class="hits">16</td><td class="source">    var self = this, pkt;</td></tr><tr><td class="line">663</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">664</td><td class="hits">16</td><td class="source">    defaults(options, self.options);</td></tr><tr class="hit"><td class="line">665</td><td class="hits">16</td><td class="source">    parseOids(options);</td></tr><tr><td class="line">666</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">667</td><td class="hits">14</td><td class="source">    if (!options.oid) {</td></tr><tr class="hit"><td class="line">668</td><td class="hits">1</td><td class="source">        return callback(null, []);</td></tr><tr><td class="line">669</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">670</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">671</td><td class="hits">13</td><td class="source">    pkt = new Packet();</td></tr><tr class="hit"><td class="line">672</td><td class="hits">13</td><td class="source">    pkt.community = options.community;</td></tr><tr class="hit"><td class="line">673</td><td class="hits">13</td><td class="source">    pkt.pdu.type = 1;</td></tr><tr class="hit"><td class="line">674</td><td class="hits">13</td><td class="source">    pkt.pdu.varbinds[0].oid = options.oid;</td></tr><tr class="hit"><td class="line">675</td><td class="hits">13</td><td class="source">    self.sendMsg(pkt, options, callback);</td></tr><tr><td class="line">676</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">677</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">678</td><td class="hits"></td><td class="source">// Shortcut to get all entries below the specified OID.</td></tr><tr><td class="line">679</td><td class="hits"></td><td class="source">// The callback will be called once with the list of</td></tr><tr><td class="line">680</td><td class="hits"></td><td class="source">// varbinds that was collected, or with an error object.</td></tr><tr><td class="line">681</td><td class="hits"></td><td class="source">// Needs `options.oid` to be an OID in array form.</td></tr><tr><td class="line">682</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">683</td><td class="hits">1</td><td class="source">Session.prototype.getSubtree = function (options, callback) {</td></tr><tr class="hit"><td class="line">684</td><td class="hits">3</td><td class="source">    var self = this, vbs = [];</td></tr><tr><td class="line">685</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">686</td><td class="hits">3</td><td class="source">    defaults(options, self.options);</td></tr><tr class="hit"><td class="line">687</td><td class="hits">3</td><td class="source">    parseOids(options);</td></tr><tr><td class="line">688</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">689</td><td class="hits">3</td><td class="source">    if (!options.oid) {</td></tr><tr class="hit"><td class="line">690</td><td class="hits">1</td><td class="source">        return callback(null, []);</td></tr><tr><td class="line">691</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">692</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">693</td><td class="hits">2</td><td class="source">    options.startOid = options.oid;</td></tr><tr><td class="line">694</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">695</td><td class="hits"></td><td class="source">    // Helper to check whether `oid` in inside the tree rooted at</td></tr><tr><td class="line">696</td><td class="hits"></td><td class="source">    // `root` or not.</td></tr><tr><td class="line">697</td><td class="hits"></td><td class="source">    function inTree(root, oid) {</td></tr><tr class="hit"><td class="line">698</td><td class="hits">11</td><td class="source">        var i;</td></tr><tr class="hit"><td class="line">699</td><td class="hits">11</td><td class="source">        if (oid.length &lt;= root.length) {</td></tr><tr class="hit"><td class="line">700</td><td class="hits">1</td><td class="source">            return false;</td></tr><tr><td class="line">701</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">702</td><td class="hits">10</td><td class="source">        for (i = 0; i &lt; root.length; i++) {</td></tr><tr class="hit"><td class="line">703</td><td class="hits">79</td><td class="source">            if (oid[i] !== root[i]) {</td></tr><tr class="hit"><td class="line">704</td><td class="hits">1</td><td class="source">                return false;</td></tr><tr><td class="line">705</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">706</td><td class="hits"></td><td class="source">        }</td></tr><tr class="hit"><td class="line">707</td><td class="hits">9</td><td class="source">        return true;</td></tr><tr><td class="line">708</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">709</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">710</td><td class="hits"></td><td class="source">    // Helper to handle the result of getNext and call the user's callback</td></tr><tr><td class="line">711</td><td class="hits"></td><td class="source">    // as appropriate. The callback will see one of the following patterns:</td></tr><tr><td class="line">712</td><td class="hits"></td><td class="source">    //  - callback([an Error object], undefined) -- an error ocurred.</td></tr><tr><td class="line">713</td><td class="hits"></td><td class="source">    //  - callback(null, [a Packet object]) -- data from under the tree.</td></tr><tr><td class="line">714</td><td class="hits"></td><td class="source">    //  - callback(null, null) -- end of tree.</td></tr><tr><td class="line">715</td><td class="hits"></td><td class="source">    function result(error, varbinds) {</td></tr><tr class="hit"><td class="line">716</td><td class="hits">11</td><td class="source">        if (error) {</td></tr><tr class="miss"><td class="line">717</td><td class="hits">0</td><td class="source">            callback(error);</td></tr><tr><td class="line">718</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="hit"><td class="line">719</td><td class="hits">11</td><td class="source">            if (inTree(options.startOid, varbinds[0].oid)) {</td></tr><tr class="hit"><td class="line">720</td><td class="hits">9</td><td class="source">                if (varbinds[0].value === 'endOfMibView' || varbinds[0].value === 'noSuchObject' || varbinds[0].value === 'noSuchInstance') {</td></tr><tr class="miss"><td class="line">721</td><td class="hits">0</td><td class="source">                    callback(null, vbs);</td></tr><tr><td class="line">722</td><td class="hits"></td><td class="source">                } else {</td></tr><tr class="hit"><td class="line">723</td><td class="hits">9</td><td class="source">                    vbs.push(varbinds[0])
Download .txt
gitextract_v45mz64j/

├── .gitignore
├── .jshintrc
├── .travis.yml
├── LICENSE
├── README.md
├── docs/
│   ├── asn1ber.html
│   ├── coverage.html
│   ├── docco.css
│   ├── example.html
│   ├── public/
│   │   └── stylesheets/
│   │       └── normalize.css
│   └── snmp.html
├── example.js
├── lib/
│   ├── asn1ber.js
│   └── snmp.js
├── package.json
└── test/
    ├── asn1ber.js
    ├── integration.js
    └── snmp.js
Download .txt
SYMBOL INDEX (25 symbols across 3 files)

FILE: lib/asn1ber.js
  function lengthArray (line 73) | function lengthArray(len) {
  function wrapper (line 98) | function wrapper(type, contents) {
  function oidInt (line 121) | function oidInt(val) {
  function oidArray (line 138) | function oidArray(oid) {
  function intArray (line 173) | function intArray(val) {
  function encodeIntegerish (line 207) | function encodeIntegerish(val, type) {
  function typeAndLength (line 366) | function typeAndLength(buf) {

FILE: lib/snmp.js
  function VarBind (line 38) | function VarBind() {
  function PDU (line 44) | function PDU() {
  function Packet (line 53) | function Packet() {
  function concatBuffers (line 66) | function concatBuffers(buffers) {
  function clearRequest (line 87) | function clearRequest(reqs, reqid) {
  function parseSingleOid (line 101) | function parseSingleOid(oid) {
  function parseOids (line 123) | function parseOids(options) {
  function defaults (line 135) | function defaults(targ, _defs) {
  function encode (line 150) | function encode(pkt) {
  function parse (line 221) | function parse(buf) {
  function compareOids (line 356) | function compareOids (oidA, oidB) {
  function msgReceived (line 397) | function msgReceived(msg, rinfo) {
  function Session (line 457) | function Session(options) {
  function transmit (line 529) | function transmit() {
  function getOne (line 629) | function getOne(c) {
  function inTree (line 721) | function inTree(root, oid) {
  function result (line 739) | function result(error, varbinds) {

FILE: test/integration.js
  function setupResponder (line 32) | function setupResponder(agent, data) {
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (435K chars).
[
  {
    "path": ".gitignore",
    "chars": 37,
    "preview": ".*.swp\ngmon.out\nnode_modules\nlib-cov\n"
  },
  {
    "path": ".jshintrc",
    "chars": 263,
    "preview": "{\n    \"curly\": true,\n    \"eqeqeq\": true,\n    \"forin\": true,\n    \"immed\": true,\n    \"latedef\": true,\n    \"newcap\": true,\n"
  },
  {
    "path": ".travis.yml",
    "chars": 84,
    "preview": "language: node_js\nnode_js:\n  - node\n  - lts/*\n  - '12'\n  - '10'\n  - '8'\ncache: yarn\n"
  },
  {
    "path": "LICENSE",
    "chars": 1058,
    "preview": "Copyright (C) 2012 Jakob Borg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis soft"
  },
  {
    "path": "README.md",
    "chars": 10322,
    "preview": "                                                                 __\n                                                    "
  },
  {
    "path": "docs/asn1ber.html",
    "chars": 38276,
    "preview": "<!DOCTYPE html>\n\n<html>\n<head>\n  <title>asn1ber.js</title>\n  <meta http-equiv=\"content-type\" content=\"text/html; charset"
  },
  {
    "path": "docs/coverage.html",
    "chars": 151232,
    "preview": "<!DOCTYPE html><html><head><title>Coverage</title><script>\n\nheadings = [];\n\nonload = function(){\n  headings = document.q"
  },
  {
    "path": "docs/docco.css",
    "chars": 9246,
    "preview": "/*--------------------- Typography ----------------------------*/\n\n@font-face {\n    font-family: 'aller-light';\n    src:"
  },
  {
    "path": "docs/example.html",
    "chars": 16827,
    "preview": "<!DOCTYPE html>\n\n<html>\n<head>\n  <title>example.js</title>\n  <meta http-equiv=\"content-type\" content=\"text/html; charset"
  },
  {
    "path": "docs/public/stylesheets/normalize.css",
    "chars": 6874,
    "preview": "/*! normalize.css v2.0.1 | MIT License | git.io/normalize */\n\n/* ======================================================="
  },
  {
    "path": "docs/snmp.html",
    "chars": 73932,
    "preview": "<!DOCTYPE html>\n\n<html>\n<head>\n  <title>snmp.js</title>\n  <meta http-equiv=\"content-type\" content=\"text/html; charset=UT"
  },
  {
    "path": "example.js",
    "chars": 4238,
    "preview": "// Example code for node-snmp-native.\n// ----\n\n// This file contains examples of how to use the library.\n\n// Basic setup"
  },
  {
    "path": "lib/asn1ber.js",
    "chars": 13577,
    "preview": "// This file implements a minimal subset of Abstract Syntax Notation One (**ASN.1**)\n// Basic Encoding Rules (**BER**), "
  },
  {
    "path": "lib/snmp.js",
    "chars": 26524,
    "preview": "// Introduction\n// -----\n// This is `node-snmp-native`, a native (Javascript) implementation of an SNMP\n// client librar"
  },
  {
    "path": "package.json",
    "chars": 1027,
    "preview": "{\n  \"name\": \"snmp-native\",\n  \"description\": \"A native Javascript SNMP implementation for Node.js\",\n  \"author\": \"Jakob Bo"
  },
  {
    "path": "test/asn1ber.js",
    "chars": 19305,
    "preview": "var assert = require('assert');\nvar asn1ber = require('../lib/asn1ber');\n\ndescribe('asn1ber', function () {\n    describe"
  },
  {
    "path": "test/integration.js",
    "chars": 29545,
    "preview": "/*globals it:false, describe:false before:false after:false beforeEach:false\n */\n\nvar assert = require('assert');\nvar dg"
  },
  {
    "path": "test/snmp.js",
    "chars": 11826,
    "preview": "var assert = require('assert');\nvar snmp = require('../lib/snmp');\n\n// A packet as generated by this library, lightly mo"
  }
]

About this extraction

This page contains the full source code of the calmh/node-snmp-native GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (404.5 KB), approximately 122.8k tokens, and a symbol index with 25 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!