blinksocks/lib/presets/_mux.js
2019-02-13 13:18:48 +08:00

190 lines
4.0 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defs = require("./defs");
var _utils = require("../utils");
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
const CMD_NEW_CONN = 0x00;
const CMD_DATA_FRAME = 0x01;
const CMD_CLOSE_CONN = 0x02;
class MuxPreset extends _defs.IPresetAddressing {
constructor(...args) {
super(...args);
_defineProperty(this, "_adBuf", null);
}
onInit() {
this._adBuf = new _utils.AdvancedBuffer({
getPacketLength: this.onReceiving.bind(this)
});
this._adBuf.on('data', this.onChunkReceived.bind(this));
}
onDestroy() {
this._adBuf.clear();
this._adBuf = null;
}
onReceiving(buffer, {
fail
}) {
if (buffer.length < 5) {
return;
}
const cmd = buffer[0];
switch (cmd) {
case CMD_NEW_CONN:
if (buffer.length < 8 + buffer[5]) {
return;
}
return 8 + buffer[5];
case CMD_DATA_FRAME:
if (buffer.length < 7) {
return;
}
return 7 + buffer.readUInt16BE(5);
case CMD_CLOSE_CONN:
return 5;
default:
fail(`unknown cmd=${cmd} dump=${(0, _utils.dumpHex)(buffer)}`);
return -1;
}
}
onChunkReceived(chunk, {
fail
}) {
const cmd = chunk[0];
const cid = chunk.slice(1, 5).toString('hex');
switch (cmd) {
case CMD_NEW_CONN:
{
const hostBuf = chunk.slice(6, -2);
const host = hostBuf.toString();
const port = chunk.readUInt16BE(6 + chunk[5]);
if (!(0, _utils.isValidHostname)(host) || !(0, _utils.isValidPort)(port)) {
return fail(`invalid host or port, host=${(0, _utils.dumpHex)(hostBuf)} port=${port}`);
}
return this.muxNewConn({
cid,
host,
port
});
}
case CMD_DATA_FRAME:
{
const dataLen = chunk.readUInt16BE(5);
return this.muxDataFrame({
cid,
data: chunk.slice(-dataLen)
});
}
case CMD_CLOSE_CONN:
return this.muxCloseConn({
cid
});
}
}
createDataFrames(cid, data) {
const chunks = (0, _utils.getRandomChunks)(data, 0x0800, 0x3fff).map(chunk => Buffer.concat([(0, _utils.numberToBuffer)(CMD_DATA_FRAME, 1), cid, (0, _utils.numberToBuffer)(chunk.length), chunk]));
return Buffer.concat(chunks);
}
createNewConn(host, port, cid) {
const _host = Buffer.from(host);
const _port = (0, _utils.numberToBuffer)(port);
return Buffer.concat([(0, _utils.numberToBuffer)(CMD_NEW_CONN, 1), cid, (0, _utils.numberToBuffer)(_host.length, 1), _host, _port]);
}
createCloseConn(cid) {
return Buffer.concat([(0, _utils.numberToBuffer)(CMD_CLOSE_CONN, 1), cid]);
}
clientOut({
buffer,
fail
}, {
host,
port,
cid,
isClosing
}) {
if (cid !== undefined) {
const _cid = Buffer.from(cid, 'hex');
if (isClosing) {
return this.createCloseConn(_cid);
}
const dataFrames = this.createDataFrames(_cid, buffer);
if (host && port) {
return Buffer.concat([this.createNewConn(host, port, _cid), dataFrames]);
}
return dataFrames;
} else {
fail(`cid is not provided, drop buffer=${(0, _utils.dumpHex)(buffer)}`);
}
}
serverOut({
buffer,
fail
}, {
cid,
isClosing
}) {
if (cid !== undefined) {
const _cid = Buffer.from(cid, 'hex');
if (isClosing) {
return this.createCloseConn(_cid);
}
return this.createDataFrames(_cid, buffer);
} else {
fail(`cid is not provided, drop buffer=${(0, _utils.dumpHex)(buffer)}`);
}
}
beforeIn({
buffer,
fail
}) {
this._adBuf.put(buffer, {
fail
});
}
}
exports.default = MuxPreset;
_defineProperty(MuxPreset, "isPrivate", true);