telehash-tcp4
Version:
Transport bindings for telehash to tcp4
142 lines (127 loc) • 3.85 kB
JavaScript
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);
});
}