From 9d6cd42767f62938904eb4f5ad3106145a762d5a Mon Sep 17 00:00:00 2001 From: Damien O'Reilly Date: Sun, 11 Jun 2017 22:57:29 +0100 Subject: [PATCH 01/13] doc: added docs for send/receive buffer sizes setRecvBufferSize and setSendBufferSize --- doc/api/dgram.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 3e77827a5e4b65..f1ea60491ce157 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -398,6 +398,26 @@ decremented to 0 by a router, it will not be forwarded. The argument passed to to `socket.setMulticastTTL()` is a number of hops between 0 and 255. The default on most systems is `1` but can vary. +### socket.setRecvBufferSize(size) + + +* `size` {number} Integer + +Sets the `SO_RCVBUF` socket option. Sets the maximum socket receive buffer +in bytes. + +### socket.setSendBufferSize(size) + + +* `size` {number} Integer + +Sets the `SO_SNDBUF` socket option. Sets the maximum socket send buffer +in bytes. + ### socket.setTTL(ttl) * `size` {number} Integer @@ -410,7 +410,7 @@ in bytes. ### socket.setSendBufferSize(size) * `size` {number} Integer diff --git a/test/parallel/test-dgram-set-socket-buffer-size.js b/test/parallel/test-dgram-set-socket-buffer-size.js index 4d9e0c6b84bd2b..877d915018df5d 100644 --- a/test/parallel/test-dgram-set-socket-buffer-size.js +++ b/test/parallel/test-dgram-set-socket-buffer-size.js @@ -5,16 +5,16 @@ const assert = require('assert'); const dgram = require('dgram'); { - // Should throw ENOTSOCK if the socket is never bound. + // Should throw error if the socket is never bound. const socket = dgram.createSocket('udp4'); assert.throws(() => { socket.setRecvBufferSize(8192); - }, /^Error: setRecvBufferSize ENOTSOCK$/); + }, /^Error: setRecvBufferSize E[A-Z]+$/); assert.throws(() => { socket.setSendBufferSize(8192); - }, /^Error: setSendBufferSize ENOTSOCK$/); + }, /^Error: setSendBufferSize E[A-Z]+$/); } { @@ -26,4 +26,4 @@ const dgram = require('dgram'); socket.setSendBufferSize(8192); socket.close(); })); -} \ No newline at end of file +} From f6bf7f248e558ec49cddef9f440498c558a6574a Mon Sep 17 00:00:00 2001 From: Damien O'Reilly Date: Mon, 12 Jun 2017 21:40:33 +0100 Subject: [PATCH 08/13] dgram: fixed syntax, added options support Docs updated. Added options support to set buffer sizes in dgram.createSocket(). --- doc/api/dgram.md | 5 ++ lib/dgram.js | 40 ++++++++++++--- lib/internal/errors.js | 2 + src/udp_wrap.cc | 21 ++++---- .../test-dgram-set-socket-buffer-size.js | 50 +++++++++++++++++-- 5 files changed, 100 insertions(+), 18 deletions(-) diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 908457ebfa377e..a5a1d5525825f9 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -481,6 +481,9 @@ changes: - version: REPLACEME pr-url: https://github.com/nodejs/node/pull/14560 description: The `lookup` option is supported. + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/13623 + description: `recvBufferSize` and `sendBufferSize` options are supported now. --> * `options` {Object} Available options are: @@ -489,6 +492,8 @@ changes: * `reuseAddr` {boolean} When `true` [`socket.bind()`][] will reuse the address, even if another process has already bound a socket on it. Optional. Defaults to `false`. + * `recvBufferSize` {number} - Optional. Sets the `SO_RCVBUF` socket value. + * `sendBufferSize` {number} - Optional. Sets the `SO_SNDBUF` socket value. * `lookup` {Function} Custom lookup function. Defaults to [`dns.lookup()`][]. Optional. * `callback` {Function} Attached as a listener for `'message'` events. Optional. diff --git a/lib/dgram.js b/lib/dgram.js index cc34a4e9953bfa..c03e2970272ce5 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -30,6 +30,7 @@ const EventEmitter = require('events'); const setInitTriggerId = require('async_hooks').setInitTriggerId; const UV_UDP_REUSEADDR = process.binding('constants').os.UV_UDP_REUSEADDR; const async_id_symbol = process.binding('async_wrap').async_id_symbol; +const uv = process.binding('uv'); const nextTick = require('internal/process/next_tick').nextTick; const UDP = process.binding('udp_wrap').UDP; @@ -121,6 +122,12 @@ function Socket(type, listener) { // If true - UV_UDP_REUSEADDR flag will be set this._reuseAddr = options && options.reuseAddr; + + if (options && options.recvBufferSize) + this._recvBufferSize = options.recvBufferSize; + + if (options && options.sendBufferSize) + this._sendBufferSize = options.sendBufferSize; if (typeof listener === 'function') this.on('message', listener); @@ -140,6 +147,12 @@ function startListening(socket) { socket._receiving = true; socket._bindState = BIND_STATE_BOUND; socket.fd = -42; // compatibility hack + + if (socket._recvBufferSize) + socket.setRecvBufferSize(socket._recvBufferSize); + + if (socket._sendBufferSize) + socket.setSendBufferSize(socket._sendBufferSize); socket.emit('listening'); } @@ -327,6 +340,14 @@ function enqueue(self, toEnqueue) { } +function isValidSize(size) { + return Number.isFinite(size) && + size <= Number.MAX_SAFE_INTEGER && + size >= 0 && + size >>> 0 === size; +} + + function onListenSuccess() { this.removeListener('error', onListenError); clearQueue.call(this); @@ -638,20 +659,27 @@ Socket.prototype.unref = function() { Socket.prototype.setRecvBufferSize = function(size) { + if (!isValidSize(size)) + throw new errors.TypeError('ERR_SOCKET_BAD_BUFFER_SIZE'); + var err = this._handle.setRecvBufferSize(size); - if (err) { - throw errnoException(err, 'setRecvBufferSize'); - } + if (err) + throw new errors.TypeError('ERR_SOCKET_SET_BUFFER_SIZE', + uv.errname(err)); + }; Socket.prototype.setSendBufferSize = function(size) { + if (!isValidSize(size)) + throw new errors.TypeError('ERR_SOCKET_BAD_BUFFER_SIZE'); + var err = this._handle.setSendBufferSize(size); - if (err) { - throw errnoException(err, 'setSendBufferSize'); - } + if (err) + throw new errors.TypeError('ERR_SOCKET_SET_BUFFER_SIZE', + uv.errname(err)); }; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 10e5be8a44056d..7d00b9e48545e1 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -245,11 +245,13 @@ E('ERR_SERVER_ALREADY_LISTEN', 'Listen method has been called more than once without closing.'); E('ERR_SOCKET_ALREADY_BOUND', 'Socket is already bound'); E('ERR_SOCKET_BAD_PORT', 'Port should be > 0 and < 65536'); +E('ERR_SOCKET_BAD_BUFFER_SIZE', 'Buffer size must be a positive integer'); E('ERR_SOCKET_BAD_TYPE', 'Bad socket type specified. Valid types are: udp4, udp6'); E('ERR_SOCKET_CANNOT_SEND', 'Unable to send data'); E('ERR_SOCKET_CLOSED', 'Socket is closed'); E('ERR_SOCKET_DGRAM_NOT_RUNNING', 'Not running'); +E('ERR_SOCKET_SET_BUFFER_SIZE', (reason) => `Coud not set buffer size: ${reason}`); E('ERR_STDERR_CLOSE', 'process.stderr cannot be closed'); E('ERR_STDOUT_CLOSE', 'process.stdout cannot be closed'); E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode'); diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index f5814e46c3aae8..58291f96f8cec6 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -46,6 +46,7 @@ using v8::Object; using v8::PropertyAttribute; using v8::PropertyCallbackInfo; using v8::String; +using v8::Uint32; using v8::Undefined; using v8::Value; @@ -225,32 +226,34 @@ void UDPWrap::Bind6(const FunctionCallbackInfo& args) { void UDPWrap::SetRecvBufferSize(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); UDPWrap* wrap; ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder(), args.GetReturnValue().Set(UV_EBADF)); CHECK(args[0]->IsUint32()); + int size = (int)args[0].As()->Value(); + int err = uv_recv_buffer_size(reinterpret_cast(&wrap->handle_), + &size); - int inputSize = args[0]->Uint32Value(); - int err = uv_recv_buffer_size(reinterpret_cast(&wrap->handle_), &inputSize); - - args.GetReturnValue().Set(err); + args.GetReturnValue().Set(err); } void UDPWrap::SetSendBufferSize(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); UDPWrap* wrap; ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder(), args.GetReturnValue().Set(UV_EBADF)); CHECK(args[0]->IsUint32()); - - int inputSize = args[0]->Uint32Value(); - int err = uv_send_buffer_size(reinterpret_cast(&wrap->handle_), &inputSize); - - args.GetReturnValue().Set(err); + int size = (int)args[0].As()->Value(); + int err = uv_send_buffer_size(reinterpret_cast(&wrap->handle_), + &size); + + args.GetReturnValue().Set(err); } diff --git a/test/parallel/test-dgram-set-socket-buffer-size.js b/test/parallel/test-dgram-set-socket-buffer-size.js index 877d915018df5d..74fcf9b1183f43 100644 --- a/test/parallel/test-dgram-set-socket-buffer-size.js +++ b/test/parallel/test-dgram-set-socket-buffer-size.js @@ -10,11 +10,55 @@ const dgram = require('dgram'); assert.throws(() => { socket.setRecvBufferSize(8192); - }, /^Error: setRecvBufferSize E[A-Z]+$/); + }, common.expectsError({ + code: 'ERR_SOCKET_SET_BUFFER_SIZE', + type: Error, + message: /^Coud not set buffer size: E[A-Z]+$/ + })); + + assert.throws(() => { + socket.setSendBufferSize(8192); + }, common.expectsError({ + code: 'ERR_SOCKET_SET_BUFFER_SIZE', + type: Error, + message: /^Coud not set buffer size: E[A-Z]+$/ + })); + +} + +{ + // Should throw error if invalid buffer size is specified + const socket = dgram.createSocket('udp4'); + + socket.bind(0, common.mustCall(() => { + assert.throws(() => { - socket.setSendBufferSize(8192); - }, /^Error: setSendBufferSize E[A-Z]+$/); + socket.setRecvBufferSize(-1); + }, common.expectsError({ + code: 'ERR_SOCKET_BAD_BUFFER_SIZE', + type: Error, + message: /^Buffer size must be a positive integer$/ + })); + + assert.throws(() => { + socket.setRecvBufferSize(Infinity); + }, common.expectsError({ + code: 'ERR_SOCKET_BAD_BUFFER_SIZE', + type: Error, + message: /^Buffer size must be a positive integer$/ + })); + + assert.throws(() => { + socket.setRecvBufferSize('Doh!'); + }, common.expectsError({ + code: 'ERR_SOCKET_BAD_BUFFER_SIZE', + type: Error, + message: /^Buffer size must be a positive integer$/ + })); + + socket.close(); + })); } { From d5789c0a46da8412774e56517a69ddf919a10f3a Mon Sep 17 00:00:00 2001 From: Damien O'Reilly Date: Wed, 14 Jun 2017 14:45:27 +0100 Subject: [PATCH 09/13] dgram: add support to get buffer sizes --- doc/api/dgram.md | 15 +++++ lib/dgram.js | 63 ++++++++++--------- lib/internal/errors.js | 2 +- src/udp_wrap.cc | 41 ++++++------ src/udp_wrap.h | 3 +- test/parallel/test-dgram-createSocket-type.js | 19 ++++++ ...ze.js => test-dgram-socket-buffer-size.js} | 45 +++++++++---- 7 files changed, 122 insertions(+), 66 deletions(-) rename test/parallel/{test-dgram-set-socket-buffer-size.js => test-dgram-socket-buffer-size.js} (54%) diff --git a/doc/api/dgram.md b/doc/api/dgram.md index a5a1d5525825f9..66ab9b635d2397 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -227,6 +227,20 @@ never have reason to call this. If `multicastInterface` is not specified, the operating system will attempt to drop membership on all valid interfaces. +### socket.getRecvBufferSize(size) + + +* Returns {number} the `SO_RCVBUF` socket receive buffer size in bytes. + +### socket.getSendBufferSize(size) + + +* Returns {number} the `SO_SNDBUF` socket send buffer size in bytes. + ### socket.ref()