diff --git a/src/node_net.cc b/src/node_net.cc index 6bf9416679..8d920c9523 100644 --- a/src/node_net.cc +++ b/src/node_net.cc @@ -136,6 +136,9 @@ static Handle Socket(const Arguments& args) { // default to TCP int domain = PF_INET; int type = SOCK_STREAM; +#ifdef SO_REUSEPORT + bool set_reuseport = false; +#endif if (args[0]->IsString()) { String::Utf8Value t(args[0]->ToString()); @@ -158,12 +161,21 @@ static Handle Socket(const Arguments& args) { } else if (0 == strcasecmp(*t, "UDP")) { domain = PF_INET; type = SOCK_DGRAM; +#ifdef SO_REUSEPORT + set_reuseport = true; +#endif } else if (0 == strcasecmp(*t, "UDP4")) { domain = PF_INET; type = SOCK_DGRAM; +#ifdef SO_REUSEPORT + set_reuseport = true; +#endif } else if (0 == strcasecmp(*t, "UDP6")) { domain = PF_INET6; type = SOCK_DGRAM; +#ifdef SO_REUSEPORT + set_reuseport = true; +#endif } else { return ThrowException(Exception::Error( String::New("Unknown socket type."))); @@ -180,6 +192,16 @@ static Handle Socket(const Arguments& args) { return ThrowException(ErrnoException(fcntl_errno, "fcntl")); } +#ifdef SO_REUSEPORT + // needed for datagrams to be able to have multiple processes listening to + // e.g. broadcasted datagrams. + if (set_reuseport) { + int flags = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const char *)&flags, + sizeof(flags)); + } +#endif + return scope.Close(Integer::New(fd)); } diff --git a/test/simple/test-dgram-multicast.js b/test/simple/test-dgram-multicast.js new file mode 100644 index 0000000000..75c4443657 --- /dev/null +++ b/test/simple/test-dgram-multicast.js @@ -0,0 +1,75 @@ +common = require("../common"); +assert = common.assert + +var dgram = require("dgram"), + sys = require('sys'), + assert = require('assert'), + Buffer = require("buffer").Buffer; +var timeoutTimer; +var LOCAL_BROADCAST_HOST = '224.0.0.1'; +var sendMessages = [ + new Buffer("First message to send"), + new Buffer("Second message to send"), + new Buffer("Third message to send"), + new Buffer("Fourth message to send") +]; +var listenSockets = []; +var sendSocket = dgram.createSocket('udp4') + .on('close', function () { console.log('sendSocket closed'); }) + .on('error', function (err) { throw err; }); +sendSocket.setBroadcast(true); +var i = 0; +sendSocket.sendNext = function (){ + sendSocket.started = true; + var buf = sendMessages[i++]; + if (!buf) { + try { sendSocket.close(); }catch(e){} + listenSockets.forEach(function (sock) { sock.close(); }); + clearTimeout(timeoutTimer); + return; + } + sendSocket.send(buf, 0, buf.length, common.PORT, LOCAL_BROADCAST_HOST, + function (err) { + if (err) throw err; + console.log('sent %s to %s', sys.inspect(buf.toString()), + LOCAL_BROADCAST_HOST+common.PORT); + process.nextTick(sendSocket.sendNext); + }); +} + +function mkListener() { + var receivedMessages = []; + var listenSocket = dgram.createSocket('udp4') + .on('message', function(buf, rinfo) { + console.log('received %s from %j', sys.inspect(buf.toString()), rinfo); + receivedMessages.push(buf); + }) + .on('close', function () { + console.log('listenSocket closed -- checking received messages'); + var count = 0; + receivedMessages.forEach(function(buf){ + for (var i=0; i