[Pkg-javascript-commits] [ltx] 121/469: client: proper SRV support
Jonas Smedegaard
dr at jones.dk
Wed Aug 31 13:01:12 UTC 2016
This is an automated email from the git hooks/post-receive script.
js pushed a commit to branch master
in repository ltx.
commit 9a41d543eb7e1700154eafc1e472a199c9089405
Author: Astro <astro at spaceboyz.net>
Date: Thu Sep 9 03:45:54 2010 +0200
client: proper SRV support
---
lib/xmpp/client.js | 45 +++++++---------
lib/xmpp/srv.js | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 169 insertions(+), 27 deletions(-)
diff --git a/lib/xmpp/client.js b/lib/xmpp/client.js
index 0479ebe..9b695a3 100644
--- a/lib/xmpp/client.js
+++ b/lib/xmpp/client.js
@@ -3,8 +3,8 @@ var JID = require('./jid').JID;
var xml = require('./xml');
var sasl = require('./sasl');
var sys = require('sys');
-var dns = require('dns');
var Buffer = require('buffer').Buffer;
+var SRV = require('./srv');
var NS_CLIENT = 'jabber:client';
var NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl';
@@ -39,39 +39,29 @@ function Client(params) {
this.xmppVersion = "1.0";
this.streamTo = this.jid.domain;
this.state = STATE_PREAUTH;
- // Immediately start stream
- this.addListener('connect', this.startStream);
this.addListener('rawStanza', this.onRawStanza);
if (params.host) {
this.connect(params.port || 5222, params.host);
} else {
var self = this;
- // TODO: improve SRV lookups
- dns.resolveSrv('_xmpp-client._tcp.' + this.jid.domain,
- function(err, addrs) {
- if (err) {
- /* no SRV record, try domain as A */
- self.connect(params.port || 5222, self.jid.domain);
- } else {
- addrs = addrs.sort(
- function(a, b) {
- if (a.priority < b.priority)
- return -1;
- else if (a.priority > b.priority)
- return 1;
- else
- return 0;
- });
- /* Epic design fail: we cannot retry
- with another SRV result because that
- will confuse the user with
- non-terminal 'error' & 'end' events.
- */
- self.connect(addrs[0].port, addrs[0].name);
- }
- });
+ var attempt = SRV.connect(this.socket,
+ ['_xmpp-client._tcp'], this.jid.domain, 5222);
+ attempt.addListener('connect', function() {
+ self.startStream();
+ });
+ attempt.addListener('error', function(e) {
+ self.emit('error', e);
+ });
}
+
+ // it's us who must restart after starttls
+ this.socket.addListener('secure', function() {
+ self.startStream();
+ });
+ this.socket.addListener('end', function() {
+ self.state = STATE_PREAUTH;
+ });
}
sys.inherits(Client, Connection.Connection);
@@ -86,6 +76,7 @@ Client.prototype.startStream = function() {
if (this.xmppVersion)
tag += " version='" + this.xmppVersion + "'";
tag += ">";
+console.log(tag);
this.send(tag);
};
diff --git a/lib/xmpp/srv.js b/lib/xmpp/srv.js
new file mode 100644
index 0000000..623df0c
--- /dev/null
+++ b/lib/xmpp/srv.js
@@ -0,0 +1,151 @@
+var dns = require('dns');
+var EventEmitter = require('events').EventEmitter;
+
+function compareNumbers(a, b) {
+ a = parseInt(a, 10);
+ b = parseInt(b, 10);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+}
+
+function groupSrvRecords(addrs) {
+ var groups = {}; // by priority
+ addrs.forEach(function(addr) {
+ if (!groups.hasOwnProperty(addr.priority))
+ groups[addr.priority] = [];
+
+ groups[addr.priority].push(addr);
+ });
+
+ var result = [];
+ Object.keys(groups).sort(compareNumbers).forEach(function(priority) {
+ var group = groups[priority];
+ var totalWeight = 0;
+ group.forEach(function(addr) {
+ totalWeight += addr.weight;
+ });
+ var w = Math.floor(Math.random() * totalWeight);
+ totalWeight = 0;
+ var candidate = group[0];
+ group.forEach(function(addr) {
+ totalWeight += addr.weight;
+ if (w < totalWeight)
+ candidate = addr;
+ });
+ if (candidate)
+ result.push(candidate);
+ });
+ return result;
+}
+
+function resolveSrv(name, cb) {
+ dns.resolveSrv(name, function(err, addrs) {
+console.log({resolveSrv:[name,err,addrs]});
+ if (err) {
+ /* no SRV record, try domain as A */
+ cb(err);
+ } else {
+ var pending = 0, error, results = [];
+ var cb1 = function(e, addrs1) {
+ error = error || e;
+ results = results.concat(addrs1);
+ pending--;
+ console.log({results:results,error:error,pending:pending});
+ if (pending < 1) {
+ cb(results ? null : error, results);
+ }
+ };
+ groupSrvRecords(addrs).forEach(function(addr) {
+ resolveHost(addr.name, function(e, a) {
+ if (a)
+ a = a.map(function(a1) {
+ return { name: a1,
+ port: addr.port };
+ });
+ cb1(e, a);
+ });
+ pending++;
+ });
+ }
+ });
+}
+
+// one of both A & AAAA, in case of broken tunnels
+function resolveHost(name, cb) {
+ var error, results = [], pending = 2;
+ var cb1 = function(e, addrs) {
+console.log({resolveHost:[name,e,addrs]});
+ error = error || e;
+ var addr = addrs && addrs[Math.floor(Math.random() * addrs.length)];
+ if (addr)
+ results.push(addr);
+
+ pending--;
+ if (pending < 1)
+ cb(results ? null : error, results);
+ };
+
+ dns.resolve4(name, cb1);
+ dns.resolve6(name, cb1);
+}
+
+// connection attempts to multiple addresses in a row
+function tryConnect(socket, addrs, listener) {
+console.log({tryConnect:addrs});
+ var onConnect = function() {
+ socket.removeListener('connect', onConnect);
+ socket.removeListener('error', onError);
+ // done!
+ listener.emit('connect');
+ };
+ var error;
+ var onError = function(e) {
+ error = e;
+ connectNext();
+ };
+ var connectNext = function() {
+ var addr = addrs.shift();
+ if (addr)
+ socket.connect(addr.port, addr.name);
+ else
+ listener.emit('error', error);
+ };
+ socket.addListener('connect', onConnect);
+ socket.addListener('error', onError);
+ connectNext();
+}
+
+// returns EventEmitter with 'connect' & 'error'
+exports.connect = function(socket, services, domain, defaultPort) {
+ var listener = new EventEmitter();
+
+ var tryServices = function() {
+ var service = services.shift();
+ if (service) {
+ resolveSrv(service + '.' + domain, function(error, addrs) {
+ if (addrs)
+ tryConnect(socket, addrs, listener);
+ else
+ tryServices();
+ });
+ } else {
+ resolveHost(domain, function(error, addrs) {
+ if (addrs) {
+ addrs = addrs.map(function(addr) {
+ return { name: addr,
+ port: defaultPort };
+ });
+ tryConnect(socket, addrs, listener);
+ } else
+ listener('error', error);
+ });
+ }
+
+ };
+ tryServices();
+
+ return listener;
+};
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/ltx.git
More information about the Pkg-javascript-commits
mailing list