From be2320d408de89054b254a0c812280054d946490 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 20 Oct 2011 15:06:53 -0700 Subject: [PATCH] Add binding to uv_getaddrinfo --- src/cares_wrap.cc | 106 ++++++++++++++++++++++++++++++++++++++ test/internet/test-dns.js | 32 +++++++++--- 2 files changed, 130 insertions(+), 8 deletions(-) diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 6a6810cff5b..8e723bb46a0 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -21,8 +21,11 @@ #include #include +#include #include +#include + #if defined(__OpenBSD__) || defined(__MINGW32__) || defined(_MSC_VER) # include #else @@ -63,6 +66,9 @@ using v8::Persistent; using v8::String; using v8::Value; + +typedef class ReqWrap GetAddrInfoReqWrap; + static Persistent oncomplete_sym; static ares_channel ares_channel; @@ -592,6 +598,104 @@ static Handle QueryWithFamily(const Arguments& args) { } +void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { + HandleScope scope; + + GetAddrInfoReqWrap* req_wrap = (GetAddrInfoReqWrap*) req->data; + + Local argv[1]; + + if (status) { + // Error + SetErrno(uv_last_error(uv_default_loop())); + argv[0] = Local::New(Null()); + } else { + // Success + struct addrinfo *address; + int n = 0; + + // Count the number of responses. + for (address = res; address; address = address->ai_next) { + n++; + } + + // Create the response array. + Local results = Array::New(n); + + char ip[INET6_ADDRSTRLEN]; + const char *addr; + + n = 0; + + // Iterate over the responses again this time creating javascript + // strings for each IP and filling the results array. + address = res; + while (address) { + assert(address->ai_socktype == SOCK_STREAM); + assert(address->ai_family == AF_INET || address->ai_family == AF_INET6); + + // Juggle pointers + addr = (address->ai_family == AF_INET ? + (char*) &((struct sockaddr_in*) address->ai_addr)->sin_addr : + (char*) &((struct sockaddr_in6*) address->ai_addr)->sin6_addr); + const char* c = inet_ntop(address->ai_family, addr, ip, INET6_ADDRSTRLEN); + + // Create JavaScript string + Local s = String::New(c); + results->Set(n, s); + + // Increment + n++; + address = address->ai_next; + } + + argv[0] = results; + } + + uv_freeaddrinfo(res); + + // Make the callback into JavaScript + MakeCallback(req_wrap->object_, "oncomplete", 1, argv); + + delete req_wrap; +} + + +static Handle GetAddrInfo(const Arguments& args) { + HandleScope scope; + + String::Utf8Value hostname(args[0]->ToString()); + + int fam = AF_INET; + if (args[1]->IsInt32() && args[1]->Int32Value() == 6) { + fam = AF_INET6; + } + + GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(); + + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = fam; + hints.ai_socktype = SOCK_STREAM; + + int r = uv_getaddrinfo(uv_default_loop(), + &req_wrap->req_, + AfterGetAddrInfo, + *hostname, + NULL, + &hints); + req_wrap->Dispatched(); + + if (r) { + SetErrno(uv_last_error(uv_default_loop())); + delete req_wrap; + return scope.Close(v8::Null()); + } else { + return scope.Close(req_wrap->object_); + } +} + + static void Initialize(Handle target) { HandleScope scope; int r; @@ -613,6 +717,8 @@ static void Initialize(Handle target) { NODE_SET_METHOD(target, "getHostByAddr", Query); NODE_SET_METHOD(target, "getHostByName", QueryWithFamily); + NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo); + target->Set(String::NewSymbol("AF_INET"), Integer::New(AF_INET)); target->Set(String::NewSymbol("AF_INET6"), Integer::New(AF_INET6)); target->Set(String::NewSymbol("AF_UNSPEC"), Integer::New(AF_UNSPEC)); diff --git a/test/internet/test-dns.js b/test/internet/test-dns.js index ea5f132e3e1..095b47ad664 100644 --- a/test/internet/test-dns.js +++ b/test/internet/test-dns.js @@ -21,7 +21,7 @@ var assert = require('assert'), dns = require('dns'), - net = require('net_uv'), + net = require('net'), isIP = net.isIP, isIPv4 = net.isIPv4, isIPv6 = net.isIPv6; @@ -57,13 +57,6 @@ function TEST(f) { } -process.on('exit', function() { - console.log(completed + ' tests completed'); - assert.equal(running, false); - assert.strictEqual(expected, completed); -}); - - function checkWrap(req) { assert.ok(typeof req === 'object'); } @@ -386,3 +379,26 @@ TEST(function test_lookup_localhost_ipv4(done) { checkWrap(req); }); */ + + +var getaddrinfoCallbackCalled = false; + +console.log("looking up nodejs.org..."); +var req = process.binding('cares_wrap').getaddrinfo('nodejs.org'); + +req.oncomplete = function(domains) { + console.log("nodejs.org = ", domains); + assert.ok(Array.isArray(domains)); + assert.ok(domains.length >= 1); + assert.ok(typeof domains[0] == 'string'); + getaddrinfoCallbackCalled = true; +}; + + + +process.on('exit', function() { + console.log(completed + ' tests completed'); + assert.equal(running, false); + assert.strictEqual(expected, completed); + assert.ok(getaddrinfoCallbackCalled); +});