• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rustymotors / server / 22336468702

24 Feb 2026 04:18AM UTC coverage: 37.969% (+2.1%) from 35.9%
22336468702

push

github

web-flow
Fix remaining peer connection reset crash vectors (#2814)

- Attach socket error handler before IP whitelist check in
onSocketConnection so non-whitelisted connections that reset don't emit
unhandled error events
- Destroy rejected sockets instead of just returning to ensure cleanup
- Stop sendQueue (not just receiveQueue) on ECONNRESET in npsPortRouter
to prevent the dead-socket write loop that fires repeated error events

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>

983 of 1184 branches covered (83.02%)

Branch coverage included in aggregate %.

186 of 467 new or added lines in 16 files covered. (39.83%)

7 existing lines in 4 files now uncovered.

7263 of 20534 relevant lines covered (35.37%)

5.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.92
/packages/shared/src/MessageNode.ts
1
import {
1✔
2
    checkMinLength,
3
    checkSize2,
4
    checkSize4,
5
    sliceBuff,
6
} from './helpers.js';
7
import type { MCOTSMessage, Serializable } from './types.js';
8

9
export class MessageNodeBody implements Serializable {
1✔
10
    protected body_: Buffer;
1✔
11

12
    constructor() {
1✔
13
        this.body_ = Buffer.alloc(4);
21✔
14
    }
21✔
15

16
    get sizeOf() {
1✔
17
        return this.body_.byteLength;
21✔
18
    }
21✔
19

20
    serialize() {
1✔
21
        return this.body_;
14✔
22
    }
14✔
23

24
    deserialize(buf: Buffer) {
1✔
25
        checkMinLength(buf, 2);
19✔
26
        this.body_ = buf;
19✔
27
    }
19✔
28

29
    get msgNumber() {
1✔
30
        return this.body_.readInt16LE();
5✔
31
    }
5✔
32

33
    set msgNumber(val: number) {
1✔
34
        checkSize2(val);
6✔
35
        this.body_.writeInt16LE(val);
6✔
36
    }
6✔
37

38
    toString() {
1✔
NEW
39
        return this.body_.toString("hex")
×
NEW
40
    }
×
41
}
1✔
42

43
export class MessageNode implements MCOTSMessage {
1✔
44
    protected connectionId_: string;
1✔
45
    protected msgLength_: number; // 2
20✔
46
    protected signature_: string; // 4
20✔
47
    protected sequence_: number; // 4
20✔
48
    protected flags_: number; // 1
20✔
49
    protected body_: MessageNodeBody;
20✔
50

51
    constructor() {
1✔
52
        this.connectionId_ = '';
20✔
53
        this.msgLength_ = 0;
20✔
54
        this.signature_ = 'TOMC';
20✔
55
        this.sequence_ = 0;
20✔
56
        this.flags_ = 0;
20✔
57
        this.body_ = new MessageNodeBody();
20✔
58
    }
20✔
59

60
    get sizeOf() {
1✔
61
        return 11 + this.body_.sizeOf;
9✔
62
    }
9✔
63

64
    serialize() {
1✔
65
        checkSize4(this.signature_.length);
8✔
66
        this.msgLength_ = 9 + this.body_.sizeOf;
8✔
67
        const buf = Buffer.alloc(this.sizeOf);
8✔
68
        let offset = 0;
8✔
69
        // Use unsigned 16-bit to support messages larger than 32767 bytes
70
        buf.writeUInt16LE(this.msgLength_, offset);
8✔
71
        offset = offset + 2;
8✔
72
        buf.write(this.signature_, offset, 'utf8');
8✔
73
        offset = offset + 4;
8✔
74
        buf.writeInt32LE(this.sequence_, offset);
8✔
75
        offset = offset + 4;
8✔
76
        buf.writeInt8(this.flags_, offset);
8✔
77
        offset = offset + 1;
8✔
78
        this.body_.serialize().copy(buf, offset);
8✔
79
        return buf;
8✔
80
    }
8✔
81

82
    deserialize(buf: Buffer) {
1✔
83
        checkMinLength(buf, 11);
3✔
84
        let offset = 0;
3✔
85
        // Use unsigned 16-bit to match serialize() and support messages larger than 32767 bytes
86
        this.msgLength_ = buf.readUInt16LE(offset);
3✔
87
        offset = offset + 2;
3✔
88
        this.signature_ = sliceBuff(buf, offset, 4).toString('utf8');
3✔
89
        offset = offset + 4;
3✔
90
        this.sequence_ = buf.readInt32LE(offset);
3✔
91
        offset = offset + 4;
3✔
92
        this.flags_ = buf.readInt8(offset);
3✔
93
        offset = offset + 1;
3✔
94
        this.body_.deserialize(buf.subarray(offset));
3✔
95
    }
3✔
96

97
    get connectionId() {
1✔
98
        return this.connectionId_;
×
99
    }
×
100

101
    set connectionId(val: string) {
1✔
102
        this.connectionId_ = val;
×
103
    }
×
104

105
    get length() {
1✔
106
        return this.msgLength_;
9✔
107
    }
9✔
108

109
    isSignatureValid() {
1✔
110
        return this.signature_ === 'TOMC';
4✔
111
    }
4✔
112

113
    get signature() {
1✔
114
        return this.signature_;
10✔
115
    }
10✔
116

117
    get sequence() {
1✔
118
        return this.sequence_;
13✔
119
    }
13✔
120

121
    set sequence(val: number) {
1✔
122
        this.sequence_ = val;
9✔
123
    }
9✔
124

125
    isSequenceSet() {
1✔
126
        return this.sequence_ !== 0;
2✔
127
    }
2✔
128

129
    get flags() {
1✔
130
        return this.flags_;
9✔
131
    }
9✔
132

133
    isPayloadEncrypted(): boolean {
1✔
134
        // Does the flags bitmask contain have 0x08 set?
135
        return (this.flags_ & 0x08) != 0;
4✔
136
    }
4✔
137

138
    isPayloadCompressed(): boolean {
1✔
139
        return (this.flags_ & 0x02) != 0;
4✔
140
    }
4✔
141

142
    setPayloadEncryption(encrypted: boolean): void {
1✔
143
        if (encrypted) {
4✔
144
            this.flags_ |= 0x08;
3✔
145
        } else {
4✔
146
            this.flags_ &= ~0x08;
1✔
147
        }
1✔
148
    }
4✔
149

150
    setPayloadCompression(encrypted: boolean): void {
1✔
151
        if (encrypted) {
3✔
152
            this.flags_ |= 0x02;
2✔
153
        } else {
3✔
154
            this.flags_ &= ~0x02;
1✔
155
        }
1✔
156
    }
3✔
157

158
    getBody() {
1✔
159
        return this.body_;
3✔
160
    }
3✔
161

162
    setBody(body: MessageNodeBody) {
1✔
163
        this.msgLength_ = body.sizeOf;
1✔
164
        this.body_ = body;
1✔
165
    }
1✔
166

167
    get msgNo() {
1✔
168
        return this.body_.msgNumber;
5✔
169
    }
5✔
170

171
    set msgNo(val: number) {
1✔
172
        checkSize2(val);
5✔
173
        this.body_.msgNumber = val;
5✔
174
    }
5✔
175

176
    toString() {
1✔
177
        return `MessageNode: ${JSON.stringify(this)}`;
3✔
178
    }
3✔
179

180
    // TODO: change usage of these
181

182
    /**
183
     * @deprecated
184
     *
185
     * see {@link signature} and {@link length}
186
     */
187
    get header() {
1✔
188
        return {
1✔
189
            mcoSig: this.signature,
1✔
190
            length: this.length,
1✔
191
        };
1✔
192
    }
1✔
193

194
    /**
195
     * @deprecated
196
     *
197
     * see {@link sequence}
198
     */
199
    get seq() {
1✔
200
        return this.sequence;
1✔
201
    }
1✔
202

203
    /**
204
     * @deprecated
205
     *
206
     * see {@link getBody} and {@link setBody}
207
     */
208
    get data() {
1✔
209
        return this.body_.serialize();
6✔
210
    }
6✔
211

212
    /**
213
     * @deprecated
214
     */
215
    getDataBuffer() {
1✔
216
        return this.body_;
×
217
    }
×
218

219
    /**
220
     * @deprecated
221
     */
222
    setDataBuffer(val: Buffer) {
1✔
223
        this.body_.deserialize(val);
15✔
224
    }
15✔
225

226
    /**
227
     * @deprecated
228
     */
229
    getByteSize() {
1✔
230
        return 11 + this.body_.sizeOf;
×
231
    }
×
232

233
    /**
234
     * @deprecated
235
     */
236
    setSequence(val: number) {
1✔
237
        this.sequence_ = val;
×
238
    }
×
239

240
    /**
241
     * @deprecated
242
     */
243
    setLength(val: number) {
1✔
244
        this.msgLength_ = val;
×
245
    }
×
246

247
    /**
248
     * @deprecated
249
     */
250
    setSignature(val: string) {
1✔
251
        this.signature_ = val;
1✔
252
    }
1✔
253

254
    /**
255
     * @deprecated
256
     */
257
    getMessageId() {
1✔
258
        return this.msgNo;
×
259
    }
×
260

261
    /**
262
     * @deprecated
263
     */
264
    setMessageId(val: number) {
1✔
265
        this.setMessageId(val);
×
266
    }
×
267

268
    /**
269
     * @deprecated
270
     */
271
    getLength() {
1✔
272
        return this.msgLength_;
×
273
    }
×
274

275
    /**
276
     * @deprecated
277
     */
278
    getSignature() {
1✔
279
        return this.signature_;
×
280
    }
×
281

282
    /**
283
     * @deprecated
284
     */
285
    getSequence() {
1✔
286
        return this.sequence_;
×
287
    }
×
288

289
    /**
290
     * @deprecated
291
     */
292
    isValidSignature() {
1✔
293
        return this.isSignatureValid();
×
294
    }
×
295

296
    /**
297
     * @deprecated
298
     */
299
    ensureValidSignature() {
1✔
300
        if (!this.isSignatureValid()) {
2✔
301
            throw new Error('Signature is not valid');
1✔
302
        }
1✔
303
    }
2✔
304

305
    /**
306
     * @deprecated
307
     */
308
    ensureNonZeroSequence() {
1✔
309
        if (this.sequence_ === 0) {
2✔
310
            throw new Error('please set sequence');
1✔
311
        }
1✔
312
    }
2✔
313

314
    /**
315
     * @deprecated
316
     */
317
    get messageId() {
1✔
318
        return this.msgNo;
×
319
    }
×
320

321
    /**
322
     * @deprecated
323
     */
324
    get messageSource() {
1✔
325
        return null;
×
326
    }
×
327

328
    /**
329
     * @deprecated
330
     */
331
    get _data() {
1✔
332
        return this.body_;
×
333
    }
×
334

335
    /**
336
     * @deprecated
337
     */
338
    _assertEnoughData() {
1✔
339
        return false;
×
340
    }
×
341

342
    /**
343
     * @deprecated
344
     */
345
    _doDeserialize() {}
1✔
346

347
    /**
348
     * @deprecated
349
     */
350

351
    _doSerialize() {}
1✔
352

353
    /**
354
     * @deprecated
355
     */
356
    toHexString() {
1✔
357
        return this.serialize().toString('hex');
1✔
358
    }
1✔
359

360
    /**
361
     * @deprecated
362
     */
363
    get sequenceNumber() {
1✔
364
        return this.sequence_
1✔
365
        }
1✔
366
    }
1✔
367

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc