constructors for the data types, allow multiple TLVs

This commit is contained in:
Artem Titoulenko 2021-09-07 18:17:26 -04:00
parent 935d97614c
commit b6ef343ead

View file

@ -19,32 +19,89 @@ function logDataStream(data){
return strs.map((str) => chunkString(str, 2).join(' ')).join('\n');
}
function TLV(buf) {
this.type = buf.slice(0, 2);
this.len = buf.slice(2, 4).readInt16BE(0)
this.payload = buf.slice(4, 4 + this.len);
this.toString = () => `TLV(${this.type.toString('hex')}, ${this.len}, ${this.payload.toString('ascii')})`;
class TLV {
static fromBuffer(buf) {
const type = buf.slice(0, 2).readInt16BE(0);
const len = buf.slice(2, 4).readInt16BE(0)
const payload = buf.slice(4, 4 + len);
return new TLV(type, payload);
}
constructor(type, payload) {
this.type = type;
this.len = payload.length;
this.payload = payload;
}
toString() {
return `TLV(${this.type}, ${this.len}, ${this.payload.toString('ascii')})`;
}
}
function SNAC(buf) {
this.family = buf.slice(0,2).readInt16BE(0);
this.service = buf.slice(2,4).readInt16BE(0);
this.flags = buf.slice(4, 6);
this.requestID = buf.slice(6, 10).readInt32BE(0);
this.payload = new TLV(buf.slice(10));
this.toString = () => `SNAC(${this.family.toString(16)},${this.service.toString(16)}) #${this.requestID}\n ${this.payload}`;
class SNAC {
static fromBuffer(buf, payloadLength = 0) {
const family = buf.slice(0,2).readInt16BE(0);
const service = buf.slice(2,4).readInt16BE(0);
const flags = buf.slice(4, 6);
const requestID = buf.slice(6, 10).readInt32BE(0);
const payload = []; // SNACs can have multiple TLVs
let payloadIdx = 10;
let cb = 0, cbLimit = 10; //circuit breaker
while (payloadIdx < payloadLength && cb < cbLimit) {
const tlv = TLV.fromBuffer(buf.slice(payloadIdx));
payload.push(tlv);
payloadIdx += tlv.len + 4; // 4 bytes for TLV type + payload length
cb++;
}
if (cb === cbLimit) {
console.error('Application error, cb limit reached');
process.exit(1);
}
return new SNAC(family, service, flags, requestID, payload);
}
constructor(family, service, flags, requestID, payload) {
this.family = family;
this.service = service;
this.flags = flags;
this.requestID = requestID;
this.payload = payload;
}
toString() {
return `SNAC(${this.family.toString(16)},${this.service.toString(16)}) #${this.requestID}\n ${this.payload}`;
}
}
function FLAP(buf) {
assert.equal(buf[0], 0x2a, 'Expected 0x2a FLAP header');
this.channel = buf[1];
this.datagramNumber = buf.slice(2,4).readInt16BE(0);
this.payloadLength = buf.slice(4, 6).readInt16BE(0);
this.payload = buf.slice(6, 6 + this.payloadLength);
this.toString = () => `ch:${this.channel}, dn: ${this.datagramNumber}, len: ${this.payloadLength}, payload:\n ${ this.payload instanceof SNAC ? this.payload.toString() : logDataStream(this.payload).split('\n').join('\n ')}`;
class FLAP {
static fromBuffer(buf) {
assert.equal(buf[0], 0x2a, 'Expected 0x2a FLAP header');
const channel = parseInt(buf[1], 16);
const datagramNumber = buf.slice(2,4).readInt16BE(0);
const payloadLength = buf.slice(4, 6).readInt16BE(0);
const payload = buf.slice(6, 6 + payloadLength);
if (this.channel === 2) {
this.payload = new SNAC(this.payload);
return new FLAP(channel, datagramNumber, payload)
}
constructor(channel, datagramNumber, payload) {
this.channel = channel;
this.datagramNumber = datagramNumber;
this.payload = payload;
this.payloadLength = this.payload.length;
if (channel === 2) {
this.payload = SNAC.fromBuffer(this.payload, this.payloadLength);
}
}
toString() {
const hasSnac = this.payload instanceof SNAC;
const payload = hasSnac ? this.payload.toString() : logDataStream(this.payload).split('\n').join('\n ');
return `ch:${this.channel}, dn: ${this.datagramNumber}, len: ${this.payloadLength}, payload:\n ${payload}`
}
}
@ -57,7 +114,7 @@ const server = net.createServer((socket) => {
});
socket.on('data', (data) => {
const flap = new FLAP(Buffer.from(data, 'hex'));
const flap = FLAP.fromBuffer(Buffer.from(data, 'hex'));
console.log('RECV', flap.toString());
});