Skip to content

Commit 1b2e294

Browse files
committed
dgram: don't hide implicit bind errors
When dgram socket implicit binding fails, an attempt is made to clean up the send queue. This was originally implemented using an 'error' handler that performed cleanup and then emitted a fake error, which concealed the original error. This was done to prevent cases where the same error was emitted twice. Now that the errorMonitor event is available, use that to perform the cleanup without impacting the actual error handling. PR-URL: #31958 Refs: nodejs/help#2484 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent fb26b13 commit 1b2e294

File tree

2 files changed

+17
-36
lines changed

2 files changed

+17
-36
lines changed

lib/dgram.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ const {
4545
ERR_SOCKET_BAD_BUFFER_SIZE,
4646
ERR_SOCKET_BAD_PORT,
4747
ERR_SOCKET_BUFFER_SIZE,
48-
ERR_SOCKET_CANNOT_SEND,
4948
ERR_SOCKET_DGRAM_IS_CONNECTED,
5049
ERR_SOCKET_DGRAM_NOT_CONNECTED,
5150
ERR_SOCKET_DGRAM_NOT_RUNNING,
@@ -506,23 +505,22 @@ function enqueue(self, toEnqueue) {
506505
// event handler that flushes the send queue after binding is done.
507506
if (state.queue === undefined) {
508507
state.queue = [];
509-
self.once('error', onListenError);
508+
self.once(EventEmitter.errorMonitor, onListenError);
510509
self.once('listening', onListenSuccess);
511510
}
512511
state.queue.push(toEnqueue);
513512
}
514513

515514

516515
function onListenSuccess() {
517-
this.removeListener('error', onListenError);
516+
this.removeListener(EventEmitter.errorMonitor, onListenError);
518517
clearQueue.call(this);
519518
}
520519

521520

522521
function onListenError(err) {
523522
this.removeListener('listening', onListenSuccess);
524523
this[kStateSymbol].queue = undefined;
525-
this.emit('error', new ERR_SOCKET_CANNOT_SEND());
526524
}
527525

528526

test/sequential/test-dgram-implicit-bind-failure.js

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,31 @@
22
'use strict';
33
const common = require('../common');
44
const assert = require('assert');
5+
const EventEmitter = require('events');
56
const dgram = require('dgram');
67
const dns = require('dns');
78
const { kStateSymbol } = require('internal/dgram');
9+
const mockError = new Error('fake DNS');
810

911
// Monkey patch dns.lookup() so that it always fails.
1012
dns.lookup = function(address, family, callback) {
11-
process.nextTick(() => { callback(new Error('fake DNS')); });
13+
process.nextTick(() => { callback(mockError); });
1214
};
1315

1416
const socket = dgram.createSocket('udp4');
15-
let dnsFailures = 0;
16-
let sendFailures = 0;
1717

18-
process.on('exit', () => {
19-
assert.strictEqual(dnsFailures, 3);
20-
assert.strictEqual(sendFailures, 3);
21-
});
22-
23-
socket.on('error', (err) => {
24-
if (/^Error: fake DNS$/.test(err)) {
25-
// The DNS lookup should fail since it is monkey patched. At that point in
26-
// time, the send queue should be populated with the send() operation. There
27-
// should also be two listeners - this function and the dgram internal one
28-
// time error handler.
29-
dnsFailures++;
30-
assert(Array.isArray(socket[kStateSymbol].queue));
31-
assert.strictEqual(socket[kStateSymbol].queue.length, 1);
32-
assert.strictEqual(socket.listenerCount('error'), 2);
33-
return;
34-
}
35-
36-
if (err.code === 'ERR_SOCKET_CANNOT_SEND') {
37-
// On error, the queue should be destroyed and this function should be
38-
// the only listener.
39-
sendFailures++;
40-
assert.strictEqual(socket[kStateSymbol].queue, undefined);
41-
assert.strictEqual(socket.listenerCount('error'), 1);
42-
return;
43-
}
44-
45-
assert.fail(`Unexpected error: ${err}`);
46-
});
18+
socket.on(EventEmitter.errorMonitor, common.mustCall((err) => {
19+
// The DNS lookup should fail since it is monkey patched. At that point in
20+
// time, the send queue should be populated with the send() operation.
21+
assert.strictEqual(err, mockError);
22+
assert(Array.isArray(socket[kStateSymbol].queue));
23+
assert.strictEqual(socket[kStateSymbol].queue.length, 1);
24+
}, 3));
25+
26+
socket.on('error', common.mustCall((err) => {
27+
assert.strictEqual(err, mockError);
28+
assert.strictEqual(socket[kStateSymbol].queue, undefined);
29+
}, 3));
4730

4831
// Initiate a few send() operations, which will fail.
4932
socket.send('foobar', common.PORT, 'localhost');

0 commit comments

Comments
 (0)