Skip to content

Commit

Permalink
add setKeepAlive function, which enables and sets the TCP keep-alive …
Browse files Browse the repository at this point in the history
…timer
  • Loading branch information
paragonRobotics authored and ry committed Apr 20, 2010
1 parent 27ec33a commit 5f8f561
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
9 changes: 9 additions & 0 deletions doc/api.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -2042,6 +2042,15 @@ Disables the Nagle algorithm. By default TCP connections use the Nagle
algorithm, they buffer data before sending it off. Setting `noDelay` will
immediately fire off data each time `stream.write()` is called.

### stream.setKeepAlive(enable=false, initialDelay)

Enable/disable keep-alive functionality, and optionally set the initial
delay before the first keepalive probe is sent on an idle stream.
Set `initialDelay` (in milliseconds) to set the delay between the last
data packet received and the first keepalive probe. Setting 0 for
initialDelay will leave the value unchanged from the default
(or previous) setting.


## DNS

Expand Down
11 changes: 10 additions & 1 deletion lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var read = binding.read;
var write = binding.write;
var toRead = binding.toRead;
var setNoDelay = binding.setNoDelay;
var setKeepAlive= binding.setKeepAlive;
var socketError = binding.socketError;
var getsockname = binding.getsockname;
var errnoException = binding.errnoException;
Expand Down Expand Up @@ -744,9 +745,17 @@ Stream.prototype.address = function () {


Stream.prototype.setNoDelay = function (v) {
if (this.type == 'tcp') setNoDelay(this.fd, v);
if ((this.type == 'tcp4')||(this.type == 'tcp6')) {
setNoDelay(this.fd, v);
}
};

Stream.prototype.setKeepAlive = function (enable, time) {
if ((this.type == 'tcp4')||(this.type == 'tcp6')) {
var secondDelay = Math.ceil(time/1000);
setKeepAlive(this.fd, enable, secondDelay);
}
};

Stream.prototype.setTimeout = function (msecs) {
timeout.enroll(this, msecs);
Expand Down
35 changes: 34 additions & 1 deletion src/node_net2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1062,11 +1062,43 @@ static Handle<Value> SetNoDelay(const Arguments& args) {
if (r < 0) {
return ThrowException(ErrnoException(errno, "setsockopt"));
}

return Undefined();
}


static Handle<Value> SetKeepAlive(const Arguments& args) {
int r;
HandleScope scope;

bool enable = false;
int time = 0;

FD_ARG(args[0])

if (args.Length() > 0) enable = args[1]->IsTrue();
if (enable == true) {
time = args[2]->Int32Value();
}

int flags = enable ? 1 : 0;
r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
if ((time > 0)&&(r >= 0)) {
#if defined(__APPLE__)
// Mac uses a different setting name than Linux
r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, (void *)&time, sizeof(time));
#elif defined(__sun)
// Solaris doesn't support TCP_KEEPIDLE, so do nothing here
#else
// assume anything else uses the Linux/BSD method
r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&time, sizeof(time));
#endif
}
if (r < 0) {
return ThrowException(ErrnoException(errno, "setsockopt"));
}
return Undefined();
}

//
// G E T A D D R I N F O
//
Expand Down Expand Up @@ -1287,6 +1319,7 @@ void InitNet2(Handle<Object> target) {
NODE_SET_METHOD(target, "socketError", SocketError);
NODE_SET_METHOD(target, "toRead", ToRead);
NODE_SET_METHOD(target, "setNoDelay", SetNoDelay);
NODE_SET_METHOD(target, "setKeepAlive", SetKeepAlive);
NODE_SET_METHOD(target, "getsockname", GetSockName);
NODE_SET_METHOD(target, "getpeername", GetPeerName);
NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
Expand Down
28 changes: 28 additions & 0 deletions test/simple/test-tcp-keepalive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require("../common");
net = require('net');

var serverConnection;
var echoServer = net.createServer(function (connection) {
serverConnection = connection;
connection.setTimeout(0);
assert.notEqual(connection.setKeepAlive,undefined);
// send a keepalive packet after 1000 ms
connection.setKeepAlive(true,1000);
connection.addListener("end", function () {
connection.end();
});
});
echoServer.listen(PORT);

var clientConnection = net.createConnection(PORT);
clientConnection.setTimeout(0);

setTimeout( function() {
// make sure both connections are still open
assert.equal(serverConnection.readyState,"open");
assert.equal(clientConnection.readyState,"open");
serverConnection.end();
clientConnection.end();
echoServer.close();
}, 1200);

0 comments on commit 5f8f561

Please sign in to comment.