From 592be014b680b70ee349dda5aa5928bde28da2cd Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 9 Apr 2014 03:04:53 +0400 Subject: [PATCH] dgram: introduce `reuseAddr` option Introduce new signature for both `dgram.createSocket` method and `dgram.Socket` constructor: dgram.createSocket(options, [listener]) Options should contain `type` property and may contain `reuseAddr` property. When `reuseAddr` is `true` - SO_REUSEADDR will be issued on socket on bind. fix #7415 Signed-off-by: Fedor Indutny --- doc/api/dgram.markdown | 7 ++++++- lib/dgram.js | 15 ++++++++++++++- src/node_constants.cc | 5 +++++ test/simple/test-dgram-broadcast-multi-process.js | 10 ++++++++-- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/doc/api/dgram.markdown b/doc/api/dgram.markdown index 5ce26de8d42..b659e6b1a97 100644 --- a/doc/api/dgram.markdown +++ b/doc/api/dgram.markdown @@ -22,8 +22,13 @@ You have to change it to this: ## dgram.createSocket(type, [callback]) +## dgram.createSocket(options, [callback]) * `type` String. Either 'udp4' or 'udp6' +* `options` Object. Should contain a `type` property and could contain + `reuseAddr` property. `false` by default. + When `reuseAddr` is `true` - `socket.bind()` will reuse address, even if the + other process has already bound a socket on it. * `callback` Function. Attached as a listener to `message` events. Optional * Returns: Socket object @@ -41,7 +46,7 @@ with `socket.address().address` and `socket.address().port`. ## Class: dgram.Socket The dgram Socket class encapsulates the datagram functionality. It -should be created via `dgram.createSocket(type, [callback])`. +should be created via `dgram.createSocket(...)` ### Event: 'message' diff --git a/lib/dgram.js b/lib/dgram.js index 3a44707e03e..6ff8cf25138 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -22,6 +22,7 @@ var assert = require('assert'); var util = require('util'); var events = require('events'); +var constants = require('constants'); var UDP = process.binding('udp_wrap').UDP; @@ -96,6 +97,11 @@ exports._createSocketHandle = function(address, port, addressType, fd) { function Socket(type, listener) { events.EventEmitter.call(this); + if (typeof type === 'object') { + var options = type; + type = options.type; + } + var handle = newHandle(type); handle.owner = this; @@ -105,6 +111,9 @@ function Socket(type, listener) { this.type = type; this.fd = null; // compatibility hack + // If true - UV_UDP_REUSEADDR flag will be set + this._reuseAddr = options && options.reuseAddr; + if (util.isFunction(listener)) this.on('message', listener); } @@ -196,7 +205,11 @@ Socket.prototype.bind = function(/*port, address, callback*/) { if (!self._handle) return; // handle has been closed in the mean time - var err = self._handle.bind(ip, port || 0, /*flags=*/ 0); + var flags = 0; + if (self._reuseAddr) + flags |= constants.UV_UDP_REUSEADDR; + + var err = self._handle.bind(ip, port || 0, flags); if (err) { self.emit('error', errnoException(err, 'bind')); self._bindState = BIND_STATE_UNBOUND; diff --git a/src/node_constants.cc b/src/node_constants.cc index c903dd90ea3..9e9881e0a7a 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -1071,12 +1071,17 @@ void DefineSystemConstants(Handle target) { #endif } +void DefineUVConstants(Handle target) { + NODE_DEFINE_CONSTANT(target, UV_UDP_REUSEADDR); +} + void DefineConstants(Handle target) { DefineErrnoConstants(target); DefineWindowsErrorConstants(target); DefineSignalConstants(target); DefineOpenSSLConstants(target); DefineSystemConstants(target); + DefineUVConstants(target); } } // namespace node diff --git a/test/simple/test-dgram-broadcast-multi-process.js b/test/simple/test-dgram-broadcast-multi-process.js index ad5b4eba82d..4d9eebc1012 100644 --- a/test/simple/test-dgram-broadcast-multi-process.js +++ b/test/simple/test-dgram-broadcast-multi-process.js @@ -157,7 +157,10 @@ if (process.argv[2] !== 'child') { })(x); } - var sendSocket = dgram.createSocket('udp4'); + var sendSocket = dgram.createSocket({ + type: 'udp4', + reuseAddr: true + }); // bind the address explicitly for sending // INADDR_BROADCAST to only one interface @@ -201,7 +204,10 @@ if (process.argv[2] !== 'child') { if (process.argv[2] === 'child') { var receivedMessages = []; - var listenSocket = dgram.createSocket('udp4'); + var listenSocket = dgram.createSocket({ + type: 'udp4', + reuseAddr: true + }); listenSocket.on('message', function(buf, rinfo) { // receive udp messages only sent from parent