Refuse a single unreadable PDU instead of the whole link (#79)

* Regression tests: a PDU the codec cannot read costs that PDU, not the link

* Refuse a single unreadable PDU instead of the whole link

* smscsim interop asserts the first attempt gets every DLR

* Record the smscsim sequence number defect as fixed

* One framing rule and one response-command lookup, per the architecture review

* Apply the stability review's nits: honest sessionError docs and one link-survives assertion
This commit is contained in:
2026-09-05 21:00:52 +02:00
committed by GitHub
parent fec4fda082
commit ea42bc6d20
11 changed files with 511 additions and 141 deletions
+14 -1
View File
@@ -3,7 +3,7 @@ import type { SmppLog } from './log.ts';
import type { Socket } from 'node:net';
import type { VoidResult } from './result.ts';
import { PduFramer } from './pdu-framer.ts';
import { pduToObj } from './pdu.ts';
import { PduRefusedError, pduToObj } from './pdu.ts';
export type PduTransportOptions = {
log: SmppLog;
@@ -14,6 +14,8 @@ export type PduTransportOptions = {
/** A complete PDU, before it is parsed. */
onFramed: (pdu: Buffer) => void;
onPdu: (pduObj: PduObject) => void;
/** A framed PDU the codec could not read. The stream is still in sync, so the link is not lost. */
onRefused: (refused: PduRefusedError) => void;
/** Nothing further can be read off this stream, whatever the socket does next. */
onUnreadable: (err: Error) => void;
};
@@ -79,6 +81,17 @@ export class PduTransport {
const parsed = pduToObj(pdu);
if (parsed.err instanceof PduRefusedError) {
this.options.log.warn('transport - refusing a PDU it could not read', {
message: parsed.err.message,
reason: parsed.err.reason,
});
this.options.onRefused(parsed.err);
continue;
}
// The framer applies framingRefusal() first, so only a caller that skips it lands here.
if (parsed.err) {
this.options.log.warn('transport - could not parse an incoming PDU', {
message: parsed.err.message,