@ntrip/caster
Version:
NTRIP caster
132 lines (131 loc) • 5.07 kB
JavaScript
;
/*
* This file is part of the @ntrip/caster distribution (https://github.com/node-ntrip/caster).
* Copyright (c) 2020 Nebojsa Cvetkovic.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SocketTransport = void 0;
const net = require("net");
const tls = require("tls");
const transport_1 = require("../transport");
const tls_1 = require("tls");
const verror_1 = __importDefault(require("verror"));
class SocketTransport extends transport_1.Transport {
constructor(manager, options) {
super(manager, options);
this.options = options;
}
static new(options) {
return (caster) => new SocketTransport(caster, options);
}
open() {
this.server = (this.options.tls === undefined ? net.createServer() : tls.createServer(this.options.tls));
this.server.on('connection', (socket) => this.accept(socket));
new Promise((resolve, reject) => {
this.server.once('listening', resolve);
this.server.once('error', reject);
}).then(() => this.emit('open'))
.catch((err) => this.emit('error', err));
this.server.listen(this.options.port);
}
close() {
this.server.close(() => this.emit('close'));
}
static matchHost(host, mask) {
const sections = mask.split('*');
let text = host;
for (let section of sections) {
const index = text.indexOf(section);
if (index < 0)
return false;
text = text.slice(index + section.length);
}
return true;
}
findMatchingSourceHost(socket) {
return this.options.sourceHosts.find(sourceHost => SocketTransport.matchHost(socket.remoteAddress, sourceHost.hostMask)
&& (sourceHost.port === undefined || sourceHost.port === socket.remotePort));
}
async accept(socket) {
socket.on('error', err => {
this.emit('clientError', new verror_1.default({
name: 'ClientError',
cause: err,
info: {
remote: {
address: socket.remoteAddress,
port: socket.remotePort,
family: socket.remoteFamily
}
}
}, "Socket server client error"));
});
let sourceHost = this.findMatchingSourceHost(socket);
if (sourceHost === undefined)
return socket.destroy();
let authResponse;
if (sourceHost.authenticate) {
const authRequest = {
type: sourceHost.type,
mountpoint: sourceHost.mountpoint,
host: socket.localAddress,
source: {
host: socket.remoteAddress,
port: socket.remotePort,
family: socket.remoteFamily
},
credentials: {
anonymous: !(socket instanceof tls_1.TLSSocket),
certificate: socket instanceof tls_1.TLSSocket ? socket.getPeerCertificate().fingerprint : undefined
}
};
authResponse = await this.caster.authenticate(authRequest);
}
const source = {
protocol: socket instanceof tls_1.TLSSocket ? 'tls' : 'tcp',
remote: {
host: socket.remoteAddress,
port: socket.remotePort,
family: socket.remoteFamily
},
toString: () => this.connectionDescription(source)
};
try {
this.connect({
type: sourceHost.type,
source: source,
mountpoint: sourceHost.mountpoint,
gga: sourceHost.gga,
str: sourceHost.str,
stream: socket,
auth: authResponse
});
}
catch (err) {
socket.destroy(err);
}
}
get description() {
return `${this.options.tls === undefined ? 'tcp' : 'tls'}[port=${this.options.port}]`;
}
connectionDescription(source) {
return `${source.protocol}://${source.remote.host}:${source.remote.port}`;
}
}
exports.SocketTransport = SocketTransport;