Browse Source

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>
archived-io.js-v0.10
Saúl Ibarra Corretgé 11 years ago
committed by Fedor Indutny
parent
commit
35b9580cd8
No known key found for this signature in database GPG Key ID: FB0E1095B1797999
  1. 11
      doc/api/dns.markdown
  2. 32
      lib/dns.js
  3. 3
      src/async-wrap.h
  4. 66
      src/cares_wrap.cc
  5. 38
      test/internet/test-dns.js

11
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

32
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));

3
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,

66
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);

38
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);

Loading…
Cancel
Save