Refuse a message past the held-message bound with ESME_RTHROTTLED, and answer a full reassembly buffer the same way
Test / lint (pull_request) Successful in 23s
Test / test (18) (pull_request) Successful in 31s
Test / test (20) (pull_request) Successful in 31s
Test / test (22) (pull_request) Successful in 31s
Test / test (24) (pull_request) Successful in 31s
Test / test (26) (pull_request) Successful in 31s
Mirror / push (push) Successful in 4s
Test / lint (pull_request) Successful in 23s
Test / test (18) (pull_request) Successful in 31s
Test / test (20) (pull_request) Successful in 31s
Test / test (22) (pull_request) Successful in 31s
Test / test (24) (pull_request) Successful in 31s
Test / test (26) (pull_request) Successful in 31s
Mirror / push (push) Successful in 4s
This commit is contained in:
+7
-26
@@ -30,7 +30,6 @@ export class HeldMessages {
|
||||
private readonly held: ExpiringGroups<Held>;
|
||||
private readonly idleWaiters = new IdleWaiters();
|
||||
private readonly log: SmppLog;
|
||||
private readonly max: number;
|
||||
private readonly maxOctets: number;
|
||||
private octets = 0;
|
||||
|
||||
@@ -42,7 +41,6 @@ export class HeldMessages {
|
||||
timeout: options.timeout,
|
||||
});
|
||||
this.log = options.log;
|
||||
this.max = options.max;
|
||||
this.maxOctets = options.maxOctets;
|
||||
}
|
||||
|
||||
@@ -50,7 +48,13 @@ export class HeldMessages {
|
||||
return this.held.size;
|
||||
}
|
||||
|
||||
/** An application that answers no message at all may not grow this without end. */
|
||||
/** Whether a message arriving now is past the bound, once the expired are swept. */
|
||||
full(): boolean {
|
||||
this.sweep();
|
||||
|
||||
return this.held.full || this.octets >= this.maxOctets;
|
||||
}
|
||||
|
||||
hold(pduObjs: PduObject[]): void {
|
||||
const key = keyOf(pduObjs);
|
||||
|
||||
@@ -63,17 +67,10 @@ export class HeldMessages {
|
||||
if (replaced) {
|
||||
this.log.warn('heldMessages - replacing a message on a re-used sequence number', { seqNr: Number(key) });
|
||||
this.delete(key, replaced);
|
||||
} else if (this.held.full) {
|
||||
this.dropOldest();
|
||||
}
|
||||
|
||||
const octets = pduObjs.reduce((sum, pduObj) => sum + retainedOctets(pduObj), 0);
|
||||
|
||||
// The message just held stays even alone past the cap: the peer is still owed its answer.
|
||||
while (this.held.size > 0 && this.octets + octets > this.maxOctets) {
|
||||
this.dropOldest();
|
||||
}
|
||||
|
||||
this.held.set(key, { octets, pduObjs });
|
||||
this.octets += octets;
|
||||
}
|
||||
@@ -109,22 +106,6 @@ export class HeldMessages {
|
||||
return this.idleWaiters.wait(() => this.held.size, timeout, signal);
|
||||
}
|
||||
|
||||
private dropOldest(): void {
|
||||
const oldest = this.held.takeOldest();
|
||||
|
||||
if (!oldest) return;
|
||||
|
||||
const [seqNr, held] = oldest;
|
||||
|
||||
this.octets -= held.octets;
|
||||
this.log.warn('heldMessages - buffer full, dropping the oldest message', {
|
||||
max: this.max,
|
||||
maxOctets: this.maxOctets,
|
||||
octets: this.octets,
|
||||
seqNr: Number(seqNr),
|
||||
});
|
||||
}
|
||||
|
||||
/** Drops every message past its deadline. Runs before each hold and on its own timer. */
|
||||
sweep(): void {
|
||||
const expired = this.held.takeExpired();
|
||||
|
||||
@@ -19,7 +19,11 @@ import { paramText } from './defs/types.ts';
|
||||
import { respIdParams, segmentId } from './sms-id.ts';
|
||||
import { respNameFor } from './defs/commands.ts';
|
||||
|
||||
/** SMPP 3.4 lists ESME_RMSGQFUL under submit_sm_resp only; 4.6.2's retryable code is another. */
|
||||
/** Asks the peer to keep the message and retry: RTHROTTLED is the SMSC's to send, so an ESME's is another. */
|
||||
function throttledStatus(carriedAs: string): ErrorName {
|
||||
return carriedAs === 'submit_sm' ? 'ESME_RTHROTTLED' : 'ESME_RX_T_APPN';
|
||||
}
|
||||
|
||||
export function refusedSegmentStatus(
|
||||
carriedAs: string,
|
||||
refusal: Refusal,
|
||||
@@ -30,7 +34,7 @@ export function refusedSegmentStatus(
|
||||
return spelling === 'sar' ? 'ESME_RINVTLVVAL' : 'ESME_RINVESMCLASS';
|
||||
}
|
||||
|
||||
return carriedAs === 'submit_sm' ? 'ESME_RMSGQFUL' : 'ESME_RX_T_APPN';
|
||||
return throttledStatus(carriedAs);
|
||||
}
|
||||
|
||||
const lostReasons: Record<LostGroup['reason'], string> = {
|
||||
@@ -212,6 +216,16 @@ export class IncomingRequests {
|
||||
* one request at a time never sends the second segment until the first has been answered.
|
||||
*/
|
||||
private async onMessage(pduObj: PduObject): Promise<void> {
|
||||
if (this.held.full()) {
|
||||
this.log.info('session - unanswered messages at their bound, asking the peer to retry', {
|
||||
cmdName: pduObj.cmdName,
|
||||
seqNr: pduObj.seqNr,
|
||||
});
|
||||
await this.session.sendReturn(pduObj, throttledStatus(this.carriedAs(pduObj)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const concat = concatOf(pduObj);
|
||||
|
||||
if (!concat) {
|
||||
|
||||
Reference in New Issue
Block a user