Low hanging fruit: Don't re-create binary parsers constantly
This commit is contained in:
parent
2c9a68d0b1
commit
cd3b8d5e76
|
@ -165,6 +165,74 @@ exports.PacketHeader = PacketHeader;
|
||||||
// * Writeup on differences between type 2, 2.2, and 2+:
|
// * Writeup on differences between type 2, 2.2, and 2+:
|
||||||
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
|
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
|
||||||
//
|
//
|
||||||
|
const PacketHeaderParser = new Parser()
|
||||||
|
.uint16le('origNode')
|
||||||
|
.uint16le('destNode')
|
||||||
|
.uint16le('year')
|
||||||
|
.uint16le('month')
|
||||||
|
.uint16le('day')
|
||||||
|
.uint16le('hour')
|
||||||
|
.uint16le('minute')
|
||||||
|
.uint16le('second')
|
||||||
|
.uint16le('baud')
|
||||||
|
.uint16le('packetType')
|
||||||
|
.uint16le('origNet')
|
||||||
|
.uint16le('destNet')
|
||||||
|
.int8('prodCodeLo')
|
||||||
|
.int8('prodRevLo') // aka serialNo
|
||||||
|
.buffer('password', { length : 8 }) // can't use string; need CP437 - see https://github.com/keichi/binary-parser/issues/33
|
||||||
|
.uint16le('origZone')
|
||||||
|
.uint16le('destZone')
|
||||||
|
//
|
||||||
|
// The following is "filler" in FTS-0001, specifics in
|
||||||
|
// FSC-0045 and FSC-0048
|
||||||
|
//
|
||||||
|
.uint16le('auxNet')
|
||||||
|
.uint16le('capWordValidate')
|
||||||
|
.int8('prodCodeHi')
|
||||||
|
.int8('prodRevHi')
|
||||||
|
.uint16le('capWord')
|
||||||
|
.uint16le('origZone2')
|
||||||
|
.uint16le('destZone2')
|
||||||
|
.uint16le('origPoint')
|
||||||
|
.uint16le('destPoint')
|
||||||
|
.uint32le('prodData');
|
||||||
|
|
||||||
|
const MessageHeaderParser = new Parser()
|
||||||
|
.uint16le('messageType')
|
||||||
|
.uint16le('ftn_msg_orig_node')
|
||||||
|
.uint16le('ftn_msg_dest_node')
|
||||||
|
.uint16le('ftn_msg_orig_net')
|
||||||
|
.uint16le('ftn_msg_dest_net')
|
||||||
|
.uint16le('ftn_attr_flags')
|
||||||
|
.uint16le('ftn_cost')
|
||||||
|
//
|
||||||
|
// It would be nice to just string() these, but we want CP437 which requires
|
||||||
|
// iconv. Another option would be to use a formatter, but until issue 33
|
||||||
|
// (https://github.com/keichi/binary-parser/issues/33) is fixed, this is cumbersome.
|
||||||
|
//
|
||||||
|
.array('modDateTime', {
|
||||||
|
type : 'uint8',
|
||||||
|
length : 20, // FTS-0001.016: 20 bytes
|
||||||
|
})
|
||||||
|
.array('toUserName', {
|
||||||
|
type : 'uint8',
|
||||||
|
// :TODO: array needs some soft of 'limit' field
|
||||||
|
readUntil : b => 0x00 === b,
|
||||||
|
})
|
||||||
|
.array('fromUserName', {
|
||||||
|
type : 'uint8',
|
||||||
|
readUntil : b => 0x00 === b,
|
||||||
|
})
|
||||||
|
.array('subject', {
|
||||||
|
type : 'uint8',
|
||||||
|
readUntil : b => 0x00 === b,
|
||||||
|
})
|
||||||
|
.array('message', {
|
||||||
|
type : 'uint8',
|
||||||
|
readUntil : b => 0x00 === b,
|
||||||
|
});
|
||||||
|
|
||||||
function Packet(options) {
|
function Packet(options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
@ -175,39 +243,7 @@ function Packet(options) {
|
||||||
|
|
||||||
let packetHeader;
|
let packetHeader;
|
||||||
try {
|
try {
|
||||||
packetHeader = new Parser()
|
packetHeader = PacketHeaderParser.parse(packetBuffer);
|
||||||
.uint16le('origNode')
|
|
||||||
.uint16le('destNode')
|
|
||||||
.uint16le('year')
|
|
||||||
.uint16le('month')
|
|
||||||
.uint16le('day')
|
|
||||||
.uint16le('hour')
|
|
||||||
.uint16le('minute')
|
|
||||||
.uint16le('second')
|
|
||||||
.uint16le('baud')
|
|
||||||
.uint16le('packetType')
|
|
||||||
.uint16le('origNet')
|
|
||||||
.uint16le('destNet')
|
|
||||||
.int8('prodCodeLo')
|
|
||||||
.int8('prodRevLo') // aka serialNo
|
|
||||||
.buffer('password', { length : 8 }) // can't use string; need CP437 - see https://github.com/keichi/binary-parser/issues/33
|
|
||||||
.uint16le('origZone')
|
|
||||||
.uint16le('destZone')
|
|
||||||
//
|
|
||||||
// The following is "filler" in FTS-0001, specifics in
|
|
||||||
// FSC-0045 and FSC-0048
|
|
||||||
//
|
|
||||||
.uint16le('auxNet')
|
|
||||||
.uint16le('capWordValidate')
|
|
||||||
.int8('prodCodeHi')
|
|
||||||
.int8('prodRevHi')
|
|
||||||
.uint16le('capWord')
|
|
||||||
.uint16le('origZone2')
|
|
||||||
.uint16le('destZone2')
|
|
||||||
.uint16le('origPoint')
|
|
||||||
.uint16le('destPoint')
|
|
||||||
.uint32le('prodData')
|
|
||||||
.parse(packetBuffer);
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
return Errors.Invalid(`Unable to parse FTN packet header: ${e.message}`);
|
return Errors.Invalid(`Unable to parse FTN packet header: ${e.message}`);
|
||||||
}
|
}
|
||||||
|
@ -544,41 +580,7 @@ function Packet(options) {
|
||||||
|
|
||||||
let msgData;
|
let msgData;
|
||||||
try {
|
try {
|
||||||
msgData = new Parser()
|
msgData = MessageHeaderParser.parse(packetBuffer);
|
||||||
.uint16le('messageType')
|
|
||||||
.uint16le('ftn_msg_orig_node')
|
|
||||||
.uint16le('ftn_msg_dest_node')
|
|
||||||
.uint16le('ftn_msg_orig_net')
|
|
||||||
.uint16le('ftn_msg_dest_net')
|
|
||||||
.uint16le('ftn_attr_flags')
|
|
||||||
.uint16le('ftn_cost')
|
|
||||||
//
|
|
||||||
// It would be nice to just string() these, but we want CP437 which requires
|
|
||||||
// iconv. Another option would be to use a formatter, but until issue 33
|
|
||||||
// (https://github.com/keichi/binary-parser/issues/33) is fixed, this is cumbersome.
|
|
||||||
//
|
|
||||||
.array('modDateTime', {
|
|
||||||
type : 'uint8',
|
|
||||||
length : 20, // FTS-0001.016: 20 bytes
|
|
||||||
})
|
|
||||||
.array('toUserName', {
|
|
||||||
type : 'uint8',
|
|
||||||
// :TODO: array needs some soft of 'limit' field
|
|
||||||
readUntil : b => 0x00 === b,
|
|
||||||
})
|
|
||||||
.array('fromUserName', {
|
|
||||||
type : 'uint8',
|
|
||||||
readUntil : b => 0x00 === b,
|
|
||||||
})
|
|
||||||
.array('subject', {
|
|
||||||
type : 'uint8',
|
|
||||||
readUntil : b => 0x00 === b,
|
|
||||||
})
|
|
||||||
.array('message', {
|
|
||||||
type : 'uint8',
|
|
||||||
readUntil : b => 0x00 === b,
|
|
||||||
})
|
|
||||||
.parse(packetBuffer);
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
return cb(Errors.Invalid(`Failed to parse FTN message header: ${e.message}`));
|
return cb(Errors.Invalid(`Failed to parse FTN message header: ${e.message}`));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,25 @@ exports.SAUCE_SIZE = SAUCE_SIZE;
|
||||||
//
|
//
|
||||||
const SAUCE_VALID_DATA_TYPES = [0, 1, 2, 3, 4, 5, 6, 7, 8 ];
|
const SAUCE_VALID_DATA_TYPES = [0, 1, 2, 3, 4, 5, 6, 7, 8 ];
|
||||||
|
|
||||||
|
const SAUCEParser = new Parser()
|
||||||
|
.buffer('id', { length : 5 } )
|
||||||
|
.buffer('version', { length : 2 } )
|
||||||
|
.buffer('title', { length: 35 } )
|
||||||
|
.buffer('author', { length : 20 } )
|
||||||
|
.buffer('group', { length: 20 } )
|
||||||
|
.buffer('date', { length: 8 } )
|
||||||
|
.uint32le('fileSize')
|
||||||
|
.int8('dataType')
|
||||||
|
.int8('fileType')
|
||||||
|
.uint16le('tinfo1')
|
||||||
|
.uint16le('tinfo2')
|
||||||
|
.uint16le('tinfo3')
|
||||||
|
.uint16le('tinfo4')
|
||||||
|
.int8('numComments')
|
||||||
|
.int8('flags')
|
||||||
|
// :TODO: does this need to be optional?
|
||||||
|
.buffer('tinfos', { length: 22 } ); // SAUCE 00.5
|
||||||
|
|
||||||
function readSAUCE(data, cb) {
|
function readSAUCE(data, cb) {
|
||||||
if(data.length < SAUCE_SIZE) {
|
if(data.length < SAUCE_SIZE) {
|
||||||
return cb(Errors.DoesNotExist('No SAUCE record present'));
|
return cb(Errors.DoesNotExist('No SAUCE record present'));
|
||||||
|
@ -33,30 +52,11 @@ function readSAUCE(data, cb) {
|
||||||
|
|
||||||
let sauceRec;
|
let sauceRec;
|
||||||
try {
|
try {
|
||||||
sauceRec = new Parser()
|
sauceRec = SAUCEParser.parse(data.slice(data.length - SAUCE_SIZE));
|
||||||
.buffer('id', { length : 5 } )
|
|
||||||
.buffer('version', { length : 2 } )
|
|
||||||
.buffer('title', { length: 35 } )
|
|
||||||
.buffer('author', { length : 20 } )
|
|
||||||
.buffer('group', { length: 20 } )
|
|
||||||
.buffer('date', { length: 8 } )
|
|
||||||
.uint32le('fileSize')
|
|
||||||
.int8('dataType')
|
|
||||||
.int8('fileType')
|
|
||||||
.uint16le('tinfo1')
|
|
||||||
.uint16le('tinfo2')
|
|
||||||
.uint16le('tinfo3')
|
|
||||||
.uint16le('tinfo4')
|
|
||||||
.int8('numComments')
|
|
||||||
.int8('flags')
|
|
||||||
// :TODO: does this need to be optional?
|
|
||||||
.buffer('tinfos', { length: 22 } ) // SAUCE 00.5
|
|
||||||
.parse(data.slice(data.length - SAUCE_SIZE));
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
return cb(Errors.Invalid('Invalid SAUCE record'));
|
return cb(Errors.Invalid('Invalid SAUCE record'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!SAUCE_ID.equals(sauceRec.id)) {
|
if(!SAUCE_ID.equals(sauceRec.id)) {
|
||||||
return cb(Errors.DoesNotExist('No SAUCE record present'));
|
return cb(Errors.DoesNotExist('No SAUCE record present'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,18 @@ OPTION_IMPLS[OPTIONS.SUPPRESS_GO_AHEAD] = function(bufs, i, event) {
|
||||||
return event;
|
return event;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TermTypeCmdParser = new Parser()
|
||||||
|
.uint8('iac1')
|
||||||
|
.uint8('sb')
|
||||||
|
.uint8('opt')
|
||||||
|
.uint8('is')
|
||||||
|
.array('ttype', {
|
||||||
|
type : 'uint8',
|
||||||
|
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
||||||
|
})
|
||||||
|
// note we read iac2 above
|
||||||
|
.uint8('se');
|
||||||
|
|
||||||
OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
||||||
if(event.commandCode !== COMMANDS.SB) {
|
if(event.commandCode !== COMMANDS.SB) {
|
||||||
OPTION_IMPLS.NO_ARGS(bufs, i, event);
|
OPTION_IMPLS.NO_ARGS(bufs, i, event);
|
||||||
|
@ -208,18 +220,7 @@ OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
||||||
|
|
||||||
let ttypeCmd;
|
let ttypeCmd;
|
||||||
try {
|
try {
|
||||||
ttypeCmd = new Parser()
|
ttypeCmd = TermTypeCmdParser.parse(bufs.toBuffer());
|
||||||
.uint8('iac1')
|
|
||||||
.uint8('sb')
|
|
||||||
.uint8('opt')
|
|
||||||
.uint8('is')
|
|
||||||
.array('ttype', {
|
|
||||||
type : 'uint8',
|
|
||||||
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
|
||||||
})
|
|
||||||
// note we read iac2 above
|
|
||||||
.uint8('se')
|
|
||||||
.parse(bufs.toBuffer());
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Log.debug( { error : e }, 'Failed parsing TTYP telnet command');
|
Log.debug( { error : e }, 'Failed parsing TTYP telnet command');
|
||||||
return event;
|
return event;
|
||||||
|
@ -242,6 +243,15 @@ OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
||||||
return event;
|
return event;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NawsCmdParser = new Parser()
|
||||||
|
.uint8('iac1')
|
||||||
|
.uint8('sb')
|
||||||
|
.uint8('opt')
|
||||||
|
.uint16be('width')
|
||||||
|
.uint16be('height')
|
||||||
|
.uint8('iac2')
|
||||||
|
.uint8('se');
|
||||||
|
|
||||||
OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
||||||
if(event.commandCode !== COMMANDS.SB) {
|
if(event.commandCode !== COMMANDS.SB) {
|
||||||
OPTION_IMPLS.NO_ARGS(bufs, i, event);
|
OPTION_IMPLS.NO_ARGS(bufs, i, event);
|
||||||
|
@ -253,15 +263,7 @@ OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
||||||
|
|
||||||
let nawsCmd;
|
let nawsCmd;
|
||||||
try {
|
try {
|
||||||
nawsCmd = new Parser()
|
nawsCmd = NawsCmdParser.parse(bufs.splice(0, 9).toBuffer());
|
||||||
.uint8('iac1')
|
|
||||||
.uint8('sb')
|
|
||||||
.uint8('opt')
|
|
||||||
.uint16be('width')
|
|
||||||
.uint16be('height')
|
|
||||||
.uint8('iac2')
|
|
||||||
.uint8('se')
|
|
||||||
.parse(bufs.splice(0, 9).toBuffer());
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Log.debug( { error : e }, 'Failed parsing NAWS telnet command');
|
Log.debug( { error : e }, 'Failed parsing NAWS telnet command');
|
||||||
return event;
|
return event;
|
||||||
|
@ -282,6 +284,18 @@ OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
||||||
// Build an array of delimiters for parsing NEW_ENVIRONMENT[_DEP]
|
// Build an array of delimiters for parsing NEW_ENVIRONMENT[_DEP]
|
||||||
//const NEW_ENVIRONMENT_DELIMITERS = _.values(NEW_ENVIRONMENT_COMMANDS);
|
//const NEW_ENVIRONMENT_DELIMITERS = _.values(NEW_ENVIRONMENT_COMMANDS);
|
||||||
|
|
||||||
|
const EnvCmdParser = new Parser()
|
||||||
|
.uint8('iac1')
|
||||||
|
.uint8('sb')
|
||||||
|
.uint8('opt')
|
||||||
|
.uint8('isOrInfo') // IS=initial, INFO=updates
|
||||||
|
.array('envBlock', {
|
||||||
|
type : 'uint8',
|
||||||
|
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
||||||
|
})
|
||||||
|
// note we consume IAC above
|
||||||
|
.uint8('se');
|
||||||
|
|
||||||
// Handle the deprecated RFC 1408 & the updated RFC 1572:
|
// Handle the deprecated RFC 1408 & the updated RFC 1572:
|
||||||
OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT_DEP] =
|
OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT_DEP] =
|
||||||
OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT] = function(bufs, i, event) {
|
OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT] = function(bufs, i, event) {
|
||||||
|
@ -306,18 +320,7 @@ OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT] = function(bufs, i, event) {
|
||||||
|
|
||||||
let envCmd;
|
let envCmd;
|
||||||
try {
|
try {
|
||||||
envCmd = new Parser()
|
envCmd = EnvCmdParser.parse(bufs.splice(0, bufs.length).toBuffer());
|
||||||
.uint8('iac1')
|
|
||||||
.uint8('sb')
|
|
||||||
.uint8('opt')
|
|
||||||
.uint8('isOrInfo') // IS=initial, INFO=updates
|
|
||||||
.array('envBlock', {
|
|
||||||
type : 'uint8',
|
|
||||||
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
|
||||||
})
|
|
||||||
// note we consume IAC above
|
|
||||||
.uint8('se')
|
|
||||||
.parse(bufs.splice(0, bufs.length).toBuffer());
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
Log.debug( { error : e }, 'Failed parsing NEW-ENVIRON telnet command');
|
Log.debug( { error : e }, 'Failed parsing NEW-ENVIRON telnet command');
|
||||||
return event;
|
return event;
|
||||||
|
|
Loading…
Reference in New Issue