Commit Graph

49 Commits

Author SHA1 Message Date
lilleman 42e6e97447 Read a receipt reporting a transient state as non-final too, so the merge waits for the real one 2026-09-03 19:28:08 +02:00
lilleman dd458bfa53 Say only what the SMSC marked, and trim the comments the review found redundant 2026-09-03 19:16:13 +02:00
lilleman 50679ec2fe Read an intermediate delivery notification as a report, and keep it out of the merge 2026-09-03 17:30:09 +02:00
lilleman 94184a9c63 Re-wrap the shutdown paragraph and leave the throw-versus-rejection note in one place 2026-09-02 12:40:51 +02:00
lilleman 3eeb0b82c0 Give a message up only once every listener has, and only count a response the wire took 2026-09-02 12:36:01 +02:00
lilleman 3aadb64df8 Release a message's hold when the response goes out, or when its listener failed 2026-09-02 08:15:26 +02:00
lilleman 471923a7b6 Log the dropped request, and scope the receipt sentence to a reconnect 2026-09-01 20:53:58 +02:00
lilleman e6250ef44e Drop a request whose link went while onRequest ran, and pin the wire in the test 2026-09-01 20:40:17 +02:00
lilleman c8d265d5fa Tie the refusal to the link, not to the hold, so a released message is refused too 2026-09-01 20:25:57 +02:00
lilleman 82a95593bd Refuse to answer a message whose link went, instead of reporting it delivered 2026-09-01 19:20:06 +02:00
lilleman f0327044b1 Cover the receipt refusal and the sweep that wakes a drain 2026-09-01 18:13:35 +02:00
lilleman 61985fb914 Say what a peer did with each receipt segment, and leave no drop unlogged 2026-09-01 17:59:37 +02:00
lilleman 67c0402def Bound the messages held for a shutdown, and report a partial receipt 2026-09-01 17:42:22 +02:00
lilleman 1e7e113bd7 Put a receipt's segments on the wire together, like a message's 2026-09-01 17:03:33 +02:00
lilleman 8becbc0ab6 Give the gate, the window and the pending map one owner 2026-09-01 16:52:15 +02:00
lilleman 3bcea108e3 Wait out the messages the application holds before shutting a session down 2026-09-01 13:58:28 +02:00
lilleman 35dd1e7678 Count every request that went out unanswered, and gate a send on a bound link 2026-09-01 10:08:56 +02:00
lilleman 8d9656b4e0 Hold a send with no link for the next one, and count the rest as unanswered 2026-09-01 08:02:37 +02:00
lilleman bfc85ee4dd Say in the options table that a proven link resets the backoff
maxDelay bounds the wait and sets the bar a link must clear, and only the
first was documented, so tuning it up quietly lengthened every recovery.

The unreadable PDU the tests write is one named constant now.
2026-08-31 22:59:57 +02:00
lilleman 8e4d472f72 Back off from a link that dies as soon as it comes up
A bind that returns is not proof the link works: an unreadable stream is
only found afterwards, so resetting the delay there handed a link that
died on arrival a fresh minDelay every cycle — one connect and bind per
second forever, which is how an account gets blocked for bind flooding.
The loop resets only once a link has outlasted maxDelay.

Also covers the unreadable stream that has no loop to retry it.
2026-08-31 22:45:29 +02:00
lilleman b1c790b9a0 Retry a stream we cannot read, and cover the framer reset on attach
A framing or codec error tears the link down rather than the session, so
the loop retries it on a fresh socket with a fresh framer — which is what
a desynced stream needs. Removing that reset failed nothing before; the
reconnect test now leaves half a PDU on the dying link, and does.

`disconnected` counts failed links rather than outages, which the README
now says, and the transport wires its socket as it is built.
2026-08-31 22:27:16 +02:00
lilleman b2d121b4f3 Emit exactly one close, and read the socket through a PduTransport
Ending a session while the link was down emitted nothing: the retried
drop had already torn it down, so close() found nothing left to do. The
terminal event is now guarded by its own flag rather than by `closed`.

