From 2582560f913132deed61786cdaa9884aa6cb7980 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 30 Dec 2009 00:53:14 -0800 Subject: [PATCH] [net2] Do hostname lookups in connect and listen --- lib/net.js | 126 +++++++++++++++++++++++++++++---------------- src/node_net2.cc | 8 ++- test-net-server.js | 4 +- 3 files changed, 90 insertions(+), 48 deletions(-) diff --git a/lib/net.js b/lib/net.js index 32a6ec2b26..655a51f6fd 100644 --- a/lib/net.js +++ b/lib/net.js @@ -283,48 +283,55 @@ Socket.prototype.connect = function () { var self = this; if (self.fd) throw new Error('Socket already opened'); + function doConnect () { + try { + connect(self.fd, arguments[0], arguments[1]); + } catch (e) { + close(self.fd); + throw e; + } + + // Don't start the read watcher until connection is established + self.readWatcher.set(self.fd, true, false); + + // How to connect on POSIX: Wait for fd to become writable, then call + // socketError() if there isn't an error, we're connected. AFAIK this a + // platform independent way determining when a non-blocking connection + // is established, but I have only seen it documented in the Linux + // Manual Page connect(2) under the error code EINPROGRESS. + self.writeWatcher.set(self.fd, false, true); + self.writeWatcher.start(); + self.writeWatcher.callback = function () { + var errno = socketError(self.fd); + if (errno == 0) { + // connection established + self.readWatcher.start(); + self.readable = true; + self.writable = true; + self.writeWatcher.callback = self._doFlush; + self.emit('connect'); + } else if (errno != EINPROGRESS) { + var e = new Error('connection error'); + e.errno = errno; + self.forceClose(e); + } + }; + } + if (typeof(arguments[0]) == 'string' && arguments.length == 1) { self.fd = socket('unix'); self.type = 'unix'; // TODO check if sockfile exists? + doConnect(arguments[0]); } else { self.fd = socket('tcp'); self.type = 'tcp'; // TODO dns resolution on arguments[1] + var port = arguments[0]; + lookupDomainName(arguments[1], function (ip) { + doConnect(port, ip); + }); } - - try { - connect(self.fd, arguments[0], arguments[1]); - } catch (e) { - close(self.fd); - throw e; - } - - // Don't start the read watcher until connection is established - self.readWatcher.set(self.fd, true, false); - - // How to connect on POSIX: Wait for fd to become writable, then call - // socketError() if there isn't an error, we're connected. AFAIK this a - // platform independent way determining when a non-blocking connection - // is established, but I have only seen it documented in the Linux - // Manual Page connect(2) under the error code EINPROGRESS. - self.writeWatcher.set(self.fd, false, true); - self.writeWatcher.start(); - self.writeWatcher.callback = function () { - var errno = socketError(self.fd); - if (errno == 0) { - // connection established - self.readWatcher.start(); - self.readable = true; - self.writable = true; - self.writeWatcher.callback = self._doFlush; - self.emit('connect'); - } else if (errno != EINPROGRESS) { - var e = new Error('connection error'); - e.errno = errno; - self.forceClose(e); - } - }; }; @@ -387,6 +394,34 @@ 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. + */ +function lookupDomainName (dn, callback) { + if (!needsLookup(dn)) { + callback(dn); + } 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]); + } else { + debug("getaddrinfo 6 " + dn); + getaddrinfo(dn, 6, function (r6) { + if (r6 instanceof Error) throw r6; + if (r6.length < 0) { + throw new Error("No address associated with hostname " + dn); + } + debug("getaddrinfo 6 found " + r6); + callback(r6[0]); + }); + } + }); + } +} + // Listen on a UNIX socket // server.listen("/tmp/socket"); @@ -400,6 +435,13 @@ 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' && arguments.length == 1) { // the first argument specifies a path self.fd = socket('unix'); @@ -415,23 +457,17 @@ Server.prototype.listen = function () { self.type = 'tcp'; // Don't bind(). OS will assign a port with INADDR_ANY. The port will be // passed to the 'listening' event. + doListen(); } else { // the first argument is the port, the second an IP self.fd = socket('tcp'); self.type = 'tcp'; - if (needsLookup(arguments[1])) { - getaddrinfo(arguments[1], function (ip) { - }); - } - // TODO dns resolution on arguments[1] - bind(self.fd, arguments[0], arguments[1]); + var port = arguments[0]; + lookupDomainName(arguments[1], function (ip) { + bind(self.fd, port, ip); + doListen(); + }); } - - listen(self.fd, 128); - self.emit("listening"); - - self.watcher.set(self.fd, true, false); - self.watcher.start(); }; diff --git a/src/node_net2.cc b/src/node_net2.cc index 0d4bb6f1f3..2d7c6c2afb 100644 --- a/src/node_net2.cc +++ b/src/node_net2.cc @@ -559,7 +559,13 @@ static int AfterResolve(eio_req *req) { Local argv[1]; if (req->result != 0) { - argv[0] = ErrnoException(errno, "getaddrinfo"); + if (req->result == EAI_NODATA) { + argv[0] = Array::New(); + } else { + argv[0] = ErrnoException(req->result, + "getaddrinfo", + gai_strerror(req->result)); + } } else { struct addrinfo *address; int n = 0; diff --git a/test-net-server.js b/test-net-server.js index 114cb67a85..8b3ce9d14c 100644 --- a/test-net-server.js +++ b/test-net-server.js @@ -28,11 +28,11 @@ var server = new net.Server(function (socket) { sys.puts("server-side socket drain"); }); }); -server.listen(8000); +server.listen(8000, "localhost"); sys.puts("server fd: " + server.fd); -var c = net.createConnection(8000); +var c = net.createConnection(8000, "localhost"); c.addListener('connect', function () { sys.puts("!!!client connected"); c.send("hello\n");