UNPKG

telehash-tcp4

Version:

Transport bindings for telehash to tcp4

142 lines (127 loc) 3.85 kB
var net = require('net'); var os = require('os'); var lob = require('lob-enc'); var upnp = require('nat-upnp'); var pmp = require('pmp'); exports.name = 'tcp4'; exports.port = 0; exports.ip = '0.0.0.0'; exports.keepalive = 30000 // add our transport to this new mesh exports.mesh = function(mesh, cbExt) { var args = mesh.args || {}; var telehash = mesh.lib; var tp = { pipes: {} }; exports.Buffer = exports.Buffer || require("buffer").Buffer; // use config options or bind any/all args.tcp4 = args.tcp4 || {} // tcp server and accept tp.server = net.createServer(function connect(sock) { tp.pipe(false, { type: 'tcp4', ip: sock.remoteAddress, port: sock.remotePort }, function(pipe) { pipe.use(sock); }); }); tp.server.on('error', function(err) { mesh.log.error('tcp4 socket fatal error', err); console.log(err) }); // turn a path into a pipe tp.pipe = function(link, path, cbPipe) { if (typeof path != 'object' || path.type != 'tcp4') return false; if (typeof path.ip != 'string' || typeof path.port != 'number') return false; var id = [path.ip, path.port].join(':'); var pipe = tp.pipes[id]; if (pipe) return cbPipe(pipe); //console.log("new pipe with keepalive", exports.keepalive) pipe = new telehash.Pipe('tcp4', args.tcp4.keepalive || exports.keepalive); tp.pipes[id] = pipe; pipe.id = id; pipe.path = path; // util to add/use this socket pipe.use = function(sock) { //console.log("use sock") pipe.chunks = lob.chunking({}, function receive(err, packet) { if (err) { if (err == "HTTP detected" && mesh.public.url) { mesh.log.debug('tcp detected http and is redirecting', mesh.public.url); var head = [ 'HTTP/1.0 302 Found', 'Access-Control-Allow-Origin: *', 'Location: ' + mesh.public.url]; pipe.sock.end(head.join('\r\n') + '\r\n'); return; } mesh.log.error('pipe chunk read error', err, pipe.id); return; } if (packet) { if (!(packet instanceof exports.Buffer)) packet = new exports.Buffer(packet) mesh.receive(packet, pipe); } }); if (pipe.sock) pipe.sock.end(); // track this sock and 'pipe' it to/from our chunks pipe.sock = sock; sock.pipe(pipe.chunks); pipe.chunks.pipe(sock); sock.on('error', function(error) {}); // ignore errors, just handle end sock.on('end', function() { //console.log("SOCKET END") pipe.emit('down', pipe) delete pipe.sock; }) } pipe.onSend = function(packet, link, cb) { // must create a connecting socket if none //console.log("sock?", !!pipe.sock, path) path.host = path.ip; if (!pipe.sock || pipe.sock.destroyed) pipe.use(net.connect(path, function() { if (!(packet instanceof Buffer)) packet = new Buffer(packet); pipe.chunks.send(packet) cb() })); else { pipe.chunks.send(packet); cb(); } } cbPipe(pipe); }; // return our current addressible paths tp.paths = function() { var ifaces = os.networkInterfaces() var address = tp.server.address(); var local = '127.0.0.1'; var best = mesh.public.ipv4; // prefer that if any set for (var dev in ifaces) { ifaces[dev].forEach(function(details) { if (details.family != 'IPv4') return; if (details.internal) { local = details.address; return; } if (!best) best = details.address; }); } best = tp.nat || best || local; return [{ type: 'tcp4', ip: best, port: address.port }]; }; tp.server.listen(args.tcp4.port ? args.tcp4.port : exports.port, args.ip || exports.ip, function(err) { if (err) mesh.log.error('tcp4 listen error', err); // TODO start pmp and upnp w/ our port cbExt(undefined, tp); }); }