diff --git a/lib/client.js b/lib/client.js index 9b4273c..68ba548 100644 --- a/lib/client.js +++ b/lib/client.js @@ -31,6 +31,7 @@ var ModifyRequest = messages.ModifyRequest; var ModifyDNRequest = messages.ModifyDNRequest; var SearchRequest = messages.SearchRequest; var UnbindRequest = messages.UnbindRequest; +var UnbindResponse = messages.UnbindResponse; var LDAPResult = messages.LDAPResult; var SearchEntry = messages.SearchEntry; @@ -138,14 +139,31 @@ function Client(options) { return self._log; }); - this.connection = this._newConnection(); this.reconnect = (typeof(options.reconnect) === 'number' ? options.reconnect : 1000); + + this.connect(); } util.inherits(Client, EventEmitter); module.exports = Client; +/** + * Connects this client, either at construct time, or after an unbind has + * been called. Under normal circumstances you don't need to call this method. + * + */ +Client.prototype.connect = function() { + if (this.connection) + return; + + var self = this; + this.connection = this._newConnection(); + this.connection.on('end', function() { + delete self.connection; + }); +}; + /** * Performs a simple authentication against the server. * @@ -675,6 +693,7 @@ Client.prototype._send = function(message, expect, callback, connection) { }; } else if (expect === 'unbind') { _writeCb = function() { + conn.unbindMessageID = message.id; conn.end(); }; } else { @@ -746,21 +765,35 @@ Client.prototype._newConnection = function() { log.trace('%s close event had_err=%s', c.ldap.id, had_err ? 'yes' : 'no'); Object.keys(c.ldap.messages).forEach(function(msgid) { - if (typeof(c.ldap.messages[msgid]) === 'function') { - var _cb = c.ldap.messages[msgid]; - delete c.ldap.messages[msgid]; - return _cb(new ConnectionError(c.ldap.id + ' closed')); - } else if (c.ldap.messages[msgid]) { - c.ldap.messages[msgid].emit('error', new ConnectionError(c.ldap.id + - ' closed')); + var err; + if (c.unbindMessageID !== parseInt(msgid, 10)) { + err = new ConnectionError(c.ldap.id + ' closed'); + } else { + err = new UnbindResponse({ + messageID: msgid, + }); + err.status = 'unbind'; + } + + if (typeof(c.ldap.messages[msgid]) === 'function') { + var callback = c.ldap.messages[msgid]; + delete c.ldap.messages[msgid]; + return callback(err); + } else if (c.ldap.messages[msgid]) { + if (err instanceof Error) + c.ldap.messages[msgid].emit('error', err); + delete c.ldap.messages[msgid]; } - delete c.ldap.messages[msgid]; }); + delete c.ldap; if (self.reconnect) { self.connection = null; - setTimeout(function() { self._newConnection() }, self.reconnect); + setTimeout(function() { + delete c.unbindMessageID; + self._newConnection(); + }, self.reconnect); } }); diff --git a/tst/client.test.js b/tst/client.test.js index c1de299..38ee284 100644 --- a/tst/client.test.js +++ b/tst/client.test.js @@ -549,8 +549,19 @@ test('abandon (GH-27)', function(t) { }); +test('unbind and reconnect (GH-30)', function(t) { + client.unbind(function(err) { + t.ifError(err); + client.once('connect', function() { + t.end(); + }); + client.connect(); + }); +}); + test('shutdown', function(t) { - client.unbind(function() { + client.unbind(function(err) { + t.ifError(err); server.on('close', function() { t.end(); });