Browse Source

Added support for multiple listeners to DNS multicast datagrams.

Some platforms require SO_REUSEPORT to be set for the socket.
v0.7.4-release
Rasmus Andersson 15 years ago
committed by Ryan Dahl
parent
commit
8d5e05668b
  1. 22
      src/node_net.cc
  2. 75
      test/simple/test-dgram-multicast.js

22
src/node_net.cc

@ -136,6 +136,9 @@ static Handle<Value> Socket(const Arguments& args) {
// default to TCP // default to TCP
int domain = PF_INET; int domain = PF_INET;
int type = SOCK_STREAM; int type = SOCK_STREAM;
#ifdef SO_REUSEPORT
bool set_reuseport = false;
#endif
if (args[0]->IsString()) { if (args[0]->IsString()) {
String::Utf8Value t(args[0]->ToString()); String::Utf8Value t(args[0]->ToString());
@ -158,12 +161,21 @@ static Handle<Value> Socket(const Arguments& args) {
} else if (0 == strcasecmp(*t, "UDP")) { } else if (0 == strcasecmp(*t, "UDP")) {
domain = PF_INET; domain = PF_INET;
type = SOCK_DGRAM; type = SOCK_DGRAM;
#ifdef SO_REUSEPORT
set_reuseport = true;
#endif
} else if (0 == strcasecmp(*t, "UDP4")) { } else if (0 == strcasecmp(*t, "UDP4")) {
domain = PF_INET; domain = PF_INET;
type = SOCK_DGRAM; type = SOCK_DGRAM;
#ifdef SO_REUSEPORT
set_reuseport = true;
#endif
} else if (0 == strcasecmp(*t, "UDP6")) { } else if (0 == strcasecmp(*t, "UDP6")) {
domain = PF_INET6; domain = PF_INET6;
type = SOCK_DGRAM; type = SOCK_DGRAM;
#ifdef SO_REUSEPORT
set_reuseport = true;
#endif
} else { } else {
return ThrowException(Exception::Error( return ThrowException(Exception::Error(
String::New("Unknown socket type."))); String::New("Unknown socket type.")));
@ -180,6 +192,16 @@ static Handle<Value> Socket(const Arguments& args) {
return ThrowException(ErrnoException(fcntl_errno, "fcntl")); 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)); return scope.Close(Integer::New(fd));
} }

75
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<sendMessages.length; ++i) {
if (buf.toString() === sendMessages[i].toString()) {
count++;
break;
}
}
});
assert.strictEqual(count, sendMessages.length);
})
.on('error', function (err) { throw err; })
.on('listening', function() {
if (!sendSocket.started) {
sendSocket.started = true;
process.nextTick(function(){ sendSocket.sendNext(); });
}
})
listenSocket.bind(common.PORT);
listenSockets.push(listenSocket);
}
mkListener();
mkListener();
mkListener();
timeoutTimer = setTimeout(function () { throw new Error("Timeout"); }, 500);
Loading…
Cancel
Save