Replace c-ares DNS with pure javascript implementation #3018

Closed
wants to merge 3 commits into
from
View
@@ -1,205 +1,96 @@
// Copyright Joyent, Inc. and other Node contributors.
//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// 'Software'), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
//
-// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var cares = process.binding('cares_wrap'),
- net = require('net'),
- isIp = net.isIP;
-
-
-function errnoException(errorno, syscall) {
- // TODO make this more compatible with ErrnoException from src/node.cc
- // Once all of Node is using this function the ErrnoException from
- // src/node.cc should be removed.
- var e = new Error(syscall + ' ' + errorno);
-
- // For backwards compatibility. libuv returns ENOENT on NXDOMAIN.
- if (errorno == 'ENOENT') {
- errorno = 'ENOTFOUND';
- }
-
- e.errno = e.code = errorno;
- e.syscall = syscall;
- return e;
-}
-
-
-// c-ares invokes a callback either synchronously or asynchronously,
-// but the dns API should always invoke a callback asynchronously.
-//
-// This function makes sure that the callback is invoked asynchronously.
-// It returns a function that invokes the callback within nextTick().
-//
-// To avoid invoking unnecessary nextTick(), `immediately` property of
-// returned function should be set to true after c-ares returned.
-//
-// Usage:
-//
-// function someAPI(callback) {
-// callback = makeAsync(callback);
-// channel.someAPI(..., callback);
-// callback.immediately = true;
-// }
-function makeAsync(callback) {
- if (typeof callback !== 'function') {
- return callback;
- }
- return function asyncCallback() {
- if (asyncCallback.immediately) {
- // The API already returned, we can invoke the callback immediately.
- callback.apply(null, arguments);
- } else {
- var args = arguments;
- process.nextTick(function() {
- callback.apply(null, args);
- });
- }
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE
+
+"use strict";
+
+exports.platform = require('dns_platform');
+
+exports.createServer = require('dns_server').createServer;
+exports.createUDPServer = require('dns_server').createUDPServer;
+exports.createTCPServer = require('dns_server').createTCPServer;
+
+var client = require('dns_client');
+exports.lookup = client.lookup;
+exports.resolve = client.resolve;
+exports.resolve4 = client.resolve4;
+exports.resolve6 = client.resolve6;
+exports.resolveMx = client.resolveMx;
+exports.resolveTxt = client.resolveTxt;
+exports.resolveSrv = client.resolveSrv;
+exports.resolveNs = client.resolveNs;
+exports.resolveCname = client.resolveCname;
+exports.reverse = client.reverse;
+
+var consts = require('dns_consts');
+exports.BADNAME = consts.BADNAME;
+exports.BADRESP = consts.BADRESP;
+exports.CONNREFUSED = consts.CONNREFUSED;
+exports.DESTRUCTION = consts.DESTRUCTION;
+exports.REFUSED = consts.REFUSED;
+exports.FORMERR = consts.FORMERR;
+exports.NODATA = consts.NODATA;
+exports.NOMEM = consts.NOMEM;
+exports.NOTFOUND = consts.NOTFOUND;
+exports.NOTIMP = consts.NOTIMP;
+exports.SERVFAIL = consts.SERVFAIL;
+exports.TIMEOUT = consts.TIMEOUT;
+exports.consts = consts;
+
+var types = require('dns_types');
+
+var createType = function(name) {
+ exports[name] = function (vals) {
+ return new types.exported[name](vals);
};
-}
-
-
-// Easy DNS A/AAAA look up
-// lookup(domain, [family,] callback)
-exports.lookup = function(domain, family, callback) {
- // parse arguments
- if (arguments.length === 2) {
- callback = family;
- family = 0;
- } else if (!family) {
- family = 0;
- } else {
- family = +family;
- if (family !== 4 && family !== 6) {
- throw new Error('invalid argument: `family` must be 4 or 6');
- }
- }
- callback = makeAsync(callback);
-
- if (!domain) {
- callback(null, null, family === 6 ? 6 : 4);
- return {};
- }
-
- // Hack required for Windows because Win7 removed the
- // localhost entry from c:\WINDOWS\system32\drivers\etc\hosts
- // See http://daniel.haxx.se/blog/2011/02/21/localhost-hack-on-windows/
- // TODO Remove this once c-ares handles this problem.
- if (process.platform == 'win32' && domain == 'localhost') {
- callback(null, '127.0.0.1', 4);
- return {};
- }
-
- var matchedFamily = net.isIP(domain);
- if (matchedFamily) {
- callback(null, domain, matchedFamily);
- return {};
- }
-
- function onanswer(addresses) {
- if (addresses) {
- if (family) {
- callback(null, addresses[0], family);
- } else {
- callback(null, addresses[0], addresses[0].indexOf(':') >= 0 ? 6 : 4);
- }
- } else {
- callback(errnoException(errno, 'getaddrinfo'));
- }
- }
-
- var wrap = cares.getaddrinfo(domain, family);
+};
- if (!wrap) {
- throw errnoException(errno, 'getaddrinfo');
+var n;
+for (n in types.exported) {
+ if (types.exported.hasOwnProperty(n)) {
+ createType(n);
}
+}
- wrap.oncomplete = onanswer;
-
- callback.immediately = true;
- return wrap;
+exports.registerType = function(name, fields) {
+ types.registerType(name, fields);
+ createType(name);
};
+var Question = require('dns_message').Question;
-function resolver(bindingName) {
- var binding = cares[bindingName];
+exports.Question = function (opts) {
+ var q = new Question(), qtype;
- return function query(name, callback) {
- function onanswer(status, result) {
- if (!status) {
- callback(null, result);
- } else {
- callback(errnoException(errno, bindingName));
- }
- }
+ q.name = opts.name;
- callback = makeAsync(callback);
- var wrap = binding(name, onanswer);
- if (!wrap) {
- throw errnoException(errno, bindingName);
- }
+ qtype = opts.type || consts.NAME_TO_QTYPE.A;
+ if (typeof(qtype) === 'string' || qtype instanceof String)
+ qtype = consts.nameToQtype(qtype.toUpperCase());
- callback.immediately = true;
- return wrap;
- }
-}
+ if (!qtype || typeof(qtype) !== 'number')
+ throw new Error("Question type must be defined and be valid");
+ q.type = qtype;
-var resolveMap = {};
-exports.resolve4 = resolveMap.A = resolver('queryA');
-exports.resolve6 = resolveMap.AAAA = resolver('queryAaaa');
-exports.resolveCname = resolveMap.CNAME = resolver('queryCname');
-exports.resolveMx = resolveMap.MX = resolver('queryMx');
-exports.resolveNs = resolveMap.NS = resolver('queryNs');
-exports.resolveTxt = resolveMap.TXT = resolver('queryTxt');
-exports.resolveSrv = resolveMap.SRV = resolver('querySrv');
-exports.reverse = resolveMap.PTR = resolver('getHostByAddr');
-
-
-exports.resolve = function(domain, type_, callback_) {
- var resolver, callback;
- if (typeof type_ == 'string') {
- resolver = resolveMap[type_];
- callback = callback_;
- } else {
- resolver = exports.resolve4;
- callback = type_;
- }
+ q.class = opts.class || consts.NAME_TO_QCLASS.IN;
- if (typeof resolver === 'function') {
- return resolver(domain, callback);
- } else {
- throw new Error('Unknown type "' + type + '"');
- }
+ return q;
};
-
-
-// ERROR CODES
-exports.BADNAME = 'EBADNAME';
-exports.BADRESP = 'EBADRESP';
-exports.CONNREFUSED = 'ECONNREFUSED';
-exports.DESTRUCTION = 'EDESTRUCTION';
-exports.REFUSED = 'EREFUSED';
-exports.FORMERR = 'EFORMERR';
-exports.NODATA = 'ENODATA';
-exports.NOMEM = 'ENOMEM';
-exports.NOTFOUND = 'ENOTFOUND';
-exports.NOTIMP = 'ENOTIMP';
-exports.SERVFAIL = 'ESERVFAIL';
-exports.TIMEOUT = 'ETIMEOUT';
+exports.Request = client.Request;
Oops, something went wrong.