From 809acd487e3036d8e2aba76ce60dfd8eb4c4b08c Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Mon, 28 Sep 2026 01:22:54 +0200 Subject: [PATCH 1/2] Size the address arrays' C-Octet Strings through cstring.size() --- src/defs/types.ts | 100 +++++++++++++++++++++++++++++---------------- test/types.test.ts | 8 ++++ todo.md | 8 ---- 3 files changed, 73 insertions(+), 43 deletions(-) diff --git a/src/defs/types.ts b/src/defs/types.ts index 6b70ab1..db3afd5 100644 --- a/src/defs/types.ts +++ b/src/defs/types.ts @@ -385,14 +385,52 @@ export const buffer: WireType = { }, }; -function sizeDestAddresses(addresses: DestAddress[]): number { +function writeSizedCstring(value: ParamValue, buf: Buffer, offset: number): Result<{ size: number }> { + const { err, size } = cstring.size(value); + + if (err) return { err }; + + const written = cstring.write(value, buf, offset); + + return written.err ? { err: written.err } : { size }; +} + +function sizeDestAddresses(addresses: DestAddress[]): Result<{ size: number }> { let size = 1; for (const dest of addresses) { - size += 'dl_name' in dest ? dest.dl_name.length + 2 : dest.destination_addr.length + 4; + const text = 'dl_name' in dest ? cstring.size(dest.dl_name) : cstring.size(dest.destination_addr); + + if (text.err) return { err: text.err }; + + size += ('dl_name' in dest ? 1 : 3) + text.size; } - return size; + return { size }; +} + +function writeDestAddress(dest: DestAddress, buf: Buffer, offset: number): Result<{ size: number }> { + if ('dl_name' in dest) { + buf.writeUInt8(2, offset); + + const name = writeSizedCstring(dest.dl_name, buf, offset + 1); + + return name.err ? { err: name.err } : { size: 1 + name.size }; + } + + buf.writeUInt8(1, offset); + + const ton = writeInt8(dest.dest_addr_ton, buf, offset + 1); + + if (ton.err) return { err: ton.err }; + + const npi = writeInt8(dest.dest_addr_npi, buf, offset + 2); + + if (npi.err) return { err: npi.err }; + + const addr = writeSizedCstring(dest.destination_addr, buf, offset + 3); + + return addr.err ? { err: addr.err } : { size: 3 + addr.size }; } export const dest_address_array: WireType = { @@ -441,14 +479,18 @@ export const dest_address_array: WireType = { size(value) { const { addresses, err } = wantDestAddresses(value); - return err ? { err } : { size: sizeDestAddresses(addresses) }; + return err ? { err } : sizeDestAddresses(addresses); }, write(value, buf, offset) { const { addresses, err } = wantDestAddresses(value); if (err) return { err }; - const rangeErr = outOfRange(buf, offset, sizeDestAddresses(addresses)); + const total = sizeDestAddresses(addresses); + + if (total.err) return { err: total.err }; + + const rangeErr = outOfRange(buf, offset, total.size); if (rangeErr) return { err: rangeErr }; @@ -457,45 +499,29 @@ export const dest_address_array: WireType = { if (count.err) return { err: count.err }; for (const dest of addresses) { - if ('dl_name' in dest) { - buf.writeUInt8(2, offset++); + const written = writeDestAddress(dest, buf, offset); - const name = cstring.write(dest.dl_name, buf, offset); + if (written.err) return { err: written.err }; - if (name.err) return { err: name.err }; - - offset += dest.dl_name.length + 1; - } else { - buf.writeUInt8(1, offset++); - - const ton = writeInt8(dest.dest_addr_ton, buf, offset++); - - if (ton.err) return { err: ton.err }; - - const npi = writeInt8(dest.dest_addr_npi, buf, offset++); - - if (npi.err) return { err: npi.err }; - - const addr = cstring.write(dest.destination_addr, buf, offset); - - if (addr.err) return { err: addr.err }; - - offset += dest.destination_addr.length + 1; - } + offset += written.size; } return {}; }, }; -function sizeUnsuccessSmes(smes: UnsuccessSme[]): number { +function sizeUnsuccessSmes(smes: UnsuccessSme[]): Result<{ size: number }> { let size = 1; for (const sme of smes) { - size += sme.destination_addr.length + 7; + const addr = cstring.size(sme.destination_addr); + + if (addr.err) return { err: addr.err }; + + size += addr.size + 6; } - return size; + return { size }; } export const unsuccess_sme_array: WireType = { @@ -540,14 +566,18 @@ export const unsuccess_sme_array: WireType = { size(value) { const { err, smes } = wantUnsuccessSmes(value); - return err ? { err } : { size: sizeUnsuccessSmes(smes) }; + return err ? { err } : sizeUnsuccessSmes(smes); }, write(value, buf, offset) { const { err, smes } = wantUnsuccessSmes(value); if (err) return { err }; - const rangeErr = outOfRange(buf, offset, sizeUnsuccessSmes(smes)); + const total = sizeUnsuccessSmes(smes); + + if (total.err) return { err: total.err }; + + const rangeErr = outOfRange(buf, offset, total.size); if (rangeErr) return { err: rangeErr }; @@ -564,11 +594,11 @@ export const unsuccess_sme_array: WireType = { if (npi.err) return { err: npi.err }; - const addr = cstring.write(sme.destination_addr, buf, offset); + const addr = writeSizedCstring(sme.destination_addr, buf, offset); if (addr.err) return { err: addr.err }; - offset += sme.destination_addr.length + 1; + offset += addr.size; const status = writeInt32(sme.error_status_code, buf, offset); diff --git a/test/types.test.ts b/test/types.test.ts index c855106..02953e3 100644 --- a/test/types.test.ts +++ b/test/types.test.ts @@ -291,6 +291,8 @@ describe('dest_address_array', () => { test('sizes every dest_address structure', () => { assert.deepEqual(types.dest_address_array.size(expected), { size: 13 }); + assert.ok(types.dest_address_array.size([{ dl_name: 'a\u0000b' }]).err instanceof Error); + assert.ok(types.dest_address_array.size([{ dest_addr_npi: 0, dest_addr_ton: 0, destination_addr: '一' }]).err instanceof Error); }); test('writes every dest_address structure', () => { @@ -335,6 +337,12 @@ describe('unsuccess_sme_array', () => { test('sizes every unsuccess_sme structure', () => { assert.deepEqual(types.unsuccess_sme_array.size(expected), { size: 21 }); + + const unwritable: UnsuccessSme[] = [ + { dest_addr_npi: 0, dest_addr_ton: 0, destination_addr: 'a\u0000b', error_status_code: 0 }, + ]; + + assert.ok(types.unsuccess_sme_array.size(unwritable).err instanceof Error); }); test('writes every unsuccess_sme structure', () => { diff --git a/todo.md b/todo.md index 364c196..cc36eea 100644 --- a/todo.md +++ b/todo.md @@ -199,14 +199,6 @@ next work ([decision](docs/decisions.md#internals-and-tests)). ### Locality — next, ahead of everything below; 5–6 today, and the gate is 7 -- [ ] **Let the two address arrays size a C-Octet String through `cstring.size()`.** - `sizeDestAddresses()` and `sizeUnsuccessSmes()` spell "len + 1" themselves, and each `offset +=` - after a write spells it a third time, so `dest_address_array` and `unsuccess_sme_array` each - know the cost in three places. Route both through `cstring.size()` and advance the offset by - what it returns. That also makes `size()` refuse where `write()` already does, so the error - arrives from the first call rather than the second; today the pair only fails closed because - `writeParams()` and `writeTlvs()` both bail on the write. From the stability review of #16. - - [ ] **Split the two questions `OutgoingRequests.linkDown()` answers.** `Session.drain()` calls it twice for opposite conclusions — "nothing to drain, success" and "the link died under us, failure" — and `outgoing-requests.ts` reads it a third way. Two named predicates. Named by 7 -- 2.52.0 From 1371137fef7ae06beb9d536cf89a70198bc210a6 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Mon, 28 Sep 2026 01:25:31 +0200 Subject: [PATCH 2/2] Branch once on a dest_address's kind when sizing it --- src/defs/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/defs/types.ts b/src/defs/types.ts index db3afd5..10d6249 100644 --- a/src/defs/types.ts +++ b/src/defs/types.ts @@ -399,11 +399,11 @@ function sizeDestAddresses(addresses: DestAddress[]): Result<{ size: number }> { let size = 1; for (const dest of addresses) { - const text = 'dl_name' in dest ? cstring.size(dest.dl_name) : cstring.size(dest.destination_addr); + const [header, text] = 'dl_name' in dest ? [1, cstring.size(dest.dl_name)] : [3, cstring.size(dest.destination_addr)]; if (text.err) return { err: text.err }; - size += ('dl_name' in dest ? 1 : 3) + text.size; + size += header + text.size; } return { size }; -- 2.52.0