diff options
author | Saúl Ibarra Corretgé <saghul@gmail.com> | 2014-06-21 00:43:00 +0200 |
---|---|---|
committer | Fedor Indutny <fedor@indutny.com> | 2014-06-27 04:02:19 +0400 |
commit | 35b9580cd84452dd76aa19715479a47074d1761b (patch) | |
tree | a21c03e8554a7033b2cff8bb389079ac6e8c0fa7 | |
parent | 922afd91649f0c356521356c57c6e04796a59cc0 (diff) | |
download | node-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.markdown | 11 | ||||
-rw-r--r-- | lib/dns.js | 32 | ||||
-rw-r--r-- | src/async-wrap.h | 3 | ||||
-rw-r--r-- | src/cares_wrap.cc | 66 | ||||
-rw-r--r-- | test/internet/test-dns.js | 38 |
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); |