dgram: hide underscored Socket properties

dgram sockets have a fair number of exposed private properties.
This commit hides them all behind a single symbol property.

PR-URL: https://github.com/nodejs/node/pull/21923
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Wyatt Preul <wpreul@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
cjihrig 2018-07-21 00:56:12 -04:00
parent d497ebbf9c
commit 79e41cc7b0
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
10 changed files with 141 additions and 89 deletions

View File

@ -23,6 +23,7 @@
const assert = require('assert'); const assert = require('assert');
const errors = require('internal/errors'); const errors = require('internal/errors');
const { kStateSymbol } = require('internal/dgram');
const { const {
ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_TYPE,
ERR_MISSING_ARGS, ERR_MISSING_ARGS,
@ -115,36 +116,40 @@ function _createSocketHandle(address, port, addressType, fd, flags) {
return handle; return handle;
} }
const kOptionSymbol = Symbol('options symbol');
function Socket(type, listener) { function Socket(type, listener) {
EventEmitter.call(this); EventEmitter.call(this);
var lookup; var lookup;
let recvBufferSize;
let sendBufferSize;
this[kOptionSymbol] = {};
if (type !== null && typeof type === 'object') { if (type !== null && typeof type === 'object') {
var options = type; var options = type;
type = options.type; type = options.type;
lookup = options.lookup; lookup = options.lookup;
this[kOptionSymbol].recvBufferSize = options.recvBufferSize; recvBufferSize = options.recvBufferSize;
this[kOptionSymbol].sendBufferSize = options.sendBufferSize; sendBufferSize = options.sendBufferSize;
} }
var handle = newHandle(type, lookup); var handle = newHandle(type, lookup);
handle.owner = this; handle.owner = this;
this._handle = handle; this[async_id_symbol] = handle.getAsyncId();
this._receiving = false;
this._bindState = BIND_STATE_UNBOUND;
this[async_id_symbol] = this._handle.getAsyncId();
this.type = type; this.type = type;
this.fd = null; // compatibility hack this.fd = null; // compatibility hack
// If true - UV_UDP_REUSEADDR flag will be set
this._reuseAddr = options && options.reuseAddr;
if (typeof listener === 'function') if (typeof listener === 'function')
this.on('message', listener); this.on('message', listener);
this[kStateSymbol] = {
handle,
receiving: false,
bindState: BIND_STATE_UNBOUND,
queue: undefined,
reuseAddr: options && options.reuseAddr, // Use UV_UDP_REUSEADDR if true.
recvBufferSize,
sendBufferSize
};
} }
util.inherits(Socket, EventEmitter); util.inherits(Socket, EventEmitter);
@ -155,33 +160,37 @@ function createSocket(type, listener) {
function startListening(socket) { function startListening(socket) {
socket._handle.onmessage = onMessage; const state = socket[kStateSymbol];
state.handle.onmessage = onMessage;
// Todo: handle errors // Todo: handle errors
socket._handle.recvStart(); state.handle.recvStart();
socket._receiving = true; state.receiving = true;
socket._bindState = BIND_STATE_BOUND; state.bindState = BIND_STATE_BOUND;
socket.fd = -42; // compatibility hack socket.fd = -42; // compatibility hack
if (socket[kOptionSymbol].recvBufferSize) if (state.recvBufferSize)
bufferSize(socket, socket[kOptionSymbol].recvBufferSize, RECV_BUFFER); bufferSize(socket, state.recvBufferSize, RECV_BUFFER);
if (socket[kOptionSymbol].sendBufferSize) if (state.sendBufferSize)
bufferSize(socket, socket[kOptionSymbol].sendBufferSize, SEND_BUFFER); bufferSize(socket, state.sendBufferSize, SEND_BUFFER);
socket.emit('listening'); socket.emit('listening');
} }
function replaceHandle(self, newHandle) { function replaceHandle(self, newHandle) {
const state = self[kStateSymbol];
const oldHandle = state.handle;
// Set up the handle that we got from master. // Set up the handle that we got from master.
newHandle.lookup = self._handle.lookup; newHandle.lookup = oldHandle.lookup;
newHandle.bind = self._handle.bind; newHandle.bind = oldHandle.bind;
newHandle.send = self._handle.send; newHandle.send = oldHandle.send;
newHandle.owner = self; newHandle.owner = self;
// Replace the existing handle by the handle we got from master. // Replace the existing handle by the handle we got from master.
self._handle.close(); oldHandle.close();
self._handle = newHandle; state.handle = newHandle;
} }
function bufferSize(self, size, buffer) { function bufferSize(self, size, buffer) {
@ -189,7 +198,7 @@ function bufferSize(self, size, buffer) {
throw new ERR_SOCKET_BAD_BUFFER_SIZE(); throw new ERR_SOCKET_BAD_BUFFER_SIZE();
const ctx = {}; const ctx = {};
const ret = self._handle.bufferSize(size, buffer, ctx); const ret = self[kStateSymbol].handle.bufferSize(size, buffer, ctx);
if (ret === undefined) { if (ret === undefined) {
throw new ERR_SOCKET_BUFFER_SIZE(ctx); throw new ERR_SOCKET_BUFFER_SIZE(ctx);
} }
@ -200,11 +209,12 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
let port = port_; let port = port_;
healthCheck(this); healthCheck(this);
const state = this[kStateSymbol];
if (this._bindState !== BIND_STATE_UNBOUND) if (state.bindState !== BIND_STATE_UNBOUND)
throw new ERR_SOCKET_ALREADY_BOUND(); throw new ERR_SOCKET_ALREADY_BOUND();
this._bindState = BIND_STATE_BINDING; state.bindState = BIND_STATE_BINDING;
if (arguments.length && typeof arguments[arguments.length - 1] === 'function') if (arguments.length && typeof arguments[arguments.length - 1] === 'function')
this.once('listening', arguments[arguments.length - 1]); this.once('listening', arguments[arguments.length - 1]);
@ -236,9 +246,9 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
} }
// resolve address first // resolve address first
this._handle.lookup(address, (err, ip) => { state.handle.lookup(address, (err, ip) => {
if (err) { if (err) {
this._bindState = BIND_STATE_UNBOUND; state.bindState = BIND_STATE_UNBOUND;
this.emit('error', err); this.emit('error', err);
return; return;
} }
@ -247,7 +257,7 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
cluster = require('cluster'); cluster = require('cluster');
var flags = 0; var flags = 0;
if (this._reuseAddr) if (state.reuseAddr)
flags |= UV_UDP_REUSEADDR; flags |= UV_UDP_REUSEADDR;
if (cluster.isWorker && !exclusive) { if (cluster.isWorker && !exclusive) {
@ -255,11 +265,11 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
if (err) { if (err) {
var ex = exceptionWithHostPort(err, 'bind', ip, port); var ex = exceptionWithHostPort(err, 'bind', ip, port);
this.emit('error', ex); this.emit('error', ex);
this._bindState = BIND_STATE_UNBOUND; state.bindState = BIND_STATE_UNBOUND;
return; return;
} }
if (!this._handle) if (!state.handle)
// handle has been closed in the mean time. // handle has been closed in the mean time.
return handle.close(); return handle.close();
@ -274,14 +284,14 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
flags: flags flags: flags
}, onHandle); }, onHandle);
} else { } else {
if (!this._handle) if (!state.handle)
return; // handle has been closed in the mean time return; // handle has been closed in the mean time
const err = this._handle.bind(ip, port || 0, flags); const err = state.handle.bind(ip, port || 0, flags);
if (err) { if (err) {
var ex = exceptionWithHostPort(err, 'bind', ip, port); var ex = exceptionWithHostPort(err, 'bind', ip, port);
this.emit('error', ex); this.emit('error', ex);
this._bindState = BIND_STATE_UNBOUND; state.bindState = BIND_STATE_UNBOUND;
// Todo: close? // Todo: close?
return; return;
} }
@ -354,14 +364,16 @@ function fixBufferList(list) {
function enqueue(self, toEnqueue) { function enqueue(self, toEnqueue) {
const state = self[kStateSymbol];
// If the send queue hasn't been initialized yet, do it, and install an // If the send queue hasn't been initialized yet, do it, and install an
// event handler that flushes the send queue after binding is done. // event handler that flushes the send queue after binding is done.
if (!self._queue) { if (state.queue === undefined) {
self._queue = []; state.queue = [];
self.once('error', onListenError); self.once('error', onListenError);
self.once('listening', onListenSuccess); self.once('listening', onListenSuccess);
} }
self._queue.push(toEnqueue); state.queue.push(toEnqueue);
} }
@ -373,14 +385,15 @@ function onListenSuccess() {
function onListenError(err) { function onListenError(err) {
this.removeListener('listening', onListenSuccess); this.removeListener('listening', onListenSuccess);
this._queue = undefined; this[kStateSymbol].queue = undefined;
this.emit('error', new ERR_SOCKET_CANNOT_SEND()); this.emit('error', new ERR_SOCKET_CANNOT_SEND());
} }
function clearQueue() { function clearQueue() {
const queue = this._queue; const state = this[kStateSymbol];
this._queue = undefined; const queue = state.queue;
state.queue = undefined;
// Flush the send queue. // Flush the send queue.
for (var i = 0; i < queue.length; i++) for (var i = 0; i < queue.length; i++)
@ -446,7 +459,9 @@ Socket.prototype.send = function(buffer,
healthCheck(this); healthCheck(this);
if (this._bindState === BIND_STATE_UNBOUND) const state = this[kStateSymbol];
if (state.bindState === BIND_STATE_UNBOUND)
this.bind({ port: 0, exclusive: true }, null); this.bind({ port: 0, exclusive: true }, null);
if (list.length === 0) if (list.length === 0)
@ -454,7 +469,7 @@ Socket.prototype.send = function(buffer,
// If the socket hasn't been bound yet, push the outbound packet onto the // If the socket hasn't been bound yet, push the outbound packet onto the
// send queue and send after binding is complete. // send queue and send after binding is complete.
if (this._bindState !== BIND_STATE_BOUND) { if (state.bindState !== BIND_STATE_BOUND) {
enqueue(this, this.send.bind(this, list, port, address, callback)); enqueue(this, this.send.bind(this, list, port, address, callback));
return; return;
} }
@ -467,10 +482,12 @@ Socket.prototype.send = function(buffer,
); );
}; };
this._handle.lookup(address, afterDns); state.handle.lookup(address, afterDns);
}; };
function doSend(ex, self, ip, list, address, port, callback) { function doSend(ex, self, ip, list, address, port, callback) {
const state = self[kStateSymbol];
if (ex) { if (ex) {
if (typeof callback === 'function') { if (typeof callback === 'function') {
process.nextTick(callback, ex); process.nextTick(callback, ex);
@ -479,7 +496,7 @@ function doSend(ex, self, ip, list, address, port, callback) {
process.nextTick(() => self.emit('error', ex)); process.nextTick(() => self.emit('error', ex));
return; return;
} else if (!self._handle) { } else if (!state.handle) {
return; return;
} }
@ -492,7 +509,7 @@ function doSend(ex, self, ip, list, address, port, callback) {
req.oncomplete = afterSend; req.oncomplete = afterSend;
} }
var err = self._handle.send(req, var err = state.handle.send(req,
list, list,
list.length, list.length,
port, port,
@ -517,18 +534,21 @@ function afterSend(err, sent) {
} }
Socket.prototype.close = function(callback) { Socket.prototype.close = function(callback) {
const state = this[kStateSymbol];
const queue = state.queue;
if (typeof callback === 'function') if (typeof callback === 'function')
this.on('close', callback); this.on('close', callback);
if (this._queue) { if (queue !== undefined) {
this._queue.push(this.close.bind(this)); queue.push(this.close.bind(this));
return this; return this;
} }
healthCheck(this); healthCheck(this);
stopReceiving(this); stopReceiving(this);
this._handle.close(); state.handle.close();
this._handle = null; state.handle = null;
defaultTriggerAsyncIdScope(this[async_id_symbol], defaultTriggerAsyncIdScope(this[async_id_symbol],
process.nextTick, process.nextTick,
socketCloseNT, socketCloseNT,
@ -547,7 +567,7 @@ Socket.prototype.address = function() {
healthCheck(this); healthCheck(this);
var out = {}; var out = {};
var err = this._handle.getsockname(out); var err = this[kStateSymbol].handle.getsockname(out);
if (err) { if (err) {
throw errnoException(err, 'getsockname'); throw errnoException(err, 'getsockname');
} }
@ -557,7 +577,7 @@ Socket.prototype.address = function() {
Socket.prototype.setBroadcast = function(arg) { Socket.prototype.setBroadcast = function(arg) {
var err = this._handle.setBroadcast(arg ? 1 : 0); var err = this[kStateSymbol].handle.setBroadcast(arg ? 1 : 0);
if (err) { if (err) {
throw errnoException(err, 'setBroadcast'); throw errnoException(err, 'setBroadcast');
} }
@ -569,7 +589,7 @@ Socket.prototype.setTTL = function(ttl) {
throw new ERR_INVALID_ARG_TYPE('ttl', 'number', ttl); throw new ERR_INVALID_ARG_TYPE('ttl', 'number', ttl);
} }
var err = this._handle.setTTL(ttl); var err = this[kStateSymbol].handle.setTTL(ttl);
if (err) { if (err) {
throw errnoException(err, 'setTTL'); throw errnoException(err, 'setTTL');
} }
@ -583,7 +603,7 @@ Socket.prototype.setMulticastTTL = function(ttl) {
throw new ERR_INVALID_ARG_TYPE('ttl', 'number', ttl); throw new ERR_INVALID_ARG_TYPE('ttl', 'number', ttl);
} }
var err = this._handle.setMulticastTTL(ttl); var err = this[kStateSymbol].handle.setMulticastTTL(ttl);
if (err) { if (err) {
throw errnoException(err, 'setMulticastTTL'); throw errnoException(err, 'setMulticastTTL');
} }
@ -593,7 +613,7 @@ Socket.prototype.setMulticastTTL = function(ttl) {
Socket.prototype.setMulticastLoopback = function(arg) { Socket.prototype.setMulticastLoopback = function(arg) {
var err = this._handle.setMulticastLoopback(arg ? 1 : 0); var err = this[kStateSymbol].handle.setMulticastLoopback(arg ? 1 : 0);
if (err) { if (err) {
throw errnoException(err, 'setMulticastLoopback'); throw errnoException(err, 'setMulticastLoopback');
} }
@ -610,7 +630,7 @@ Socket.prototype.setMulticastInterface = function(interfaceAddress) {
'interfaceAddress', 'string', interfaceAddress); 'interfaceAddress', 'string', interfaceAddress);
} }
const err = this._handle.setMulticastInterface(interfaceAddress); const err = this[kStateSymbol].handle.setMulticastInterface(interfaceAddress);
if (err) { if (err) {
throw errnoException(err, 'setMulticastInterface'); throw errnoException(err, 'setMulticastInterface');
} }
@ -624,7 +644,8 @@ Socket.prototype.addMembership = function(multicastAddress,
throw new ERR_MISSING_ARGS('multicastAddress'); throw new ERR_MISSING_ARGS('multicastAddress');
} }
var err = this._handle.addMembership(multicastAddress, interfaceAddress); const { handle } = this[kStateSymbol];
var err = handle.addMembership(multicastAddress, interfaceAddress);
if (err) { if (err) {
throw errnoException(err, 'addMembership'); throw errnoException(err, 'addMembership');
} }
@ -639,7 +660,8 @@ Socket.prototype.dropMembership = function(multicastAddress,
throw new ERR_MISSING_ARGS('multicastAddress'); throw new ERR_MISSING_ARGS('multicastAddress');
} }
var err = this._handle.dropMembership(multicastAddress, interfaceAddress); const { handle } = this[kStateSymbol];
var err = handle.dropMembership(multicastAddress, interfaceAddress);
if (err) { if (err) {
throw errnoException(err, 'dropMembership'); throw errnoException(err, 'dropMembership');
} }
@ -647,7 +669,7 @@ Socket.prototype.dropMembership = function(multicastAddress,
function healthCheck(socket) { function healthCheck(socket) {
if (!socket._handle) { if (!socket[kStateSymbol].handle) {
// Error message from dgram_legacy.js. // Error message from dgram_legacy.js.
throw new ERR_SOCKET_DGRAM_NOT_RUNNING(); throw new ERR_SOCKET_DGRAM_NOT_RUNNING();
} }
@ -655,11 +677,13 @@ function healthCheck(socket) {
function stopReceiving(socket) { function stopReceiving(socket) {
if (!socket._receiving) const state = socket[kStateSymbol];
if (!state.receiving)
return; return;
socket._handle.recvStop(); state.handle.recvStop();
socket._receiving = false; state.receiving = false;
socket.fd = null; // compatibility hack socket.fd = null; // compatibility hack
} }
@ -675,16 +699,20 @@ function onMessage(nread, handle, buf, rinfo) {
Socket.prototype.ref = function() { Socket.prototype.ref = function() {
if (this._handle) const handle = this[kStateSymbol].handle;
this._handle.ref();
if (handle)
handle.ref();
return this; return this;
}; };
Socket.prototype.unref = function() { Socket.prototype.unref = function() {
if (this._handle) const handle = this[kStateSymbol].handle;
this._handle.unref();
if (handle)
handle.unref();
return this; return this;
}; };

View File

@ -32,6 +32,7 @@ const { isUint8Array } = require('internal/util/types');
const spawn_sync = process.binding('spawn_sync'); const spawn_sync = process.binding('spawn_sync');
const { HTTPParser } = process.binding('http_parser'); const { HTTPParser } = process.binding('http_parser');
const { freeParser } = require('_http_common'); const { freeParser } = require('_http_common');
const { kStateSymbol } = require('internal/dgram');
const { const {
UV_EACCES, UV_EACCES,
@ -181,7 +182,7 @@ const handleConversion = {
send: function(message, socket, options) { send: function(message, socket, options) {
message.dgramType = socket.type; message.dgramType = socket.type;
return socket._handle; return socket[kStateSymbol].handle;
}, },
got: function(message, handle, emit) { got: function(message, handle, emit) {

4
lib/internal/dgram.js Normal file
View File

@ -0,0 +1,4 @@
'use strict';
const kStateSymbol = Symbol('state symbol');
module.exports = { kStateSymbol };

View File

@ -104,6 +104,7 @@
'lib/internal/crypto/sig.js', 'lib/internal/crypto/sig.js',
'lib/internal/crypto/util.js', 'lib/internal/crypto/util.js',
'lib/internal/constants.js', 'lib/internal/constants.js',
'lib/internal/dgram.js',
'lib/internal/dns/promises.js', 'lib/internal/dns/promises.js',
'lib/internal/dns/utils.js', 'lib/internal/dns/utils.js',
'lib/internal/domexception.js', 'lib/internal/domexception.js',

View File

@ -1,13 +1,16 @@
// Flags: --expose-internals
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const dgram = require('dgram'); const dgram = require('dgram');
const { kStateSymbol } = require('internal/dgram');
const socket = dgram.createSocket('udp4'); const socket = dgram.createSocket('udp4');
const lookup = socket._handle.lookup; const { handle } = socket[kStateSymbol];
const lookup = handle.lookup;
// Test the scenario where the socket is closed during a bind operation. // Test the scenario where the socket is closed during a bind operation.
socket._handle.bind = common.mustNotCall('bind() should not be called.'); handle.bind = common.mustNotCall('bind() should not be called.');
socket._handle.lookup = common.mustCall(function(address, callback) { handle.lookup = common.mustCall(function(address, callback) {
socket.close(common.mustCall(() => { socket.close(common.mustCall(() => {
lookup.call(this, address, callback); lookup.call(this, address, callback);
})); }));

View File

@ -19,6 +19,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE. // USE OR OTHER DEALINGS IN THE SOFTWARE.
// Flags: --expose-internals
'use strict'; 'use strict';
// Ensure that if a dgram socket is closed before the DNS lookup completes, it // Ensure that if a dgram socket is closed before the DNS lookup completes, it
// won't crash. // won't crash.
@ -26,11 +27,12 @@
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const dgram = require('dgram'); const dgram = require('dgram');
const { kStateSymbol } = require('internal/dgram');
const buf = Buffer.alloc(1024, 42); const buf = Buffer.alloc(1024, 42);
let socket = dgram.createSocket('udp4'); let socket = dgram.createSocket('udp4');
const handle = socket._handle; const { handle } = socket[kStateSymbol];
// get a random port for send // get a random port for send
const portGetter = dgram.createSocket('udp4') const portGetter = dgram.createSocket('udp4')

View File

@ -1,8 +1,11 @@
// Flags: --expose-internals
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const dgram = require('dgram'); const dgram = require('dgram');
const { kStateSymbol } = require('internal/dgram');
const s = dgram.createSocket('udp4'); const s = dgram.createSocket('udp4');
const { handle } = s[kStateSymbol];
s.on('error', common.mustCall((err) => { s.on('error', common.mustCall((err) => {
s.close(); s.close();
@ -13,4 +16,4 @@ s.on('error', common.mustCall((err) => {
})); }));
s.on('message', common.mustNotCall('no message should be received.')); s.on('message', common.mustNotCall('no message should be received.'));
s.bind(common.mustCall(() => s._handle.onmessage(-1, s._handle, null, null))); s.bind(common.mustCall(() => handle.onmessage(-1, handle, null, null)));

View File

@ -1,7 +1,9 @@
// Flags: --expose-internals
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const dgram = require('dgram'); const dgram = require('dgram');
const { kStateSymbol } = require('internal/dgram');
const mockError = new Error('mock DNS error'); const mockError = new Error('mock DNS error');
function getSocket(callback) { function getSocket(callback) {
@ -9,7 +11,7 @@ function getSocket(callback) {
socket.on('message', common.mustNotCall('Should not receive any messages.')); socket.on('message', common.mustNotCall('Should not receive any messages.'));
socket.bind(common.mustCall(() => { socket.bind(common.mustCall(() => {
socket._handle.lookup = function(address, callback) { socket[kStateSymbol].handle.lookup = function(address, callback) {
process.nextTick(callback, mockError); process.nextTick(callback, mockError);
}; };
@ -57,7 +59,7 @@ getSocket((socket) => {
); );
}); });
socket._handle.send = function() { socket[kStateSymbol].handle.send = function() {
return errCode; return errCode;
}; };

View File

@ -1,3 +1,4 @@
// Flags: --expose-internals
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
@ -25,22 +26,25 @@ const strictEqual = require('assert').strictEqual;
const dgram = require('dgram'); const dgram = require('dgram');
const { kStateSymbol } = require('internal/dgram');
// dgram ipv4 // dgram ipv4
{ {
const sock4 = dgram.createSocket('udp4'); const sock4 = dgram.createSocket('udp4');
strictEqual(Object.getPrototypeOf(sock4._handle).hasOwnProperty('hasRef'), const handle = sock4[kStateSymbol].handle;
strictEqual(Object.getPrototypeOf(handle).hasOwnProperty('hasRef'),
true, 'udp_wrap: ipv4: hasRef() missing'); true, 'udp_wrap: ipv4: hasRef() missing');
strictEqual(sock4._handle.hasRef(), strictEqual(handle.hasRef(),
true, 'udp_wrap: ipv4: not initially refed'); true, 'udp_wrap: ipv4: not initially refed');
sock4.unref(); sock4.unref();
strictEqual(sock4._handle.hasRef(), strictEqual(handle.hasRef(),
false, 'udp_wrap: ipv4: unref() ineffective'); false, 'udp_wrap: ipv4: unref() ineffective');
sock4.ref(); sock4.ref();
strictEqual(sock4._handle.hasRef(), strictEqual(handle.hasRef(),
true, 'udp_wrap: ipv4: ref() ineffective'); true, 'udp_wrap: ipv4: ref() ineffective');
sock4._handle.close(common.mustCall(() => handle.close(common.mustCall(() =>
strictEqual(sock4._handle.hasRef(), strictEqual(handle.hasRef(),
false, 'udp_wrap: ipv4: not unrefed on close'))); false, 'udp_wrap: ipv4: not unrefed on close')));
} }
@ -48,18 +52,20 @@ const dgram = require('dgram');
// dgram ipv6 // dgram ipv6
{ {
const sock6 = dgram.createSocket('udp6'); const sock6 = dgram.createSocket('udp6');
strictEqual(Object.getPrototypeOf(sock6._handle).hasOwnProperty('hasRef'), const handle = sock6[kStateSymbol].handle;
strictEqual(Object.getPrototypeOf(handle).hasOwnProperty('hasRef'),
true, 'udp_wrap: ipv6: hasRef() missing'); true, 'udp_wrap: ipv6: hasRef() missing');
strictEqual(sock6._handle.hasRef(), strictEqual(handle.hasRef(),
true, 'udp_wrap: ipv6: not initially refed'); true, 'udp_wrap: ipv6: not initially refed');
sock6.unref(); sock6.unref();
strictEqual(sock6._handle.hasRef(), strictEqual(handle.hasRef(),
false, 'udp_wrap: ipv6: unref() ineffective'); false, 'udp_wrap: ipv6: unref() ineffective');
sock6.ref(); sock6.ref();
strictEqual(sock6._handle.hasRef(), strictEqual(handle.hasRef(),
true, 'udp_wrap: ipv6: ref() ineffective'); true, 'udp_wrap: ipv6: ref() ineffective');
sock6._handle.close(common.mustCall(() => handle.close(common.mustCall(() =>
strictEqual(sock6._handle.hasRef(), strictEqual(handle.hasRef(),
false, 'udp_wrap: ipv6: not unrefed on close'))); false, 'udp_wrap: ipv6: not unrefed on close')));
} }

View File

@ -1,8 +1,10 @@
// Flags: --expose-internals
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const dgram = require('dgram'); const dgram = require('dgram');
const dns = require('dns'); const dns = require('dns');
const { kStateSymbol } = require('internal/dgram');
// Monkey patch dns.lookup() so that it always fails. // Monkey patch dns.lookup() so that it always fails.
dns.lookup = function(address, family, callback) { dns.lookup = function(address, family, callback) {
@ -25,8 +27,8 @@ socket.on('error', (err) => {
// should also be two listeners - this function and the dgram internal one // should also be two listeners - this function and the dgram internal one
// time error handler. // time error handler.
dnsFailures++; dnsFailures++;
assert(Array.isArray(socket._queue)); assert(Array.isArray(socket[kStateSymbol].queue));
assert.strictEqual(socket._queue.length, 1); assert.strictEqual(socket[kStateSymbol].queue.length, 1);
assert.strictEqual(socket.listenerCount('error'), 2); assert.strictEqual(socket.listenerCount('error'), 2);
return; return;
} }
@ -35,7 +37,7 @@ socket.on('error', (err) => {
// On error, the queue should be destroyed and this function should be // On error, the queue should be destroyed and this function should be
// the only listener. // the only listener.
sendFailures++; sendFailures++;
assert.strictEqual(socket._queue, undefined); assert.strictEqual(socket[kStateSymbol].queue, undefined);
assert.strictEqual(socket.listenerCount('error'), 1); assert.strictEqual(socket.listenerCount('error'), 1);
return; return;
} }