|
|
@ -21,8 +21,11 @@ |
|
|
|
|
|
|
|
#include <assert.h> |
|
|
|
#include <node.h> |
|
|
|
#include <req_wrap.h> |
|
|
|
#include <uv.h> |
|
|
|
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
#if defined(__OpenBSD__) || defined(__MINGW32__) || defined(_MSC_VER) |
|
|
|
# include <nameser.h> |
|
|
|
#else |
|
|
@ -63,6 +66,9 @@ using v8::Persistent; |
|
|
|
using v8::String; |
|
|
|
using v8::Value; |
|
|
|
|
|
|
|
|
|
|
|
typedef class ReqWrap<uv_getaddrinfo_t> GetAddrInfoReqWrap; |
|
|
|
|
|
|
|
static Persistent<String> oncomplete_sym; |
|
|
|
|
|
|
|
static ares_channel ares_channel; |
|
|
@ -592,6 +598,104 @@ static Handle<Value> QueryWithFamily(const Arguments& args) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
GetAddrInfoReqWrap* req_wrap = (GetAddrInfoReqWrap*) req->data; |
|
|
|
|
|
|
|
Local<Value> argv[1]; |
|
|
|
|
|
|
|
if (status) { |
|
|
|
// Error
|
|
|
|
SetErrno(uv_last_error(uv_default_loop())); |
|
|
|
argv[0] = Local<Value>::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<Array> 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<String> 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<Value> 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<Object> target) { |
|
|
|
HandleScope scope; |
|
|
|
int r; |
|
|
@ -613,6 +717,8 @@ static void Initialize(Handle<Object> target) { |
|
|
|
NODE_SET_METHOD(target, "getHostByAddr", Query<GetHostByAddrWrap>); |
|
|
|
NODE_SET_METHOD(target, "getHostByName", QueryWithFamily<GetHostByNameWrap>); |
|
|
|
|
|
|
|
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)); |
|
|
|