Skip to content

Commit

Permalink
Merge pull request #1 from jfrconley/master
Browse files Browse the repository at this point in the history
Add support for node cluster
  • Loading branch information
Ardalan Amini authored Jan 16, 2019
2 parents 8ae9642 + 0f0b47f commit d76f1d3
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 12 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ Create a new TCP server. Options include:

``` js
{
allowHalfOpen: false // set to true to allow half open TCP connections
allowHalfOpen: false, // set to true to allow half open TCP connections
reusePort: true // Disable if you don't want SO_REUSEPORT to be set (SO_REUSEADDR on windows)
}
```

Expand Down
3 changes: 2 additions & 1 deletion lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class Connection extends events.EventEmitter {
this._onwrite,
this._onread,
this._onfinish,
this._onclose
this._onclose,
0
)

if (server) {
Expand Down
11 changes: 10 additions & 1 deletion lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const binding = require('./binding')
const Connection = require('./connection')
const lookup = require('./lookup')
const events = require('events')
const semver = require('semver')
const os = require('os')

class Server extends events.EventEmitter {
constructor (opts) {
Expand All @@ -10,6 +12,12 @@ class Server extends events.EventEmitter {

this.connections = []
this.allowHalfOpen = !!opts.allowHalfOpen
this.reusePort = (opts.reusePort || opts.reusePort == null) ? 1 : 0

// SO_REUSEPORT is only supported on kernel 3.9+
if (os.platform() === 'linux' && !semver.satisfies(semver.coerce(os.release()), '>=3.9')) {
this.reusePort = 0
}

this._closed = false
this._address = null
Expand Down Expand Up @@ -71,7 +79,8 @@ class Server extends events.EventEmitter {
null,
null,
null,
this._onclose
this._onclose,
this.reusePort
)
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dependencies": {
"napi-macros": "^1.3.0",
"node-gyp-build": "^3.3.0",
"semver": "^5.5.1",
"unordered-set": "^2.0.0"
},
"devDependencies": {
Expand Down
26 changes: 24 additions & 2 deletions src/turbo_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,38 @@ static void on_uv_connect (uv_connect_t* req, int status) {
}

NAPI_METHOD(turbo_net_tcp_init) {
NAPI_ARGV(8)
NAPI_ARGV(9)
NAPI_ARGV_BUFFER_CAST(turbo_net_tcp_t *, self, 0)
NAPI_ARGV_UINT32(reusePort, 8)

int err;
uv_tcp_t *handle = &(self->handle);

handle->data = self;
self->env = env;

NAPI_UV_THROWS(err, uv_tcp_init(uv_default_loop(), handle));
// SO_REUSEADDR on windows
#ifdef _WIN32
if (!reusePort) {
NAPI_UV_THROWS(err, uv_tcp_init(uv_default_loop(), handle));
} else {
NAPI_UV_THROWS(err, uv_tcp_init_ex(uv_default_loop(), handle, AF_INET));
uv_os_fd_t fd;
int on = 1;
NAPI_UV_THROWS(err, uv_fileno((const uv_handle_t *) handle, &fd));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
}
#else
if (!reusePort) {
NAPI_UV_THROWS(err, uv_tcp_init(uv_default_loop(), handle));
} else {
NAPI_UV_THROWS(err, uv_tcp_init_ex(uv_default_loop(), handle, AF_INET));
uv_os_fd_t fd;
int on = 1;
NAPI_UV_THROWS(err, uv_fileno((const uv_handle_t *) handle, &fd));
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
}
#endif

napi_create_reference(env, argv[1], 1, &(self->ctx));
napi_create_reference(env, argv[2], 1, &(self->on_alloc_connection));
Expand Down
31 changes: 29 additions & 2 deletions test/server.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const tape = require('tape')
const turbo = require('../')
const os = require('os')
const semver = require('semver')

tape('listen', function (t) {
const server = turbo.createServer()
Expand Down Expand Up @@ -46,10 +48,14 @@ tape('address no listen', function (t) {
})

tape('listen on used port', function (t) {
const server = turbo.createServer()
const server = turbo.createServer({
reusePort: false
})

server.listen(function () {
const another = turbo.createServer()
const another = turbo.createServer({
reusePort: false
})

another.on('error', function (err) {
server.close()
Expand All @@ -60,3 +66,24 @@ tape('listen on used port', function (t) {
another.listen(server.address().port)
})
})

tape(`listen on used port (SO_REUSEPORT) (${os.platform()}:${os.release()})`, function (t) {
if (os.platform() === 'linux' && !semver.satisfies(semver.coerce(os.release()), '>=3.9')) {
t.pass('SO_REUSEPORT only supported on kernel 3.9+')
t.end()
return
}

const server = turbo.createServer()

server.listen(function () {
const another = turbo.createServer()

another.listen(server.address().port, function () {
server.close()
another.close()
t.pass('should not error')
t.end()
})
})
})
10 changes: 5 additions & 5 deletions test/write.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const tape = require('tape')
const turbo = require('../')

tape('writev', function (t) {
const server = turbo.createServer(echo)
const server = turbo.createServer(echo, {reusePort: false})

server.listen(function () {
const client = turbo.connect(server.address().port)
Expand All @@ -22,7 +22,7 @@ tape('writev', function (t) {
})

tape('writev after connect', function (t) {
const server = turbo.createServer(echo)
const server = turbo.createServer(echo, {reusePort: false})

server.listen(function () {
const client = turbo.connect(server.address().port)
Expand All @@ -44,7 +44,7 @@ tape('writev after connect', function (t) {
})

tape('writev before and after connect', function (t) {
const server = turbo.createServer(echo)
const server = turbo.createServer(echo, {reusePort: false})

server.listen(function () {
const client = turbo.connect(server.address().port)
Expand Down Expand Up @@ -73,7 +73,7 @@ tape('writev before and after connect', function (t) {
})

tape('writev twice', function (t) {
const server = turbo.createServer(echo)
const server = turbo.createServer(echo, {reusePort: false})

server.listen(function () {
const client = turbo.connect(server.address().port)
Expand All @@ -99,7 +99,7 @@ tape('writev twice', function (t) {
})

tape('write 256 buffers', function (t) {
const server = turbo.createServer(echo)
const server = turbo.createServer(echo, {reusePort: false})

server.listen(function () {
const client = turbo.connect(server.address().port)
Expand Down

0 comments on commit d76f1d3

Please sign in to comment.