-
Notifications
You must be signed in to change notification settings - Fork 7.3k
net: allow cluster workers to listen on exclusive ports #8238
Changes from 6 commits
235f79a
2a21811
9d11d17
6915f2a
e0c721c
ac42564
4679955
ab26f7e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1140,10 +1140,12 @@ Server.prototype._listen2 = function(address, port, addressType, backlog, fd) { | |
}; | ||
|
||
|
||
function listen(self, address, port, addressType, backlog, fd) { | ||
function listen(self, address, port, addressType, backlog, fd, exclusive) { | ||
exclusive = !!exclusive; | ||
|
||
if (!cluster) cluster = require('cluster'); | ||
|
||
if (cluster.isMaster) { | ||
if (cluster.isMaster || exclusive) { | ||
self._listen2(address, port, addressType, backlog, fd); | ||
return; | ||
} | ||
|
@@ -1191,24 +1193,34 @@ Server.prototype.listen = function() { | |
|
||
var TCP = process.binding('tcp_wrap').TCP; | ||
|
||
if (arguments.length == 0 || util.isFunction(arguments[0])) { | ||
if (arguments.length === 0 || util.isFunction(arguments[0])) { | ||
// Bind to a random port. | ||
listen(self, null, 0, null, backlog); | ||
|
||
} else if (arguments[0] && util.isObject(arguments[0])) { | ||
} else if (util.isObject(arguments[0])) { | ||
var h = arguments[0]; | ||
if (h._handle) { | ||
h = h._handle; | ||
} else if (h.handle) { | ||
h = h.handle; | ||
} | ||
h = h._handle || h.handle || h; | ||
|
||
if (h instanceof TCP) { | ||
self._handle = h; | ||
listen(self, null, -1, -1, backlog); | ||
} else if (util.isNumber(h.fd) && h.fd >= 0) { | ||
listen(self, null, null, null, backlog, h.fd); | ||
} else { | ||
throw new Error('Invalid listen argument: ' + h); | ||
// The first argument is a configuration object | ||
if (h.backlog) | ||
backlog = h.backlog; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't it actually be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
||
if (util.isNumber(h.port)) { | ||
if (h.host) | ||
listenAfterLookup(h.port, h.host, backlog, h.exclusive); | ||
else | ||
listen(self, null, h.port, 4, backlog, undefined, h.exclusive); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary style change. |
||
} else if (h.path && isPipeName(h.path)) { | ||
var pipeName = self._pipeName = h.path; | ||
listen(self, pipeName, -1, -1, backlog, undefined, h.exclusive); | ||
} else { | ||
throw new Error('Invalid listen argument: ' + h); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. |
||
} | ||
} else if (isPipeName(arguments[0])) { | ||
// UNIX socket or Windows pipe. | ||
|
@@ -1223,14 +1235,20 @@ Server.prototype.listen = function() { | |
|
||
} else { | ||
// The first argument is the port, the second an IP. | ||
require('dns').lookup(arguments[1], function(err, ip, addressType) { | ||
listenAfterLookup(port, arguments[1], backlog); | ||
} | ||
|
||
function listenAfterLookup(port, address, backlog, exclusive) { | ||
require('dns').lookup(address, function(err, ip, addressType) { | ||
if (err) { | ||
self.emit('error', err); | ||
} else { | ||
listen(self, ip, port, ip ? addressType : 4, backlog); | ||
addressType = ip ? addressType : 4; | ||
listen(self, ip, port, addressType, backlog, undefined, exclusive); | ||
} | ||
}); | ||
} | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. drop the |
||
|
||
return self; | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// 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. | ||
|
||
var common = require('../common'); | ||
var assert = require('assert'); | ||
var cluster = require('cluster'); | ||
var dgram = require('dgram'); | ||
|
||
function noop() {} | ||
|
||
if (cluster.isMaster) { | ||
var worker1 = cluster.fork(); | ||
|
||
worker1.on('message', function(msg) { | ||
assert.equal(msg, 'success'); | ||
var worker2 = cluster.fork(); | ||
|
||
worker2.on('message', function(msg) { | ||
assert.equal(msg, 'socket2:EADDRINUSE'); | ||
worker1.kill(); | ||
worker2.kill(); | ||
}); | ||
}); | ||
} else { | ||
var socket1 = dgram.createSocket('udp4', noop); | ||
var socket2 = dgram.createSocket('udp4', noop); | ||
|
||
socket1.on('error', function(err) { | ||
// no errors expected | ||
process.send('socket1:' + err.code); | ||
}); | ||
|
||
socket2.on('error', function(err) { | ||
// an error is expected on the second worker | ||
process.send('socket2:' + err.code); | ||
}); | ||
|
||
socket1.bind({ | ||
address: 'localhost', | ||
port: common.PORT, | ||
exclusive: false | ||
}, function() { | ||
socket2.bind({port: common.PORT + 1, exclusive: true}, function() { | ||
// the first worker should succeed | ||
process.send('success'); | ||
}); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// 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. | ||
|
||
var common = require('../common'); | ||
var assert = require('assert'); | ||
var cluster = require('cluster'); | ||
var net = require('net'); | ||
|
||
function noop() {} | ||
|
||
if (cluster.isMaster) { | ||
var worker1 = cluster.fork(); | ||
|
||
worker1.on('message', function(msg) { | ||
assert.equal(msg, 'success'); | ||
var worker2 = cluster.fork(); | ||
|
||
worker2.on('message', function(msg) { | ||
assert.equal(msg, 'server2:EADDRINUSE'); | ||
worker1.kill(); | ||
worker2.kill(); | ||
}); | ||
}); | ||
} else { | ||
var server1 = net.createServer(noop); | ||
var server2 = net.createServer(noop); | ||
|
||
server1.on('error', function(err) { | ||
// no errors expected | ||
process.send('server1:' + err.code); | ||
}); | ||
|
||
server2.on('error', function(err) { | ||
// an error is expected on the second worker | ||
process.send('server2:' + err.code); | ||
}); | ||
|
||
server1.listen({ | ||
host: 'localhost', | ||
port: common.PORT, | ||
exclusive: false | ||
}, function() { | ||
server2.listen({port: common.PORT + 1, exclusive: true}, function() { | ||
// the first worker should succeed | ||
process.send('success'); | ||
}); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trailing whitespace