You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

370 lines
10 KiB

  1. #include "dns_parser.h"
  2. #include <node.h>
  3. #include <v8.h>
  4. #include <ares.h>
  5. #include <ares_dns.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netdb.h>
  9. #include <string.h>
  10. #include <arpa/nameser.h>
  11. #include <arpa/inet.h>
  12. #ifdef __OpenBSD__
  13. # ifndef ns_t_a
  14. # include <nameser.h>
  15. # endif
  16. #endif // __OpenBSD__
  17. namespace ares {
  18. class Channel : public node::ObjectWrap {
  19. public:
  20. Channel();
  21. virtual ~Channel();
  22. static void Initialize(v8::Handle<v8::Object> target);
  23. private:
  24. static v8::Persistent<v8::FunctionTemplate> constructor_template;
  25. static v8::Handle<v8::Value> New(const v8::Arguments& args);
  26. static v8::Handle<v8::Value> Query(const v8::Arguments& args);
  27. static v8::Handle<v8::Value> SetServers(const v8::Arguments& args);
  28. static v8::Handle<v8::Value> Timeout(const v8::Arguments& args);
  29. static v8::Handle<v8::Value> ProcessFD(const v8::Arguments& args);
  30. ares_channel channel;
  31. static void SockStateCb(void *data, int sock, int read, int write);
  32. static void QueryCb(void *arg, int status, int timeouts, unsigned char* abuf, int alen);
  33. struct ares_addr_node *servers;
  34. };
  35. v8::Persistent<v8::FunctionTemplate> Channel::constructor_template;
  36. static v8::Persistent<v8::String> callback_symbol;
  37. static void Initialize(v8::Handle<v8::Object> target) {
  38. v8::HandleScope scope;
  39. int r = ares_library_init(ARES_LIB_INIT_ALL);
  40. if (0 != r) {
  41. // TODO
  42. // ThrowException(Exception::Error(String::New(ares_strerror(r))));
  43. assert(r == 0);
  44. }
  45. target->Set(v8::String::NewSymbol("SOCKET_BAD"), v8::Integer::New(ARES_SOCKET_BAD));
  46. target->Set(v8::String::NewSymbol("AF_INET"), v8::Integer::New(AF_INET));
  47. target->Set(v8::String::NewSymbol("AF_INET6"), v8::Integer::New(AF_INET6));
  48. target->Set(v8::String::NewSymbol("NODATA"), v8::Integer::New(ARES_ENODATA));
  49. target->Set(v8::String::NewSymbol("FORMERR"), v8::Integer::New(ARES_EFORMERR));
  50. target->Set(v8::String::NewSymbol("BADRESP"), v8::Integer::New(ARES_EBADRESP));
  51. target->Set(v8::String::NewSymbol("NOTFOUND"), v8::Integer::New(ARES_ENOTFOUND));
  52. target->Set(v8::String::NewSymbol("BADNAME"), v8::Integer::New(ARES_EBADNAME));
  53. target->Set(v8::String::NewSymbol("TIMEOUT"), v8::Integer::New(ARES_ETIMEOUT));
  54. target->Set(v8::String::NewSymbol("CONNREFUSED"), v8::Integer::New(ARES_ECONNREFUSED));
  55. target->Set(v8::String::NewSymbol("NOMEM"), v8::Integer::New(ARES_ENOMEM));
  56. target->Set(v8::String::NewSymbol("DESTRUCTION"), v8::Integer::New(ARES_EDESTRUCTION));
  57. // Only occur if the ARES_FLAG_NOCHECKRESP flag was specified
  58. target->Set(v8::String::NewSymbol("NOTIMP"), v8::Integer::New(ARES_ENOTIMP));
  59. target->Set(v8::String::NewSymbol("EREFUSED"), v8::Integer::New(ARES_EREFUSED));
  60. target->Set(v8::String::NewSymbol("SERVFAIL"), v8::Integer::New(ARES_ESERVFAIL));
  61. Channel::Initialize(target);
  62. }
  63. void Channel::Initialize(v8::Handle<v8::Object> target) {
  64. v8::HandleScope scope;
  65. v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(Channel::New);
  66. constructor_template = v8::Persistent<v8::FunctionTemplate>::New(t);
  67. constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
  68. constructor_template->SetClassName(v8::String::NewSymbol("Channel"));
  69. using namespace v8;
  70. NODE_SET_PROTOTYPE_METHOD(constructor_template, "query", Channel::Query);
  71. NODE_SET_PROTOTYPE_METHOD(constructor_template, "timeout", Channel::Timeout);
  72. NODE_SET_PROTOTYPE_METHOD(constructor_template, "processFD", Channel::ProcessFD);
  73. NODE_SET_PROTOTYPE_METHOD(constructor_template, "setServers", Channel::SetServers);
  74. target->Set(v8::String::NewSymbol("Channel"), constructor_template->GetFunction());
  75. callback_symbol = NODE_PSYMBOL("callback");
  76. }
  77. Channel::Channel() : servers(0) {
  78. }
  79. Channel::~Channel() {
  80. delete [] servers;
  81. }
  82. v8::Handle<v8::Value> Channel::New(const v8::Arguments& args) {
  83. v8::HandleScope scope;
  84. struct ares_options options;
  85. int optmask = 0;
  86. Channel *c = new Channel();
  87. c->Wrap(args.This());
  88. if (args.Length() > 0) {
  89. if(!args[0]->IsObject()) {
  90. return v8::ThrowException(v8::Exception::TypeError(
  91. v8::String::New("Bad Options Argument")));
  92. }
  93. v8::Local<v8::Object> options_o = v8::Local<v8::Object>::Cast(args[0]);
  94. v8::Local<v8::Value> cb = options_o->Get(v8::String::NewSymbol("SOCK_STATE_CB"));
  95. if (!cb.IsEmpty()) {
  96. c->handle_->Set(callback_symbol, cb);
  97. options.sock_state_cb_data = c;
  98. options.sock_state_cb = Channel::SockStateCb;
  99. optmask |= ARES_OPT_SOCK_STATE_CB;
  100. }
  101. }
  102. ares_init_options(&c->channel, &options, optmask);
  103. return args.This();
  104. }
  105. v8::Handle<v8::Value> Channel::Query(const v8::Arguments& args) {
  106. v8::HandleScope scope;
  107. Channel *c = node::ObjectWrap::Unwrap<Channel>(args.Holder());
  108. assert(c);
  109. if (!args[0]->IsString()) {
  110. return v8::ThrowException(v8::Exception::TypeError(
  111. v8::String::New("First argument must be a name")));
  112. }
  113. if (!args[1]->IsInt32()) {
  114. return v8::ThrowException(v8::Exception::TypeError(
  115. v8::String::New("Second argument must be a query type!!")));
  116. }
  117. if (!args[2]->IsFunction()) {
  118. return v8::ThrowException(v8::Exception::TypeError(
  119. v8::String::New("Third argument must be a callback")));
  120. }
  121. v8::String::Utf8Value name(args[0]->ToString());
  122. int type = args[1]->Int32Value();
  123. ares_query(c->channel, *name, ns_c_in, type, QueryCb, node::cb_persist(args[2]));
  124. return v8::Undefined();
  125. }
  126. v8::Handle<v8::Value> Channel::Timeout(const v8::Arguments& args) {
  127. v8::HandleScope scope;
  128. Channel *c = ObjectWrap::Unwrap<Channel>(args.Holder());
  129. assert(c);
  130. if (!args[0]->IsInt32()) {
  131. return v8::ThrowException(v8::Exception::Error(
  132. v8::String::New("First argument must be an integer number of milliseconds")));
  133. }
  134. struct timeval tvbuf, maxtv, *ret;
  135. int64_t time = args[0]->IntegerValue();
  136. maxtv.tv_sec = time/1000;
  137. maxtv.tv_usec = (time % 1000) * 1000;
  138. ret = ares_timeout(c->channel, (time > 0) ? &maxtv : NULL, &tvbuf);
  139. return scope.Close(v8::Integer::New(ret ? ret->tv_sec * 1000 + ret->tv_usec / 1000 : -1));
  140. }
  141. v8::Handle<v8::Value> Channel::ProcessFD(const v8::Arguments& args) {
  142. v8::HandleScope scope;
  143. Channel *c = ObjectWrap::Unwrap<Channel>(args.Holder());
  144. assert(c);
  145. int read_fd, write_fd;
  146. if (!args[0]->IsInt32()) {
  147. return v8::ThrowException(v8::Exception::Error(
  148. v8::String::New("First argument must be a file descriptor or SOCKET_BAD")));
  149. }
  150. read_fd = args[0]->Int32Value();
  151. if (args.Length() > 1) {
  152. if (!args[1]->IsInt32()) {
  153. return v8::ThrowException(v8::Exception::Error(
  154. v8::String::New("Second argument must be a file descriptor or SOCKET_BAD")));
  155. }
  156. write_fd = args[1]->Int32Value();
  157. } else {
  158. write_fd = ARES_SOCKET_BAD;
  159. }
  160. ares_process_fd(c->channel, read_fd, write_fd);
  161. return v8::Undefined();
  162. }
  163. static bool parse_addr(v8::Handle<v8::Value> v, ares_addr_node &a) {
  164. memset(&a, 0, sizeof(a));
  165. if (!v->IsString()) return false;
  166. v8::String::Utf8Value s(v->ToString());
  167. // avoiding buffer overflows in the following strcat
  168. // 2001:0db8:85a3:08d3:1319:8a2e:0370:7334
  169. // 39 = max ipv6 address.
  170. if (s.length() > INET6_ADDRSTRLEN) return false;
  171. if (inet_pton(AF_INET, *s, &(a.addr.addr4)) > 0) {
  172. a.family = AF_INET;
  173. return true;
  174. }
  175. if (inet_pton(AF_INET6, *s, &(a.addr.addr6)) > 0) {
  176. a.family = AF_INET6;
  177. return true;
  178. }
  179. return false;
  180. }
  181. v8::Handle<v8::Value> Channel::SetServers(const v8::Arguments& args) {
  182. int status;
  183. v8::HandleScope scope;
  184. Channel *c = node::ObjectWrap::Unwrap<Channel>(args.Holder());
  185. assert(c);
  186. if (args.Length() == 0) {
  187. status = ares_set_servers(c->channel, NULL);
  188. if (ARES_SUCCESS != status) return v8::ThrowException(dns_parser::AresException(status));
  189. delete [] c->servers;
  190. c->servers = 0;
  191. return v8::Undefined();
  192. }
  193. if (args[0]->IsString()) {
  194. ares_addr_node *servers = new ares_addr_node[args.Length()];
  195. for (int i = 0, l = args.Length(); i < l; i++) {
  196. if (i > 0) servers[i-1].next = &servers[i];
  197. if (!parse_addr(args[i], servers[i])) {
  198. return v8::ThrowException(v8::Exception::Error(
  199. v8::String::New("Arguments must be strings with valid IP addresses")));
  200. }
  201. }
  202. status = ares_set_servers(c->channel, servers);
  203. if (ARES_SUCCESS != status) return v8::ThrowException(dns_parser::AresException(status));
  204. return v8::Undefined();
  205. }
  206. if (args[0]->IsArray()) {
  207. v8::Local<v8::Array> a = v8::Local<v8::Array>::Cast(args[0]);
  208. if (args.Length() == 0) {
  209. status = ares_set_servers(c->channel, NULL);
  210. if (ARES_SUCCESS != status) return v8::ThrowException(dns_parser::AresException(status));
  211. delete [] c->servers;
  212. c->servers = 0;
  213. return v8::Undefined();
  214. }
  215. ares_addr_node *servers = new ares_addr_node[args.Length()];
  216. for (int i = 0, l = a->Length(); i < l; i++) {
  217. if (i > 0) servers[i-1].next = &servers[i];
  218. if (!parse_addr(a->Get(i), servers[i])) {
  219. return v8::ThrowException(v8::Exception::Error(
  220. v8::String::New("Arguments must be strings with valid IP addresses")));
  221. }
  222. }
  223. status = ares_set_servers(c->channel, servers);
  224. if (ARES_SUCCESS != status) return v8::ThrowException(dns_parser::AresException(status));
  225. return v8::Undefined();
  226. }
  227. return v8::ThrowException(v8::Exception::Error(
  228. v8::String::New("Arguments must be strings with valid IP addresses")));
  229. }
  230. void Channel::SockStateCb(void *data, int sock, int read, int write) {
  231. Channel *c = static_cast<Channel*>(data);
  232. v8::HandleScope scope;
  233. v8::Local<v8::Value> callback_v = c->handle_->Get(callback_symbol);
  234. if (!callback_v->IsFunction()) return;
  235. v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(callback_v);
  236. v8::Local<v8::Value> argv[3];
  237. argv[0] = v8::Integer::New(sock);
  238. argv[1] = v8::Integer::New(read);
  239. argv[2] = v8::Integer::New(write);
  240. v8::TryCatch try_catch;
  241. callback->Call(c->handle_, 3, argv);
  242. if (try_catch.HasCaught()) {
  243. node::FatalException(try_catch);
  244. }
  245. }
  246. void Channel::QueryCb(void *arg, int status, int timeouts, unsigned char* abuf, int alen) {
  247. v8::HandleScope scope;
  248. v8::Persistent<v8::Function> *cb = node::cb_unwrap(arg);
  249. v8::Local<v8::Value> result;
  250. if (status != ARES_SUCCESS && 0 == alen) {
  251. result = dns_parser::AresException(status);
  252. } else {
  253. result = dns_parser::parse_dns_response(abuf, alen, &status);
  254. }
  255. v8::TryCatch try_catch;
  256. if (status != ARES_SUCCESS) {
  257. (*cb)->Call(v8::Context::GetCurrent()->Global(), 1, &result);
  258. } else {
  259. v8::Local<v8::Value> argv[2] = { v8::Local<v8::Value>::New(v8::Null()), result };
  260. (*cb)->Call(v8::Context::GetCurrent()->Global(), 2, argv);
  261. }
  262. node::cb_destroy(cb);
  263. if (try_catch.HasCaught()) {
  264. node::FatalException(try_catch);
  265. }
  266. }
  267. } // namespace ares
  268. extern "C" void
  269. init (v8::Handle<v8::Object> target) {
  270. v8::HandleScope scope;
  271. ares::Initialize(target);
  272. dns_parser::Initialize(target);
  273. }