Browse Source

Add support for file descriptor type detection.

setImplementationMethods checks the type of a socket and defines different
behavior based on the type, so auto detect it if type not implicitly
specified.
v0.7.4-release
Daniel Ennis 14 years ago
committed by Ryan Dahl
parent
commit
911cbd0cef
  1. 34
      lib/net.js
  2. 72
      src/node_net.cc
  3. 24
      test/simple/test-gets-auto-fd.js

34
lib/net.js

@ -226,7 +226,7 @@ function Socket(options) {
this.allowHalfOpen = options.allowHalfOpen || false; this.allowHalfOpen = options.allowHalfOpen || false;
} else if (typeof options == 'number') { } else if (typeof options == 'number') {
this.fd = arguments[0]; this.fd = arguments[0];
this.type = arguments[1]; this.type = arguments[1] || null;
} }
if (parseInt(this.fd, 10) >= 0) { if (parseInt(this.fd, 10) >= 0) {
@ -235,6 +235,7 @@ function Socket(options) {
setImplmentationMethods(this); setImplmentationMethods(this);
} }
} }
util.inherits(Socket, stream.Stream); util.inherits(Socket, stream.Stream);
exports.Socket = Socket; exports.Socket = Socket;
@ -250,7 +251,7 @@ Socket.prototype.open = function(fd, type) {
initSocket(this); initSocket(this);
this.fd = fd; this.fd = fd;
this.type = type || null; this.type = type || getFdType(fd)
this.readable = true; this.readable = true;
setImplmentationMethods(this); setImplmentationMethods(this);
@ -1142,10 +1143,37 @@ Server.prototype.close = function() {
} }
}; };
function getFdType(fd) {
var type = 'file';
var family;
try {
type = binding.getsocktype(fd);
family = binding.getsockfamily(fd);
if (family == "AF_UNIX") {
type = "unix";
} else if (type == "SOCK_STREAM" && family == "AF_INET") {
type = "tcp";
} else if (type == "SOCK_STREAM" && family == "AF_INET6") {
type = "tcp6";
} else if (type == "SOCK_DGRAM" && family == "AF_INET") {
type = "udp";
} else if (type == "SOCK_DGRAM" && family == "AF_INET6") {
type = "udp6";
}
} catch (e) {
if (e.code == 'ENOTSOCK') {
type = 'file';
} else {
throw e;
}
}
return type;
}
exports.getFdType = getFdType;
var dummyFD = null; var dummyFD = null;
var lastEMFILEWarning = 0; var lastEMFILEWarning = 0;
// Ensures to have at least on free file-descriptor free. // Ensures to have at least one free file-descriptor free.
// callback should only use 1 file descriptor and close it before end of call // callback should only use 1 file descriptor and close it before end of call
function rescueEMFILE(callback) { function rescueEMFILE(callback) {
// Output a warning, but only at most every 5 seconds. // Output a warning, but only at most every 5 seconds.

72
src/node_net.cc

@ -591,6 +591,42 @@ static Handle<Value> GetSockName(const Arguments& args) {
return scope.Close(info); return scope.Close(info);
} }
static Handle<Value> GetSockFamily(const Arguments& args) {
HandleScope scope;
FD_ARG(args[0])
Local<Value> result;
struct sockaddr_storage address_storage;
socklen_t len = sizeof(struct sockaddr_storage);
#ifdef __POSIX__
if (0 > getsockname(fd, (struct sockaddr *) &address_storage, &len)) {
return ThrowException(ErrnoException(errno, "getsockname"));
}
#else // __MINGW32__
if (SOCKET_ERROR == getsockname(_get_osfhandle(fd),
(struct sockaddr *) &address_storage, &len)) {
return ThrowException(ErrnoException(WSAGetLastError(), "getsockname"));
}
#endif // __MINGW32__
switch ((address_storage).ss_family) {
case AF_INET6:
result = String::New("AF_INET6");
break;
case AF_INET:
result = String::New("AF_INET");
break;
case AF_UNIX:
result = String::New("AF_UNIX");
break;
default:
result = Integer::New((address_storage).ss_family);
}
scope.Close(result);
}
static Handle<Value> GetPeerName(const Arguments& args) { static Handle<Value> GetPeerName(const Arguments& args) {
HandleScope scope; HandleScope scope;
@ -720,6 +756,40 @@ static Handle<Value> SocketError(const Arguments& args) {
return scope.Close(Integer::New(error)); return scope.Close(Integer::New(error));
} }
static Handle<Value> GetSockType(const Arguments& args) {
HandleScope scope;
FD_ARG(args[0])
int type;
socklen_t len = sizeof(int);
#ifdef __POSIX__
int r = getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len);
if (r < 0) {
return ThrowException(ErrnoException(errno, "getsockopt"));
}
#else // __MINGW32__
int r = getsockopt(_get_osfhandle(fd), SOL_SOCKET, SO_TYPE, (char*)&type, &len);
if (r < 0) {
return ThrowException(ErrnoException(WSAGetLastError(), "getsockopt"));
}
#endif
Local<Value> result;
switch (type) {
case SOCK_STREAM:
result = String::New("SOCK_STREAM");
break;
case SOCK_DGRAM:
result = String::New("SOCK_DGRAM");
break;
default:
result = Integer::New(type);
}
return scope.Close(result);
}
// var bytesRead = t.read(fd, buffer, offset, length); // var bytesRead = t.read(fd, buffer, offset, length);
// returns null on EAGAIN or EINTR, raises an exception on all other errors // returns null on EAGAIN or EINTR, raises an exception on all other errors
@ -1760,6 +1830,8 @@ void InitNet(Handle<Object> target) {
NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo); NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
NODE_SET_METHOD(target, "isIP", IsIP); NODE_SET_METHOD(target, "isIP", IsIP);
NODE_SET_METHOD(target, "errnoException", CreateErrnoException); NODE_SET_METHOD(target, "errnoException", CreateErrnoException);
NODE_SET_METHOD(target, "getsocktype", GetSockType);
NODE_SET_METHOD(target, "getsockfamily", GetSockFamily);
errno_symbol = NODE_PSYMBOL("errno"); errno_symbol = NODE_PSYMBOL("errno");
syscall_symbol = NODE_PSYMBOL("syscall"); syscall_symbol = NODE_PSYMBOL("syscall");

24
test/simple/test-gets-auto-fd.js

@ -0,0 +1,24 @@
var assert = require('assert');
var net = require('net');
var common = require('../common');
var server = net.createServer();
//test unix sockets
var fds = process.binding('net').socketpair();
var unixsocket = new net.Socket(fds[0]);
assert.ok(unixsocket.type == 'unix', 'Should be UNIX');
//test that stdin is default file
assert.ok(process.stdin.type == 'file', 'Should be File');
//test tcp sockets.
server.listen(function() {
var client = net.createConnection(this.address().port);
client.on('connect', function() {
var newStream = new net.Socket(client.fd);
assert.ok(newStream.type == 'tcp', 'Should be TCP');
client.destroy();
server.close();
});
});
Loading…
Cancel
Save