Nikolai Gorchilov
Nikolai Gorchilov

Reputation: 927

How to setsockopt under node.js?

Is there a setsockopt/getsockopt-like socket options manipulation functionality in node.js?

Upvotes: 4

Views: 3768

Answers (3)

ShortFuse
ShortFuse

Reputation: 6824

I'm expanding on the comment left by socketpair which shows getsockopt. You can accomplish this by using ffi and ref. I've reformatted this to allow it to be easily manipulated.

I edited my comment because I had to make some changes to make the code work on both Linux and Win32. I had to create a node library for Windows to get the socket handle and pass it to setsockopt. Be aware that Linux and Windows may have different values for socket options

Edit: Here's a cleaned up piece of of production code I'm using:

var net = require("net");
var ffi = require("ffi");
var ref = require("ref");
var getSocketHandleAddress;

var SOL_SOCKET = 0x1;
var SO_OOBINLINE = 0xA;
var _setsockopt;

if (process.platform == "win32") {
  SOL_SOCKET = 0xffff;
  SO_OOBINLINE = 0x0100;
}

var setSocketOption = function (handle, level, option, value) {
  if (!_setsockopt) {
    var library;
    var paramTypes;
    if (process.platform === "win32") {
      library = "ws2_32.dll";
      paramTypes = [
        ref.types.int,
        ref.types.int,
        ref.types.int,
        ref.refType(ref.types.void),
        ref.types.int
      ];
    } else {
      paramTypes = [
        ref.types.int,
        ref.types.int,
        ref.types.int,
        ref.refType(ref.types.void),
        ref.refType(ref.types.int)
      ];
    }
    var lib = new ffi.DynamicLibrary(library);
    _setsockopt = ffi.ForeignFunction(
      lib.get("setsockopt"),
      ref.types.int,
      paramTypes);
  }
  var refType;
  var length;
  if (typeof value === "boolean") {
    refType = ref.types.bool;
  } else {
    refType = ref.types.int;
  }
  if (process.platform !== "win32") {
    return _setsockopt(
      handle.fd, 
      level, 
      option, 
      ref.alloc(refType, value), 
      ref.alloc(ref.types.int, refType.size)
    );
  }
  if (!getSocketHandleAddress) {
    getSocketHandleAddress = require("getsockethandleaddress");
  }
  return _setsockopt(
    getSocketHandleAddress.getAddress(handle),
    level,
    option,
    ref.alloc(refType, value), 
    refType.size
  );

};

var tcpserver = net.createServer(function (socket) {
  var ret = setSocketOption(socket._handle, SOL_SOCKET, SO_OOBINLINE, true);
  if (ret !== 0) {
    console.error("OOB Inline socket option failed: " + ret);
  }
});

Upvotes: 7

George
George

Reputation: 1466

Kind of late but here is a pacakge on npm https://www.npmjs.com/package/net-keepalive

Provides high-level access to socket options like TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT

var Net = require('net')
  , NetKeepAlive = require('net-keepalive')
;

// Create a TCP Server
var srv = Net.createServer(function(s){>
  console.log('Connected %j', s.address())
  // Doesn't matter what it does
  s.pipe(s)
});

// Start on some port
srv.listen(1337, function(){
  console.log('Listening on %j', srv.address())
});

// Connect to that server
var s = Net.createConnection({port:1337}, function(){
  console.log('Connected to %j', s.address())

  //IMPORTANT: KeepAlive must be enabled for this to work
  s.setKeepAlive(true, 1000)

  // Set TCP_KEEPINTVL for this specific socket
  NetKeepAlive.setKeepAliveInterval(s, 1000)

  // and TCP_KEEPCNT
  NetKeepAlive.setKeepAliveProbes(s, 1)
});

Upvotes: -1

socketpair
socketpair

Reputation: 1998

This is my getsockopt:

var ffi = require('ffi');
var net = require('net');
var StructType = require('ref-struct');
var ref = require('ref');

var current = ffi.Library(null, {
  'getsockopt': [ 'int', [ 'int', 'int', 'int', 'pointer', 'pointer']],
  'ntohs': ['uint16', ['uint16']],
//    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

});

var SOL_IP = 0;
var SO_ORIGINAL_DST = 80;
var AF_INET = 2;

var sockaddr_in = StructType([
    ['int16', 'sin_family'],
    ['uint16', 'sin_port'],
    ['uint32', 'sin_addr'],
    ['uint32', 'trash1'],
    ['uint32', 'trash2'],
]);

function get_original_dst(client) {
    var dst = new sockaddr_in;
    var dstlen = ref.alloc(ref.types.int, sockaddr_in.size);
    var r = current.getsockopt(client._handle.fd, SOL_IP, SO_ORIGINAL_DST, dst.ref(), dstlen);
    if (r === -1)
        throw new Error("getsockopt(SO_ORIGINAL_DST) error");
    if (dst.sin_family !== AF_INET)
        throw new Error("getsockopt(SO_ORIGINAL_DST) returns unknown family: " + dst.sin_family );

    // TODO: inet_ntop. inet_ntoa is _UNSAFE_
    var ipaddr = dst.ref(); ipaddr = ipaddr[4] + "." + ipaddr[5] + "." + ipaddr[6] + "." + ipaddr[7];

    return [ipaddr, current.ntohs(dst.sin_port)];
}

module.exports.get_original_dst = get_original_dst;

Upvotes: 4

Related Questions