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>
This commit is contained in:
parent
922afd9164
commit
35b9580cd8
@ -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
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));
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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…
x
Reference in New Issue
Block a user