Answer every segment of an inbound concatenated message as it arrives (#83)

* Regression tests for answering every inbound segment as it arrives

* Answer every segment of an inbound concatenated message as it arrives

* Record the segment-by-segment answer in AGENTS.md and README

* Regression tests for an empty message_id on deliver_sm_resp

* Answer a deliver_sm with the empty message_id SMPP 3.4 makes it

* Record Jasmin's refusal of a deliver_sm_resp message_id

* Mark the Jasmin multipart deadlock fixed

* Regression tests for the architecture review's findings

* Give the segment id notation an owner, and every segment a status

* Correct what the ids reach and what a lost group tells the application

* Regression tests for a group lost to its own octet overrun

* Report a group lost to its own overrun, and refuse by the command it arrived on

* Keep the docs true about what a segment is answered with

* Count only the answered segments of a group lost to an overrun

* Report only what a lost group cost, and say which cap bit
This commit is contained in:
2026-09-06 04:16:11 +02:00
committed by GitHub
parent 66b49ebfb3
commit 5b7b563dc2
14 changed files with 824 additions and 160 deletions
+10 -1
View File
@@ -165,6 +165,10 @@ segment as they arrive rather than being a relay itself. Worth a decision record
each segment as it's held, not only once the group completes; or document that a `server()` sitting
behind a serializing relay needs its own segment-level ack), but not fixed here per the phase rules.
**Fixed** in [#83](https://github.com/larvit/larvitsmpp/pull/83): every segment is answered as it
arrives, with `<base>-<n>` off an id the group is opened with. All four multi-segment cases pass, in
200-360 ms each, malformed 0 and expert errors 0.
## Peer quirks
- **Jasmin's own `enquireLinkTimerSecs` (30, `[smpp-server]` default) is an idle timer, not a strict
@@ -175,7 +179,7 @@ behind a serializing relay needs its own segment-level ack), but not fixed here
Every id the real client's `submit_sm_resp` carried matched exactly what the fake upstream's
`sendResp()` assigned; the later receipt named the same id. Since the fake upstream here is this
library's own `server()`, a multi-segment message's ids came back in this library's own
`<base>-<n>` shape - an artifact of the test rig (our own server reassembling before answering),
`<base>-<n>` shape - an artifact of the test rig (our own server minting one base per group),
not evidence that Jasmin itself produces that convention; a real upstream SMSC would very likely
hand back unrelated ids per segment, as the research notes expected.
- **`smpps_throughput`, not the connector's `submit_throughput`, gates an ESME's own submission
@@ -194,6 +198,11 @@ behind a serializing relay needs its own segment-level ack), but not fixed here
printf-style placeholders, nothing is written into the URL by the caller. `dlr-level=1` fires once,
immediately, with `message_status=ESME_ROK` (an SMSC-ack, not a terminal state); `dlr-level=3`
additionally fires once more, later, with the real terminal status (`DELIVRD` here).
- **Jasmin FINs the connection on a `deliver_sm_resp` carrying a `message_id`.** SMPP 3.4 4.6.2
makes that field unused and NULL, and Jasmin's own decoder sizes it at one octet; a 38-octet UUID
in it cost the link immediately after the response, taking the rest of the MO group with it. Found
by the fix for the multipart deadlock above, which is what first had this library answer an inbound
`deliver_sm` in this suite at all; the field now goes out empty.
- **jcli is a plain-text protocol dressed as Telnet** - it sends real `IAC`/option-negotiation bytes
and a couple of ANSI escapes in its banner, but never waits for or requires a reply to them; a raw
socket client that ignores negotiation entirely and just reads/writes lines works throughout.