lib/server.js
function Server(options) {
  if (options) {
    if (typeof (options) !== 'object')
      throw new TypeError('options (object) required');
    if (typeof (options.log) !== 'object')
      throw new TypeError('options.log must be an object');

    if (options.certificate || options.key) {
      if (!(options.certificate && options.key) ||
          (typeof (options.certificate) !== 'string' &&
          !Buffer.isBuffer(options.certificate)) ||
          (typeof (options.key) !== 'string' &&
          !Buffer.isBuffer(options.key))) {
        throw new TypeError('options.certificate and options.key ' +
                            '(string or buffer) are both required for TLS');
      }
    }
  } else {
    options = {};
  }
  var self = this;

  EventEmitter.call(this, options);

  this._chain = [];
  this.log = options.log;
  this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true;

  var log = this.log;

  function setupConnection(c) {
    assert.ok(c);

    if (c.type === 'unix') {
      c.remoteAddress = self.server.path;
      c.remotePort = c.fd;
    } else if (c.socket) {
      // TLS
      c.remoteAddress = c.socket.remoteAddress;
      c.remotePort = c.socket.remotePort;
    }


    var rdn = new dn.RDN({cn: 'anonymous'});

    c.ldap = {
      id: c.remoteAddress + ':' + c.remotePort,
      config: options,
      _bindDN: new DN([rdn])
    };
    c.addListener('timeout', function () {
      log.trace('%s timed out', c.ldap.id);
      c.destroy();
    });
    c.addListener('end', function () {
      log.trace('%s shutdown', c.ldap.id);
    });
    c.addListener('error', function (err) {
      log.warn('%s unexpected connection error', c.ldap.id, err);
      self.emit('clientError', err);
      c.destroy();
    });
    c.addListener('close', function (had_err) {
      log.trace('%s close; had_err=%j', c.ldap.id, had_err);
      c.end();
    });

    c.ldap.__defineGetter__('bindDN', function () {
      return c.ldap._bindDN;
    });
    c.ldap.__defineSetter__('bindDN', function (val) {
      if (!(val instanceof DN))
        throw new TypeError('DN required');

      c.ldap._bindDN = val;
      return val;
    });
    return c;
  }

  function newConnection(c) {
    setupConnection(c);
    log.trace('new connection from %s', c.ldap.id);

    dtrace.fire('server-connection', function () {
      return [c.remoteAddress];
    });

    c.parser = new Parser({
      log: options.log
    });
    c.parser.on('message', function (req) {
      req.connection = c;
      req.logId = c.ldap.id + '::' + req.messageID;
      req.startTime = new Date().getTime();

      if (log.debug())
        log.debug('%s: message received: req=%j', c.ldap.id, req.json);

      var res = getResponse(req);
      if (!res) {
        log.warn('Unimplemented server method: %s', req.type);
        c.destroy();
        return false;
      }

      // parse string DNs for routing/etc
      try {
        switch (req.protocolOp) {
        case Protocol.LDAP_REQ_BIND:
          req.name = dn.parse(req.name);
          break;
        case Protocol.LDAP_REQ_ADD:
        case Protocol.LDAP_REQ_COMPARE:
        case Protocol.LDAP_REQ_DELETE:
          req.entry = dn.parse(req.entry);
          break;
        case Protocol.LDAP_REQ_MODIFY:
          req.object = dn.parse(req.object);
          break;
        case Protocol.LDAP_REQ_MODRDN:
          req.entry = dn.parse(req.entry);
          // TODO: handle newRdn/Superior
          break;
        case Protocol.LDAP_REQ_SEARCH:
          req.baseObject = dn.parse(req.baseObject);
          break;
        default:
          break;
        }
      } catch (e) {
        if (self.strictDN) {
          return res.end(errors.LDAP_INVALID_DN_SYNTAX);
        }
      }

      res.connection = c;
      res.logId = req.logId;
      res.requestDN = req.dn;

      var chain = self._getHandlerChain(req, res);

      var i = 0;
      return function (err) {
        function sendError(err) {
          res.status = err.code || errors.LDAP_OPERATIONS_ERROR;
          res.matchedDN = req.suffix ? req.suffix.toString() : '';
          res.errorMessage = err.message || '';
          return res.end();
        }

        function after() {
          if (!self._postChain || !self._postChain.length)
            return;

          function next() {} // stub out next for the post chain

          self._postChain.forEach(function (c) {
            c.call(self, req, res, next);
          });
        }

        if (err) {
          log.trace('%s sending error: %s', req.logId, err.stack || err);
          self.emit('clientError', err);
          sendError(err);
          return after();
        }

        try {
          var next = arguments.callee;
          if (chain.handlers[i])
            return chain.handlers[i++].call(chain.backend, req, res, next);

          if (req.protocolOp === Protocol.LDAP_REQ_BIND && res.status === 0)
            c.ldap.bindDN = req.dn;

          return after();
        } catch (e) {
          if (!e.stack)
            e.stack = e.toString();
          log.error('%s uncaught exception: %s', req.logId, e.stack);
          return sendError(new errors.OperationsError(e.message));
        }

      }();
    });

    c.parser.on('error', function (err, message) {
      self.emit('error', new VError(err, 'Parser error for %s', c.ldap.id));

      if (!message)
        return c.destroy();

      var res = getResponse(message);
      if (!res)
        return c.destroy();

      res.status = 0x02; // protocol error
      res.errorMessage = err.toString();
      return c.end(res.toBer());
    });

    c.on('data', function (data) {
      if (log.trace())
        log.trace('data on %s: %s', c.ldap.id, util.inspect(data));

      c.parser.write(data);
    });

  } // end newConnection

  this.routes = {};
  if ((options.cert || options.certificate) && options.key) {
    options.cert = options.cert || options.certificate;
    this.server = tls.createServer(options, newConnection);
  } else {
    this.server = net.createServer(newConnection);
  }
  this.server.log = options.log;
  this.server.ldap = {
    config: options
  };
  this.server.on('close', function () {
    self.emit('close');
  });
  this.server.on('error', function (err) {
    self.emit('error', err);
  });
}
function Server(options) {
  if (options) {
    if (typeof (options) !== 'object')
      throw new TypeError('options (object) required');
    if (typeof (options.log) !== 'object')
      throw new TypeError('options.log must be an object');

    if (options.certificate || options.key) {
      if (!(options.certificate && options.key) ||
          (typeof (options.certificate) !== 'string' &&
          !Buffer.isBuffer(options.certificate)) ||
          (typeof (options.key) !== 'string' &&
          !Buffer.isBuffer(options.key))) {
        throw new TypeError('options.certificate and options.key ' +
                            '(string or buffer) are both required for TLS');
      }
    }
  } else {
    options = {};
  }
  var self = this;

  EventEmitter.call(this, options);

  this._chain = [];
  this.log = options.log;
  this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true;

  var log = this.log;

  function setupConnection(c) {
    assert.ok(c);

    if (c.type === 'unix') {
      c.remoteAddress = self.server.path;
      c.remotePort = c.fd;
    } else if (c.socket) {
      // TLS
      c.remoteAddress = c.socket.remoteAddress;
      c.remotePort = c.socket.remotePort;
    }


    var rdn = new dn.RDN({cn: 'anonymous'});

    c.ldap = {
      id: c.remoteAddress + ':' + c.remotePort,
      config: options,
      _bindDN: new DN([rdn])
    };
    c.addListener('timeout', function () {
      log.trace('%s timed out', c.ldap.id);
      c.destroy();
    });
    c.addListener('end', function () {
      log.trace('%s shutdown', c.ldap.id);
    });
    c.addListener('error', function (err) {
      log.warn('%s unexpected connection error', c.ldap.id, err);
      self.emit('clientError', err);
      c.destroy();
    });
    c.addListener('close', function (had_err) {
      log.trace('%s close; had_err=%j', c.ldap.id, had_err);
      c.end();
    });

    c.ldap.__defineGetter__('bindDN', function () {
      return c.ldap._bindDN;
    });
    c.ldap.__defineSetter__('bindDN', function (val) {
      if (!(val instanceof DN))
        throw new TypeError('DN required');

      c.ldap._bindDN = val;
      return val;
    });
    return c;
  }

  function newConnection(c) {
    setupConnection(c);
    log.trace('new connection from %s', c.ldap.id);

    dtrace.fire('server-connection', function () {
      return [c.remoteAddress];
    });

    c.parser = new Parser({
      log: options.log
    });
    c.parser.on('message', function (req) {
      req.connection = c;
      req.logId = c.ldap.id + '::' + req.messageID;
      req.startTime = new Date().getTime();

      if (log.debug())
        log.debug('%s: message received: req=%j', c.ldap.id, req.json);

      var res = getResponse(req);
      if (!res) {
        log.warn('Unimplemented server method: %s', req.type);
        c.destroy();
        return false;
      }

      // parse string DNs for routing/etc
      try {
        switch (req.protocolOp) {
        case Protocol.LDAP_REQ_BIND:
          req.name = dn.parse(req.name);
          break;
        case Protocol.LDAP_REQ_ADD:
        case Protocol.LDAP_REQ_COMPARE:
        case Protocol.LDAP_REQ_DELETE:
          req.entry = dn.parse(req.entry);
          break;
        case Protocol.LDAP_REQ_MODIFY:
          req.object = dn.parse(req.object);
          break;
        case Protocol.LDAP_REQ_MODRDN:
          req.entry = dn.parse(req.entry);
          // TODO: handle newRdn/Superior
          break;
        case Protocol.LDAP_REQ_SEARCH:
          req.baseObject = dn.parse(req.baseObject);
          break;
        default:
          break;
        }
      } catch (e) {
        if (self.strictDN) {
          return res.end(errors.LDAP_INVALID_DN_SYNTAX);
        }
      }

      res.connection = c;
      res.logId = req.logId;
      res.requestDN = req.dn;

      var chain = self._getHandlerChain(req, res);

      var i = 0;
      return function (err) {
        function sendError(err) {
          res.status = err.code || errors.LDAP_OPERATIONS_ERROR;
          res.matchedDN = req.suffix ? req.suffix.toString() : '';
          res.errorMessage = err.message || '';
          return res.end();
        }

        function after() {
          if (!self._postChain || !self._postChain.length)
            return;

          function next() {} // stub out next for the post chain

          self._postChain.forEach(function (c) {
            c.call(self, req, res, next);
          });
        }

        if (err) {
          log.trace('%s sending error: %s', req.logId, err.stack || err);
          self.emit('clientError', err);
          sendError(err);
          return after();
        }

        try {
          var next = arguments.callee;
          if (chain.handlers[i])
            return chain.handlers[i++].call(chain.backend, req, res, next);

          if (req.protocolOp === Protocol.LDAP_REQ_BIND && res.status === 0)
            c.ldap.bindDN = req.dn;

          return after();
        } catch (e) {
          if (!e.stack)
            e.stack = e.toString();
          log.error('%s uncaught exception: %s', req.logId, e.stack);
          return sendError(new errors.OperationsError(e.message));
        }

      }();
    });

    c.parser.on('error', function (err, message) {
      self.emit('error', new VError(err, 'Parser error for %s', c.ldap.id));

      if (!message)
        return c.destroy();

      var res = getResponse(message);
      if (!res)
        return c.destroy();

      res.status = 0x02; // protocol error
      res.errorMessage = err.toString();
      return c.end(res.toBer());
    });

    c.on('data', function (data) {
      if (log.trace())
        log.trace('data on %s: %s', c.ldap.id, util.inspect(data));

      c.parser.write(data);
    });

  } // end newConnection

  this.routes = {};
  if ((options.cert || options.certificate) && options.key) {
    options.cert = options.cert || options.certificate;
    this.server = tls.createServer(options, newConnection);
  } else {
    this.server = net.createServer(newConnection);
  }
  this.server.log = options.log;
  this.server.ldap = {
    config: options
  };
  this.server.on('close', function () {
    self.emit('close');
  });
  this.server.on('error', function (err) {
    self.emit('error', err);
  });
}
/--- API 
Constructs a new server that you can call .listen() on, in the various
forms node supports.  You need to first assign some handlers to the various
LDAP operations however.

The options object currently only takes a certificate/private key, and a
bunyan logger handle.

This object exposes the following events:
- 'error'
- 'close'

@param {Object} options (optional) parameterization object.
@throws {TypeError} on bad input.