Bind as SMPP 3.4 by default, with interfaceVersion to override it
This commit is contained in:
@@ -77,7 +77,8 @@ Every one is optional.
|
||||
| `host` / `port` | `localhost` / `2775` | Where to connect. |
|
||||
| `username` / `password` | `user` / `pass` | Bind credentials (`system_id` and `password`). |
|
||||
| `bindType` | `transceiver` | `transceiver`, `transmitter` or `receiver`. |
|
||||
| `systemType`, `addressRange`, `addrTon`, `addrNpi`, `interfaceVersion` | `''`, `''`, `0`, `0`, `0x50` | The remaining bind fields, for operators that require them. |
|
||||
| `interfaceVersion` | `0x34` | The SMPP version declared at bind. `0x50` for an SMSC that requires SMPP 5.0. |
|
||||
| `systemType`, `addressRange`, `addrTon`, `addrNpi` | `''`, `''`, `0`, `0` | The remaining bind fields, for operators that require them. |
|
||||
| `tls` | `false` | `true` for defaults, or a `tls.ConnectionOptions` object for a private CA or a client certificate. |
|
||||
| `enquireLinkInterval` | `20000` | How often to send `enquire_link` on a quiet link. |
|
||||
| `responseTimeout` | `30000` | How long to wait for a response before giving up on it. |
|
||||
@@ -275,8 +276,9 @@ have worked around any of these, remove the workaround:
|
||||
reported the full length, so it went out corrupt. In UCS2 that is any message ending in a
|
||||
character like 一 (U+4E00), which made the bug routine for CJK text.
|
||||
- Short or malformed PDUs threw out of the codec instead of being reported as a parse failure.
|
||||
- Binds now declare `interface_version` 0x50. 0.4.0 declared 0x00, because the default in its own
|
||||
command table was never applied. Pass `interfaceVersion: 0x34` to bind as SMPP 3.4.
|
||||
- Binds now declare `interface_version` 0x34. 0.4.0 declared 0x00, which tells the SMSC the ESME
|
||||
speaks SMPP 3.3 or earlier — and a spec-following SMSC then withholds every optional parameter,
|
||||
including the TLVs delivery receipts are carried in.
|
||||
- `submit_multi` was missing its `sm_length` field, so its `short_message` never round-tripped.
|
||||
|
||||
The corrected framing is cross-checked against [node-smpp](https://github.com/farhadi/node-smpp), an
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@ const defaults = {
|
||||
bindType: 'transceiver',
|
||||
enquireLinkInterval: 20_000,
|
||||
host: 'localhost',
|
||||
/** SMPP 5.0. 0.4.0 declared 0x00 because its per-parameter default was never applied. */
|
||||
interfaceVersion: 0x50,
|
||||
/** SMPP 3.4. The 3.4 spec reserves every value above it, so 0x50 is undefined to a 3.4 SMSC. */
|
||||
interfaceVersion: 0x34,
|
||||
password: 'pass',
|
||||
port: 2775,
|
||||
username: 'user',
|
||||
|
||||
@@ -69,7 +69,7 @@ describe('our encoder against the reference parser', () => {
|
||||
const parsed = referenceParse(ourBuffer({
|
||||
cmdName: 'bind_transceiver',
|
||||
params: {
|
||||
interface_version: 0x50,
|
||||
interface_version: 0x34,
|
||||
password: 'bar',
|
||||
system_id: 'foo',
|
||||
system_type: 'smpp',
|
||||
@@ -80,7 +80,7 @@ describe('our encoder against the reference parser', () => {
|
||||
assert.equal(parsed.command, 'bind_transceiver');
|
||||
assert.equal(parsed.system_id, 'foo');
|
||||
assert.equal(parsed.password, 'bar');
|
||||
assert.equal(parsed.interface_version, 0x50);
|
||||
assert.equal(parsed.interface_version, 0x34);
|
||||
});
|
||||
|
||||
test('a deliver_sm carrying delivery receipt TLVs', () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { Session } from '../src/session.ts';
|
||||
import type { Sms } from '../src/sms.ts';
|
||||
import type { SmppServer } from '../src/server.ts';
|
||||
import { client } from '../src/client.ts';
|
||||
import { isCommand } from '../src/pdu.ts';
|
||||
import { server } from '../src/server.ts';
|
||||
|
||||
async function startServer(options: Parameters<typeof server>[0] = {}): Promise<SmppServer> {
|
||||
@@ -93,6 +94,30 @@ describe('bind', () => {
|
||||
assert.equal(await responded, '00000010800000150000000400000001');
|
||||
await smpp.close();
|
||||
});
|
||||
|
||||
test('declares SMPP 3.4 by default and the version the caller asks for', async () => {
|
||||
const smpp = await startServer();
|
||||
const declared: (number | undefined)[] = [];
|
||||
|
||||
smpp.on('session', session => {
|
||||
session.on('incomingPduObj', pduObj => {
|
||||
if (isCommand(pduObj, 'bind_transceiver')) {
|
||||
declared.push(pduObj.params.interface_version);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const { session: byDefault } = await connect(smpp);
|
||||
const { session: asFive } = await connect(smpp, { interfaceVersion: 0x50 });
|
||||
|
||||
assert.ok(byDefault);
|
||||
assert.ok(asFive);
|
||||
assert.deepEqual(declared, [0x34, 0x50]);
|
||||
|
||||
await byDefault.unbind();
|
||||
await asFive.unbind();
|
||||
await smpp.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('sending', () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ rules there constrain every item below.
|
||||
|
||||
## Status
|
||||
|
||||
The rewrite is **feature complete and green**: 136 tests, lint and typecheck clean, verified on Node
|
||||
The rewrite is **feature complete and green**: 137 tests, lint and typecheck clean, verified on Node
|
||||
18, 20, 22 and 24. What is left is release work and a few things worth adding before or after 1.0.0.
|
||||
|
||||
```bash
|
||||
@@ -62,10 +62,6 @@ Every defect listed in the AGENTS.md table has a regression test naming the beha
|
||||
|
||||
## Before publishing 1.0.0
|
||||
|
||||
- [ ] **Decide the `interface_version` default.** Binds now declare 0x50, which is what 0.4.0's own
|
||||
command table intended but never applied — it actually sent 0x00. 0x34 (SMPP 3.4) is the more
|
||||
conservative choice and is what most SMSCs implement. Flagged to the maintainer; the README
|
||||
documents 0x50 and the `interfaceVersion` option overrides it either way.
|
||||
- [ ] Create the `@larvit/smpp` package on npm and add `NPM_TOKEN` to the repository secrets, which
|
||||
`.github/workflows/release.yaml` needs.
|
||||
- [ ] Tag `v1.0.0` to publish.
|
||||
@@ -78,6 +74,10 @@ Every defect listed in the AGENTS.md table has a regression test naming the beha
|
||||
- [ ] **In-flight sends across a reconnect.** They currently fail with "Session closed before a
|
||||
response arrived" and the caller retries. Re-queueing them automatically would be friendlier
|
||||
but risks duplicate delivery, so it needs a decision before it is built.
|
||||
- [ ] **The server never returns the `sc_interface_version` TLV.** The 3.4 spec has an ESME read its
|
||||
absence from a bind response as "this SMSC does not support optional parameters", and ours
|
||||
does send DLR TLVs. Returning it has to be conditional: a peer that declared below 0x34 must
|
||||
not be sent optional parameters at all.
|
||||
- [ ] **TLS is untested.** The code path is right (`tls.connect` / `tls.createServer`, options
|
||||
passed through) but no test exercises a handshake. Needs a self-signed certificate fixture.
|
||||
- [ ] **`submit_multi` and the broadcast commands** encode and decode, but nothing exercises them
|
||||
|
||||
Reference in New Issue
Block a user