node/lib/dgram.js

972 lines
24 KiB
JavaScript
Raw Normal View History

// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
2011-08-20 01:47:40 +00:00
const { Object } = primordials;
const errors = require('internal/errors');
const {
kStateSymbol,
_createSocketHandle,
newHandle,
} = require('internal/dgram');
const { guessHandleType } = internalBinding('util');
const {
isLegalPort,
} = require('internal/net');
const {
ERR_INVALID_ARG_TYPE,
ERR_MISSING_ARGS,
ERR_SOCKET_ALREADY_BOUND,
ERR_SOCKET_BAD_BUFFER_SIZE,
ERR_SOCKET_BAD_PORT,
ERR_SOCKET_BUFFER_SIZE,
ERR_SOCKET_CANNOT_SEND,
ERR_SOCKET_DGRAM_IS_CONNECTED,
ERR_SOCKET_DGRAM_NOT_CONNECTED,
ERR_SOCKET_DGRAM_NOT_RUNNING,
ERR_INVALID_FD_TYPE
} = errors.codes;
const {
isInt32,
validateString,
validateNumber
} = require('internal/validators');
const { Buffer } = require('buffer');
const { deprecate } = require('internal/util');
const { isUint8Array } = require('internal/util/types');
const EventEmitter = require('events');
const {
defaultTriggerAsyncIdScope,
symbols: { async_id_symbol, owner_symbol }
} = require('internal/async_hooks');
const { UV_UDP_REUSEADDR } = internalBinding('constants').os;
2011-08-20 01:47:40 +00:00
const {
constants: { UV_UDP_IPV6ONLY },
UDP,
SendWrap
} = internalBinding('udp_wrap');
2011-08-20 01:47:40 +00:00
const BIND_STATE_UNBOUND = 0;
const BIND_STATE_BINDING = 1;
const BIND_STATE_BOUND = 2;
const CONNECT_STATE_DISCONNECTED = 0;
const CONNECT_STATE_CONNECTING = 1;
const CONNECT_STATE_CONNECTED = 2;
const RECV_BUFFER = true;
const SEND_BUFFER = false;
// Lazily loaded
2013-01-22 22:52:20 +00:00
var cluster = null;
2011-08-20 01:47:40 +00:00
const errnoException = errors.errnoException;
const exceptionWithHostPort = errors.exceptionWithHostPort;
2011-08-20 01:47:40 +00:00
function Socket(type, listener) {
EventEmitter.call(this);
var lookup;
let recvBufferSize;
let sendBufferSize;
2011-08-20 01:47:40 +00:00
let options;
if (type !== null && typeof type === 'object') {
options = type;
type = options.type;
lookup = options.lookup;
recvBufferSize = options.recvBufferSize;
sendBufferSize = options.sendBufferSize;
}
const handle = newHandle(type, lookup);
handle[owner_symbol] = this;
2011-08-20 01:47:40 +00:00
this[async_id_symbol] = handle.getAsyncId();
2011-08-20 01:47:40 +00:00
this.type = type;
if (typeof listener === 'function')
2011-08-20 01:47:40 +00:00
this.on('message', listener);
this[kStateSymbol] = {
handle,
receiving: false,
bindState: BIND_STATE_UNBOUND,
connectState: CONNECT_STATE_DISCONNECTED,
queue: undefined,
reuseAddr: options && options.reuseAddr, // Use UV_UDP_REUSEADDR if true.
ipv6Only: options && options.ipv6Only,
recvBufferSize,
sendBufferSize
};
2011-08-20 01:47:40 +00:00
}
Object.setPrototypeOf(Socket.prototype, EventEmitter.prototype);
Object.setPrototypeOf(Socket, EventEmitter);
2011-08-20 01:47:40 +00:00
function createSocket(type, listener) {
2011-08-20 01:47:40 +00:00
return new Socket(type, listener);
}
2011-08-20 01:47:40 +00:00
2013-01-22 22:52:20 +00:00
function startListening(socket) {
const state = socket[kStateSymbol];
state.handle.onmessage = onMessage;
2013-01-22 22:52:20 +00:00
// Todo: handle errors
state.handle.recvStart();
state.receiving = true;
state.bindState = BIND_STATE_BOUND;
2013-01-22 22:52:20 +00:00
if (state.recvBufferSize)
bufferSize(socket, state.recvBufferSize, RECV_BUFFER);
if (state.sendBufferSize)
bufferSize(socket, state.sendBufferSize, SEND_BUFFER);
2013-01-22 22:52:20 +00:00
socket.emit('listening');
}
function replaceHandle(self, newHandle) {
const state = self[kStateSymbol];
const oldHandle = state.handle;
2013-01-22 22:52:20 +00:00
// Set up the handle that we got from master.
newHandle.lookup = oldHandle.lookup;
newHandle.bind = oldHandle.bind;
newHandle.send = oldHandle.send;
newHandle[owner_symbol] = self;
// Replace the existing handle by the handle we got from master.
oldHandle.close();
state.handle = newHandle;
// Check if the udp handle was connected and set the state accordingly
if (isConnected(self))
state.connectState = CONNECT_STATE_CONNECTED;
}
function bufferSize(self, size, buffer) {
if (size >>> 0 !== size)
throw new ERR_SOCKET_BAD_BUFFER_SIZE();
const ctx = {};
const ret = self[kStateSymbol].handle.bufferSize(size, buffer, ctx);
if (ret === undefined) {
errors: improve SystemError messages This commit improves the SystemError messages by allowing user to combine a custom message and the libuv error message. Also since we now prefer use subclasses to construct the errors instead of using `new errors.SystemError()` directly, this removes the behavior of assigning a default error code `ERR_SYSTEM_ERROR` to SystemError and requires the user to directly use the `ERR_SYSTEM_ERROR` class to construct errors instead. Also merges `makeNodeError` into the SystemError class definition since that's the only place the function gets used and it seems unnecessary to introduce another level of inheritance. SystemError now directly inherits from Error instead of an intermmediate Error class that inherits from Error. Class hierarchy before this patch: ERR_SOCKET_BUFFER_SIZE -> Error (use message formatted by SystemError) ERR_SYSTEM_ERROR -> NodeError (temp) -> Error After: ERR_SOCKET_BUFFER_SIZE -> SystemError -> Error ERR_TTY_INIT_FAILED -> SystemError -> Error ERR_SYSTEM_ERROR -> SystemError -> Error Error messages before this patch: ``` const dgram = require('dgram'); const socket = dgram.createSocket('udp4'); socket.setRecvBufferSize(8192); // Error [ERR_SOCKET_BUFFER_SIZE]: Could not get or set buffer // size: Error [ERR_SYSTEM_ERROR]: bad file descriptor: // EBADF [uv_recv_buffer_size] // at bufferSize (dgram.js:191:11) // at Socket.setRecvBufferSize (dgram.js:689:3) const tty = require('tty'); new tty.WriteStream(1 << 30); // Error [ERR_SYSTEM_ERROR]: invalid argument: EINVAL [uv_tty_init] // at new WriteStream (tty.js:84:11) ``` After: ``` const dgram = require('dgram'); const socket = dgram.createSocket('udp4'); socket.setRecvBufferSize(8192); // SystemError [ERR_SOCKET_BUFFER_SIZE]: Could not get or set buffer // size: uv_recv_buffer_size returned EBADF (bad file descriptor) // at bufferSize (dgram.js:191:11) // at Socket.setRecvBufferSize (dgram.js:689:3) const tty = require('tty'); new tty.WriteStream(1 << 30); // SystemError [ERR_TTY_INIT_FAILED]: TTY initialization failed: // uv_tty_init returned EINVAL (invalid argument) // at new WriteStream (tty.js:84:11) ``` PR-URL: https://github.com/nodejs/node/pull/19514 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
2018-03-20 16:46:30 +00:00
throw new ERR_SOCKET_BUFFER_SIZE(ctx);
}
return ret;
}
// Query master process to get the server handle and utilize it.
function bindServerHandle(self, options, errCb) {
if (!cluster)
cluster = require('cluster');
const state = self[kStateSymbol];
cluster._getServer(self, options, (err, handle) => {
if (err) {
errCb(err);
return;
}
if (!state.handle) {
// Handle has been closed in the mean time.
return handle.close();
}
replaceHandle(self, handle);
startListening(self);
});
}
Socket.prototype.bind = function(port_, address_ /* , callback */) {
let port = port_;
2011-08-20 01:47:40 +00:00
healthCheck(this);
const state = this[kStateSymbol];
2011-08-20 01:47:40 +00:00
if (state.bindState !== BIND_STATE_UNBOUND)
throw new ERR_SOCKET_ALREADY_BOUND();
2013-01-22 22:52:20 +00:00
state.bindState = BIND_STATE_BINDING;
2013-01-22 22:52:20 +00:00
if (arguments.length && typeof arguments[arguments.length - 1] === 'function')
this.once('listening', arguments[arguments.length - 1]);
if (port instanceof UDP) {
replaceHandle(this, port);
startListening(this);
return this;
}
// Open an existing fd instead of creating a new one.
if (port !== null && typeof port === 'object' &&
isInt32(port.fd) && port.fd > 0) {
const fd = port.fd;
const exclusive = !!port.exclusive;
const state = this[kStateSymbol];
if (!cluster)
cluster = require('cluster');
if (cluster.isWorker && !exclusive) {
bindServerHandle(this, {
address: null,
port: null,
addressType: this.type,
fd,
flags: null
}, (err) => {
// Callback to handle error.
const ex = errnoException(err, 'open');
this.emit('error', ex);
state.bindState = BIND_STATE_UNBOUND;
});
return this;
}
const type = guessHandleType(fd);
if (type !== 'UDP')
throw new ERR_INVALID_FD_TYPE(type);
const err = state.handle.open(fd);
if (err)
throw errnoException(err, 'open');
// Check if the udp handle was connected and set the state accordingly
if (isConnected(this))
state.connectState = CONNECT_STATE_CONNECTED;
startListening(this);
return this;
}
var address;
var exclusive;
if (port !== null && typeof port === 'object') {
address = port.address || '';
exclusive = !!port.exclusive;
port = port.port;
} else {
address = typeof address_ === 'function' ? '' : address_;
exclusive = false;
}
// Defaulting address for bind to all interfaces
if (!address) {
if (this.type === 'udp4')
address = '0.0.0.0';
else
address = '::';
}
// Resolve address first
state.handle.lookup(address, (err, ip) => {
2011-08-20 01:47:40 +00:00
if (err) {
state.bindState = BIND_STATE_UNBOUND;
this.emit('error', err);
return;
}
2013-01-22 22:52:20 +00:00
if (!cluster)
cluster = require('cluster');
var flags = 0;
if (state.reuseAddr)
flags |= UV_UDP_REUSEADDR;
if (state.ipv6Only)
flags |= UV_UDP_IPV6ONLY;
if (cluster.isWorker && !exclusive) {
bindServerHandle(this, {
address: ip,
port: port,
addressType: this.type,
fd: -1,
flags: flags
}, (err) => {
// Callback to handle error.
const ex = exceptionWithHostPort(err, 'bind', ip, port);
this.emit('error', ex);
state.bindState = BIND_STATE_UNBOUND;
});
2013-01-22 22:52:20 +00:00
} else {
if (!state.handle)
return; // Handle has been closed in the mean time
2013-01-22 22:52:20 +00:00
const err = state.handle.bind(ip, port || 0, flags);
if (err) {
var ex = exceptionWithHostPort(err, 'bind', ip, port);
this.emit('error', ex);
state.bindState = BIND_STATE_UNBOUND;
2013-01-22 22:52:20 +00:00
// Todo: close?
return;
}
startListening(this);
2013-01-22 22:52:20 +00:00
}
});
return this;
2011-08-20 01:47:40 +00:00
};
function validatePort(port) {
const legal = isLegalPort(port);
if (legal)
port = port | 0;
if (!legal || port === 0)
throw new ERR_SOCKET_BAD_PORT(port);
return port;
}
Socket.prototype.connect = function(port, address, callback) {
port = validatePort(port);
if (typeof address === 'function') {
callback = address;
address = '';
} else if (address === undefined) {
address = '';
}
validateString(address, 'address');
const state = this[kStateSymbol];
if (state.connectState !== CONNECT_STATE_DISCONNECTED)
throw new ERR_SOCKET_DGRAM_IS_CONNECTED();
state.connectState = CONNECT_STATE_CONNECTING;
if (state.bindState === BIND_STATE_UNBOUND)
this.bind({ port: 0, exclusive: true }, null);
if (state.bindState !== BIND_STATE_BOUND) {
enqueue(this, _connect.bind(this, port, address, callback));
return;
}
_connect.call(this, port, address, callback);
};
function _connect(port, address, callback) {
const state = this[kStateSymbol];
if (callback)
this.once('connect', callback);
const afterDns = (ex, ip) => {
defaultTriggerAsyncIdScope(
this[async_id_symbol],
doConnect,
ex, this, ip, address, port, callback
);
};
state.handle.lookup(address, afterDns);
}
function doConnect(ex, self, ip, address, port, callback) {
const state = self[kStateSymbol];
if (!state.handle)
return;
if (!ex) {
const err = state.handle.connect(ip, port);
if (err) {
ex = exceptionWithHostPort(err, 'connect', address, port);
}
}
if (ex) {
state.connectState = CONNECT_STATE_DISCONNECTED;
return process.nextTick(() => {
if (callback) {
self.removeListener('connect', callback);
callback(ex);
} else {
self.emit('error', ex);
}
});
}
state.connectState = CONNECT_STATE_CONNECTED;
process.nextTick(() => self.emit('connect'));
}
Socket.prototype.disconnect = function() {
const state = this[kStateSymbol];
if (state.connectState !== CONNECT_STATE_CONNECTED)
throw new ERR_SOCKET_DGRAM_NOT_CONNECTED();
const err = state.handle.disconnect();
if (err)
throw errnoException(err, 'connect');
else
state.connectState = CONNECT_STATE_DISCONNECTED;
};
// Thin wrapper around `send`, here for compatibility with dgram_legacy.js
2011-08-20 01:47:40 +00:00
Socket.prototype.sendto = function(buffer,
offset,
length,
port,
address,
callback) {
validateNumber(offset, 'offset');
validateNumber(length, 'length');
validateNumber(port, 'port');
validateString(address, 'address');
2011-08-20 01:47:40 +00:00
this.send(buffer, offset, length, port, address, callback);
};
function sliceBuffer(buffer, offset, length) {
if (typeof buffer === 'string') {
buffer = Buffer.from(buffer);
} else if (!isUint8Array(buffer)) {
throw new ERR_INVALID_ARG_TYPE('buffer',
['Buffer', 'Uint8Array', 'string'], buffer);
}
offset = offset >>> 0;
length = length >>> 0;
return buffer.slice(offset, offset + length);
}
function fixBufferList(list) {
const newlist = new Array(list.length);
for (var i = 0, l = list.length; i < l; i++) {
var buf = list[i];
if (typeof buf === 'string')
newlist[i] = Buffer.from(buf);
else if (!isUint8Array(buf))
return null;
else
newlist[i] = buf;
}
return newlist;
}
function enqueue(self, toEnqueue) {
const state = self[kStateSymbol];
// 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.
if (state.queue === undefined) {
state.queue = [];
self.once('error', onListenError);
self.once('listening', onListenSuccess);
}
state.queue.push(toEnqueue);
}
function onListenSuccess() {
this.removeListener('error', onListenError);
clearQueue.call(this);
}
function onListenError(err) {
this.removeListener('listening', onListenSuccess);
this[kStateSymbol].queue = undefined;
this.emit('error', new ERR_SOCKET_CANNOT_SEND());
}
function clearQueue() {
const state = this[kStateSymbol];
const queue = state.queue;
state.queue = undefined;
// Flush the send queue.
for (var i = 0; i < queue.length; i++)
queue[i]();
}
function isConnected(self) {
try {
self.remoteAddress();
return true;
} catch {
return false;
}
}
// valid combinations
// For connectionless sockets
// send(buffer, offset, length, port, address, callback)
// send(buffer, offset, length, port, address)
// send(buffer, offset, length, port, callback)
// send(buffer, offset, length, port)
// send(bufferOrList, port, address, callback)
// send(bufferOrList, port, address)
// send(bufferOrList, port, callback)
// send(bufferOrList, port)
// For connected sockets
// send(buffer, offset, length, callback)
// send(buffer, offset, length)
// send(bufferOrList, callback)
// send(bufferOrList)
2011-08-20 01:47:40 +00:00
Socket.prototype.send = function(buffer,
offset,
length,
port,
address,
callback) {
let list;
const state = this[kStateSymbol];
const connected = state.connectState === CONNECT_STATE_CONNECTED;
if (!connected) {
if (address || (port && typeof port !== 'function')) {
buffer = sliceBuffer(buffer, offset, length);
} else {
callback = port;
port = offset;
address = length;
}
} else if (typeof length === 'number') {
buffer = sliceBuffer(buffer, offset, length);
if (typeof port === 'function') {
callback = port;
port = null;
} else if (port || address) {
throw new ERR_SOCKET_DGRAM_IS_CONNECTED();
}
} else {
callback = offset;
}
2012-02-23 00:51:27 +00:00
if (!Array.isArray(buffer)) {
if (typeof buffer === 'string') {
list = [ Buffer.from(buffer) ];
} else if (!isUint8Array(buffer)) {
throw new ERR_INVALID_ARG_TYPE('buffer',
['Buffer', 'Uint8Array', 'string'],
buffer);
} else {
list = [ buffer ];
}
} else if (!(list = fixBufferList(buffer))) {
throw new ERR_INVALID_ARG_TYPE('buffer list arguments',
['Buffer', 'string'], buffer);
}
if (!connected)
port = validatePort(port);
2012-02-23 00:51:27 +00:00
// Normalize callback so it's either a function or undefined but not anything
// else.
if (typeof callback !== 'function')
callback = undefined;
2011-08-20 01:47:40 +00:00
if (typeof address === 'function') {
callback = address;
address = undefined;
} else if (address && typeof address !== 'string') {
throw new ERR_INVALID_ARG_TYPE('address', ['string', 'falsy'], address);
}
healthCheck(this);
if (state.bindState === BIND_STATE_UNBOUND)
this.bind({ port: 0, exclusive: true }, null);
if (list.length === 0)
list.push(Buffer.alloc(0));
// If the socket hasn't been bound yet, push the outbound packet onto the
// send queue and send after binding is complete.
if (state.bindState !== BIND_STATE_BOUND) {
enqueue(this, this.send.bind(this, list, port, address, callback));
return;
}
2011-08-20 01:47:40 +00:00
const afterDns = (ex, ip) => {
defaultTriggerAsyncIdScope(
this[async_id_symbol],
doSend,
ex, this, ip, list, address, port, callback
);
};
if (!connected) {
state.handle.lookup(address, afterDns);
} else {
afterDns(null, null);
}
2011-08-20 01:47:40 +00:00
};
function doSend(ex, self, ip, list, address, port, callback) {
const state = self[kStateSymbol];
if (ex) {
if (typeof callback === 'function') {
process.nextTick(callback, ex);
return;
}
process.nextTick(() => self.emit('error', ex));
return;
} else if (!state.handle) {
return;
}
const req = new SendWrap();
req.list = list; // Keep reference alive.
req.address = address;
req.port = port;
if (callback) {
req.callback = callback;
req.oncomplete = afterSend;
}
let err;
if (port)
err = state.handle.send(req, list, list.length, port, ip, !!callback);
else
err = state.handle.send(req, list, list.length, !!callback);
if (err && callback) {
// Don't emit as error, dgram_legacy.js compatibility
const ex = exceptionWithHostPort(err, 'send', address, port);
process.nextTick(callback, ex);
}
}
function afterSend(err, sent) {
if (err) {
err = exceptionWithHostPort(err, 'send', this.address, this.port);
} else {
err = null;
}
this.callback(err, sent);
2011-08-20 01:47:40 +00:00
}
Socket.prototype.close = function(callback) {
const state = this[kStateSymbol];
const queue = state.queue;
if (typeof callback === 'function')
this.on('close', callback);
if (queue !== undefined) {
queue.push(this.close.bind(this));
return this;
}
healthCheck(this);
stopReceiving(this);
state.handle.close();
state.handle = null;
defaultTriggerAsyncIdScope(this[async_id_symbol],
process.nextTick,
socketCloseNT,
this);
return this;
2011-08-20 01:47:40 +00:00
};
function socketCloseNT(self) {
self.emit('close');
}
2011-08-20 01:47:40 +00:00
Socket.prototype.address = function() {
healthCheck(this);
2011-08-20 01:47:40 +00:00
const out = {};
const err = this[kStateSymbol].handle.getsockname(out);
if (err) {
throw errnoException(err, 'getsockname');
}
2011-08-20 01:47:40 +00:00
return out;
2011-08-20 01:47:40 +00:00
};
Socket.prototype.remoteAddress = function() {
healthCheck(this);
const state = this[kStateSymbol];
if (state.connectState !== CONNECT_STATE_CONNECTED)
throw new ERR_SOCKET_DGRAM_NOT_CONNECTED();
var out = {};
var err = state.handle.getpeername(out);
if (err)
throw errnoException(err, 'getpeername');
return out;
};
2011-08-20 01:47:40 +00:00
Socket.prototype.setBroadcast = function(arg) {
const err = this[kStateSymbol].handle.setBroadcast(arg ? 1 : 0);
if (err) {
throw errnoException(err, 'setBroadcast');
}
2011-08-20 01:47:40 +00:00
};
Socket.prototype.setTTL = function(ttl) {
validateNumber(ttl, 'ttl');
2012-01-23 22:52:08 +00:00
const err = this[kStateSymbol].handle.setTTL(ttl);
if (err) {
throw errnoException(err, 'setTTL');
2012-01-23 22:52:08 +00:00
}
return ttl;
2011-08-20 01:47:40 +00:00
};
Socket.prototype.setMulticastTTL = function(ttl) {
validateNumber(ttl, 'ttl');
const err = this[kStateSymbol].handle.setMulticastTTL(ttl);
if (err) {
throw errnoException(err, 'setMulticastTTL');
}
return ttl;
2011-08-20 01:47:40 +00:00
};
Socket.prototype.setMulticastLoopback = function(arg) {
const err = this[kStateSymbol].handle.setMulticastLoopback(arg ? 1 : 0);
if (err) {
throw errnoException(err, 'setMulticastLoopback');
}
return arg; // 0.4 compatibility
2011-08-20 01:47:40 +00:00
};
Socket.prototype.setMulticastInterface = function(interfaceAddress) {
healthCheck(this);
validateString(interfaceAddress, 'interfaceAddress');
const err = this[kStateSymbol].handle.setMulticastInterface(interfaceAddress);
if (err) {
throw errnoException(err, 'setMulticastInterface');
}
};
2011-08-20 01:47:40 +00:00
Socket.prototype.addMembership = function(multicastAddress,
interfaceAddress) {
healthCheck(this);
if (!multicastAddress) {
throw new ERR_MISSING_ARGS('multicastAddress');
}
const { handle } = this[kStateSymbol];
const err = handle.addMembership(multicastAddress, interfaceAddress);
if (err) {
throw errnoException(err, 'addMembership');
}
2011-08-20 01:47:40 +00:00
};
Socket.prototype.dropMembership = function(multicastAddress,
interfaceAddress) {
healthCheck(this);
if (!multicastAddress) {
throw new ERR_MISSING_ARGS('multicastAddress');
}
const { handle } = this[kStateSymbol];
const err = handle.dropMembership(multicastAddress, interfaceAddress);
if (err) {
throw errnoException(err, 'dropMembership');
}
2011-08-20 01:47:40 +00:00
};
function healthCheck(socket) {
if (!socket[kStateSymbol].handle) {
// Error message from dgram_legacy.js.
throw new ERR_SOCKET_DGRAM_NOT_RUNNING();
}
}
2011-08-20 01:47:40 +00:00
function stopReceiving(socket) {
const state = socket[kStateSymbol];
if (!state.receiving)
2011-08-20 01:47:40 +00:00
return;
state.handle.recvStop();
state.receiving = false;
}
2011-08-20 01:47:40 +00:00
function onMessage(nread, handle, buf, rinfo) {
const self = handle[owner_symbol];
if (nread < 0) {
return self.emit('error', errnoException(nread, 'recvmsg'));
}
rinfo.size = buf.length; // compatibility
self.emit('message', buf, rinfo);
2011-08-20 01:47:40 +00:00
}
Socket.prototype.ref = function() {
const handle = this[kStateSymbol].handle;
if (handle)
handle.ref();
return this;
};
Socket.prototype.unref = function() {
const handle = this[kStateSymbol].handle;
if (handle)
handle.unref();
return this;
};
Socket.prototype.setRecvBufferSize = function(size) {
bufferSize(this, size, RECV_BUFFER);
};
Socket.prototype.setSendBufferSize = function(size) {
bufferSize(this, size, SEND_BUFFER);
};
Socket.prototype.getRecvBufferSize = function() {
return bufferSize(this, 0, RECV_BUFFER);
};
Socket.prototype.getSendBufferSize = function() {
return bufferSize(this, 0, SEND_BUFFER);
};
// Deprecated private APIs.
Object.defineProperty(Socket.prototype, '_handle', {
get: deprecate(function() {
return this[kStateSymbol].handle;
}, 'Socket.prototype._handle is deprecated', 'DEP0112'),
set: deprecate(function(val) {
this[kStateSymbol].handle = val;
}, 'Socket.prototype._handle is deprecated', 'DEP0112')
});
Object.defineProperty(Socket.prototype, '_receiving', {
get: deprecate(function() {
return this[kStateSymbol].receiving;
}, 'Socket.prototype._receiving is deprecated', 'DEP0112'),
set: deprecate(function(val) {
this[kStateSymbol].receiving = val;
}, 'Socket.prototype._receiving is deprecated', 'DEP0112')
});
Object.defineProperty(Socket.prototype, '_bindState', {
get: deprecate(function() {
return this[kStateSymbol].bindState;
}, 'Socket.prototype._bindState is deprecated', 'DEP0112'),
set: deprecate(function(val) {
this[kStateSymbol].bindState = val;
}, 'Socket.prototype._bindState is deprecated', 'DEP0112')
});
Object.defineProperty(Socket.prototype, '_queue', {
get: deprecate(function() {
return this[kStateSymbol].queue;
}, 'Socket.prototype._queue is deprecated', 'DEP0112'),
set: deprecate(function(val) {
this[kStateSymbol].queue = val;
}, 'Socket.prototype._queue is deprecated', 'DEP0112')
});
Object.defineProperty(Socket.prototype, '_reuseAddr', {
get: deprecate(function() {
return this[kStateSymbol].reuseAddr;
}, 'Socket.prototype._reuseAddr is deprecated', 'DEP0112'),
set: deprecate(function(val) {
this[kStateSymbol].reuseAddr = val;
}, 'Socket.prototype._reuseAddr is deprecated', 'DEP0112')
});
Socket.prototype._healthCheck = deprecate(function() {
healthCheck(this);
}, 'Socket.prototype._healthCheck() is deprecated', 'DEP0112');
Socket.prototype._stopReceiving = deprecate(function() {
stopReceiving(this);
}, 'Socket.prototype._stopReceiving() is deprecated', 'DEP0112');
// Legacy alias on the C++ wrapper object. This is not public API, so we may
// want to runtime-deprecate it at some point. There's no hurry, though.
Object.defineProperty(UDP.prototype, 'owner', {
get() { return this[owner_symbol]; },
set(v) { return this[owner_symbol] = v; }
});
module.exports = {
_createSocketHandle: deprecate(
_createSocketHandle,
'dgram._createSocketHandle() is deprecated',
'DEP0112'
),
createSocket,
Socket
};