diff --git a/lib/dgram.js b/lib/dgram.js index d29d1e7b190f3a..94f44d520220ff 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -211,8 +211,21 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) { state.bindState = BIND_STATE_BINDING; - if (arguments.length && typeof arguments[arguments.length - 1] === 'function') - this.once('listening', arguments[arguments.length - 1]); + const cb = arguments.length && arguments[arguments.length - 1]; + if (typeof cb === 'function') { + function removeListeners() { + this.removeListener('error', removeListeners); + this.removeListener('listening', onListening); + } + + function onListening() { + removeListeners.call(this); + cb.call(this); + } + + this.on('error', removeListeners); + this.on('listening', onListening); + } if (port instanceof UDP) { replaceHandle(this, port); @@ -240,8 +253,8 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) { }, (err) => { // Callback to handle error. const ex = errnoException(err, 'open'); - this.emit('error', ex); state.bindState = BIND_STATE_UNBOUND; + this.emit('error', ex); }); return this; } @@ -309,8 +322,8 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) { }, (err) => { // Callback to handle error. const ex = exceptionWithHostPort(err, 'bind', ip, port); - this.emit('error', ex); state.bindState = BIND_STATE_UNBOUND; + this.emit('error', ex); }); } else { if (!state.handle) @@ -319,8 +332,8 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) { const err = state.handle.bind(ip, port || 0, flags); if (err) { const ex = exceptionWithHostPort(err, 'bind', ip, port); - this.emit('error', ex); state.bindState = BIND_STATE_UNBOUND; + this.emit('error', ex); // Todo: close? return; } diff --git a/test/parallel/test-dgram-bind-error-repeat.js b/test/parallel/test-dgram-bind-error-repeat.js new file mode 100644 index 00000000000000..a520d30a519cd2 --- /dev/null +++ b/test/parallel/test-dgram-bind-error-repeat.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); +const dgram = require('dgram'); + +// Regression test for https://github.com/nodejs/node/issues/30209 +// No warning should be emitted when re-trying `.bind()` on UDP sockets +// repeatedly. + +process.on('warning', common.mustNotCall()); + +const reservePortSocket = dgram.createSocket('udp4'); +reservePortSocket.bind(() => { + const { port } = reservePortSocket.address(); + + const newSocket = dgram.createSocket('udp4'); + + let errors = 0; + newSocket.on('error', common.mustCall(() => { + if (++errors < 20) { + newSocket.bind(port, common.mustNotCall()); + } else { + newSocket.close(); + reservePortSocket.close(); + } + }, 20)); + newSocket.bind(port, common.mustNotCall()); +});