summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaúl Ibarra Corretgé <saghul@gmail.com>2014-06-21 00:43:00 +0200
committerFedor Indutny <fedor@indutny.com>2014-06-27 04:02:19 +0400
commit35b9580cd84452dd76aa19715479a47074d1761b (patch)
treea21c03e8554a7033b2cff8bb389079ac6e8c0fa7
parent922afd91649f0c356521356c57c6e04796a59cc0 (diff)
downloadnode-new-35b9580cd84452dd76aa19715479a47074d1761b.tar.gz
dns: introduce lookupService function
Uses getnameinfo to resolve an address an port into a hostname and service. Signed-off-by: Fedor Indutny <fedor@indutny.com>
-rw-r--r--doc/api/dns.markdown11
-rw-r--r--lib/dns.js32
-rw-r--r--src/async-wrap.h3
-rw-r--r--src/cares_wrap.cc66
-rw-r--r--test/internet/test-dns.js38
5 files changed, 149 insertions, 1 deletions
diff --git a/doc/api/dns.markdown b/doc/api/dns.markdown
index 0221a7e5c0..94e19a3f72 100644
--- a/doc/api/dns.markdown
+++ b/doc/api/dns.markdown
@@ -49,6 +49,17 @@ the hostname does not exist but also when the lookup fails in other ways
such as no available file descriptors.
+# dns.lookupService(address, port, callback)
+
+Resolves the given address and port into a hostname and service using
+`getnameinfo`.
+
+The callback has arguments `(err, hostname, service)`. The `hostname` and
+`service` arguments are strings (e.g. `'localhost'` and `'http'` respectively).
+
+On error, `err` is an `Error` object, where `err.code` is the error code.
+
+
## dns.resolve(hostname, [rrtype], callback)
Resolves a hostname (e.g. `'google.com'`) into an array of the record types
diff --git a/lib/dns.js b/lib/dns.js
index 9634ea1c0a..f1b63a1f65 100644
--- a/lib/dns.js
+++ b/lib/dns.js
@@ -144,6 +144,38 @@ exports.lookup = function(hostname, family, callback) {
};
+function onlookupservice(err, host, service) {
+ if (err)
+ return this.callback(errnoException(err, 'getnameinfo', this.host));
+
+ this.callback(null, host, service);
+}
+
+
+// lookupService(address, port, callback)
+exports.lookupService = function(host, port, callback) {
+ if (arguments.length !== 3)
+ throw new Error('invalid arguments');
+
+ if (cares.isIP(host) === 0)
+ throw new TypeError('host needs to be a valid IP address');
+
+ callback = makeAsync(callback);
+
+ var req = {
+ callback: callback,
+ host: host,
+ port: port,
+ oncomplete: onlookupservice
+ };
+ var err = cares.getnameinfo(req, host, port);
+ if (err) throw errnoException(err, 'getnameinfo', host);
+
+ callback.immediately = true;
+ return req;
+};
+
+
function onresolve(err, result) {
if (err)
this.callback(errnoException(err, this.bindingName, this.hostname));
diff --git a/src/async-wrap.h b/src/async-wrap.h
index 3f48290ed8..1b1802a68f 100644
--- a/src/async-wrap.h
+++ b/src/async-wrap.h
@@ -53,7 +53,8 @@ class AsyncWrap : public BaseObject {
PROVIDER_TLSWRAP = 1 << 14,
PROVIDER_TTYWRAP = 1 << 15,
PROVIDER_UDPWRAP = 1 << 16,
- PROVIDER_ZLIB = 1 << 17
+ PROVIDER_ZLIB = 1 << 17,
+ PROVIDER_GETNAMEINFOREQWRAP = 1 << 18
};
inline AsyncWrap(Environment* env,
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index 5e8aa25921..7523e9df65 100644
--- a/src/cares_wrap.cc
+++ b/src/cares_wrap.cc
@@ -65,6 +65,7 @@ using v8::String;
using v8::Value;
typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap;
+typedef class ReqWrap<uv_getnameinfo_t> GetNameInfoReqWrap;
static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
@@ -958,6 +959,37 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
}
+void AfterGetNameInfo(uv_getnameinfo_t* req,
+ int status,
+ const char* hostname,
+ const char* service) {
+ GetNameInfoReqWrap* req_wrap = static_cast<GetNameInfoReqWrap*>(req->data);
+ Environment* env = req_wrap->env();
+
+ HandleScope handle_scope(env->isolate());
+ Context::Scope context_scope(env->context());
+
+ Local<Value> argv[] = {
+ Integer::New(env->isolate(), status),
+ Null(env->isolate()),
+ Null(env->isolate())
+ };
+
+ if (status == 0) {
+ // Success
+ Local<String> js_hostname = OneByteString(env->isolate(), hostname);
+ Local<String> js_service = OneByteString(env->isolate(), service);
+ argv[1] = js_hostname;
+ argv[2] = js_service;
+ }
+
+ // Make the callback into JavaScript
+ req_wrap->MakeCallback(env->oncomplete_string(), ARRAY_SIZE(argv), argv);
+
+ delete req_wrap;
+}
+
+
static void IsIP(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate());
@@ -1025,6 +1057,39 @@ static void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
}
+static void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
+ HandleScope handle_scope(env->isolate());
+
+ CHECK(args[0]->IsObject());
+ CHECK(args[1]->IsString());
+ CHECK(args[2]->IsUint32());
+ Local<Object> req_wrap_obj = args[0].As<Object>();
+ node::Utf8Value ip(args[1]);
+ const unsigned port = args[2]->Uint32Value();
+ struct sockaddr_storage addr;
+
+ CHECK(uv_ip4_addr(*ip, port, reinterpret_cast<sockaddr_in*>(&addr)) == 0 ||
+ uv_ip6_addr(*ip, port, reinterpret_cast<sockaddr_in6*>(&addr)) == 0);
+
+ GetNameInfoReqWrap* req_wrap =
+ new GetNameInfoReqWrap(env,
+ req_wrap_obj,
+ AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP);
+
+ int err = uv_getnameinfo(env->event_loop(),
+ &req_wrap->req_,
+ AfterGetNameInfo,
+ (struct sockaddr*)&addr,
+ NI_NAMEREQD);
+ req_wrap->Dispatched();
+ if (err)
+ delete req_wrap;
+
+ args.GetReturnValue().Set(err);
+}
+
+
static void GetServers(const FunctionCallbackInfo<Value>& args) {
HandleScope handle_scope(args.GetIsolate());
Environment* env = Environment::GetCurrent(args.GetIsolate());
@@ -1168,6 +1233,7 @@ static void Initialize(Handle<Object> target,
NODE_SET_METHOD(target, "getHostByAddr", Query<GetHostByAddrWrap>);
NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
+ NODE_SET_METHOD(target, "getnameinfo", GetNameInfo);
NODE_SET_METHOD(target, "isIP", IsIP);
NODE_SET_METHOD(target, "strerror", StrError);
diff --git a/test/internet/test-dns.js b/test/internet/test-dns.js
index d3f95429ad..0c5e436502 100644
--- a/test/internet/test-dns.js
+++ b/test/internet/test-dns.js
@@ -431,6 +431,44 @@ TEST(function test_lookup_localhost_ipv4(done) {
});
+TEST(function test_lookupservice_ip_ipv4(done) {
+ var req = dns.lookupService('127.0.0.1', 80, function(err, host, service) {
+ if (err) throw err;
+ assert.strictEqual(host, 'localhost');
+ assert.strictEqual(service, 'http');
+
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
+TEST(function test_lookupservice_ip_ipv6(done) {
+ var req = dns.lookupService('::1', 80, function(err, host, service) {
+ if (err) throw err;
+ assert.strictEqual(host, 'localhost');
+ assert.strictEqual(service, 'http');
+
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
+TEST(function test_lookupservice_invalid(done) {
+ var req = dns.lookupService('1.2.3.4', 80, function(err, host, service) {
+ assert(err instanceof Error);
+ assert.strictEqual(err.code, 'ENOTFOUND');
+
+ done();
+ });
+
+ checkWrap(req);
+});
+
+
TEST(function test_reverse_failure(done) {
var req = dns.reverse('0.0.0.0', function(err) {
assert(err instanceof Error);