Use AF_INET sockets instead of always AF_INET6
You can get AF_INET6 still, it's just not the only choice.
This commit is contained in:
parent
fdae14070c
commit
b9106b0ecd
69
lib/net.js
69
lib/net.js
@ -39,7 +39,7 @@ var setNoDelay = binding.setNoDelay;
|
||||
var socketError = binding.socketError;
|
||||
var getsockname = binding.getsockname;
|
||||
var getaddrinfo = binding.getaddrinfo;
|
||||
var needsLookup = binding.needsLookup;
|
||||
var isIP = binding.isIP;
|
||||
var errnoException = binding.errnoException;
|
||||
var EINPROGRESS = binding.EINPROGRESS;
|
||||
var ENOENT = binding.ENOENT;
|
||||
@ -422,6 +422,7 @@ Stream.prototype.write = function (data, encoding) {
|
||||
Stream.prototype._writeOut = function (data, encoding) {
|
||||
if (!this.writable) throw new Error('Stream is not writable');
|
||||
|
||||
if (data.length == 0) return true;
|
||||
|
||||
var buffer, off, len;
|
||||
var bytesWritten, charsWritten;
|
||||
@ -566,6 +567,8 @@ function doConnect (socket, port, host) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug('connecting to ' + host + ' : ' + port);
|
||||
|
||||
// Don't start the read watcher until connection is established
|
||||
socket._readWatcher.set(socket.fd, true, false);
|
||||
|
||||
@ -607,13 +610,13 @@ Stream.prototype.connect = function () {
|
||||
var port = parseInt(arguments[0]);
|
||||
|
||||
if (port >= 0) {
|
||||
self.fd = socket('tcp');
|
||||
//debug('new fd = ' + self.fd);
|
||||
self.type = 'tcp';
|
||||
// TODO dns resolution on arguments[1]
|
||||
var port = arguments[0];
|
||||
self._resolving = true;
|
||||
lookupDomainName(arguments[1], function (ip) {
|
||||
lookupDomainName(arguments[1], function (ip, isV4) {
|
||||
self.type = isV4 ? 'tcp4' : 'tcp6';
|
||||
self.fd = socket(self.type);
|
||||
self._resolving = false;
|
||||
doConnect(self, port, ip);
|
||||
});
|
||||
@ -729,8 +732,8 @@ function Server (listener) {
|
||||
if (!peerInfo) return;
|
||||
|
||||
var s = new Stream(peerInfo.fd);
|
||||
s.remoteAddress = peerInfo.remoteAddress;
|
||||
s.remotePort = peerInfo.remotePort;
|
||||
s.remoteAddress = peerInfo.address;
|
||||
s.remotePort = peerInfo.port;
|
||||
s.type = self.type;
|
||||
s.server = self;
|
||||
s.resume();
|
||||
@ -750,25 +753,27 @@ exports.createServer = function (listener) {
|
||||
return new Server(listener);
|
||||
};
|
||||
|
||||
/* This function does both an ipv4 and ipv6 look up.
|
||||
* It first tries the ipv4 look up, if that fails, then it does the ipv6.
|
||||
*/
|
||||
// This function does both an ipv4 and ipv6 look up.
|
||||
// It first tries the ipv4 look up, if that fails, then it does the ipv6.
|
||||
// callback(dn, isV4
|
||||
function lookupDomainName (dn, callback) {
|
||||
if (!needsLookup(dn)) {
|
||||
var kind = isIP(dn);
|
||||
debug('kind = ' + kind);
|
||||
if (kind) {
|
||||
// Always wait until the next tick this is so people can do
|
||||
//
|
||||
// server.listen(8000);
|
||||
// server.addListener('listening', fn);
|
||||
//
|
||||
// Marginally slower, but a lot fewer WTFs.
|
||||
process.nextTick(function () { callback(dn); })
|
||||
process.nextTick(function () { callback(dn, kind == 4 ? true : false); })
|
||||
} else {
|
||||
debug("getaddrinfo 4 " + dn);
|
||||
getaddrinfo(dn, 4, function (r4) {
|
||||
if (r4 instanceof Error) throw r4;
|
||||
if (r4.length > 0) {
|
||||
debug("getaddrinfo 4 found " + r4);
|
||||
callback(r4[0]);
|
||||
callback(r4[0], true);
|
||||
} else {
|
||||
debug("getaddrinfo 6 " + dn);
|
||||
getaddrinfo(dn, 6, function (r6) {
|
||||
@ -777,7 +782,7 @@ function lookupDomainName (dn, callback) {
|
||||
throw new Error("No address associated with hostname " + dn);
|
||||
}
|
||||
debug("getaddrinfo 6 found " + r6);
|
||||
callback(r6[0]);
|
||||
callback(r6[0], false);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -797,13 +802,6 @@ Server.prototype.listen = function () {
|
||||
var self = this;
|
||||
if (self.fd) throw new Error('Server already opened');
|
||||
|
||||
function doListen () {
|
||||
listen(self.fd, 128);
|
||||
self.watcher.set(self.fd, true, false);
|
||||
self.watcher.start();
|
||||
self.emit("listening");
|
||||
}
|
||||
|
||||
if (typeof(arguments[0]) == 'string') {
|
||||
// the first argument specifies a path
|
||||
self.fd = socket('unix');
|
||||
@ -815,7 +813,7 @@ Server.prototype.listen = function () {
|
||||
if (err) {
|
||||
if (err.errno == ENOENT) {
|
||||
bind(self.fd, path);
|
||||
doListen();
|
||||
self._doListen();
|
||||
} else {
|
||||
throw r;
|
||||
}
|
||||
@ -828,30 +826,41 @@ Server.prototype.listen = function () {
|
||||
throw err;
|
||||
} else {
|
||||
bind(self.fd, path);
|
||||
doListen();
|
||||
self._doListen();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (!arguments[0]) {
|
||||
} else if (!arguments[1]) {
|
||||
// Don't bind(). OS will assign a port with INADDR_ANY.
|
||||
// The port can be found with server.address()
|
||||
self.fd = socket('tcp');
|
||||
self.type = 'tcp';
|
||||
doListen();
|
||||
self.type = 'tcp4';
|
||||
self.fd = socket(self.type);
|
||||
bind(self.fd, arguments[0]);
|
||||
process.nextTick(function () {
|
||||
self._doListen();
|
||||
});
|
||||
} else {
|
||||
// the first argument is the port, the second an IP
|
||||
self.fd = socket('tcp');
|
||||
self.type = 'tcp';
|
||||
var port = arguments[0];
|
||||
lookupDomainName(arguments[1], function (ip) {
|
||||
lookupDomainName(arguments[1], function (ip, isV4) {
|
||||
self.type = isV4 ? 'tcp4' : 'tcp6';
|
||||
self.fd = socket(self.type);
|
||||
bind(self.fd, port, ip);
|
||||
doListen();
|
||||
self._doListen();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype._doListen = function () {
|
||||
listen(this.fd, 128);
|
||||
this.watcher.set(this.fd, true, false);
|
||||
this.watcher.start();
|
||||
this.emit("listening");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Server.prototype.address = function () {
|
||||
return getsockname(this.fd);
|
||||
|
163
src/node_net2.cc
163
src/node_net2.cc
@ -38,8 +38,6 @@ static Persistent<String> errno_symbol;
|
||||
static Persistent<String> syscall_symbol;
|
||||
|
||||
static Persistent<String> fd_symbol;
|
||||
static Persistent<String> remote_address_symbol;
|
||||
static Persistent<String> remote_port_symbol;
|
||||
static Persistent<String> address_symbol;
|
||||
static Persistent<String> port_symbol;
|
||||
static Persistent<String> type_symbol;
|
||||
@ -467,20 +465,27 @@ static Handle<Value> Socket(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
// default to TCP
|
||||
int domain = PF_INET6;
|
||||
int domain = PF_INET;
|
||||
int type = SOCK_STREAM;
|
||||
|
||||
if (args[0]->IsString()) {
|
||||
String::Utf8Value t(args[0]->ToString());
|
||||
// FIXME optimize this cascade.
|
||||
if (0 == strcasecmp(*t, "TCP")) {
|
||||
domain = PF_INET;
|
||||
type = SOCK_STREAM;
|
||||
} else if (0 == strcasecmp(*t, "TCP4")) {
|
||||
domain = PF_INET;
|
||||
type = SOCK_STREAM;
|
||||
} else if (0 == strcasecmp(*t, "TCP6")) {
|
||||
domain = PF_INET6;
|
||||
type = SOCK_STREAM;
|
||||
} else if (0 == strcasecmp(*t, "UNIX")) {
|
||||
domain = PF_UNIX;
|
||||
type = SOCK_STREAM;
|
||||
} else if (0 == strcasecmp(*t, "UDP")) {
|
||||
domain = PF_INET6;
|
||||
type = SOCK_DGRAM;
|
||||
} else if (0 == strcasecmp(*t, "UNIX")) {
|
||||
domain = PF_UNIX;
|
||||
type = SOCK_STREAM;
|
||||
} else {
|
||||
return ThrowException(Exception::Error(
|
||||
String::New("Unknown socket type.")));
|
||||
@ -505,13 +510,14 @@ static Handle<Value> Socket(const Arguments& args) {
|
||||
// (yes this is all to avoid one small heap alloc)
|
||||
static struct sockaddr *addr;
|
||||
static socklen_t addrlen;
|
||||
static struct sockaddr_un un;
|
||||
static struct sockaddr_in6 in6;
|
||||
static inline Handle<Value> ParseAddressArgs(Handle<Value> first,
|
||||
Handle<Value> second,
|
||||
struct in6_addr default_addr
|
||||
) {
|
||||
if (first->IsString() && second->IsUndefined()) {
|
||||
bool is_bind) {
|
||||
static struct sockaddr_un un;
|
||||
static struct sockaddr_in in;
|
||||
static struct sockaddr_in6 in6;
|
||||
|
||||
if (first->IsString() && !second->IsString()) {
|
||||
// UNIX
|
||||
String::Utf8Value path(first->ToString());
|
||||
|
||||
@ -528,36 +534,32 @@ static inline Handle<Value> ParseAddressArgs(Handle<Value> first,
|
||||
|
||||
} else {
|
||||
// TCP or UDP
|
||||
int port = first->Int32Value();
|
||||
memset(&in, 0, sizeof in);
|
||||
memset(&in6, 0, sizeof in6);
|
||||
|
||||
int port = first->Int32Value();
|
||||
in.sin_port = in6.sin6_port = htons(port);
|
||||
in.sin_family = AF_INET;
|
||||
in6.sin6_family = AF_INET6;
|
||||
|
||||
bool is_ipv4 = true;
|
||||
|
||||
if (!second->IsString()) {
|
||||
in6.sin6_addr = default_addr;
|
||||
in.sin_addr.s_addr = htonl(is_bind ? INADDR_ANY : INADDR_LOOPBACK);
|
||||
in6.sin6_addr = is_bind ? in6addr_any : in6addr_loopback;
|
||||
} else {
|
||||
String::Utf8Value ip(second->ToString());
|
||||
|
||||
char ipv6[255] = "::FFFF:";
|
||||
|
||||
if (inet_pton(AF_INET, *ip, &(in6.sin6_addr)) > 0) {
|
||||
// If this is an IPv4 address then we need to change it
|
||||
// to the IPv4-mapped-on-IPv6 format which looks like
|
||||
// ::FFFF:<IPv4 address>
|
||||
// For more information see "Address Format" ipv6(7) and
|
||||
// "BUGS" in inet_pton(3)
|
||||
strcat(ipv6, *ip);
|
||||
} else {
|
||||
strcpy(ipv6, *ip);
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, ipv6, &(in6.sin6_addr)) <= 0) {
|
||||
return ErrnoException(errno, "inet_pton", "Invalid IP Address");
|
||||
if (inet_pton(AF_INET, *ip, &(in.sin_addr)) <= 0) {
|
||||
is_ipv4 = false;
|
||||
if (inet_pton(AF_INET6, *ip, &(in6.sin6_addr)) <= 0) {
|
||||
return ErrnoException(errno, "inet_pton", "Invalid IP Address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in6.sin6_family = AF_INET6;
|
||||
in6.sin6_port = htons(port);
|
||||
|
||||
addr = (struct sockaddr*)&in6;
|
||||
addrlen = sizeof in6;
|
||||
addr = is_ipv4 ? (struct sockaddr*)&in : (struct sockaddr*)&in6;
|
||||
addrlen = is_ipv4 ? sizeof in : sizeof in6;
|
||||
}
|
||||
return Handle<Value>();
|
||||
}
|
||||
@ -578,7 +580,7 @@ static Handle<Value> Bind(const Arguments& args) {
|
||||
|
||||
FD_ARG(args[0])
|
||||
|
||||
Handle<Value> error = ParseAddressArgs(args[1], args[2], in6addr_any);
|
||||
Handle<Value> error = ParseAddressArgs(args[1], args[2], true);
|
||||
if (!error.IsEmpty()) return ThrowException(error);
|
||||
|
||||
int flags = 1;
|
||||
@ -658,7 +660,7 @@ static Handle<Value> Connect(const Arguments& args) {
|
||||
|
||||
FD_ARG(args[0])
|
||||
|
||||
Handle<Value> error = ParseAddressArgs(args[1], args[2], in6addr_loopback);
|
||||
Handle<Value> error = ParseAddressArgs(args[1], args[2], false);
|
||||
if (!error.IsEmpty()) return ThrowException(error);
|
||||
|
||||
int r = connect(fd, addr, addrlen);
|
||||
@ -671,6 +673,31 @@ static Handle<Value> Connect(const Arguments& args) {
|
||||
}
|
||||
|
||||
|
||||
#define ADDRESS_TO_JS(info, address_storage) \
|
||||
do { \
|
||||
char ip[INET6_ADDRSTRLEN]; \
|
||||
int port; \
|
||||
struct sockaddr_in *a4; \
|
||||
struct sockaddr_in6 *a6; \
|
||||
switch ((address_storage).ss_family) { \
|
||||
case AF_INET6: \
|
||||
a6 = (struct sockaddr_in6*)&(address_storage); \
|
||||
inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \
|
||||
port = ntohs(a6->sin6_port); \
|
||||
(info)->Set(address_symbol, String::New(ip)); \
|
||||
(info)->Set(port_symbol, Integer::New(port)); \
|
||||
break; \
|
||||
case AF_INET: \
|
||||
a4 = (struct sockaddr_in*)&(address_storage); \
|
||||
inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \
|
||||
port = ntohs(a4->sin_port); \
|
||||
(info)->Set(address_symbol, String::New(ip)); \
|
||||
(info)->Set(port_symbol, Integer::New(port)); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
static Handle<Value> GetSockName(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
@ -687,17 +714,7 @@ static Handle<Value> GetSockName(const Arguments& args) {
|
||||
|
||||
Local<Object> info = Object::New();
|
||||
|
||||
if (address_storage.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *a = (struct sockaddr_in6*)&address_storage;
|
||||
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &(a->sin6_addr), ip, INET6_ADDRSTRLEN);
|
||||
|
||||
int port = ntohs(a->sin6_port);
|
||||
|
||||
info->Set(address_symbol, String::New(ip));
|
||||
info->Set(port_symbol, Integer::New(port));
|
||||
}
|
||||
ADDRESS_TO_JS(info, address_storage);
|
||||
|
||||
return scope.Close(info);
|
||||
}
|
||||
@ -719,17 +736,7 @@ static Handle<Value> GetPeerName(const Arguments& args) {
|
||||
|
||||
Local<Object> info = Object::New();
|
||||
|
||||
if (address_storage.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *a = (struct sockaddr_in6*)&address_storage;
|
||||
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &(a->sin6_addr), ip, INET6_ADDRSTRLEN);
|
||||
|
||||
int port = ntohs(a->sin6_port);
|
||||
|
||||
info->Set(remote_address_symbol, String::New(ip));
|
||||
info->Set(remote_port_symbol, Integer::New(port));
|
||||
}
|
||||
ADDRESS_TO_JS(info, address_storage);
|
||||
|
||||
return scope.Close(info);
|
||||
}
|
||||
@ -753,8 +760,8 @@ static Handle<Value> Listen(const Arguments& args) {
|
||||
// var peerInfo = t.accept(server_fd);
|
||||
//
|
||||
// peerInfo.fd
|
||||
// peerInfo.remoteAddress
|
||||
// peerInfo.remotePort
|
||||
// peerInfo.address
|
||||
// peerInfo.port
|
||||
//
|
||||
// Returns a new nonblocking socket fd. If the listen queue is empty the
|
||||
// function returns null (wait for server_fd to become readable and try
|
||||
@ -784,17 +791,7 @@ static Handle<Value> Accept(const Arguments& args) {
|
||||
|
||||
peer_info->Set(fd_symbol, Integer::New(peer_fd));
|
||||
|
||||
if (address_storage.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *a = (struct sockaddr_in6*)&address_storage;
|
||||
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &(a->sin6_addr), ip, INET6_ADDRSTRLEN);
|
||||
|
||||
int port = ntohs(a->sin6_port);
|
||||
|
||||
peer_info->Set(remote_address_symbol, String::New(ip));
|
||||
peer_info->Set(remote_port_symbol, Integer::New(port));
|
||||
}
|
||||
ADDRESS_TO_JS(peer_info, address_storage);
|
||||
|
||||
return scope.Close(peer_info);
|
||||
}
|
||||
@ -1226,28 +1223,28 @@ static Handle<Value> GetAddrInfo(const Arguments& args) {
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> NeedsLookup(const Arguments& args) {
|
||||
static Handle<Value> IsIP(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
if (args[0]->IsNull() || args[0]->IsUndefined()) return False();
|
||||
|
||||
if (!args[0]->IsString()) {
|
||||
return scope.Close(Integer::New(4));
|
||||
}
|
||||
|
||||
String::Utf8Value s(args[0]->ToString());
|
||||
|
||||
// avoiding buffer overflows in the following strcat
|
||||
// 2001:0db8:85a3:08d3:1319:8a2e:0370:7334
|
||||
// 39 = max ipv6 address.
|
||||
if (s.length() > INET6_ADDRSTRLEN) return True();
|
||||
if (s.length() > INET6_ADDRSTRLEN) {
|
||||
return scope.Close(Integer::New(0));
|
||||
}
|
||||
|
||||
struct sockaddr_in6 a;
|
||||
|
||||
if (inet_pton(AF_INET, *s, &(a.sin6_addr)) > 0) return False();
|
||||
if (inet_pton(AF_INET6, *s, &(a.sin6_addr)) > 0) return False();
|
||||
if (inet_pton(AF_INET, *s, &(a.sin6_addr)) > 0) return scope.Close(Integer::New(4));
|
||||
if (inet_pton(AF_INET6, *s, &(a.sin6_addr)) > 0) return scope.Close(Integer::New(6));
|
||||
|
||||
char ipv6[255] = "::FFFF:";
|
||||
strcat(ipv6, *s);
|
||||
if (inet_pton(AF_INET6, ipv6, &(a.sin6_addr)) > 0) return False();
|
||||
|
||||
return True();
|
||||
return scope.Close(Integer::New(0));
|
||||
}
|
||||
|
||||
|
||||
@ -1291,7 +1288,7 @@ void InitNet2(Handle<Object> target) {
|
||||
NODE_SET_METHOD(target, "getsockname", GetSockName);
|
||||
NODE_SET_METHOD(target, "getpeername", GetPeerName);
|
||||
NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
|
||||
NODE_SET_METHOD(target, "needsLookup", NeedsLookup);
|
||||
NODE_SET_METHOD(target, "isIP", IsIP);
|
||||
NODE_SET_METHOD(target, "errnoException", CreateErrnoException);
|
||||
|
||||
target->Set(String::NewSymbol("ENOENT"), Integer::New(ENOENT));
|
||||
@ -1305,8 +1302,6 @@ void InitNet2(Handle<Object> target) {
|
||||
errno_symbol = NODE_PSYMBOL("errno");
|
||||
syscall_symbol = NODE_PSYMBOL("syscall");
|
||||
fd_symbol = NODE_PSYMBOL("fd");
|
||||
remote_address_symbol = NODE_PSYMBOL("remoteAddress");
|
||||
remote_port_symbol = NODE_PSYMBOL("remotePort");
|
||||
address_symbol = NODE_PSYMBOL("address");
|
||||
port_symbol = NODE_PSYMBOL("port");
|
||||
}
|
||||
|
@ -11,10 +11,12 @@ function pingPongTest (port, host, on_complete) {
|
||||
var server = net.createServer(function (socket) {
|
||||
assert.equal(true, socket.remoteAddress !== null);
|
||||
assert.equal(true, socket.remoteAddress !== undefined);
|
||||
if (host === "127.0.0.1")
|
||||
if (host === "127.0.0.1" || host === "localhost" || !host) {
|
||||
assert.equal(socket.remoteAddress, "127.0.0.1");
|
||||
else if (host == null)
|
||||
} else {
|
||||
puts('host = ' + host + ', remoteAddress = ' + socket.remoteAddress);
|
||||
assert.equal(socket.remoteAddress, "::1");
|
||||
}
|
||||
|
||||
socket.setEncoding("utf8");
|
||||
socket.setNoDelay();
|
||||
|
Loading…
x
Reference in New Issue
Block a user