[Pkg-javascript-commits] [ltx] 63/469: new experimental s2s & router code
Jonas Smedegaard
dr at jones.dk
Wed Aug 31 13:01:01 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 6167033750ecb8c13d2724438ca4ece597b687eb
Author: Astro <astro at spaceboyz.net>
Date: Sat Sep 4 19:47:32 2010 +0200
new experimental s2s & router code
---
lib/xmpp.js | 2 +
lib/xmpp/router.js | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/xmpp/server.js | 156 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 331 insertions(+)
diff --git a/lib/xmpp.js b/lib/xmpp.js
index e74b311..d63fc36 100644
--- a/lib/xmpp.js
+++ b/lib/xmpp.js
@@ -2,9 +2,11 @@ var Client = require('./xmpp/client').Client;
var Component = require('./xmpp/component').Component;
var JID = require('./xmpp/jid').JID;
var XML = require('./xmpp/xml');
+var Router = require('./xmpp/router');
exports.Client = Client;
exports.Component = Component;
exports.JID = JID;
exports.XML = XML;
exports.Element = XML.Element;
+exports.Router = Router.Router;
diff --git a/lib/xmpp/router.js b/lib/xmpp/router.js
new file mode 100644
index 0000000..d7d5d11
--- /dev/null
+++ b/lib/xmpp/router.js
@@ -0,0 +1,173 @@
+var net = require('net');
+var Server = require('./server');
+var JID = require('./jid');
+
+
+dbgStream = function(tag, stream) {
+ stream.on('data', function(data) {
+ console.log(tag + ' in: ' + data);
+ });
+ stream.on('error', function(e) {
+ console.log(tag + ' error: ' + e.stack);
+ });
+ stream.on('close', function() {
+ console.log(tag + ' close');
+ });
+ var oldSend = stream.send;
+ stream.send = function(data) {
+ console.log(tag + ' out: ' + data);
+ oldSend.call(stream, data);
+ };
+};
+
+function DomainContext(domain) {
+ this.domain = domain;
+ this.s2sIn = {};
+ this.s2sOut = {};
+}
+
+DomainContext.prototype.getOut = function(domain) {
+ var self = this;
+
+ if (this.s2sOut.hasOwnProperty(domain)) {
+ return this.s2sOut[domain];
+ } else {
+ var outStream = this.s2sOut[domain] =
+ Server.makeOutgoingServer(domain);
+ outStream.dbKey = generateKey();
+ outStream.addListener('online', function() {
+ outStream.dialbackKey(self.domain, domain, outStream.dbKey);
+ });
+ outStream.addListener('dialbackResult', function(from, to, isValid) {
+ console.log({outDialbackResult:arguments});
+ if (isValid) {
+ outStream.isValid = true;
+ console.log({outStreamQueue:outStream.queue});
+ if (outStream.queue) {
+ outStream.queue.forEach(function(stanza) {
+ outStream.send(stanza);
+ });
+ delete outStream.queue;
+ }
+ } else {
+ outStream.emit('error', new Error('Dialback failure'));
+ }
+ });
+ outStream.addListener('error', function() {
+ // TODO: purge queue
+ delete self.s2sOut[domain];
+ });
+
+ dbgStream('outgoing', outStream);
+ return outStream;
+ }
+};
+
+DomainContext.prototype.send = function(stanza) {
+ var self = this;
+ // TODO: return on empty to
+ var domain = (new JID.JID(stanza.attrs.to)).domain;
+
+ var outStream = this.getOut(domain);
+ if (outStream.isValid)
+ outStream.send(stanza);
+ else {
+ outStream.queue = outStream.queue || [];
+ outStream.queue.push(stanza);
+ }
+};
+
+DomainContext.prototype.verifyDialback = function(domain, id, key) {
+ var outStream;
+ if (this.s2sOut.hasOwnProperty(domain) &&
+ (outStream = this.s2sOut[domain])) {
+
+ var isValid = outStream.streamAttrs.id === id &&
+ outStream.dbKey === key;
+
+ outStream.dialbackResult(this.domain, domain, isValid);
+ return isValid;
+ } else
+ return false;
+};
+
+function Router(s2sPort) {
+ var self = this;
+ this.ctxs = {};
+
+ net.createServer(function(stream) {
+ dbgStream('incoming', stream);
+ var domain;
+ stream.verifyDialback = function(from, to, id, key) {
+ domain = from;
+ return self.verifyDialback(from, to, id, key);
+ };
+ Server.makeIncomingServer(stream);
+ stream.addListener('dialbackVerify', function(from, to, id, key) {
+ isValid = self.verifyDialback(from, to, id, key);
+ stream.dialbackVerified(to, from, id, isValid);
+ });
+ stream.addListener('dialbackKey', function(from, to, key) {
+ var outStream = self.getContext(to).getOut(from);
+ var sendVerify = function() {
+ outStream.dialbackVerify(to, from, stream.streamId, key);
+
+ var onVerified;
+ onVerified = function(from, to, id, isValid) {
+ stream.dialbackResult(to, from, isValid);
+
+ outStream.removeListener('dialbackVerified', onVerified);
+ };
+ outStream.addListener('dialbackVerified', onVerified);
+ };
+ if (outStream.writable)
+ sendVerify();
+ else {
+ var connectHook;
+ var connectHook = function() {
+ sendVerify();
+ outStream.removeListener('connect', step);
+ };
+ outStream.addListener('connect', connectHook);
+ }
+ });
+ }).listen(s2sPort || 5269);
+}
+exports.Router = Router;
+
+Router.prototype.send = function(stanza) {
+ if (stanza.root)
+ stanza = stanza.root();
+
+ console.log({send:stanza});
+ if (stanza.attrs && stanza.attrs.from) {
+ var domain = (new JID.JID(stanza.attrs.from)).domain;
+ this.getContext(domain).send(stanza);
+ } else
+ throw 'Sending stanza without destination';
+};
+
+Router.prototype.hasContext = function(domain) {
+ return this.ctxs.hasOwnProperty(domain);
+};
+
+Router.prototype.getContext = function(domain) {
+ if (this.ctxs.hasOwnProperty(domain))
+ return this.ctxs[domain];
+ else
+ return (this.ctxs[domain] = new DomainContext(domain));
+};
+
+Router.prototype.verifyDialback = function(from, to, id, key) {
+ return this.hasContext(to) &&
+ this.getContext(to).verifyDialback(from, id, key);
+};
+
+
+function generateKey() {
+ var r = new Buffer(16);
+ for(var i = 0; i < r.length; i++) {
+ r[i] = 48 + Math.floor(Math.random() * 10); // '0'..'9'
+ }
+ return r.toString();
+}
diff --git a/lib/xmpp/server.js b/lib/xmpp/server.js
new file mode 100644
index 0000000..b2582ae
--- /dev/null
+++ b/lib/xmpp/server.js
@@ -0,0 +1,156 @@
+var dns = require('dns');
+var Connection = require('./connection');
+var xml = require('./xml');
+
+var NS_SERVER = 'jabber:server';
+var NS_DIALBACK = 'jabber:server:dialback';
+
+/**
+ * Dialback-specific events:
+ * (1) dialbackKey(from, to, key)
+ * (2) dialbackVerify(from, to, id, key)
+ * (3) dialbackVerified(from, to, id, isValid)
+ * (4) dialbackResult(from, to, isValid)
+ */
+function initServer(self) {
+ self.xmlns = NS_SERVER;
+ self.xmppVersion = '1.0';
+
+ self.addListener('rawStanza', function(stanza) {
+ var key = stanza.getText();
+
+ if (stanza.is('result', NS_DIALBACK) &&
+ stanza.attrs.from && stanza.attrs.to &&
+ key.length > 0) {
+
+ self.emit('dialbackKey',
+ stanza.attrs.from, stanza.attrs.to,
+ key);
+
+ } else if (stanza.is('verify', NS_DIALBACK) &&
+ stanza.attrs.from && stanza.attrs.to &&
+ stanza.attrs.id && key.length > 0) {
+
+ self.emit('dialbackVerify',
+ stanza.attrs.from, stanza.attrs.to,
+ stanza.attrs.id, key);
+
+ } else if (stanza.is('verify', NS_DIALBACK) &&
+ stanza.attrs.from && stanza.attrs.to &&
+ stanza.attrs.id && stanza.attrs.type) {
+
+ self.emit('dialbackVerified',
+ stanza.attrs.from, stanza.attrs.to,
+ stanza.attrs.id, stanza.attrs.type == 'valid');
+
+ } else if (stanza.is('result', NS_DIALBACK) &&
+ stanza.attrs.from && stanza.attrs.to &&
+ stanza.attrs.type) {
+
+ self.emit('dialbackResult',
+ stanza.attrs.from, stanza.attrs.to,
+ stanza.attrs.type == 'valid');
+ } else
+ self.emit('stanza', stanza);
+ });
+
+ self.dialbackKey = function(from, to, key) {
+ self.send(new xml.Element('db:result', { to: to,
+ from: from }).
+ t(key)
+ );
+ };
+ self.dialbackVerify = function(from, to, id, key) {
+ self.send(new xml.Element('db:verify', { to: to,
+ from: from,
+ id: id }).
+ t(key)
+ );
+ };
+ self.dialbackVerified = function(from, to, id, isValid) {
+ self.send(new xml.Element('db:verify', { to: to,
+ from: from,
+ id: id,
+ type: isValid ? 'valid' : 'invalid' })
+ );
+ };
+ self.dialbackResult = function(from, to, isValid) {
+ self.send(new xml.Element('db:result', { to: to,
+ from: from,
+ type: isValid ? 'valid' : 'invalid' })
+ );
+ };
+}
+
+exports.makeIncomingServer = function(self) {
+ Connection.makeConnection(self);
+
+ initServer(self);
+ self.startStream();
+ self.streamId = generateId();
+
+ self.addListener('streamStart', function(streamAttrs) {
+ var tag = "<stream:stream xmlns='" + self.xmlns +
+ "' xmlns:stream='" + Connection.NS_STREAM +
+ "' xmlns:db='" + NS_DIALBACK +
+ "' id='" + self.streamId + "'";
+ if (self.xmppVersion)
+ tag += " version='" + self.xmppVersion + "'";
+ tag += "><stream:features/>";
+ self.send(tag);
+ });
+
+ return self;
+};
+
+function dnsLookup(domain, cb) {
+ dns.resolveSrv('_xmpp-server._tcp.' + domain, function(error, data) {
+ if (data[0])
+ cb(data[0].name, data[0].port);
+ else
+ dns.resolveSrv('_jabber._tcp.' + domain, function(error, data) {
+ if (data[0])
+ cb(data[0].name, data[0].port);
+ else
+ cb(domain, 5269);
+ });
+ });
+}
+
+exports.makeOutgoingServer = function(domain) {
+ var self = new Connection.Connection();
+ initServer(self);
+ self.startStream = function() {
+ Connection.Connection.prototype.startStream.call(self);
+
+ var tag = "<stream:stream xmlns='" + self.xmlns +
+ "' xmlns:stream='" + Connection.NS_STREAM +
+ "' xmlns:db='" + NS_DIALBACK +
+ "' to='" + domain + "'";
+ if (self.xmppVersion)
+ tag += " version='" + self.xmppVersion + "'";
+ tag += ">";
+ self.send(tag);
+ };
+
+ dnsLookup(domain, function(host, port) {
+ self.connect(port, host);
+ self.addListener('connect', self.startStream);
+ });
+
+ self.addListener('rawStanza', function(stanza) {
+ if (stanza.is('features', Connection.NS_STREAM)) {
+ self.emit('online');
+ }
+ });
+
+ return self;
+};
+
+function generateId() {
+ var r = new Buffer(16);
+ for(var i = 0; i < r.length; i++) {
+ r[i] = 48 + Math.floor(Math.random() * 10); // '0'..'9'
+ }
+ return r.toString();
+};
--
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