The socket, the framer and the parse move to PduTransport, which is what
takes session.ts back under its line cap; `session.sock` reads through a
getter. The backoff also refuses an inverted pair and an unknown key.
2026-08-31 21:53:11 +02:00
lilleman 880454b4f4 Split a retried drop out of close, and range-check the backoff
`close` fires only where nothing will bring the session back; a drop the
reconnect loop will retry is `disconnected`, pairing with `reconnected`.
`minDelay: 0` never doubles, so the backoff never started — both delays
are range-checked now, and only `false` spells reconnect off.
2026-08-31 21:11:19 +02:00
lilleman 18177053bc Re-bind a dropped client link by default, and take false to turn it off
Surviving a drop is most of what the session layer is for, and behind an
opt-in an application that never read the options table got none of it.
`reconnect` still takes `{ minDelay, maxDelay }` to retune the backoff;
`false` is the one spelling for off.
2026-08-31 20:18:29 +02:00
lilleman 706b61d6ca Leave an unknown notation alone and read a receipt's TLV as the id the submit answered 2026-08-30 23:01:39 +02:00
lilleman 696e018b77 Derive the notation names from one table and refuse an smsIdFormat that is not the pair 2026-08-30 22:45:02 +02:00
lilleman 8e5b9bb556 Read a peer's submit and receipt message ids into one notation before comparing them 2026-08-30 22:35:09 +02:00
lilleman 7e8af3c308 Tear down at once on a peer unbind and stop reporting a reconnect after close 2026-08-30 21:01:46 +02:00
lilleman 5c618e0061 Stop accepting before the drain and report the link that dropped during it 2026-08-30 20:27:38 +02:00
lilleman bebd74b42b Drain the requests already on the wire before close() and unbind() tear down 2026-08-30 20:08:36 +02:00
lilleman 5c797f5383 Forget the base closed longest ago rather than the one handed out again 2026-08-30 11:31:22 +02:00
lilleman aa3cf41c7f Merge a message id base once so a straggler cannot join a later report 2026-08-30 11:17:02 +02:00
lilleman 0e8f298957 Route a rejecting async listener to sessionError instead of the process 2026-08-27 22:22:51 +02:00
lilleman b9f77ec969 Decode a receipt body before reading it and stop an unnameable state TLV overriding it 2026-08-27 16:08:54 +02:00
lilleman 4c08fe8fa3 Classify a deliver_sm by esm_class and document the messageDlr precondition 2026-08-27 15:52:33 +02:00
lilleman 9225f6ca23 Surface the session-layer features in a table at the top of the README 2026-08-27 15:35:49 +02:00
lilleman 366fa26b1c Enforce bind direction, cap segments per message and pin the README examples 2026-08-27 14:07:42 +02:00
lilleman 8d245c82c4 Declare the logger contract in the library instead of depending on @larvit/log 2026-08-27 13:42:58 +02:00
lilleman 8a182604b7 Address the CodeRabbit review: inbound SMS, binary payloads and untrusted input 2026-08-27 11:52:43 +02:00
lilleman 884afdb87b Stop a thrown listener escaping, bound what a peer can pin, and drop the body from failure responses 2026-08-27 10:55:34 +02:00
lilleman 5af75a3c57 Close the stability findings and settle the sendResp, sendSms and unbind contracts 2026-08-27 00:17:48 +02:00
lilleman 435fa42708 Decompose the codec, document the session surface and record the review decisions 2026-08-26 22:59:39 +02:00
lilleman 6d842a8539 Split the session, gate optional parameters on the peer version, own the SMPP version in defs 2026-08-26 22:41:28 +02:00
lilleman f0858aacf8 Answer 3.4 binds with sc_interface_version and cover TLS with tests 2026-08-26 17:16:54 +02:00
lilleman 694c3a506e Bind as SMPP 3.4 by default, with interfaceVersion to override it 2026-08-26 15:41:44 +02:00
lilleman 54b73205ac Document the finished API and make the test scripts portable across Node versions 2026-08-25 17:02:57 +02:00
lilleman db5dc8cd15 Add message helpers: segmentation, bit counting and SMPP time 2026-08-25 16:23:23 +02:00
lilleman 79c9df79c6 Record wire-format defects and drop the dormant filters layer 2026-08-25 16:20:25 +02:00
lilleman 16c935bb18 Scaffold ESM TypeScript rewrite as @larvit/smpp 2026-08-25 16:02:27 +02:00