mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
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.
This commit is contained in:
parent
19e53512b8
commit
911cbd0cef
36
lib/net.js
36
lib/net.js
@ -226,7 +226,7 @@ function Socket(options) {
|
||||
this.allowHalfOpen = options.allowHalfOpen || false;
|
||||
} else if (typeof options == 'number') {
|
||||
this.fd = arguments[0];
|
||||
this.type = arguments[1];
|
||||
this.type = arguments[1] || null;
|
||||
}
|
||||
|
||||
if (parseInt(this.fd, 10) >= 0) {
|
||||
@ -235,6 +235,7 @@ function Socket(options) {
|
||||
setImplmentationMethods(this);
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(Socket, stream.Stream);
|
||||
exports.Socket = Socket;
|
||||
|
||||
@ -250,7 +251,7 @@ Socket.prototype.open = function(fd, type) {
|
||||
initSocket(this);
|
||||
|
||||
this.fd = fd;
|
||||
this.type = type || null;
|
||||
this.type = type || getFdType(fd)
|
||||
this.readable = true;
|
||||
|
||||
setImplmentationMethods(this);
|
||||
@ -1142,16 +1143,43 @@ 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 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
|
||||
function rescueEMFILE(callback) {
|
||||
// Output a warning, but only at most every 5 seconds.
|
||||
var now = new Date();
|
||||
if (now - lastEMFILEWarning > 5000) {
|
||||
console.error('(node) Hit max file limit. Increase "ulimit - n"');
|
||||
console.error('(node) Hit max file limit. Increase "ulimit -n"');
|
||||
lastEMFILEWarning = now;
|
||||
}
|
||||
|
||||
|
@ -591,6 +591,42 @@ static Handle<Value> GetSockName(const Arguments& args) {
|
||||
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) {
|
||||
HandleScope scope;
|
||||
@ -720,6 +756,40 @@ static Handle<Value> SocketError(const Arguments& args) {
|
||||
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);
|
||||
// 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, "isIP", IsIP);
|
||||
NODE_SET_METHOD(target, "errnoException", CreateErrnoException);
|
||||
NODE_SET_METHOD(target, "getsocktype", GetSockType);
|
||||
NODE_SET_METHOD(target, "getsockfamily", GetSockFamily);
|
||||
|
||||
errno_symbol = NODE_PSYMBOL("errno");
|
||||
syscall_symbol = NODE_PSYMBOL("syscall");
|
||||
|
24
test/simple/test-gets-auto-fd.js
Normal file
24
test/simple/test-gets-auto-fd.js
Normal file
@ -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…
Reference in New Issue
Block a user